blob: 6e28e5afa220abaa602c494e32e2b68fc9136399 [file] [log] [blame]
jcgregorio2d66d4f2006-02-07 05:34:14 +00001#!/usr/bin/env python2.4
2"""
3httplib2test
4
5A set of unit tests for httplib2.py.
6
7Requires Python 2.4 or later
8"""
9
10__author__ = "Joe Gregorio (joe@bitworking.org)"
11__copyright__ = "Copyright 2006, Joe Gregorio"
12__contributors__ = []
13__license__ = "MIT"
14__history__ = """ """
15__version__ = "0.1 ($Rev: 118 $)"
16
17
Joe Gregoriob6c90c42011-02-11 01:03:22 -050018import StringIO
19import base64
jcgregoriode8238d2007-03-07 19:08:26 +000020import httplib
21import httplib2
22import os
Joe Gregoriob6c90c42011-02-11 01:03:22 -050023import socket
24import sys
jcgregoriode8238d2007-03-07 19:08:26 +000025import time
Joe Gregoriob6c90c42011-02-11 01:03:22 -050026import unittest
27import urlparse
jcgregorio8421f272006-02-14 18:19:51 +000028
Joe Gregoriob53de9b2011-06-07 15:44:51 -040029try:
30 import ssl
31except ImportError:
32 pass
Joe Gregorio694a8122011-02-13 21:40:09 -050033
jcgregorio8421f272006-02-14 18:19:51 +000034# Python 2.3 support
35if not hasattr(unittest.TestCase, 'assertTrue'):
36 unittest.TestCase.assertTrue = unittest.TestCase.failUnless
37 unittest.TestCase.assertFalse = unittest.TestCase.failIf
38
jcgregorio2d66d4f2006-02-07 05:34:14 +000039# The test resources base uri
40base = 'http://bitworking.org/projects/httplib2/test/'
41#base = 'http://localhost/projects/httplib2/test/'
jcgregorio90fb4a42006-11-17 16:19:47 +000042cacheDirName = ".cache"
jcgregorio2d66d4f2006-02-07 05:34:14 +000043
jcgregoriode8238d2007-03-07 19:08:26 +000044
45class CredentialsTest(unittest.TestCase):
46 def test(self):
47 c = httplib2.Credentials()
48 c.add("joe", "password")
49 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
50 self.assertEqual(("joe", "password"), list(c.iter(""))[0])
51 c.add("fred", "password2", "wellformedweb.org")
52 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
53 self.assertEqual(1, len(list(c.iter("bitworking.org"))))
54 self.assertEqual(2, len(list(c.iter("wellformedweb.org"))))
55 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
56 c.clear()
57 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
58 c.add("fred", "password2", "wellformedweb.org")
59 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
60 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
61 self.assertEqual(0, len(list(c.iter(""))))
62
63
jcgregorio2d66d4f2006-02-07 05:34:14 +000064class ParserTest(unittest.TestCase):
65 def testFromStd66(self):
66 self.assertEqual( ('http', 'example.com', '', None, None ), httplib2.parse_uri("http://example.com"))
67 self.assertEqual( ('https', 'example.com', '', None, None ), httplib2.parse_uri("https://example.com"))
68 self.assertEqual( ('https', 'example.com:8080', '', None, None ), httplib2.parse_uri("https://example.com:8080"))
69 self.assertEqual( ('http', 'example.com', '/', None, None ), httplib2.parse_uri("http://example.com/"))
70 self.assertEqual( ('http', 'example.com', '/path', None, None ), httplib2.parse_uri("http://example.com/path"))
71 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', None ), httplib2.parse_uri("http://example.com/path?a=1&b=2"))
72 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
73 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
74
jcgregorio2d66d4f2006-02-07 05:34:14 +000075
jcgregorioa46fe4e2006-11-16 04:13:45 +000076class UrlNormTest(unittest.TestCase):
77 def test(self):
78 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://example.org")[-1])
79 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://EXAMple.org")[-1])
80 self.assertEqual( "http://example.org/?=b", httplib2.urlnorm("http://EXAMple.org?=b")[-1])
81 self.assertEqual( "http://example.org/mypath?a=b", httplib2.urlnorm("http://EXAMple.org/mypath?a=b")[-1])
82 self.assertEqual( "http://localhost:80/", httplib2.urlnorm("http://localhost:80")[-1])
jcgregoriob4e9ab02006-11-17 15:53:15 +000083 self.assertEqual( httplib2.urlnorm("http://localhost:80/"), httplib2.urlnorm("HTTP://LOCALHOST:80"))
jcgregorio132d28e2007-01-23 16:22:53 +000084 try:
85 httplib2.urlnorm("/")
86 self.fail("Non-absolute URIs should raise an exception")
87 except httplib2.RelativeURIError:
88 pass
jcgregorioa46fe4e2006-11-16 04:13:45 +000089
90class UrlSafenameTest(unittest.TestCase):
91 def test(self):
92 # Test that different URIs end up generating different safe names
93 self.assertEqual( "example.org,fred,a=b,58489f63a7a83c3b7794a6a398ee8b1f", httplib2.safename("http://example.org/fred/?a=b"))
94 self.assertEqual( "example.org,fred,a=b,8c5946d56fec453071f43329ff0be46b", httplib2.safename("http://example.org/fred?/a=b"))
95 self.assertEqual( "www.example.org,fred,a=b,499c44b8d844a011b67ea2c015116968", httplib2.safename("http://www.example.org/fred?/a=b"))
96 self.assertEqual( httplib2.safename(httplib2.urlnorm("http://www")[-1]), httplib2.safename(httplib2.urlnorm("http://WWW")[-1]))
97 self.assertEqual( "www.example.org,fred,a=b,692e843a333484ce0095b070497ab45d", httplib2.safename("https://www.example.org/fred?/a=b"))
98 self.assertNotEqual( httplib2.safename("http://www"), httplib2.safename("https://www"))
99 # Test the max length limits
100 uri = "http://" + ("w" * 200) + ".org"
101 uri2 = "http://" + ("w" * 201) + ".org"
102 self.assertNotEqual( httplib2.safename(uri2), httplib2.safename(uri))
103 # Max length should be 200 + 1 (",") + 32
104 self.assertEqual(233, len(httplib2.safename(uri2)))
105 self.assertEqual(233, len(httplib2.safename(uri)))
106 # Unicode
jcgregoriodebceec2006-12-12 20:26:02 +0000107 if sys.version_info >= (2,3):
108 self.assertEqual( "xn--http,-4y1d.org,fred,a=b,579924c35db315e5a32e3d9963388193", httplib2.safename(u"http://\u2304.org/fred/?a=b"))
jcgregorioa46fe4e2006-11-16 04:13:45 +0000109
jcgregorio14644372007-07-30 14:13:37 +0000110class _MyResponse(StringIO.StringIO):
111 def __init__(self, body, **kwargs):
112 StringIO.StringIO.__init__(self, body)
113 self.headers = kwargs
114
115 def iteritems(self):
116 return self.headers.iteritems()
117
118
119class _MyHTTPConnection(object):
120 "This class is just a mock of httplib.HTTPConnection used for testing"
121
122 def __init__(self, host, port=None, key_file=None, cert_file=None,
joe.gregoriof28536d2007-10-23 14:10:11 +0000123 strict=None, timeout=None, proxy_info=None):
jcgregorio14644372007-07-30 14:13:37 +0000124 self.host = host
125 self.port = port
126 self.timeout = timeout
127 self.log = ""
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400128 self.sock = None
jcgregorio14644372007-07-30 14:13:37 +0000129
130 def set_debuglevel(self, level):
131 pass
132
133 def connect(self):
134 "Connect to a host on a given port."
135 pass
136
137 def close(self):
138 pass
139
140 def request(self, method, request_uri, body, headers):
141 pass
142
143 def getresponse(self):
144 return _MyResponse("the body", status="200")
jcgregorioa46fe4e2006-11-16 04:13:45 +0000145
jcgregorio90fb4a42006-11-17 16:19:47 +0000146
jcgregorio2d66d4f2006-02-07 05:34:14 +0000147class HttpTest(unittest.TestCase):
148 def setUp(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400149 if os.path.exists(cacheDirName):
jcgregorio7e3608f2006-06-15 13:01:53 +0000150 [os.remove(os.path.join(cacheDirName, file)) for file in os.listdir(cacheDirName)]
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400151
152 if sys.version_info < (2, 6):
153 disable_cert_validation = True
154 else:
155 disable_cert_validation = False
156 self.http = httplib2.Http(
157 cacheDirName,
158 disable_ssl_certificate_validation=disable_cert_validation)
jcgregorio36140b52006-06-13 02:17:52 +0000159 self.http.clear_credentials()
jcgregorio2d66d4f2006-02-07 05:34:14 +0000160
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500161 def testIPv6NoSSL(self):
162 try:
163 self.http.request("http://[::1]/")
164 except socket.gaierror:
165 self.fail("should get the address family right for IPv6")
166 except socket.error:
167 # Even if IPv6 isn't installed on a machine it should just raise socket.error
168 pass
169
170 def testIPv6SSL(self):
171 try:
172 self.http.request("https://[::1]/")
173 except socket.gaierror:
174 self.fail("should get the address family right for IPv6")
Jason R. Coombscee15da2011-08-09 09:13:34 -0400175 except httplib2.CertificateHostnameMismatch:
176 # We connected and verified that the certificate doesn't match
177 # the name. Good enough.
178 pass
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500179 except socket.error:
180 # Even if IPv6 isn't installed on a machine it should just raise socket.error
181 pass
182
jcgregorio14644372007-07-30 14:13:37 +0000183 def testConnectionType(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400184 self.http.force_exception_to_status_code = False
jcgregorio14644372007-07-30 14:13:37 +0000185 response, content = self.http.request("http://bitworking.org", connection_type=_MyHTTPConnection)
186 self.assertEqual(response['content-location'], "http://bitworking.org")
187 self.assertEqual(content, "the body")
188
jcgregorio6a638172007-01-23 16:40:23 +0000189 def testGetUnknownServer(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400190 self.http.force_exception_to_status_code = False
jcgregorio6a638172007-01-23 16:40:23 +0000191 try:
192 self.http.request("http://fred.bitworking.org/")
193 self.fail("An httplib2.ServerNotFoundError Exception must be thrown on an unresolvable server.")
194 except httplib2.ServerNotFoundError:
195 pass
196
jcgregorio07a9a4a2007-03-08 21:18:39 +0000197 # Now test with exceptions turned off
198 self.http.force_exception_to_status_code = True
199
200 (response, content) = self.http.request("http://fred.bitworking.org/")
201 self.assertEqual(response['content-type'], 'text/plain')
202 self.assertTrue(content.startswith("Unable to find"))
203 self.assertEqual(response.status, 400)
204
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500205 def testGetConnectionRefused(self):
206 self.http.force_exception_to_status_code = False
207 try:
208 self.http.request("http://localhost:7777/")
209 self.fail("An socket.error exception must be thrown on Connection Refused.")
210 except socket.error:
211 pass
212
213 # Now test with exceptions turned off
214 self.http.force_exception_to_status_code = True
215
216 (response, content) = self.http.request("http://localhost:7777/")
217 self.assertEqual(response['content-type'], 'text/plain')
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400218 self.assertTrue("Connection refused" in content
219 or "actively refused" in content,
220 "Unexpected status %(content)s" % vars())
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500221 self.assertEqual(response.status, 400)
222
jcgregorioa898f8f2006-12-12 17:16:55 +0000223 def testGetIRI(self):
jcgregoriodebceec2006-12-12 20:26:02 +0000224 if sys.version_info >= (2,3):
225 uri = urlparse.urljoin(base, u"reflector/reflector.cgi?d=\N{CYRILLIC CAPITAL LETTER DJE}")
226 (response, content) = self.http.request(uri, "GET")
227 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400228 self.assertTrue(d.has_key('QUERY_STRING'))
229 self.assertTrue(d['QUERY_STRING'].find('%D0%82') > 0)
230
jcgregorio2d66d4f2006-02-07 05:34:14 +0000231 def testGetIsDefaultMethod(self):
232 # Test that GET is the default method
233 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000234 (response, content) = self.http.request(uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000235 self.assertEqual(response['x-method'], "GET")
236
237 def testDifferentMethods(self):
238 # Test that all methods can be used
239 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
240 for method in ["GET", "PUT", "DELETE", "POST"]:
jcgregorio36140b52006-06-13 02:17:52 +0000241 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000242 self.assertEqual(response['x-method'], method)
243
Joe Gregoriob628c0b2009-07-16 12:28:04 -0400244 def testHeadRead(self):
245 # Test that we don't try to read the response of a HEAD request
246 # since httplib blocks response.read() for HEAD requests.
247 # Oddly enough this doesn't appear as a problem when doing HEAD requests
248 # against Apache servers.
249 uri = "http://www.google.com/"
250 (response, content) = self.http.request(uri, "HEAD")
251 self.assertEqual(response.status, 200)
252 self.assertEqual(content, "")
253
jcgregorio2d66d4f2006-02-07 05:34:14 +0000254 def testGetNoCache(self):
255 # Test that can do a GET w/o the cache turned on.
256 http = httplib2.Http()
257 uri = urlparse.urljoin(base, "304/test_etag.txt")
258 (response, content) = http.request(uri, "GET")
259 self.assertEqual(response.status, 200)
jcgregorioa0713ab2006-07-01 05:21:34 +0000260 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000261
Joe Gregorioe202d212009-07-16 14:57:52 -0400262 def testGetOnlyIfCachedCacheHit(self):
263 # Test that can do a GET with cache and 'only-if-cached'
264 uri = urlparse.urljoin(base, "304/test_etag.txt")
265 (response, content) = self.http.request(uri, "GET")
266 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
267 self.assertEqual(response.fromcache, True)
268 self.assertEqual(response.status, 200)
269
jcgregorioe4ce13e2006-04-02 03:05:08 +0000270 def testGetOnlyIfCachedCacheMiss(self):
271 # Test that can do a GET with no cache with 'only-if-cached'
jcgregorioe4ce13e2006-04-02 03:05:08 +0000272 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorioe202d212009-07-16 14:57:52 -0400273 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
jcgregorioe4ce13e2006-04-02 03:05:08 +0000274 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400275 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000276
277 def testGetOnlyIfCachedNoCacheAtAll(self):
278 # Test that can do a GET with no cache with 'only-if-cached'
279 # Of course, there might be an intermediary beyond us
280 # that responds to the 'only-if-cached', so this
281 # test can't really be guaranteed to pass.
282 http = httplib2.Http()
283 uri = urlparse.urljoin(base, "304/test_etag.txt")
284 (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
285 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400286 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000287
jcgregorio2d66d4f2006-02-07 05:34:14 +0000288 def testUserAgent(self):
289 # Test that we provide a default user-agent
290 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000291 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000292 self.assertEqual(response.status, 200)
293 self.assertTrue(content.startswith("Python-httplib2/"))
294
295 def testUserAgentNonDefault(self):
296 # Test that the default user-agent can be over-ridden
joe.gregoriof28536d2007-10-23 14:10:11 +0000297
jcgregorio2d66d4f2006-02-07 05:34:14 +0000298 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000299 (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000300 self.assertEqual(response.status, 200)
301 self.assertTrue(content.startswith("fred/1.0"))
302
303 def testGet300WithLocation(self):
304 # Test the we automatically follow 300 redirects if a Location: header is provided
305 uri = urlparse.urljoin(base, "300/with-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000306 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000307 self.assertEqual(response.status, 200)
308 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000309 self.assertEqual(response.previous.status, 300)
310 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000311
312 # Confirm that the intermediate 300 is not cached
jcgregorio36140b52006-06-13 02:17:52 +0000313 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000314 self.assertEqual(response.status, 200)
315 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000316 self.assertEqual(response.previous.status, 300)
317 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000318
jcgregorio2f1e1422007-05-03 13:17:33 +0000319 def testGet300WithLocationNoRedirect(self):
320 # Test the we automatically follow 300 redirects if a Location: header is provided
321 self.http.follow_redirects = False
322 uri = urlparse.urljoin(base, "300/with-location-header.asis")
323 (response, content) = self.http.request(uri, "GET")
324 self.assertEqual(response.status, 300)
325
jcgregorio2d66d4f2006-02-07 05:34:14 +0000326 def testGet300WithoutLocation(self):
327 # Not giving a Location: header in a 300 response is acceptable
328 # In which case we just return the 300 response
329 uri = urlparse.urljoin(base, "300/without-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000330 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000331 self.assertEqual(response.status, 300)
332 self.assertTrue(response['content-type'].startswith("text/html"))
jcgregorioa0713ab2006-07-01 05:21:34 +0000333 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000334
335 def testGet301(self):
336 # Test that we automatically follow 301 redirects
337 # and that we cache the 301 response
338 uri = urlparse.urljoin(base, "301/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000339 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000340 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000341 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000342 self.assertTrue(response.has_key('content-location'))
343 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000344 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000345 self.assertEqual(response.previous.status, 301)
346 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000347
jcgregorio36140b52006-06-13 02:17:52 +0000348 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000349 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000350 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000351 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000352 self.assertEqual(response.previous.status, 301)
353 self.assertEqual(response.previous.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000354
Joe Gregorio694a8122011-02-13 21:40:09 -0500355 def testHead301(self):
356 # Test that we automatically follow 301 redirects
357 uri = urlparse.urljoin(base, "301/onestep.asis")
358 destination = urlparse.urljoin(base, "302/final-destination.txt")
359 (response, content) = self.http.request(uri, "HEAD")
360 self.assertEqual(response.status, 200)
361 self.assertEqual(response.previous.status, 301)
362 self.assertEqual(response.previous.fromcache, False)
jcgregorio2f1e1422007-05-03 13:17:33 +0000363
364 def testGet301NoRedirect(self):
365 # Test that we automatically follow 301 redirects
366 # and that we cache the 301 response
367 self.http.follow_redirects = False
368 uri = urlparse.urljoin(base, "301/onestep.asis")
369 destination = urlparse.urljoin(base, "302/final-destination.txt")
370 (response, content) = self.http.request(uri, "GET")
371 self.assertEqual(response.status, 301)
372
373
jcgregorio2d66d4f2006-02-07 05:34:14 +0000374 def testGet302(self):
375 # Test that we automatically follow 302 redirects
376 # and that we DO NOT cache the 302 response
377 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000378 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000379 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000380 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000381 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000382 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000383 self.assertEqual(response.previous.status, 302)
384 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000385
386 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000387 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000388 self.assertEqual(response.status, 200)
389 self.assertEqual(response.fromcache, True)
jcgregorio772adc82006-11-17 21:52:34 +0000390 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000391 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000392 self.assertEqual(response.previous.status, 302)
393 self.assertEqual(response.previous.fromcache, False)
jcgregorio772adc82006-11-17 21:52:34 +0000394 self.assertEqual(response.previous['content-location'], uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000395
396 uri = urlparse.urljoin(base, "302/twostep.asis")
397
jcgregorio36140b52006-06-13 02:17:52 +0000398 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000399 self.assertEqual(response.status, 200)
400 self.assertEqual(response.fromcache, True)
401 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000402 self.assertEqual(response.previous.status, 302)
403 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000404
405 def testGet302RedirectionLimit(self):
406 # Test that we can set a lower redirection limit
407 # and that we raise an exception when we exceed
408 # that limit.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400409 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000410
jcgregorio2d66d4f2006-02-07 05:34:14 +0000411 uri = urlparse.urljoin(base, "302/twostep.asis")
412 try:
jcgregorio36140b52006-06-13 02:17:52 +0000413 (response, content) = self.http.request(uri, "GET", redirections = 1)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000414 self.fail("This should not happen")
415 except httplib2.RedirectLimit:
416 pass
417 except Exception, e:
418 self.fail("Threw wrong kind of exception ")
419
jcgregorio07a9a4a2007-03-08 21:18:39 +0000420 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400421 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000422
423 (response, content) = self.http.request(uri, "GET", redirections = 1)
424 self.assertEqual(response.status, 500)
425 self.assertTrue(response.reason.startswith("Redirected more"))
426 self.assertEqual("302", response['status'])
427 self.assertTrue(content.startswith("<html>"))
428 self.assertTrue(response.previous != None)
429
jcgregorio2d66d4f2006-02-07 05:34:14 +0000430 def testGet302NoLocation(self):
431 # Test that we throw an exception when we get
432 # a 302 with no Location: header.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400433 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000434 uri = urlparse.urljoin(base, "302/no-location.asis")
435 try:
jcgregorio36140b52006-06-13 02:17:52 +0000436 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000437 self.fail("Should never reach here")
438 except httplib2.RedirectMissingLocation:
439 pass
440 except Exception, e:
441 self.fail("Threw wrong kind of exception ")
442
jcgregorio07a9a4a2007-03-08 21:18:39 +0000443 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400444 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000445
446 (response, content) = self.http.request(uri, "GET")
447 self.assertEqual(response.status, 500)
448 self.assertTrue(response.reason.startswith("Redirected but"))
449 self.assertEqual("302", response['status'])
450 self.assertTrue(content.startswith("This is content"))
Joe Gregorio84e33252011-05-03 09:09:13 -0400451
Joe Gregorioac335ff2011-11-14 12:29:03 -0500452 def testGet301ViaHttps(self):
453 # Google always redirects to https://www.google.com
454 (response, content) = self.http.request("https://code.google.com/apis/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000455 self.assertEqual(200, response.status)
Joe Gregorioac335ff2011-11-14 12:29:03 -0500456 self.assertEqual(301, response.previous.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000457
458 def testGetViaHttps(self):
459 # Test that we can handle HTTPS
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400460 (response, content) = self.http.request("https://www.google.com/adsense/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000461 self.assertEqual(200, response.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000462
463 def testGetViaHttpsSpecViolationOnLocation(self):
464 # Test that we follow redirects through HTTPS
465 # even if they violate the spec by including
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400466 # a relative Location: header instead of an
jcgregorio2d66d4f2006-02-07 05:34:14 +0000467 # absolute one.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400468 (response, content) = self.http.request("https://www.google.com/adsense", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000469 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000470 self.assertNotEqual(None, response.previous)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000471
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400472 def testSslCertValidation(self):
473 if sys.version_info >= (2, 6):
474 # Test that we get an ssl.SSLError when specifying a non-existent CA
475 # certs file.
476 http = httplib2.Http(ca_certs='/nosuchfile')
477 self.assertRaises(ssl.SSLError,
478 http.request, "https://www.google.com/", "GET")
479
480 # Test that we get a SSLHandshakeError if we try to access
481 # https;//www.google.com, using a CA cert file that doesn't contain
482 # the CA Gogole uses (i.e., simulating a cert that's not signed by a
483 # trusted CA).
484 other_ca_certs = os.path.join(
485 os.path.dirname(os.path.abspath(httplib2.__file__ )),
486 "test", "other_cacerts.txt")
487 http = httplib2.Http(ca_certs=other_ca_certs)
488 self.assertRaises(httplib2.SSLHandshakeError,
489 http.request, "https://www.google.com/", "GET")
490
Joe Gregorioc69dc782011-06-23 08:56:59 -0400491 def testSslCertValidationDoubleDots(self):
492 if sys.version_info >= (2, 6):
493 # Test that we get match a double dot cert
494 try:
495 self.http.request("https://1.www.appspot.com/", "GET")
496 except httplib2.CertificateHostnameMismatch:
497 self.fail('cert with *.*.appspot.com should not raise an exception.')
498
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400499 def testSslHostnameValidation(self):
500 if sys.version_info >= (2, 6):
501 # The SSL server at google.com:443 returns a certificate for
502 # 'www.google.com', which results in a host name mismatch.
503 # Note that this test only works because the ssl module and httplib2
504 # do not support SNI; for requests specifying a server name of
505 # 'google.com' via SNI, a matching cert would be returned.
506 self.assertRaises(httplib2.CertificateHostnameMismatch,
507 self.http.request, "https://google.com/", "GET")
508
509 def testSslCertValidationWithoutSslModuleFails(self):
510 if sys.version_info < (2, 6):
511 http = httplib2.Http(disable_ssl_certificate_validation=False)
512 self.assertRaises(httplib2.CertificateValidationUnsupported,
513 http.request, "https://www.google.com/", "GET")
jcgregoriode8238d2007-03-07 19:08:26 +0000514
515 def testGetViaHttpsKeyCert(self):
jcgregorio2f1e1422007-05-03 13:17:33 +0000516 # At this point I can only test
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400517 # that the key and cert files are passed in
518 # correctly to httplib. It would be nice to have
jcgregorio2f1e1422007-05-03 13:17:33 +0000519 # a real https endpoint to test against.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400520
521 # bitworking.org presents an certificate for a non-matching host
522 # (*.webfaction.com), so we need to disable cert checking for this test.
523 http = httplib2.Http(timeout=2, disable_ssl_certificate_validation=True)
jcgregoriode8238d2007-03-07 19:08:26 +0000524
525 http.add_certificate("akeyfile", "acertfile", "bitworking.org")
526 try:
527 (response, content) = http.request("https://bitworking.org", "GET")
528 except:
529 pass
530 self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
531 self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
532
jcgregorio2f1e1422007-05-03 13:17:33 +0000533 try:
534 (response, content) = http.request("https://notthere.bitworking.org", "GET")
535 except:
536 pass
537 self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
538 self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
539
540
541
jcgregoriode8238d2007-03-07 19:08:26 +0000542
jcgregorio2d66d4f2006-02-07 05:34:14 +0000543 def testGet303(self):
544 # Do a follow-up GET on a Location: header
545 # returned from a POST that gave a 303.
546 uri = urlparse.urljoin(base, "303/303.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000547 (response, content) = self.http.request(uri, "POST", " ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000548 self.assertEqual(response.status, 200)
549 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000550 self.assertEqual(response.previous.status, 303)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000551
jcgregorio2f1e1422007-05-03 13:17:33 +0000552 def testGet303NoRedirect(self):
553 # Do a follow-up GET on a Location: header
554 # returned from a POST that gave a 303.
555 self.http.follow_redirects = False
556 uri = urlparse.urljoin(base, "303/303.cgi")
557 (response, content) = self.http.request(uri, "POST", " ")
558 self.assertEqual(response.status, 303)
559
jcgregorio2d66d4f2006-02-07 05:34:14 +0000560 def test303ForDifferentMethods(self):
561 # Test that all methods can be used
562 uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400563 for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
jcgregorio36140b52006-06-13 02:17:52 +0000564 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000565 self.assertEqual(response['x-method'], method_on_303)
566
567 def testGet304(self):
568 # Test that we use ETags properly to validate our cache
569 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000570 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000571 self.assertNotEqual(response['etag'], "")
572
jcgregorio36140b52006-06-13 02:17:52 +0000573 (response, content) = self.http.request(uri, "GET")
574 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000575 self.assertEqual(response.status, 200)
576 self.assertEqual(response.fromcache, True)
577
jcgregorio90fb4a42006-11-17 16:19:47 +0000578 cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
579 f = open(cache_file_name, "r")
580 status_line = f.readline()
581 f.close()
582
583 self.assertTrue(status_line.startswith("status:"))
584
jcgregorio36140b52006-06-13 02:17:52 +0000585 (response, content) = self.http.request(uri, "HEAD")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000586 self.assertEqual(response.status, 200)
587 self.assertEqual(response.fromcache, True)
588
jcgregorio36140b52006-06-13 02:17:52 +0000589 (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000590 self.assertEqual(response.status, 206)
591 self.assertEqual(response.fromcache, False)
592
jcgregorio25185622006-10-28 05:12:34 +0000593 def testGetIgnoreEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400594 # Test that we can forcibly ignore ETags
jcgregorio25185622006-10-28 05:12:34 +0000595 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
596 (response, content) = self.http.request(uri, "GET")
597 self.assertNotEqual(response['etag'], "")
598
599 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
600 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400601 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000602
603 self.http.ignore_etag = True
604 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
605 d = self.reflector(content)
606 self.assertEqual(response.fromcache, False)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400607 self.assertFalse(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000608
jcgregorio4b145e82007-01-18 19:46:34 +0000609 def testOverrideEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400610 # Test that we can forcibly ignore ETags
jcgregorio4b145e82007-01-18 19:46:34 +0000611 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
612 (response, content) = self.http.request(uri, "GET")
613 self.assertNotEqual(response['etag'], "")
614
615 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
616 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400617 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
618 self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio4b145e82007-01-18 19:46:34 +0000619
pilgrim00a352e2009-05-29 04:04:44 +0000620 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0', 'if-none-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +0000621 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400622 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
623 self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio25185622006-10-28 05:12:34 +0000624
pilgrim00a352e2009-05-29 04:04:44 +0000625#MAP-commented this out because it consistently fails
626# def testGet304EndToEnd(self):
627# # Test that end to end headers get overwritten in the cache
628# uri = urlparse.urljoin(base, "304/end2end.cgi")
629# (response, content) = self.http.request(uri, "GET")
630# self.assertNotEqual(response['etag'], "")
631# old_date = response['date']
632# time.sleep(2)
633#
634# (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
635# # The response should be from the cache, but the Date: header should be updated.
636# new_date = response['date']
637# self.assertNotEqual(new_date, old_date)
638# self.assertEqual(response.status, 200)
639# self.assertEqual(response.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000640
641 def testGet304LastModified(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400642 # Test that we can still handle a 304
jcgregorio2d66d4f2006-02-07 05:34:14 +0000643 # by only using the last-modified cache validator.
644 uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000645 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000646
647 self.assertNotEqual(response['last-modified'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000648 (response, content) = self.http.request(uri, "GET")
649 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000650 self.assertEqual(response.status, 200)
651 self.assertEqual(response.fromcache, True)
652
653 def testGet307(self):
654 # Test that we do follow 307 redirects but
655 # do not cache the 307
656 uri = urlparse.urljoin(base, "307/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000657 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000658 self.assertEqual(response.status, 200)
659 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000660 self.assertEqual(response.previous.status, 307)
661 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000662
jcgregorio36140b52006-06-13 02:17:52 +0000663 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000664 self.assertEqual(response.status, 200)
665 self.assertEqual(response.fromcache, True)
666 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000667 self.assertEqual(response.previous.status, 307)
668 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000669
670 def testGet410(self):
671 # Test that we pass 410's through
672 uri = urlparse.urljoin(base, "410/410.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000673 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000674 self.assertEqual(response.status, 410)
675
chris dent89f15142009-12-24 14:02:57 -0600676 def testVaryHeaderSimple(self):
677 """
678 RFC 2616 13.6
679 When the cache receives a subsequent request whose Request-URI
680 specifies one or more cache entries including a Vary header field,
681 the cache MUST NOT use such a cache entry to construct a response
682 to the new request unless all of the selecting request-headers
683 present in the new request match the corresponding stored
684 request-headers in the original request.
685 """
686 # test that the vary header is sent
687 uri = urlparse.urljoin(base, "vary/accept.asis")
688 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
689 self.assertEqual(response.status, 200)
690 self.assertTrue(response.has_key('vary'))
691
692 # get the resource again, from the cache since accept header in this
693 # request is the same as the request
694 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
695 self.assertEqual(response.status, 200)
696 self.assertEqual(response.fromcache, True, msg="Should be from cache")
697
698 # get the resource again, not from cache since Accept headers does not match
699 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
700 self.assertEqual(response.status, 200)
701 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
702
703 # get the resource again, without any Accept header, so again no match
704 (response, content) = self.http.request(uri, "GET")
705 self.assertEqual(response.status, 200)
706 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
707
708 def testNoVary(self):
709 # when there is no vary, a different Accept header (e.g.) should not
710 # impact if the cache is used
711 # test that the vary header is not sent
712 uri = urlparse.urljoin(base, "vary/no-vary.asis")
713 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
714 self.assertEqual(response.status, 200)
715 self.assertFalse(response.has_key('vary'))
716
717 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
718 self.assertEqual(response.status, 200)
719 self.assertEqual(response.fromcache, True, msg="Should be from cache")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400720
chris dent89f15142009-12-24 14:02:57 -0600721 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
722 self.assertEqual(response.status, 200)
723 self.assertEqual(response.fromcache, True, msg="Should be from cache")
724
725 def testVaryHeaderDouble(self):
726 uri = urlparse.urljoin(base, "vary/accept-double.asis")
727 (response, content) = self.http.request(uri, "GET", headers={
728 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
729 self.assertEqual(response.status, 200)
730 self.assertTrue(response.has_key('vary'))
731
732 # we are from cache
733 (response, content) = self.http.request(uri, "GET", headers={
734 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
735 self.assertEqual(response.fromcache, True, msg="Should be from cache")
736
737 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
738 self.assertEqual(response.status, 200)
739 self.assertEqual(response.fromcache, False)
740
741 # get the resource again, not from cache, varied headers don't match exact
742 (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})
743 self.assertEqual(response.status, 200)
744 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
745
jcgregorio88ef89b2010-05-13 23:42:11 -0400746 def testVaryUnusedHeader(self):
747 # A header's value is not considered to vary if it's not used at all.
748 uri = urlparse.urljoin(base, "vary/unused-header.asis")
749 (response, content) = self.http.request(uri, "GET", headers={
750 'Accept': 'text/plain'})
751 self.assertEqual(response.status, 200)
752 self.assertTrue(response.has_key('vary'))
753
754 # we are from cache
755 (response, content) = self.http.request(uri, "GET", headers={
756 'Accept': 'text/plain',})
757 self.assertEqual(response.fromcache, True, msg="Should be from cache")
758
chris dent89f15142009-12-24 14:02:57 -0600759
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000760 def testHeadGZip(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400761 # Test that we don't try to decompress a HEAD response
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000762 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
763 (response, content) = self.http.request(uri, "HEAD")
764 self.assertEqual(response.status, 200)
765 self.assertNotEqual(int(response['content-length']), 0)
766 self.assertEqual(content, "")
767
jcgregorio2d66d4f2006-02-07 05:34:14 +0000768 def testGetGZip(self):
769 # Test that we support gzip compression
770 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000771 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000772 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000773 self.assertFalse(response.has_key('content-encoding'))
joe.gregorio8b6d2312007-12-16 05:42:07 +0000774 self.assertTrue(response.has_key('-content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000775 self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000776 self.assertEqual(content, "This is the final destination.\n")
777
Joe Gregoriod1137c52011-02-13 19:27:35 -0500778 def testPostAndGZipResponse(self):
779 uri = urlparse.urljoin(base, "gzip/post.cgi")
780 (response, content) = self.http.request(uri, "POST", body=" ")
781 self.assertEqual(response.status, 200)
782 self.assertFalse(response.has_key('content-encoding'))
783 self.assertTrue(response.has_key('-content-encoding'))
784
jcgregorio2d66d4f2006-02-07 05:34:14 +0000785 def testGetGZipFailure(self):
786 # Test that we raise a good exception when the gzip fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400787 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000788 uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
789 try:
jcgregorio36140b52006-06-13 02:17:52 +0000790 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000791 self.fail("Should never reach here")
792 except httplib2.FailedToDecompressContent:
793 pass
794 except Exception:
795 self.fail("Threw wrong kind of exception")
796
jcgregorio07a9a4a2007-03-08 21:18:39 +0000797 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400798 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000799
800 (response, content) = self.http.request(uri, "GET")
801 self.assertEqual(response.status, 500)
802 self.assertTrue(response.reason.startswith("Content purported"))
803
804 def testTimeout(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400805 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000806 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
807 try:
808 import socket
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400809 socket.setdefaulttimeout(1)
jcgregorio07a9a4a2007-03-08 21:18:39 +0000810 except:
811 # Don't run the test if we can't set the timeout
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400812 return
jcgregorio07a9a4a2007-03-08 21:18:39 +0000813 (response, content) = self.http.request(uri)
814 self.assertEqual(response.status, 408)
815 self.assertTrue(response.reason.startswith("Request Timeout"))
816 self.assertTrue(content.startswith("Request Timeout"))
817
jcgregoriob2697912007-03-09 02:23:47 +0000818 def testIndividualTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000819 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
820 http = httplib2.Http(timeout=1)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400821 http.force_exception_to_status_code = True
jcgregoriob2697912007-03-09 02:23:47 +0000822
823 (response, content) = http.request(uri)
824 self.assertEqual(response.status, 408)
825 self.assertTrue(response.reason.startswith("Request Timeout"))
826 self.assertTrue(content.startswith("Request Timeout"))
827
jcgregorio07a9a4a2007-03-08 21:18:39 +0000828
Joe Gregorio1a7609f2009-07-16 10:59:44 -0400829 def testHTTPSInitTimeout(self):
830 c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
831 self.assertEqual(47, c.timeout)
832
jcgregorio2d66d4f2006-02-07 05:34:14 +0000833 def testGetDeflate(self):
834 # Test that we support deflate compression
835 uri = urlparse.urljoin(base, "deflate/deflated.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000836 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000837 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000838 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000839 self.assertEqual(int(response['content-length']), len("This is the final destination."))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000840 self.assertEqual(content, "This is the final destination.")
841
842 def testGetDeflateFailure(self):
843 # Test that we raise a good exception when the deflate fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400844 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000845
jcgregorio2d66d4f2006-02-07 05:34:14 +0000846 uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
847 try:
jcgregorio36140b52006-06-13 02:17:52 +0000848 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000849 self.fail("Should never reach here")
850 except httplib2.FailedToDecompressContent:
851 pass
852 except Exception:
853 self.fail("Threw wrong kind of exception")
854
jcgregorio07a9a4a2007-03-08 21:18:39 +0000855 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400856 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000857
858 (response, content) = self.http.request(uri, "GET")
859 self.assertEqual(response.status, 500)
860 self.assertTrue(response.reason.startswith("Content purported"))
861
jcgregorio2d66d4f2006-02-07 05:34:14 +0000862 def testGetDuplicateHeaders(self):
863 # Test that duplicate headers get concatenated via ','
864 uri = urlparse.urljoin(base, "duplicate-headers/multilink.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000865 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000866 self.assertEqual(response.status, 200)
867 self.assertEqual(content, "This is content\n")
868 self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
869
870 def testGetCacheControlNoCache(self):
871 # Test Cache-Control: no-cache on requests
872 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000873 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000874 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000875 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000876 self.assertEqual(response.status, 200)
877 self.assertEqual(response.fromcache, True)
878
jcgregorio36140b52006-06-13 02:17:52 +0000879 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000880 self.assertEqual(response.status, 200)
881 self.assertEqual(response.fromcache, False)
882
883 def testGetCacheControlPragmaNoCache(self):
884 # Test Pragma: no-cache on requests
885 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000886 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000887 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000888 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000889 self.assertEqual(response.status, 200)
890 self.assertEqual(response.fromcache, True)
891
jcgregorio36140b52006-06-13 02:17:52 +0000892 (response, content) = self.http.request(uri, "GET", headers={'Pragma': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000893 self.assertEqual(response.status, 200)
894 self.assertEqual(response.fromcache, False)
895
896 def testGetCacheControlNoStoreRequest(self):
897 # A no-store request means that the response should not be stored.
898 uri = urlparse.urljoin(base, "304/test_etag.txt")
899
jcgregorio36140b52006-06-13 02:17:52 +0000900 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000901 self.assertEqual(response.status, 200)
902 self.assertEqual(response.fromcache, False)
903
jcgregorio36140b52006-06-13 02:17:52 +0000904 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000905 self.assertEqual(response.status, 200)
906 self.assertEqual(response.fromcache, False)
907
908 def testGetCacheControlNoStoreResponse(self):
909 # A no-store response means that the response should not be stored.
910 uri = urlparse.urljoin(base, "no-store/no-store.asis")
911
jcgregorio36140b52006-06-13 02:17:52 +0000912 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000913 self.assertEqual(response.status, 200)
914 self.assertEqual(response.fromcache, False)
915
jcgregorio36140b52006-06-13 02:17:52 +0000916 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000917 self.assertEqual(response.status, 200)
918 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000919
920 def testGetCacheControlNoCacheNoStoreRequest(self):
921 # Test that a no-store, no-cache clears the entry from the cache
922 # even if it was cached previously.
923 uri = urlparse.urljoin(base, "304/test_etag.txt")
924
jcgregorio36140b52006-06-13 02:17:52 +0000925 (response, content) = self.http.request(uri, "GET")
926 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000927 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000928 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
929 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000930 self.assertEqual(response.status, 200)
931 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000932
933 def testUpdateInvalidatesCache(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400934 # Test that calling PUT or DELETE on a
jcgregorio2d66d4f2006-02-07 05:34:14 +0000935 # URI that is cache invalidates that cache.
936 uri = urlparse.urljoin(base, "304/test_etag.txt")
937
jcgregorio36140b52006-06-13 02:17:52 +0000938 (response, content) = self.http.request(uri, "GET")
939 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000940 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000941 (response, content) = self.http.request(uri, "DELETE")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000942 self.assertEqual(response.status, 405)
943
jcgregorio36140b52006-06-13 02:17:52 +0000944 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000945 self.assertEqual(response.fromcache, False)
946
947 def testUpdateUsesCachedETag(self):
Joe Gregoriobd682082011-05-24 14:06:09 -0400948 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio2d66d4f2006-02-07 05:34:14 +0000949 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
950
jcgregorio36140b52006-06-13 02:17:52 +0000951 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000952 self.assertEqual(response.status, 200)
953 self.assertEqual(response.fromcache, False)
jcgregorio36140b52006-06-13 02:17:52 +0000954 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000955 self.assertEqual(response.status, 200)
956 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -0400957 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000958 self.assertEqual(response.status, 200)
Joe Gregoriocd868102009-09-29 17:09:16 -0400959 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000960 self.assertEqual(response.status, 412)
961
Joe Gregoriobd682082011-05-24 14:06:09 -0400962 def testUpdatePatchUsesCachedETag(self):
963 # Test that we natively support http://www.w3.org/1999/04/Editing/
964 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
965
966 (response, content) = self.http.request(uri, "GET")
967 self.assertEqual(response.status, 200)
968 self.assertEqual(response.fromcache, False)
969 (response, content) = self.http.request(uri, "GET")
970 self.assertEqual(response.status, 200)
971 self.assertEqual(response.fromcache, True)
972 (response, content) = self.http.request(uri, "PATCH", body="foo")
973 self.assertEqual(response.status, 200)
974 (response, content) = self.http.request(uri, "PATCH", body="foo")
975 self.assertEqual(response.status, 412)
976
977
joe.gregorio700f04d2008-09-06 04:46:32 +0000978 def testUpdateUsesCachedETagAndOCMethod(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400979 # Test that we natively support http://www.w3.org/1999/04/Editing/
joe.gregorio700f04d2008-09-06 04:46:32 +0000980 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
981
982 (response, content) = self.http.request(uri, "GET")
983 self.assertEqual(response.status, 200)
984 self.assertEqual(response.fromcache, False)
985 (response, content) = self.http.request(uri, "GET")
986 self.assertEqual(response.status, 200)
987 self.assertEqual(response.fromcache, True)
988 self.http.optimistic_concurrency_methods.append("DELETE")
989 (response, content) = self.http.request(uri, "DELETE")
990 self.assertEqual(response.status, 200)
991
992
jcgregorio4b145e82007-01-18 19:46:34 +0000993 def testUpdateUsesCachedETagOverridden(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400994 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio4b145e82007-01-18 19:46:34 +0000995 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
996
997 (response, content) = self.http.request(uri, "GET")
998 self.assertEqual(response.status, 200)
999 self.assertEqual(response.fromcache, False)
1000 (response, content) = self.http.request(uri, "GET")
1001 self.assertEqual(response.status, 200)
1002 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -04001003 (response, content) = self.http.request(uri, "PUT", body="foo", headers={'if-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +00001004 self.assertEqual(response.status, 412)
1005
jcgregorio2d66d4f2006-02-07 05:34:14 +00001006 def testBasicAuth(self):
1007 # Test Basic Authentication
1008 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001009 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001010 self.assertEqual(response.status, 401)
1011
1012 uri = urlparse.urljoin(base, "basic/")
jcgregorio36140b52006-06-13 02:17:52 +00001013 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001014 self.assertEqual(response.status, 401)
1015
jcgregorio36140b52006-06-13 02:17:52 +00001016 self.http.add_credentials('joe', 'password')
1017 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001018 self.assertEqual(response.status, 200)
1019
1020 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001021 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001022 self.assertEqual(response.status, 200)
1023
jcgregoriode8238d2007-03-07 19:08:26 +00001024 def testBasicAuthWithDomain(self):
1025 # Test Basic Authentication
1026 uri = urlparse.urljoin(base, "basic/file.txt")
1027 (response, content) = self.http.request(uri, "GET")
1028 self.assertEqual(response.status, 401)
1029
1030 uri = urlparse.urljoin(base, "basic/")
1031 (response, content) = self.http.request(uri, "GET")
1032 self.assertEqual(response.status, 401)
1033
1034 self.http.add_credentials('joe', 'password', "example.org")
1035 (response, content) = self.http.request(uri, "GET")
1036 self.assertEqual(response.status, 401)
1037
1038 uri = urlparse.urljoin(base, "basic/file.txt")
1039 (response, content) = self.http.request(uri, "GET")
1040 self.assertEqual(response.status, 401)
1041
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001042 domain = urlparse.urlparse(base)[1]
jcgregoriode8238d2007-03-07 19:08:26 +00001043 self.http.add_credentials('joe', 'password', domain)
1044 (response, content) = self.http.request(uri, "GET")
1045 self.assertEqual(response.status, 200)
1046
1047 uri = urlparse.urljoin(base, "basic/file.txt")
1048 (response, content) = self.http.request(uri, "GET")
1049 self.assertEqual(response.status, 200)
1050
1051
1052
1053
1054
1055
jcgregorio2d66d4f2006-02-07 05:34:14 +00001056 def testBasicAuthTwoDifferentCredentials(self):
jcgregorioadbb4f82006-05-19 15:17:42 +00001057 # Test Basic Authentication with multiple sets of credentials
jcgregorio2d66d4f2006-02-07 05:34:14 +00001058 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001059 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001060 self.assertEqual(response.status, 401)
1061
1062 uri = urlparse.urljoin(base, "basic2/")
jcgregorio36140b52006-06-13 02:17:52 +00001063 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001064 self.assertEqual(response.status, 401)
1065
jcgregorio36140b52006-06-13 02:17:52 +00001066 self.http.add_credentials('fred', 'barney')
1067 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001068 self.assertEqual(response.status, 200)
1069
1070 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001071 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001072 self.assertEqual(response.status, 200)
1073
1074 def testBasicAuthNested(self):
1075 # Test Basic Authentication with resources
1076 # that are nested
1077 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001078 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001079 self.assertEqual(response.status, 401)
1080
1081 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001082 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001083 self.assertEqual(response.status, 401)
1084
jcgregorioadbb4f82006-05-19 15:17:42 +00001085 # Now add in credentials one at a time and test.
jcgregorio36140b52006-06-13 02:17:52 +00001086 self.http.add_credentials('joe', 'password')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001087
1088 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001089 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001090 self.assertEqual(response.status, 200)
1091
1092 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001093 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001094 self.assertEqual(response.status, 401)
1095
jcgregorio36140b52006-06-13 02:17:52 +00001096 self.http.add_credentials('fred', 'barney')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001097
1098 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001099 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001100 self.assertEqual(response.status, 200)
1101
1102 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001103 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001104 self.assertEqual(response.status, 200)
1105
1106 def testDigestAuth(self):
1107 # Test that we support Digest Authentication
1108 uri = urlparse.urljoin(base, "digest/")
jcgregorio36140b52006-06-13 02:17:52 +00001109 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001110 self.assertEqual(response.status, 401)
1111
jcgregorio36140b52006-06-13 02:17:52 +00001112 self.http.add_credentials('joe', 'password')
1113 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001114 self.assertEqual(response.status, 200)
1115
1116 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001117 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001118
1119 def testDigestAuthNextNonceAndNC(self):
1120 # Test that if the server sets nextnonce that we reset
1121 # the nonce count back to 1
1122 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001123 self.http.add_credentials('joe', 'password')
1124 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001125 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1126 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +00001127 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001128 info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
1129 self.assertEqual(response.status, 200)
1130
1131 if info.has_key('nextnonce'):
1132 self.assertEqual(info2['nc'], 1)
1133
1134 def testDigestAuthStale(self):
1135 # Test that we can handle a nonce becoming stale
1136 uri = urlparse.urljoin(base, "digest-expire/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001137 self.http.add_credentials('joe', 'password')
1138 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001139 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1140 self.assertEqual(response.status, 200)
1141
1142 time.sleep(3)
1143 # Sleep long enough that the nonce becomes stale
1144
jcgregorio36140b52006-06-13 02:17:52 +00001145 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001146 self.assertFalse(response.fromcache)
1147 self.assertTrue(response._stale_digest)
1148 info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
1149 self.assertEqual(response.status, 200)
1150
1151 def reflector(self, content):
jcgregorio25185622006-10-28 05:12:34 +00001152 return dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
jcgregorio2d66d4f2006-02-07 05:34:14 +00001153
1154 def testReflector(self):
1155 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +00001156 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001157 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001158 self.assertTrue(d.has_key('HTTP_USER_AGENT'))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001159
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001160 def testConnectionClose(self):
1161 uri = "http://www.google.com/"
1162 (response, content) = self.http.request(uri, "GET")
1163 for c in self.http.connections.values():
1164 self.assertNotEqual(None, c.sock)
1165 (response, content) = self.http.request(uri, "GET", headers={"connection": "close"})
1166 for c in self.http.connections.values():
1167 self.assertEqual(None, c.sock)
1168
1169
jcgregorio36140b52006-06-13 02:17:52 +00001170try:
1171 import memcache
1172 class HttpTestMemCached(HttpTest):
1173 def setUp(self):
1174 self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
jcgregorio47d24672006-06-29 05:18:59 +00001175 #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
jcgregorio36140b52006-06-13 02:17:52 +00001176 self.http = httplib2.Http(self.cache)
1177 self.cache.flush_all()
jcgregorio47d24672006-06-29 05:18:59 +00001178 # Not exactly sure why the sleep is needed here, but
1179 # if not present then some unit tests that rely on caching
1180 # fail. Memcached seems to lose some sets immediately
1181 # after a flush_all if the set is to a value that
1182 # was previously cached. (Maybe the flush is handled async?)
1183 time.sleep(1)
jcgregorio36140b52006-06-13 02:17:52 +00001184 self.http.clear_credentials()
1185except:
1186 pass
1187
1188
1189
chris dent89f15142009-12-24 14:02:57 -06001190
jcgregoriodb8dfc82006-03-31 14:59:46 +00001191# ------------------------------------------------------------------------
jcgregorio2d66d4f2006-02-07 05:34:14 +00001192
1193class HttpPrivateTest(unittest.TestCase):
1194
1195 def testParseCacheControl(self):
1196 # Test that we can parse the Cache-Control header
1197 self.assertEqual({}, httplib2._parse_cache_control({}))
1198 self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
1199 cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
1200 self.assertEqual(cc['no-cache'], 1)
1201 self.assertEqual(cc['max-age'], '7200')
1202 cc = httplib2._parse_cache_control({'cache-control': ' , '})
1203 self.assertEqual(cc[''], 1)
1204
Joe Gregorioe314e8b2009-07-16 20:11:28 -04001205 try:
1206 cc = httplib2._parse_cache_control({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'})
1207 self.assertTrue("max-age" in cc)
1208 except:
1209 self.fail("Should not throw exception")
1210
jcgregorio2d66d4f2006-02-07 05:34:14 +00001211 def testNormalizeHeaders(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001212 # Test that we normalize headers to lowercase
jcgregorio2d66d4f2006-02-07 05:34:14 +00001213 h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
1214 self.assertTrue(h.has_key('cache-control'))
1215 self.assertTrue(h.has_key('other'))
1216 self.assertEqual('Stuff', h['other'])
1217
1218 def testExpirationModelTransparent(self):
1219 # Test that no-cache makes our request TRANSPARENT
1220 response_headers = {
1221 'cache-control': 'max-age=7200'
1222 }
1223 request_headers = {
1224 'cache-control': 'no-cache'
1225 }
1226 self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
1227
jcgregorio45865012007-01-18 16:38:22 +00001228 def testMaxAgeNonNumeric(self):
1229 # Test that no-cache makes our request TRANSPARENT
1230 response_headers = {
1231 'cache-control': 'max-age=fred, min-fresh=barney'
1232 }
1233 request_headers = {
1234 }
1235 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1236
1237
jcgregorio2d66d4f2006-02-07 05:34:14 +00001238 def testExpirationModelNoCacheResponse(self):
1239 # The date and expires point to an entry that should be
1240 # FRESH, but the no-cache over-rides that.
1241 now = time.time()
1242 response_headers = {
1243 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1244 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1245 'cache-control': 'no-cache'
1246 }
1247 request_headers = {
1248 }
1249 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1250
1251 def testExpirationModelStaleRequestMustReval(self):
1252 # must-revalidate forces STALE
1253 self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
1254
1255 def testExpirationModelStaleResponseMustReval(self):
1256 # must-revalidate forces STALE
1257 self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
1258
1259 def testExpirationModelFresh(self):
1260 response_headers = {
1261 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1262 'cache-control': 'max-age=2'
1263 }
1264 request_headers = {
1265 }
1266 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1267 time.sleep(3)
1268 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1269
1270 def testExpirationMaxAge0(self):
1271 response_headers = {
1272 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1273 'cache-control': 'max-age=0'
1274 }
1275 request_headers = {
1276 }
1277 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1278
1279 def testExpirationModelDateAndExpires(self):
1280 now = time.time()
1281 response_headers = {
1282 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1283 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1284 }
1285 request_headers = {
1286 }
1287 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1288 time.sleep(3)
1289 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1290
jcgregoriof9511052007-06-01 14:56:34 +00001291 def testExpiresZero(self):
1292 now = time.time()
1293 response_headers = {
1294 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1295 'expires': "0",
1296 }
1297 request_headers = {
1298 }
1299 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1300
jcgregorio2d66d4f2006-02-07 05:34:14 +00001301 def testExpirationModelDateOnly(self):
1302 now = time.time()
1303 response_headers = {
1304 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
1305 }
1306 request_headers = {
1307 }
1308 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1309
1310 def testExpirationModelOnlyIfCached(self):
1311 response_headers = {
1312 }
1313 request_headers = {
1314 'cache-control': 'only-if-cached',
1315 }
1316 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1317
1318 def testExpirationModelMaxAgeBoth(self):
1319 now = time.time()
1320 response_headers = {
1321 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1322 'cache-control': 'max-age=2'
1323 }
1324 request_headers = {
1325 'cache-control': 'max-age=0'
1326 }
1327 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1328
1329 def testExpirationModelDateAndExpiresMinFresh1(self):
1330 now = time.time()
1331 response_headers = {
1332 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1333 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1334 }
1335 request_headers = {
1336 'cache-control': 'min-fresh=2'
1337 }
1338 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1339
1340 def testExpirationModelDateAndExpiresMinFresh2(self):
1341 now = time.time()
1342 response_headers = {
1343 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1344 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1345 }
1346 request_headers = {
1347 'cache-control': 'min-fresh=2'
1348 }
1349 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1350
1351 def testParseWWWAuthenticateEmpty(self):
1352 res = httplib2._parse_www_authenticate({})
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001353 self.assertEqual(len(res.keys()), 0)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001354
jcgregoriofd22e432006-04-27 02:00:08 +00001355 def testParseWWWAuthenticate(self):
1356 # different uses of spaces around commas
1357 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
1358 self.assertEqual(len(res.keys()), 1)
1359 self.assertEqual(len(res['test'].keys()), 5)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001360
jcgregoriofd22e432006-04-27 02:00:08 +00001361 # tokens with non-alphanum
1362 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
1363 self.assertEqual(len(res.keys()), 1)
1364 self.assertEqual(len(res['t*!%#st'].keys()), 2)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001365
jcgregoriofd22e432006-04-27 02:00:08 +00001366 # quoted string with quoted pairs
1367 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
1368 self.assertEqual(len(res.keys()), 1)
1369 self.assertEqual(res['test']['realm'], 'a "test" realm')
1370
1371 def testParseWWWAuthenticateStrict(self):
1372 httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
1373 self.testParseWWWAuthenticate();
1374 httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
1375
jcgregorio2d66d4f2006-02-07 05:34:14 +00001376 def testParseWWWAuthenticateBasic(self):
1377 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
1378 basic = res['basic']
1379 self.assertEqual('me', basic['realm'])
1380
1381 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
1382 basic = res['basic']
1383 self.assertEqual('me', basic['realm'])
1384 self.assertEqual('MD5', basic['algorithm'])
1385
1386 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
1387 basic = res['basic']
1388 self.assertEqual('me', basic['realm'])
1389 self.assertEqual('MD5', basic['algorithm'])
1390
1391 def testParseWWWAuthenticateBasic2(self):
1392 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
1393 basic = res['basic']
1394 self.assertEqual('me', basic['realm'])
1395 self.assertEqual('fred', basic['other'])
1396
1397 def testParseWWWAuthenticateBasic3(self):
1398 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
1399 basic = res['basic']
1400 self.assertEqual('me', basic['realm'])
1401
1402
1403 def testParseWWWAuthenticateDigest(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001404 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001405 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
1406 digest = res['digest']
1407 self.assertEqual('testrealm@host.com', digest['realm'])
1408 self.assertEqual('auth,auth-int', digest['qop'])
1409
1410
1411 def testParseWWWAuthenticateMultiple(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001412 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001413 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
1414 digest = res['digest']
1415 self.assertEqual('testrealm@host.com', digest['realm'])
1416 self.assertEqual('auth,auth-int', digest['qop'])
1417 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1418 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1419 basic = res['basic']
1420 self.assertEqual('me', basic['realm'])
1421
1422 def testParseWWWAuthenticateMultiple2(self):
1423 # Handle an added comma between challenges, which might get thrown in if the challenges were
1424 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001425 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001426 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
1427 digest = res['digest']
1428 self.assertEqual('testrealm@host.com', digest['realm'])
1429 self.assertEqual('auth,auth-int', digest['qop'])
1430 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1431 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1432 basic = res['basic']
1433 self.assertEqual('me', basic['realm'])
1434
1435 def testParseWWWAuthenticateMultiple3(self):
1436 # Handle an added comma between challenges, which might get thrown in if the challenges were
1437 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001438 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001439 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1440 digest = res['digest']
1441 self.assertEqual('testrealm@host.com', digest['realm'])
1442 self.assertEqual('auth,auth-int', digest['qop'])
1443 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1444 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1445 basic = res['basic']
1446 self.assertEqual('me', basic['realm'])
1447 wsse = res['wsse']
1448 self.assertEqual('foo', wsse['realm'])
1449 self.assertEqual('UsernameToken', wsse['profile'])
1450
1451 def testParseWWWAuthenticateMultiple4(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001452 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1453 'Digest realm="test-real.m@host.com", qop \t=\t"\tauth,auth-int", nonce="(*)&^&$%#",opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001454 digest = res['digest']
1455 self.assertEqual('test-real.m@host.com', digest['realm'])
1456 self.assertEqual('\tauth,auth-int', digest['qop'])
1457 self.assertEqual('(*)&^&$%#', digest['nonce'])
1458
1459 def testParseWWWAuthenticateMoreQuoteCombos(self):
1460 res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
1461 digest = res['digest']
1462 self.assertEqual('myrealm', digest['realm'])
1463
Joe Gregorio6fa3cf22011-02-13 22:45:06 -05001464 def testParseWWWAuthenticateMalformed(self):
1465 try:
1466 res = httplib2._parse_www_authenticate({'www-authenticate':'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'})
1467 self.fail("should raise an exception")
1468 except httplib2.MalformedHeader:
1469 pass
1470
jcgregorio2d66d4f2006-02-07 05:34:14 +00001471 def testDigestObject(self):
1472 credentials = ('joe', 'password')
1473 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001474 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001475 headers = {}
1476 response = {
1477 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
1478 }
1479 content = ""
Joe Gregorio875a8b52011-06-13 14:06:23 -04001480
jcgregorio6cbab7e2006-04-21 20:35:43 +00001481 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001482 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
Joe Gregorio875a8b52011-06-13 14:06:23 -04001483 our_request = "authorization: %s" % headers['authorization']
1484 working_request = 'authorization: Digest username="joe", realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", uri="/projects/httplib2/test/digest/", algorithm=MD5, response="97ed129401f7cdc60e5db58a80f3ea8b", qop=auth, nc=00000001, cnonce="33033375ec278a46"'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001485 self.assertEqual(our_request, working_request)
1486
Joe Gregorio03d99102011-06-22 16:55:52 -04001487 def testDigestObjectWithOpaque(self):
1488 credentials = ('joe', 'password')
1489 host = None
1490 request_uri = '/projects/httplib2/test/digest/'
1491 headers = {}
1492 response = {
1493 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", opaque="atestopaque"'
1494 }
1495 content = ""
1496
1497 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
1498 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
1499 our_request = "authorization: %s" % headers['authorization']
1500 working_request = 'authorization: Digest username="joe", realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", uri="/projects/httplib2/test/digest/", algorithm=MD5, response="97ed129401f7cdc60e5db58a80f3ea8b", qop=auth, nc=00000001, cnonce="33033375ec278a46", opaque="atestopaque"'
1501 self.assertEqual(our_request, working_request)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001502
1503 def testDigestObjectStale(self):
1504 credentials = ('joe', 'password')
1505 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001506 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001507 headers = {}
1508 response = httplib2.Response({ })
1509 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1510 response.status = 401
1511 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001512 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001513 # Returns true to force a retry
1514 self.assertTrue( d.response(response, content) )
1515
1516 def testDigestObjectAuthInfo(self):
1517 credentials = ('joe', 'password')
1518 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001519 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001520 headers = {}
1521 response = httplib2.Response({ })
1522 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1523 response['authentication-info'] = 'nextnonce="fred"'
1524 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001525 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001526 # Returns true to force a retry
1527 self.assertFalse( d.response(response, content) )
1528 self.assertEqual('fred', d.challenge['nonce'])
1529 self.assertEqual(1, d.challenge['nc'])
1530
1531 def testWsseAlgorithm(self):
1532 digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
1533 expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
1534 self.assertEqual(expected, digest)
1535
jcgregoriodb8dfc82006-03-31 14:59:46 +00001536 def testEnd2End(self):
1537 # one end to end header
1538 response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
1539 end2end = httplib2._get_end2end_headers(response)
1540 self.assertTrue('content-type' in end2end)
1541 self.assertTrue('te' not in end2end)
1542 self.assertTrue('connection' not in end2end)
1543
1544 # one end to end header that gets eliminated
1545 response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
1546 end2end = httplib2._get_end2end_headers(response)
1547 self.assertTrue('content-type' not in end2end)
1548 self.assertTrue('te' not in end2end)
1549 self.assertTrue('connection' not in end2end)
1550
1551 # Degenerate case of no headers
1552 response = {}
1553 end2end = httplib2._get_end2end_headers(response)
1554 self.assertEquals(0, len(end2end))
1555
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001556 # Degenerate case of connection referrring to a header not passed in
jcgregoriodb8dfc82006-03-31 14:59:46 +00001557 response = {'connection': 'content-type'}
1558 end2end = httplib2._get_end2end_headers(response)
1559 self.assertEquals(0, len(end2end))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001560
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001561
1562class TestProxyInfo(unittest.TestCase):
1563 def setUp(self):
1564 self.orig_env = dict(os.environ)
1565
1566 def tearDown(self):
1567 os.environ.clear()
1568 os.environ.update(self.orig_env)
1569
1570 def test_from_url(self):
1571 pi = httplib2.ProxyInfo.from_url('http://myproxy.example.com')
1572 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1573 self.assertEquals(pi.proxy_port, 80)
1574 self.assertEquals(pi.proxy_user, None)
1575
1576 def test_from_url_ident(self):
1577 pi = httplib2.ProxyInfo.from_url('http://zoidberg:fish@someproxy:99')
1578 self.assertEquals(pi.proxy_host, 'someproxy')
1579 self.assertEquals(pi.proxy_port, 99)
1580 self.assertEquals(pi.proxy_user, 'zoidberg')
1581 self.assertEquals(pi.proxy_pass, 'fish')
1582
1583 def test_from_env(self):
1584 os.environ['http_proxy'] = 'http://myproxy.example.com:8080'
1585 pi = httplib2.ProxyInfo.from_environment()
1586 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1587 self.assertEquals(pi.proxy_port, 8080)
1588 self.assertEquals(pi.bypass_hosts, [])
1589
1590 def test_from_env_no_proxy(self):
1591 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1592 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
1593 os.environ['no_proxy'] = 'localhost,otherhost.domain.local'
1594 pi = httplib2.ProxyInfo.from_environment('https')
1595 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1596 self.assertEquals(pi.proxy_port, 81)
1597 self.assertEquals(pi.bypass_hosts, ['localhost',
1598 'otherhost.domain.local'])
1599
1600 def test_from_env_none(self):
1601 os.environ.clear()
1602 pi = httplib2.ProxyInfo.from_environment()
1603 self.assertEquals(pi, None)
1604
Jason R. Coombs43840892011-08-09 10:30:46 -04001605 def test_applies_to(self):
1606 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1607 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
Jason R. Coombs96279c52011-08-16 12:53:27 -04001608 os.environ['no_proxy'] = 'localhost,otherhost.domain.local,example.com'
Jason R. Coombs43840892011-08-09 10:30:46 -04001609 pi = httplib2.ProxyInfo.from_environment()
1610 self.assertFalse(pi.applies_to('localhost'))
1611 self.assertTrue(pi.applies_to('www.google.com'))
Jason R. Coombs96279c52011-08-16 12:53:27 -04001612 self.assertFalse(pi.applies_to('www.example.com'))
1613
1614 def test_no_proxy_star(self):
1615 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1616 os.environ['NO_PROXY'] = '*'
1617 pi = httplib2.ProxyInfo.from_environment()
1618 for host in ('localhost', '169.254.38.192', 'www.google.com'):
1619 self.assertFalse(pi.applies_to(host))
Jason R. Coombs43840892011-08-09 10:30:46 -04001620
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001621
chris dent89f15142009-12-24 14:02:57 -06001622if __name__ == '__main__':
1623 unittest.main()