blob: 104eaf7a894f9a86a845cd4f8c4535438fc409f2 [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 Gregorio46546a62012-10-03 14:31:10 -040023import pickle
Joe Gregoriob6c90c42011-02-11 01:03:22 -050024import socket
25import sys
jcgregoriode8238d2007-03-07 19:08:26 +000026import time
Joe Gregoriob6c90c42011-02-11 01:03:22 -050027import unittest
28import urlparse
jcgregorio8421f272006-02-14 18:19:51 +000029
Joe Gregoriob53de9b2011-06-07 15:44:51 -040030try:
31 import ssl
32except ImportError:
33 pass
Joe Gregorio694a8122011-02-13 21:40:09 -050034
jcgregorio8421f272006-02-14 18:19:51 +000035# Python 2.3 support
36if not hasattr(unittest.TestCase, 'assertTrue'):
37 unittest.TestCase.assertTrue = unittest.TestCase.failUnless
38 unittest.TestCase.assertFalse = unittest.TestCase.failIf
39
jcgregorio2d66d4f2006-02-07 05:34:14 +000040# The test resources base uri
41base = 'http://bitworking.org/projects/httplib2/test/'
42#base = 'http://localhost/projects/httplib2/test/'
jcgregorio90fb4a42006-11-17 16:19:47 +000043cacheDirName = ".cache"
jcgregorio2d66d4f2006-02-07 05:34:14 +000044
jcgregoriode8238d2007-03-07 19:08:26 +000045
46class CredentialsTest(unittest.TestCase):
47 def test(self):
48 c = httplib2.Credentials()
49 c.add("joe", "password")
50 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
51 self.assertEqual(("joe", "password"), list(c.iter(""))[0])
52 c.add("fred", "password2", "wellformedweb.org")
53 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
54 self.assertEqual(1, len(list(c.iter("bitworking.org"))))
55 self.assertEqual(2, len(list(c.iter("wellformedweb.org"))))
56 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
57 c.clear()
58 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
59 c.add("fred", "password2", "wellformedweb.org")
60 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
61 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
62 self.assertEqual(0, len(list(c.iter(""))))
63
64
jcgregorio2d66d4f2006-02-07 05:34:14 +000065class ParserTest(unittest.TestCase):
66 def testFromStd66(self):
67 self.assertEqual( ('http', 'example.com', '', None, None ), httplib2.parse_uri("http://example.com"))
68 self.assertEqual( ('https', 'example.com', '', None, None ), httplib2.parse_uri("https://example.com"))
69 self.assertEqual( ('https', 'example.com:8080', '', None, None ), httplib2.parse_uri("https://example.com:8080"))
70 self.assertEqual( ('http', 'example.com', '/', None, None ), httplib2.parse_uri("http://example.com/"))
71 self.assertEqual( ('http', 'example.com', '/path', None, None ), httplib2.parse_uri("http://example.com/path"))
72 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', None ), httplib2.parse_uri("http://example.com/path?a=1&b=2"))
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 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
75
jcgregorio2d66d4f2006-02-07 05:34:14 +000076
jcgregorioa46fe4e2006-11-16 04:13:45 +000077class UrlNormTest(unittest.TestCase):
78 def test(self):
79 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://example.org")[-1])
80 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://EXAMple.org")[-1])
81 self.assertEqual( "http://example.org/?=b", httplib2.urlnorm("http://EXAMple.org?=b")[-1])
82 self.assertEqual( "http://example.org/mypath?a=b", httplib2.urlnorm("http://EXAMple.org/mypath?a=b")[-1])
83 self.assertEqual( "http://localhost:80/", httplib2.urlnorm("http://localhost:80")[-1])
jcgregoriob4e9ab02006-11-17 15:53:15 +000084 self.assertEqual( httplib2.urlnorm("http://localhost:80/"), httplib2.urlnorm("HTTP://LOCALHOST:80"))
jcgregorio132d28e2007-01-23 16:22:53 +000085 try:
86 httplib2.urlnorm("/")
87 self.fail("Non-absolute URIs should raise an exception")
88 except httplib2.RelativeURIError:
89 pass
jcgregorioa46fe4e2006-11-16 04:13:45 +000090
91class UrlSafenameTest(unittest.TestCase):
92 def test(self):
93 # Test that different URIs end up generating different safe names
94 self.assertEqual( "example.org,fred,a=b,58489f63a7a83c3b7794a6a398ee8b1f", httplib2.safename("http://example.org/fred/?a=b"))
95 self.assertEqual( "example.org,fred,a=b,8c5946d56fec453071f43329ff0be46b", httplib2.safename("http://example.org/fred?/a=b"))
96 self.assertEqual( "www.example.org,fred,a=b,499c44b8d844a011b67ea2c015116968", httplib2.safename("http://www.example.org/fred?/a=b"))
97 self.assertEqual( httplib2.safename(httplib2.urlnorm("http://www")[-1]), httplib2.safename(httplib2.urlnorm("http://WWW")[-1]))
98 self.assertEqual( "www.example.org,fred,a=b,692e843a333484ce0095b070497ab45d", httplib2.safename("https://www.example.org/fred?/a=b"))
99 self.assertNotEqual( httplib2.safename("http://www"), httplib2.safename("https://www"))
100 # Test the max length limits
101 uri = "http://" + ("w" * 200) + ".org"
102 uri2 = "http://" + ("w" * 201) + ".org"
103 self.assertNotEqual( httplib2.safename(uri2), httplib2.safename(uri))
104 # Max length should be 200 + 1 (",") + 32
105 self.assertEqual(233, len(httplib2.safename(uri2)))
106 self.assertEqual(233, len(httplib2.safename(uri)))
107 # Unicode
jcgregoriodebceec2006-12-12 20:26:02 +0000108 if sys.version_info >= (2,3):
109 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 +0000110
jcgregorio14644372007-07-30 14:13:37 +0000111class _MyResponse(StringIO.StringIO):
112 def __init__(self, body, **kwargs):
113 StringIO.StringIO.__init__(self, body)
114 self.headers = kwargs
115
116 def iteritems(self):
117 return self.headers.iteritems()
118
119
120class _MyHTTPConnection(object):
121 "This class is just a mock of httplib.HTTPConnection used for testing"
122
123 def __init__(self, host, port=None, key_file=None, cert_file=None,
joe.gregoriof28536d2007-10-23 14:10:11 +0000124 strict=None, timeout=None, proxy_info=None):
jcgregorio14644372007-07-30 14:13:37 +0000125 self.host = host
126 self.port = port
127 self.timeout = timeout
128 self.log = ""
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400129 self.sock = None
jcgregorio14644372007-07-30 14:13:37 +0000130
131 def set_debuglevel(self, level):
132 pass
133
134 def connect(self):
135 "Connect to a host on a given port."
136 pass
137
138 def close(self):
139 pass
140
141 def request(self, method, request_uri, body, headers):
142 pass
143
144 def getresponse(self):
145 return _MyResponse("the body", status="200")
jcgregorioa46fe4e2006-11-16 04:13:45 +0000146
Joe Gregorio1d3a7092013-03-08 14:14:56 -0500147class _MyHTTPBadStatusConnection(object):
148 "Mock of httplib.HTTPConnection that raises BadStatusLine."
149
150 num_calls = 0
151
152 def __init__(self, host, port=None, key_file=None, cert_file=None,
153 strict=None, timeout=None, proxy_info=None):
154 self.host = host
155 self.port = port
156 self.timeout = timeout
157 self.log = ""
158 self.sock = None
159 _MyHTTPBadStatusConnection.num_calls = 0
160
161 def set_debuglevel(self, level):
162 pass
163
164 def connect(self):
165 pass
166
167 def close(self):
168 pass
169
170 def request(self, method, request_uri, body, headers):
171 pass
172
173 def getresponse(self):
174 _MyHTTPBadStatusConnection.num_calls += 1
175 raise httplib.BadStatusLine("")
176
jcgregorio90fb4a42006-11-17 16:19:47 +0000177
jcgregorio2d66d4f2006-02-07 05:34:14 +0000178class HttpTest(unittest.TestCase):
179 def setUp(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400180 if os.path.exists(cacheDirName):
jcgregorio7e3608f2006-06-15 13:01:53 +0000181 [os.remove(os.path.join(cacheDirName, file)) for file in os.listdir(cacheDirName)]
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400182
183 if sys.version_info < (2, 6):
184 disable_cert_validation = True
185 else:
186 disable_cert_validation = False
187 self.http = httplib2.Http(
188 cacheDirName,
189 disable_ssl_certificate_validation=disable_cert_validation)
jcgregorio36140b52006-06-13 02:17:52 +0000190 self.http.clear_credentials()
jcgregorio2d66d4f2006-02-07 05:34:14 +0000191
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500192 def testIPv6NoSSL(self):
193 try:
194 self.http.request("http://[::1]/")
195 except socket.gaierror:
196 self.fail("should get the address family right for IPv6")
197 except socket.error:
198 # Even if IPv6 isn't installed on a machine it should just raise socket.error
199 pass
200
201 def testIPv6SSL(self):
202 try:
203 self.http.request("https://[::1]/")
204 except socket.gaierror:
205 self.fail("should get the address family right for IPv6")
Jason R. Coombscee15da2011-08-09 09:13:34 -0400206 except httplib2.CertificateHostnameMismatch:
207 # We connected and verified that the certificate doesn't match
208 # the name. Good enough.
209 pass
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500210 except socket.error:
211 # Even if IPv6 isn't installed on a machine it should just raise socket.error
212 pass
213
jcgregorio14644372007-07-30 14:13:37 +0000214 def testConnectionType(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400215 self.http.force_exception_to_status_code = False
jcgregorio14644372007-07-30 14:13:37 +0000216 response, content = self.http.request("http://bitworking.org", connection_type=_MyHTTPConnection)
217 self.assertEqual(response['content-location'], "http://bitworking.org")
218 self.assertEqual(content, "the body")
219
Joe Gregorio1d3a7092013-03-08 14:14:56 -0500220 def testBadStatusLineRetry(self):
221 old_retries = httplib2.RETRIES
222 httplib2.RETRIES = 1
223 self.http.force_exception_to_status_code = False
224 try:
225 response, content = self.http.request("http://bitworking.org",
226 connection_type=_MyHTTPBadStatusConnection)
227 except httplib.BadStatusLine:
228 self.assertEqual(2, _MyHTTPBadStatusConnection.num_calls)
229 httplib2.RETRIES = old_retries
230
jcgregorio6a638172007-01-23 16:40:23 +0000231 def testGetUnknownServer(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400232 self.http.force_exception_to_status_code = False
jcgregorio6a638172007-01-23 16:40:23 +0000233 try:
234 self.http.request("http://fred.bitworking.org/")
235 self.fail("An httplib2.ServerNotFoundError Exception must be thrown on an unresolvable server.")
236 except httplib2.ServerNotFoundError:
237 pass
238
jcgregorio07a9a4a2007-03-08 21:18:39 +0000239 # Now test with exceptions turned off
240 self.http.force_exception_to_status_code = True
241
242 (response, content) = self.http.request("http://fred.bitworking.org/")
243 self.assertEqual(response['content-type'], 'text/plain')
244 self.assertTrue(content.startswith("Unable to find"))
245 self.assertEqual(response.status, 400)
246
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500247 def testGetConnectionRefused(self):
248 self.http.force_exception_to_status_code = False
249 try:
250 self.http.request("http://localhost:7777/")
251 self.fail("An socket.error exception must be thrown on Connection Refused.")
252 except socket.error:
253 pass
254
255 # Now test with exceptions turned off
256 self.http.force_exception_to_status_code = True
257
258 (response, content) = self.http.request("http://localhost:7777/")
259 self.assertEqual(response['content-type'], 'text/plain')
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400260 self.assertTrue("Connection refused" in content
261 or "actively refused" in content,
262 "Unexpected status %(content)s" % vars())
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500263 self.assertEqual(response.status, 400)
264
jcgregorioa898f8f2006-12-12 17:16:55 +0000265 def testGetIRI(self):
jcgregoriodebceec2006-12-12 20:26:02 +0000266 if sys.version_info >= (2,3):
267 uri = urlparse.urljoin(base, u"reflector/reflector.cgi?d=\N{CYRILLIC CAPITAL LETTER DJE}")
268 (response, content) = self.http.request(uri, "GET")
269 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400270 self.assertTrue(d.has_key('QUERY_STRING'))
271 self.assertTrue(d['QUERY_STRING'].find('%D0%82') > 0)
272
jcgregorio2d66d4f2006-02-07 05:34:14 +0000273 def testGetIsDefaultMethod(self):
274 # Test that GET is the default method
275 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000276 (response, content) = self.http.request(uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000277 self.assertEqual(response['x-method'], "GET")
278
279 def testDifferentMethods(self):
280 # Test that all methods can be used
281 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
282 for method in ["GET", "PUT", "DELETE", "POST"]:
jcgregorio36140b52006-06-13 02:17:52 +0000283 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000284 self.assertEqual(response['x-method'], method)
285
Joe Gregoriob628c0b2009-07-16 12:28:04 -0400286 def testHeadRead(self):
287 # Test that we don't try to read the response of a HEAD request
288 # since httplib blocks response.read() for HEAD requests.
289 # Oddly enough this doesn't appear as a problem when doing HEAD requests
290 # against Apache servers.
291 uri = "http://www.google.com/"
292 (response, content) = self.http.request(uri, "HEAD")
293 self.assertEqual(response.status, 200)
294 self.assertEqual(content, "")
295
jcgregorio2d66d4f2006-02-07 05:34:14 +0000296 def testGetNoCache(self):
297 # Test that can do a GET w/o the cache turned on.
298 http = httplib2.Http()
299 uri = urlparse.urljoin(base, "304/test_etag.txt")
300 (response, content) = http.request(uri, "GET")
301 self.assertEqual(response.status, 200)
jcgregorioa0713ab2006-07-01 05:21:34 +0000302 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000303
Joe Gregorioe202d212009-07-16 14:57:52 -0400304 def testGetOnlyIfCachedCacheHit(self):
305 # Test that can do a GET with cache and 'only-if-cached'
306 uri = urlparse.urljoin(base, "304/test_etag.txt")
307 (response, content) = self.http.request(uri, "GET")
308 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
309 self.assertEqual(response.fromcache, True)
310 self.assertEqual(response.status, 200)
311
jcgregorioe4ce13e2006-04-02 03:05:08 +0000312 def testGetOnlyIfCachedCacheMiss(self):
313 # Test that can do a GET with no cache with 'only-if-cached'
jcgregorioe4ce13e2006-04-02 03:05:08 +0000314 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorioe202d212009-07-16 14:57:52 -0400315 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
jcgregorioe4ce13e2006-04-02 03:05:08 +0000316 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400317 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000318
319 def testGetOnlyIfCachedNoCacheAtAll(self):
320 # Test that can do a GET with no cache with 'only-if-cached'
321 # Of course, there might be an intermediary beyond us
322 # that responds to the 'only-if-cached', so this
323 # test can't really be guaranteed to pass.
324 http = httplib2.Http()
325 uri = urlparse.urljoin(base, "304/test_etag.txt")
326 (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
327 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400328 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000329
jcgregorio2d66d4f2006-02-07 05:34:14 +0000330 def testUserAgent(self):
331 # Test that we provide a default user-agent
332 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000333 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000334 self.assertEqual(response.status, 200)
335 self.assertTrue(content.startswith("Python-httplib2/"))
336
337 def testUserAgentNonDefault(self):
338 # Test that the default user-agent can be over-ridden
joe.gregoriof28536d2007-10-23 14:10:11 +0000339
jcgregorio2d66d4f2006-02-07 05:34:14 +0000340 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000341 (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000342 self.assertEqual(response.status, 200)
343 self.assertTrue(content.startswith("fred/1.0"))
344
345 def testGet300WithLocation(self):
346 # Test the we automatically follow 300 redirects if a Location: header is provided
347 uri = urlparse.urljoin(base, "300/with-location-header.asis")
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)
350 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000351 self.assertEqual(response.previous.status, 300)
352 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000353
354 # Confirm that the intermediate 300 is not cached
jcgregorio36140b52006-06-13 02:17:52 +0000355 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000356 self.assertEqual(response.status, 200)
357 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000358 self.assertEqual(response.previous.status, 300)
359 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000360
jcgregorio2f1e1422007-05-03 13:17:33 +0000361 def testGet300WithLocationNoRedirect(self):
362 # Test the we automatically follow 300 redirects if a Location: header is provided
363 self.http.follow_redirects = False
364 uri = urlparse.urljoin(base, "300/with-location-header.asis")
365 (response, content) = self.http.request(uri, "GET")
366 self.assertEqual(response.status, 300)
367
jcgregorio2d66d4f2006-02-07 05:34:14 +0000368 def testGet300WithoutLocation(self):
369 # Not giving a Location: header in a 300 response is acceptable
370 # In which case we just return the 300 response
371 uri = urlparse.urljoin(base, "300/without-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000372 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000373 self.assertEqual(response.status, 300)
374 self.assertTrue(response['content-type'].startswith("text/html"))
jcgregorioa0713ab2006-07-01 05:21:34 +0000375 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000376
377 def testGet301(self):
378 # Test that we automatically follow 301 redirects
379 # and that we cache the 301 response
380 uri = urlparse.urljoin(base, "301/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000381 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000382 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000383 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000384 self.assertTrue(response.has_key('content-location'))
385 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000386 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000387 self.assertEqual(response.previous.status, 301)
388 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000389
jcgregorio36140b52006-06-13 02:17:52 +0000390 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000391 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000392 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000393 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000394 self.assertEqual(response.previous.status, 301)
395 self.assertEqual(response.previous.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000396
Joe Gregorio694a8122011-02-13 21:40:09 -0500397 def testHead301(self):
398 # Test that we automatically follow 301 redirects
399 uri = urlparse.urljoin(base, "301/onestep.asis")
400 destination = urlparse.urljoin(base, "302/final-destination.txt")
401 (response, content) = self.http.request(uri, "HEAD")
402 self.assertEqual(response.status, 200)
403 self.assertEqual(response.previous.status, 301)
404 self.assertEqual(response.previous.fromcache, False)
jcgregorio2f1e1422007-05-03 13:17:33 +0000405
406 def testGet301NoRedirect(self):
407 # Test that we automatically follow 301 redirects
408 # and that we cache the 301 response
409 self.http.follow_redirects = False
410 uri = urlparse.urljoin(base, "301/onestep.asis")
411 destination = urlparse.urljoin(base, "302/final-destination.txt")
412 (response, content) = self.http.request(uri, "GET")
413 self.assertEqual(response.status, 301)
414
415
jcgregorio2d66d4f2006-02-07 05:34:14 +0000416 def testGet302(self):
417 # Test that we automatically follow 302 redirects
418 # and that we DO NOT cache the 302 response
419 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000420 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000421 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000422 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000423 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000424 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000425 self.assertEqual(response.previous.status, 302)
426 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000427
428 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000429 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000430 self.assertEqual(response.status, 200)
431 self.assertEqual(response.fromcache, True)
jcgregorio772adc82006-11-17 21:52:34 +0000432 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000433 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000434 self.assertEqual(response.previous.status, 302)
435 self.assertEqual(response.previous.fromcache, False)
jcgregorio772adc82006-11-17 21:52:34 +0000436 self.assertEqual(response.previous['content-location'], uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000437
438 uri = urlparse.urljoin(base, "302/twostep.asis")
439
jcgregorio36140b52006-06-13 02:17:52 +0000440 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000441 self.assertEqual(response.status, 200)
442 self.assertEqual(response.fromcache, True)
443 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000444 self.assertEqual(response.previous.status, 302)
445 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000446
447 def testGet302RedirectionLimit(self):
448 # Test that we can set a lower redirection limit
449 # and that we raise an exception when we exceed
450 # that limit.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400451 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000452
jcgregorio2d66d4f2006-02-07 05:34:14 +0000453 uri = urlparse.urljoin(base, "302/twostep.asis")
454 try:
jcgregorio36140b52006-06-13 02:17:52 +0000455 (response, content) = self.http.request(uri, "GET", redirections = 1)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000456 self.fail("This should not happen")
457 except httplib2.RedirectLimit:
458 pass
459 except Exception, e:
460 self.fail("Threw wrong kind of exception ")
461
jcgregorio07a9a4a2007-03-08 21:18:39 +0000462 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400463 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000464
465 (response, content) = self.http.request(uri, "GET", redirections = 1)
466 self.assertEqual(response.status, 500)
467 self.assertTrue(response.reason.startswith("Redirected more"))
468 self.assertEqual("302", response['status'])
469 self.assertTrue(content.startswith("<html>"))
470 self.assertTrue(response.previous != None)
471
jcgregorio2d66d4f2006-02-07 05:34:14 +0000472 def testGet302NoLocation(self):
473 # Test that we throw an exception when we get
474 # a 302 with no Location: header.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400475 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000476 uri = urlparse.urljoin(base, "302/no-location.asis")
477 try:
jcgregorio36140b52006-06-13 02:17:52 +0000478 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000479 self.fail("Should never reach here")
480 except httplib2.RedirectMissingLocation:
481 pass
482 except Exception, e:
483 self.fail("Threw wrong kind of exception ")
484
jcgregorio07a9a4a2007-03-08 21:18:39 +0000485 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400486 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000487
488 (response, content) = self.http.request(uri, "GET")
489 self.assertEqual(response.status, 500)
490 self.assertTrue(response.reason.startswith("Redirected but"))
491 self.assertEqual("302", response['status'])
492 self.assertTrue(content.startswith("This is content"))
Joe Gregorio84e33252011-05-03 09:09:13 -0400493
Joe Gregorioac335ff2011-11-14 12:29:03 -0500494 def testGet301ViaHttps(self):
495 # Google always redirects to https://www.google.com
496 (response, content) = self.http.request("https://code.google.com/apis/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000497 self.assertEqual(200, response.status)
Joe Gregorioac335ff2011-11-14 12:29:03 -0500498 self.assertEqual(301, response.previous.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000499
500 def testGetViaHttps(self):
501 # Test that we can handle HTTPS
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400502 (response, content) = self.http.request("https://www.google.com/adsense/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000503 self.assertEqual(200, response.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000504
505 def testGetViaHttpsSpecViolationOnLocation(self):
506 # Test that we follow redirects through HTTPS
507 # even if they violate the spec by including
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400508 # a relative Location: header instead of an
jcgregorio2d66d4f2006-02-07 05:34:14 +0000509 # absolute one.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400510 (response, content) = self.http.request("https://www.google.com/adsense", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000511 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000512 self.assertNotEqual(None, response.previous)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000513
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400514 def testSslCertValidation(self):
515 if sys.version_info >= (2, 6):
516 # Test that we get an ssl.SSLError when specifying a non-existent CA
517 # certs file.
518 http = httplib2.Http(ca_certs='/nosuchfile')
519 self.assertRaises(ssl.SSLError,
520 http.request, "https://www.google.com/", "GET")
521
522 # Test that we get a SSLHandshakeError if we try to access
523 # https;//www.google.com, using a CA cert file that doesn't contain
524 # the CA Gogole uses (i.e., simulating a cert that's not signed by a
525 # trusted CA).
526 other_ca_certs = os.path.join(
527 os.path.dirname(os.path.abspath(httplib2.__file__ )),
528 "test", "other_cacerts.txt")
529 http = httplib2.Http(ca_certs=other_ca_certs)
530 self.assertRaises(httplib2.SSLHandshakeError,
531 http.request, "https://www.google.com/", "GET")
532
Joe Gregorioc69dc782011-06-23 08:56:59 -0400533 def testSslCertValidationDoubleDots(self):
534 if sys.version_info >= (2, 6):
535 # Test that we get match a double dot cert
536 try:
537 self.http.request("https://1.www.appspot.com/", "GET")
538 except httplib2.CertificateHostnameMismatch:
539 self.fail('cert with *.*.appspot.com should not raise an exception.')
540
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400541 def testSslHostnameValidation(self):
Joe Gregorio3e563132012-03-02 10:52:45 -0500542 pass
543 # No longer a valid test.
544 #if sys.version_info >= (2, 6):
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400545 # The SSL server at google.com:443 returns a certificate for
546 # 'www.google.com', which results in a host name mismatch.
547 # Note that this test only works because the ssl module and httplib2
548 # do not support SNI; for requests specifying a server name of
549 # 'google.com' via SNI, a matching cert would be returned.
Joe Gregorio3e563132012-03-02 10:52:45 -0500550 # self.assertRaises(httplib2.CertificateHostnameMismatch,
551 # self.http.request, "https://google.com/", "GET")
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400552
553 def testSslCertValidationWithoutSslModuleFails(self):
554 if sys.version_info < (2, 6):
555 http = httplib2.Http(disable_ssl_certificate_validation=False)
556 self.assertRaises(httplib2.CertificateValidationUnsupported,
557 http.request, "https://www.google.com/", "GET")
jcgregoriode8238d2007-03-07 19:08:26 +0000558
559 def testGetViaHttpsKeyCert(self):
jcgregorio2f1e1422007-05-03 13:17:33 +0000560 # At this point I can only test
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400561 # that the key and cert files are passed in
562 # correctly to httplib. It would be nice to have
jcgregorio2f1e1422007-05-03 13:17:33 +0000563 # a real https endpoint to test against.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400564
565 # bitworking.org presents an certificate for a non-matching host
566 # (*.webfaction.com), so we need to disable cert checking for this test.
567 http = httplib2.Http(timeout=2, disable_ssl_certificate_validation=True)
jcgregoriode8238d2007-03-07 19:08:26 +0000568
569 http.add_certificate("akeyfile", "acertfile", "bitworking.org")
570 try:
571 (response, content) = http.request("https://bitworking.org", "GET")
572 except:
573 pass
574 self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
575 self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
576
jcgregorio2f1e1422007-05-03 13:17:33 +0000577 try:
578 (response, content) = http.request("https://notthere.bitworking.org", "GET")
579 except:
580 pass
581 self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
582 self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
583
584
585
jcgregoriode8238d2007-03-07 19:08:26 +0000586
jcgregorio2d66d4f2006-02-07 05:34:14 +0000587 def testGet303(self):
588 # Do a follow-up GET on a Location: header
589 # returned from a POST that gave a 303.
590 uri = urlparse.urljoin(base, "303/303.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000591 (response, content) = self.http.request(uri, "POST", " ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000592 self.assertEqual(response.status, 200)
593 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000594 self.assertEqual(response.previous.status, 303)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000595
jcgregorio2f1e1422007-05-03 13:17:33 +0000596 def testGet303NoRedirect(self):
597 # Do a follow-up GET on a Location: header
598 # returned from a POST that gave a 303.
599 self.http.follow_redirects = False
600 uri = urlparse.urljoin(base, "303/303.cgi")
601 (response, content) = self.http.request(uri, "POST", " ")
602 self.assertEqual(response.status, 303)
603
jcgregorio2d66d4f2006-02-07 05:34:14 +0000604 def test303ForDifferentMethods(self):
605 # Test that all methods can be used
606 uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400607 for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
jcgregorio36140b52006-06-13 02:17:52 +0000608 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000609 self.assertEqual(response['x-method'], method_on_303)
610
Joe Gregoriob30ed372012-07-23 14:45:17 -0400611 def test303AndForwardAuthorizationHeader(self):
612 # Test that all methods can be used
613 uri = urlparse.urljoin(base, "303/redirect-to-header-reflector.cgi")
614 headers = {'authorization': 'Bearer foo'}
615 response, content = self.http.request(uri, 'GET', body=" ",
616 headers=headers)
617 # self.assertTrue('authorization' not in content)
618 self.http.follow_all_redirects = True
619 self.http.forward_authorization_headers = True
620 response, content = self.http.request(uri, 'GET', body=" ",
621 headers=headers)
622 # Oh, how I wish Apache didn't eat the Authorization header.
623 # self.assertTrue('authorization' in content)
624
jcgregorio2d66d4f2006-02-07 05:34:14 +0000625 def testGet304(self):
626 # Test that we use ETags properly to validate our cache
627 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000628 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000629 self.assertNotEqual(response['etag'], "")
630
jcgregorio36140b52006-06-13 02:17:52 +0000631 (response, content) = self.http.request(uri, "GET")
632 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000633 self.assertEqual(response.status, 200)
634 self.assertEqual(response.fromcache, True)
635
jcgregorio90fb4a42006-11-17 16:19:47 +0000636 cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
637 f = open(cache_file_name, "r")
638 status_line = f.readline()
639 f.close()
640
641 self.assertTrue(status_line.startswith("status:"))
642
jcgregorio36140b52006-06-13 02:17:52 +0000643 (response, content) = self.http.request(uri, "HEAD")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000644 self.assertEqual(response.status, 200)
645 self.assertEqual(response.fromcache, True)
646
jcgregorio36140b52006-06-13 02:17:52 +0000647 (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000648 self.assertEqual(response.status, 206)
649 self.assertEqual(response.fromcache, False)
650
jcgregorio25185622006-10-28 05:12:34 +0000651 def testGetIgnoreEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400652 # Test that we can forcibly ignore ETags
jcgregorio25185622006-10-28 05:12:34 +0000653 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
654 (response, content) = self.http.request(uri, "GET")
655 self.assertNotEqual(response['etag'], "")
656
657 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
658 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400659 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000660
661 self.http.ignore_etag = True
662 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
663 d = self.reflector(content)
664 self.assertEqual(response.fromcache, False)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400665 self.assertFalse(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000666
jcgregorio4b145e82007-01-18 19:46:34 +0000667 def testOverrideEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400668 # Test that we can forcibly ignore ETags
jcgregorio4b145e82007-01-18 19:46:34 +0000669 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
670 (response, content) = self.http.request(uri, "GET")
671 self.assertNotEqual(response['etag'], "")
672
673 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
674 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400675 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
676 self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio4b145e82007-01-18 19:46:34 +0000677
pilgrim00a352e2009-05-29 04:04:44 +0000678 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0', 'if-none-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +0000679 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400680 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
681 self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio25185622006-10-28 05:12:34 +0000682
pilgrim00a352e2009-05-29 04:04:44 +0000683#MAP-commented this out because it consistently fails
684# def testGet304EndToEnd(self):
685# # Test that end to end headers get overwritten in the cache
686# uri = urlparse.urljoin(base, "304/end2end.cgi")
687# (response, content) = self.http.request(uri, "GET")
688# self.assertNotEqual(response['etag'], "")
689# old_date = response['date']
690# time.sleep(2)
691#
692# (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
693# # The response should be from the cache, but the Date: header should be updated.
694# new_date = response['date']
695# self.assertNotEqual(new_date, old_date)
696# self.assertEqual(response.status, 200)
697# self.assertEqual(response.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000698
699 def testGet304LastModified(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400700 # Test that we can still handle a 304
jcgregorio2d66d4f2006-02-07 05:34:14 +0000701 # by only using the last-modified cache validator.
702 uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000703 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000704
705 self.assertNotEqual(response['last-modified'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000706 (response, content) = self.http.request(uri, "GET")
707 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000708 self.assertEqual(response.status, 200)
709 self.assertEqual(response.fromcache, True)
710
711 def testGet307(self):
712 # Test that we do follow 307 redirects but
713 # do not cache the 307
714 uri = urlparse.urljoin(base, "307/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000715 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000716 self.assertEqual(response.status, 200)
717 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000718 self.assertEqual(response.previous.status, 307)
719 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000720
jcgregorio36140b52006-06-13 02:17:52 +0000721 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000722 self.assertEqual(response.status, 200)
723 self.assertEqual(response.fromcache, True)
724 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000725 self.assertEqual(response.previous.status, 307)
726 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000727
728 def testGet410(self):
729 # Test that we pass 410's through
730 uri = urlparse.urljoin(base, "410/410.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000731 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000732 self.assertEqual(response.status, 410)
733
chris dent89f15142009-12-24 14:02:57 -0600734 def testVaryHeaderSimple(self):
735 """
736 RFC 2616 13.6
737 When the cache receives a subsequent request whose Request-URI
738 specifies one or more cache entries including a Vary header field,
739 the cache MUST NOT use such a cache entry to construct a response
740 to the new request unless all of the selecting request-headers
741 present in the new request match the corresponding stored
742 request-headers in the original request.
743 """
744 # test that the vary header is sent
745 uri = urlparse.urljoin(base, "vary/accept.asis")
746 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
747 self.assertEqual(response.status, 200)
748 self.assertTrue(response.has_key('vary'))
749
750 # get the resource again, from the cache since accept header in this
751 # request is the same as the request
752 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
753 self.assertEqual(response.status, 200)
754 self.assertEqual(response.fromcache, True, msg="Should be from cache")
755
756 # get the resource again, not from cache since Accept headers does not match
757 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
758 self.assertEqual(response.status, 200)
759 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
760
761 # get the resource again, without any Accept header, so again no match
762 (response, content) = self.http.request(uri, "GET")
763 self.assertEqual(response.status, 200)
764 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
765
766 def testNoVary(self):
Joe Gregorio46546a62012-10-03 14:31:10 -0400767 pass
chris dent89f15142009-12-24 14:02:57 -0600768 # when there is no vary, a different Accept header (e.g.) should not
769 # impact if the cache is used
770 # test that the vary header is not sent
Joe Gregorio46546a62012-10-03 14:31:10 -0400771 # uri = urlparse.urljoin(base, "vary/no-vary.asis")
772 # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
773 # self.assertEqual(response.status, 200)
774 # self.assertFalse(response.has_key('vary'))
chris dent89f15142009-12-24 14:02:57 -0600775
Joe Gregorio46546a62012-10-03 14:31:10 -0400776 # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
777 # self.assertEqual(response.status, 200)
778 # self.assertEqual(response.fromcache, True, msg="Should be from cache")
779 #
780 # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
781 # self.assertEqual(response.status, 200)
782 # self.assertEqual(response.fromcache, True, msg="Should be from cache")
chris dent89f15142009-12-24 14:02:57 -0600783
784 def testVaryHeaderDouble(self):
785 uri = urlparse.urljoin(base, "vary/accept-double.asis")
786 (response, content) = self.http.request(uri, "GET", headers={
787 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
788 self.assertEqual(response.status, 200)
789 self.assertTrue(response.has_key('vary'))
790
791 # we are from cache
792 (response, content) = self.http.request(uri, "GET", headers={
793 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
794 self.assertEqual(response.fromcache, True, msg="Should be from cache")
795
796 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
797 self.assertEqual(response.status, 200)
798 self.assertEqual(response.fromcache, False)
799
800 # get the resource again, not from cache, varied headers don't match exact
801 (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})
802 self.assertEqual(response.status, 200)
803 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
804
jcgregorio88ef89b2010-05-13 23:42:11 -0400805 def testVaryUnusedHeader(self):
806 # A header's value is not considered to vary if it's not used at all.
807 uri = urlparse.urljoin(base, "vary/unused-header.asis")
808 (response, content) = self.http.request(uri, "GET", headers={
809 'Accept': 'text/plain'})
810 self.assertEqual(response.status, 200)
811 self.assertTrue(response.has_key('vary'))
812
813 # we are from cache
814 (response, content) = self.http.request(uri, "GET", headers={
815 'Accept': 'text/plain',})
816 self.assertEqual(response.fromcache, True, msg="Should be from cache")
817
chris dent89f15142009-12-24 14:02:57 -0600818
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000819 def testHeadGZip(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400820 # Test that we don't try to decompress a HEAD response
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000821 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
822 (response, content) = self.http.request(uri, "HEAD")
823 self.assertEqual(response.status, 200)
824 self.assertNotEqual(int(response['content-length']), 0)
825 self.assertEqual(content, "")
826
jcgregorio2d66d4f2006-02-07 05:34:14 +0000827 def testGetGZip(self):
828 # Test that we support gzip compression
829 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000830 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000831 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000832 self.assertFalse(response.has_key('content-encoding'))
joe.gregorio8b6d2312007-12-16 05:42:07 +0000833 self.assertTrue(response.has_key('-content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000834 self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000835 self.assertEqual(content, "This is the final destination.\n")
836
Joe Gregoriod1137c52011-02-13 19:27:35 -0500837 def testPostAndGZipResponse(self):
838 uri = urlparse.urljoin(base, "gzip/post.cgi")
839 (response, content) = self.http.request(uri, "POST", body=" ")
840 self.assertEqual(response.status, 200)
841 self.assertFalse(response.has_key('content-encoding'))
842 self.assertTrue(response.has_key('-content-encoding'))
843
jcgregorio2d66d4f2006-02-07 05:34:14 +0000844 def testGetGZipFailure(self):
845 # Test that we raise a good exception when the gzip fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400846 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000847 uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
848 try:
jcgregorio36140b52006-06-13 02:17:52 +0000849 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000850 self.fail("Should never reach here")
851 except httplib2.FailedToDecompressContent:
852 pass
853 except Exception:
854 self.fail("Threw wrong kind of exception")
855
jcgregorio07a9a4a2007-03-08 21:18:39 +0000856 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400857 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000858
859 (response, content) = self.http.request(uri, "GET")
860 self.assertEqual(response.status, 500)
861 self.assertTrue(response.reason.startswith("Content purported"))
862
863 def testTimeout(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400864 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000865 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
866 try:
867 import socket
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400868 socket.setdefaulttimeout(1)
jcgregorio07a9a4a2007-03-08 21:18:39 +0000869 except:
870 # Don't run the test if we can't set the timeout
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400871 return
jcgregorio07a9a4a2007-03-08 21:18:39 +0000872 (response, content) = self.http.request(uri)
873 self.assertEqual(response.status, 408)
874 self.assertTrue(response.reason.startswith("Request Timeout"))
875 self.assertTrue(content.startswith("Request Timeout"))
876
jcgregoriob2697912007-03-09 02:23:47 +0000877 def testIndividualTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000878 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
879 http = httplib2.Http(timeout=1)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400880 http.force_exception_to_status_code = True
jcgregoriob2697912007-03-09 02:23:47 +0000881
882 (response, content) = http.request(uri)
883 self.assertEqual(response.status, 408)
884 self.assertTrue(response.reason.startswith("Request Timeout"))
885 self.assertTrue(content.startswith("Request Timeout"))
886
jcgregorio07a9a4a2007-03-08 21:18:39 +0000887
Joe Gregorio1a7609f2009-07-16 10:59:44 -0400888 def testHTTPSInitTimeout(self):
889 c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
890 self.assertEqual(47, c.timeout)
891
jcgregorio2d66d4f2006-02-07 05:34:14 +0000892 def testGetDeflate(self):
893 # Test that we support deflate compression
894 uri = urlparse.urljoin(base, "deflate/deflated.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000895 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000896 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000897 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000898 self.assertEqual(int(response['content-length']), len("This is the final destination."))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000899 self.assertEqual(content, "This is the final destination.")
900
901 def testGetDeflateFailure(self):
902 # Test that we raise a good exception when the deflate fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400903 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000904
jcgregorio2d66d4f2006-02-07 05:34:14 +0000905 uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
906 try:
jcgregorio36140b52006-06-13 02:17:52 +0000907 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000908 self.fail("Should never reach here")
909 except httplib2.FailedToDecompressContent:
910 pass
911 except Exception:
912 self.fail("Threw wrong kind of exception")
913
jcgregorio07a9a4a2007-03-08 21:18:39 +0000914 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400915 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000916
917 (response, content) = self.http.request(uri, "GET")
918 self.assertEqual(response.status, 500)
919 self.assertTrue(response.reason.startswith("Content purported"))
920
jcgregorio2d66d4f2006-02-07 05:34:14 +0000921 def testGetDuplicateHeaders(self):
922 # Test that duplicate headers get concatenated via ','
923 uri = urlparse.urljoin(base, "duplicate-headers/multilink.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000924 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000925 self.assertEqual(response.status, 200)
926 self.assertEqual(content, "This is content\n")
927 self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
928
929 def testGetCacheControlNoCache(self):
930 # Test Cache-Control: no-cache on requests
931 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000932 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000933 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000934 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000935 self.assertEqual(response.status, 200)
936 self.assertEqual(response.fromcache, True)
937
jcgregorio36140b52006-06-13 02:17:52 +0000938 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000939 self.assertEqual(response.status, 200)
940 self.assertEqual(response.fromcache, False)
941
942 def testGetCacheControlPragmaNoCache(self):
943 # Test Pragma: no-cache on requests
944 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000945 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000946 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000947 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000948 self.assertEqual(response.status, 200)
949 self.assertEqual(response.fromcache, True)
950
jcgregorio36140b52006-06-13 02:17:52 +0000951 (response, content) = self.http.request(uri, "GET", headers={'Pragma': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000952 self.assertEqual(response.status, 200)
953 self.assertEqual(response.fromcache, False)
954
955 def testGetCacheControlNoStoreRequest(self):
956 # A no-store request means that the response should not be stored.
957 uri = urlparse.urljoin(base, "304/test_etag.txt")
958
jcgregorio36140b52006-06-13 02:17:52 +0000959 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000960 self.assertEqual(response.status, 200)
961 self.assertEqual(response.fromcache, False)
962
jcgregorio36140b52006-06-13 02:17:52 +0000963 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000964 self.assertEqual(response.status, 200)
965 self.assertEqual(response.fromcache, False)
966
967 def testGetCacheControlNoStoreResponse(self):
968 # A no-store response means that the response should not be stored.
969 uri = urlparse.urljoin(base, "no-store/no-store.asis")
970
jcgregorio36140b52006-06-13 02:17:52 +0000971 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000972 self.assertEqual(response.status, 200)
973 self.assertEqual(response.fromcache, False)
974
jcgregorio36140b52006-06-13 02:17:52 +0000975 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000976 self.assertEqual(response.status, 200)
977 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000978
979 def testGetCacheControlNoCacheNoStoreRequest(self):
980 # Test that a no-store, no-cache clears the entry from the cache
981 # even if it was cached previously.
982 uri = urlparse.urljoin(base, "304/test_etag.txt")
983
jcgregorio36140b52006-06-13 02:17:52 +0000984 (response, content) = self.http.request(uri, "GET")
985 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000986 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000987 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
988 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000989 self.assertEqual(response.status, 200)
990 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000991
992 def testUpdateInvalidatesCache(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400993 # Test that calling PUT or DELETE on a
jcgregorio2d66d4f2006-02-07 05:34:14 +0000994 # URI that is cache invalidates that cache.
995 uri = urlparse.urljoin(base, "304/test_etag.txt")
996
jcgregorio36140b52006-06-13 02:17:52 +0000997 (response, content) = self.http.request(uri, "GET")
998 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000999 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +00001000 (response, content) = self.http.request(uri, "DELETE")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001001 self.assertEqual(response.status, 405)
1002
jcgregorio36140b52006-06-13 02:17:52 +00001003 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001004 self.assertEqual(response.fromcache, False)
1005
1006 def testUpdateUsesCachedETag(self):
Joe Gregoriobd682082011-05-24 14:06:09 -04001007 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio2d66d4f2006-02-07 05:34:14 +00001008 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
1009
jcgregorio36140b52006-06-13 02:17:52 +00001010 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001011 self.assertEqual(response.status, 200)
1012 self.assertEqual(response.fromcache, False)
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, 200)
1015 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -04001016 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001017 self.assertEqual(response.status, 200)
Joe Gregoriocd868102009-09-29 17:09:16 -04001018 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001019 self.assertEqual(response.status, 412)
1020
Joe Gregoriobd682082011-05-24 14:06:09 -04001021 def testUpdatePatchUsesCachedETag(self):
1022 # Test that we natively support http://www.w3.org/1999/04/Editing/
1023 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
1024
1025 (response, content) = self.http.request(uri, "GET")
1026 self.assertEqual(response.status, 200)
1027 self.assertEqual(response.fromcache, False)
1028 (response, content) = self.http.request(uri, "GET")
1029 self.assertEqual(response.status, 200)
1030 self.assertEqual(response.fromcache, True)
1031 (response, content) = self.http.request(uri, "PATCH", body="foo")
1032 self.assertEqual(response.status, 200)
1033 (response, content) = self.http.request(uri, "PATCH", body="foo")
1034 self.assertEqual(response.status, 412)
1035
1036
joe.gregorio700f04d2008-09-06 04:46:32 +00001037 def testUpdateUsesCachedETagAndOCMethod(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001038 # Test that we natively support http://www.w3.org/1999/04/Editing/
joe.gregorio700f04d2008-09-06 04:46:32 +00001039 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
1040
1041 (response, content) = self.http.request(uri, "GET")
1042 self.assertEqual(response.status, 200)
1043 self.assertEqual(response.fromcache, False)
1044 (response, content) = self.http.request(uri, "GET")
1045 self.assertEqual(response.status, 200)
1046 self.assertEqual(response.fromcache, True)
1047 self.http.optimistic_concurrency_methods.append("DELETE")
1048 (response, content) = self.http.request(uri, "DELETE")
1049 self.assertEqual(response.status, 200)
1050
1051
jcgregorio4b145e82007-01-18 19:46:34 +00001052 def testUpdateUsesCachedETagOverridden(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001053 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio4b145e82007-01-18 19:46:34 +00001054 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
1055
1056 (response, content) = self.http.request(uri, "GET")
1057 self.assertEqual(response.status, 200)
1058 self.assertEqual(response.fromcache, False)
1059 (response, content) = self.http.request(uri, "GET")
1060 self.assertEqual(response.status, 200)
1061 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -04001062 (response, content) = self.http.request(uri, "PUT", body="foo", headers={'if-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +00001063 self.assertEqual(response.status, 412)
1064
jcgregorio2d66d4f2006-02-07 05:34:14 +00001065 def testBasicAuth(self):
1066 # Test Basic Authentication
1067 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001068 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001069 self.assertEqual(response.status, 401)
1070
1071 uri = urlparse.urljoin(base, "basic/")
jcgregorio36140b52006-06-13 02:17:52 +00001072 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001073 self.assertEqual(response.status, 401)
1074
jcgregorio36140b52006-06-13 02:17:52 +00001075 self.http.add_credentials('joe', 'password')
1076 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001077 self.assertEqual(response.status, 200)
1078
1079 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001080 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001081 self.assertEqual(response.status, 200)
1082
jcgregoriode8238d2007-03-07 19:08:26 +00001083 def testBasicAuthWithDomain(self):
1084 # Test Basic Authentication
1085 uri = urlparse.urljoin(base, "basic/file.txt")
1086 (response, content) = self.http.request(uri, "GET")
1087 self.assertEqual(response.status, 401)
1088
1089 uri = urlparse.urljoin(base, "basic/")
1090 (response, content) = self.http.request(uri, "GET")
1091 self.assertEqual(response.status, 401)
1092
1093 self.http.add_credentials('joe', 'password', "example.org")
1094 (response, content) = self.http.request(uri, "GET")
1095 self.assertEqual(response.status, 401)
1096
1097 uri = urlparse.urljoin(base, "basic/file.txt")
1098 (response, content) = self.http.request(uri, "GET")
1099 self.assertEqual(response.status, 401)
1100
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001101 domain = urlparse.urlparse(base)[1]
jcgregoriode8238d2007-03-07 19:08:26 +00001102 self.http.add_credentials('joe', 'password', domain)
1103 (response, content) = self.http.request(uri, "GET")
1104 self.assertEqual(response.status, 200)
1105
1106 uri = urlparse.urljoin(base, "basic/file.txt")
1107 (response, content) = self.http.request(uri, "GET")
1108 self.assertEqual(response.status, 200)
1109
1110
1111
1112
1113
1114
jcgregorio2d66d4f2006-02-07 05:34:14 +00001115 def testBasicAuthTwoDifferentCredentials(self):
jcgregorioadbb4f82006-05-19 15:17:42 +00001116 # Test Basic Authentication with multiple sets of credentials
jcgregorio2d66d4f2006-02-07 05:34:14 +00001117 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001118 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001119 self.assertEqual(response.status, 401)
1120
1121 uri = urlparse.urljoin(base, "basic2/")
jcgregorio36140b52006-06-13 02:17:52 +00001122 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001123 self.assertEqual(response.status, 401)
1124
jcgregorio36140b52006-06-13 02:17:52 +00001125 self.http.add_credentials('fred', 'barney')
1126 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001127 self.assertEqual(response.status, 200)
1128
1129 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001130 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001131 self.assertEqual(response.status, 200)
1132
1133 def testBasicAuthNested(self):
1134 # Test Basic Authentication with resources
1135 # that are nested
1136 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001137 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001138 self.assertEqual(response.status, 401)
1139
1140 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001141 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001142 self.assertEqual(response.status, 401)
1143
jcgregorioadbb4f82006-05-19 15:17:42 +00001144 # Now add in credentials one at a time and test.
jcgregorio36140b52006-06-13 02:17:52 +00001145 self.http.add_credentials('joe', 'password')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001146
1147 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001148 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001149 self.assertEqual(response.status, 200)
1150
1151 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001152 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001153 self.assertEqual(response.status, 401)
1154
jcgregorio36140b52006-06-13 02:17:52 +00001155 self.http.add_credentials('fred', 'barney')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001156
1157 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001158 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001159 self.assertEqual(response.status, 200)
1160
1161 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001162 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001163 self.assertEqual(response.status, 200)
1164
1165 def testDigestAuth(self):
1166 # Test that we support Digest Authentication
1167 uri = urlparse.urljoin(base, "digest/")
jcgregorio36140b52006-06-13 02:17:52 +00001168 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001169 self.assertEqual(response.status, 401)
1170
jcgregorio36140b52006-06-13 02:17:52 +00001171 self.http.add_credentials('joe', 'password')
1172 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001173 self.assertEqual(response.status, 200)
1174
1175 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001176 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001177
1178 def testDigestAuthNextNonceAndNC(self):
1179 # Test that if the server sets nextnonce that we reset
1180 # the nonce count back to 1
1181 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001182 self.http.add_credentials('joe', 'password')
1183 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001184 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1185 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +00001186 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001187 info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
1188 self.assertEqual(response.status, 200)
1189
1190 if info.has_key('nextnonce'):
1191 self.assertEqual(info2['nc'], 1)
1192
1193 def testDigestAuthStale(self):
1194 # Test that we can handle a nonce becoming stale
1195 uri = urlparse.urljoin(base, "digest-expire/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001196 self.http.add_credentials('joe', 'password')
1197 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001198 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1199 self.assertEqual(response.status, 200)
1200
1201 time.sleep(3)
1202 # Sleep long enough that the nonce becomes stale
1203
jcgregorio36140b52006-06-13 02:17:52 +00001204 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001205 self.assertFalse(response.fromcache)
1206 self.assertTrue(response._stale_digest)
1207 info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
1208 self.assertEqual(response.status, 200)
1209
1210 def reflector(self, content):
jcgregorio25185622006-10-28 05:12:34 +00001211 return dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
jcgregorio2d66d4f2006-02-07 05:34:14 +00001212
1213 def testReflector(self):
1214 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +00001215 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001216 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001217 self.assertTrue(d.has_key('HTTP_USER_AGENT'))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001218
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001219 def testConnectionClose(self):
1220 uri = "http://www.google.com/"
1221 (response, content) = self.http.request(uri, "GET")
1222 for c in self.http.connections.values():
1223 self.assertNotEqual(None, c.sock)
1224 (response, content) = self.http.request(uri, "GET", headers={"connection": "close"})
1225 for c in self.http.connections.values():
1226 self.assertEqual(None, c.sock)
1227
Joe Gregorio46546a62012-10-03 14:31:10 -04001228 def testPickleHttp(self):
1229 pickled_http = pickle.dumps(self.http)
1230 new_http = pickle.loads(pickled_http)
1231
1232 self.assertEqual(sorted(new_http.__dict__.keys()),
1233 sorted(self.http.__dict__.keys()))
1234 for key in new_http.__dict__:
1235 if key in ('certificates', 'credentials'):
1236 self.assertEqual(new_http.__dict__[key].credentials,
1237 self.http.__dict__[key].credentials)
1238 elif key == 'cache':
1239 self.assertEqual(new_http.__dict__[key].cache,
1240 self.http.__dict__[key].cache)
1241 else:
1242 self.assertEqual(new_http.__dict__[key],
1243 self.http.__dict__[key])
1244
1245 def testPickleHttpWithConnection(self):
1246 self.http.request('http://bitworking.org',
1247 connection_type=_MyHTTPConnection)
1248 pickled_http = pickle.dumps(self.http)
1249 new_http = pickle.loads(pickled_http)
1250
1251 self.assertEqual(self.http.connections.keys(), ['http:bitworking.org'])
1252 self.assertEqual(new_http.connections, {})
1253
1254 def testPickleCustomRequestHttp(self):
1255 def dummy_request(*args, **kwargs):
1256 return new_request(*args, **kwargs)
1257 dummy_request.dummy_attr = 'dummy_value'
1258
1259 self.http.request = dummy_request
1260 pickled_http = pickle.dumps(self.http)
1261 self.assertFalse("S'request'" in pickled_http)
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001262
jcgregorio36140b52006-06-13 02:17:52 +00001263try:
1264 import memcache
1265 class HttpTestMemCached(HttpTest):
1266 def setUp(self):
1267 self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
jcgregorio47d24672006-06-29 05:18:59 +00001268 #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
jcgregorio36140b52006-06-13 02:17:52 +00001269 self.http = httplib2.Http(self.cache)
1270 self.cache.flush_all()
jcgregorio47d24672006-06-29 05:18:59 +00001271 # Not exactly sure why the sleep is needed here, but
1272 # if not present then some unit tests that rely on caching
1273 # fail. Memcached seems to lose some sets immediately
1274 # after a flush_all if the set is to a value that
1275 # was previously cached. (Maybe the flush is handled async?)
1276 time.sleep(1)
jcgregorio36140b52006-06-13 02:17:52 +00001277 self.http.clear_credentials()
1278except:
1279 pass
1280
1281
1282
chris dent89f15142009-12-24 14:02:57 -06001283
jcgregoriodb8dfc82006-03-31 14:59:46 +00001284# ------------------------------------------------------------------------
jcgregorio2d66d4f2006-02-07 05:34:14 +00001285
1286class HttpPrivateTest(unittest.TestCase):
1287
1288 def testParseCacheControl(self):
1289 # Test that we can parse the Cache-Control header
1290 self.assertEqual({}, httplib2._parse_cache_control({}))
1291 self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
1292 cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
1293 self.assertEqual(cc['no-cache'], 1)
1294 self.assertEqual(cc['max-age'], '7200')
1295 cc = httplib2._parse_cache_control({'cache-control': ' , '})
1296 self.assertEqual(cc[''], 1)
1297
Joe Gregorioe314e8b2009-07-16 20:11:28 -04001298 try:
1299 cc = httplib2._parse_cache_control({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'})
1300 self.assertTrue("max-age" in cc)
1301 except:
1302 self.fail("Should not throw exception")
1303
jcgregorio2d66d4f2006-02-07 05:34:14 +00001304 def testNormalizeHeaders(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001305 # Test that we normalize headers to lowercase
jcgregorio2d66d4f2006-02-07 05:34:14 +00001306 h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
1307 self.assertTrue(h.has_key('cache-control'))
1308 self.assertTrue(h.has_key('other'))
1309 self.assertEqual('Stuff', h['other'])
1310
1311 def testExpirationModelTransparent(self):
1312 # Test that no-cache makes our request TRANSPARENT
1313 response_headers = {
1314 'cache-control': 'max-age=7200'
1315 }
1316 request_headers = {
1317 'cache-control': 'no-cache'
1318 }
1319 self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
1320
jcgregorio45865012007-01-18 16:38:22 +00001321 def testMaxAgeNonNumeric(self):
1322 # Test that no-cache makes our request TRANSPARENT
1323 response_headers = {
1324 'cache-control': 'max-age=fred, min-fresh=barney'
1325 }
1326 request_headers = {
1327 }
1328 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1329
1330
jcgregorio2d66d4f2006-02-07 05:34:14 +00001331 def testExpirationModelNoCacheResponse(self):
1332 # The date and expires point to an entry that should be
1333 # FRESH, but the no-cache over-rides that.
1334 now = time.time()
1335 response_headers = {
1336 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1337 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1338 'cache-control': 'no-cache'
1339 }
1340 request_headers = {
1341 }
1342 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1343
1344 def testExpirationModelStaleRequestMustReval(self):
1345 # must-revalidate forces STALE
1346 self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
1347
1348 def testExpirationModelStaleResponseMustReval(self):
1349 # must-revalidate forces STALE
1350 self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
1351
1352 def testExpirationModelFresh(self):
1353 response_headers = {
1354 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1355 'cache-control': 'max-age=2'
1356 }
1357 request_headers = {
1358 }
1359 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1360 time.sleep(3)
1361 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1362
1363 def testExpirationMaxAge0(self):
1364 response_headers = {
1365 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1366 'cache-control': 'max-age=0'
1367 }
1368 request_headers = {
1369 }
1370 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1371
1372 def testExpirationModelDateAndExpires(self):
1373 now = time.time()
1374 response_headers = {
1375 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1376 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1377 }
1378 request_headers = {
1379 }
1380 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1381 time.sleep(3)
1382 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1383
jcgregoriof9511052007-06-01 14:56:34 +00001384 def testExpiresZero(self):
1385 now = time.time()
1386 response_headers = {
1387 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1388 'expires': "0",
1389 }
1390 request_headers = {
1391 }
1392 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1393
jcgregorio2d66d4f2006-02-07 05:34:14 +00001394 def testExpirationModelDateOnly(self):
1395 now = time.time()
1396 response_headers = {
1397 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
1398 }
1399 request_headers = {
1400 }
1401 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1402
1403 def testExpirationModelOnlyIfCached(self):
1404 response_headers = {
1405 }
1406 request_headers = {
1407 'cache-control': 'only-if-cached',
1408 }
1409 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1410
1411 def testExpirationModelMaxAgeBoth(self):
1412 now = time.time()
1413 response_headers = {
1414 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1415 'cache-control': 'max-age=2'
1416 }
1417 request_headers = {
1418 'cache-control': 'max-age=0'
1419 }
1420 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1421
1422 def testExpirationModelDateAndExpiresMinFresh1(self):
1423 now = time.time()
1424 response_headers = {
1425 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1426 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1427 }
1428 request_headers = {
1429 'cache-control': 'min-fresh=2'
1430 }
1431 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1432
1433 def testExpirationModelDateAndExpiresMinFresh2(self):
1434 now = time.time()
1435 response_headers = {
1436 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1437 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1438 }
1439 request_headers = {
1440 'cache-control': 'min-fresh=2'
1441 }
1442 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1443
1444 def testParseWWWAuthenticateEmpty(self):
1445 res = httplib2._parse_www_authenticate({})
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001446 self.assertEqual(len(res.keys()), 0)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001447
jcgregoriofd22e432006-04-27 02:00:08 +00001448 def testParseWWWAuthenticate(self):
1449 # different uses of spaces around commas
1450 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
1451 self.assertEqual(len(res.keys()), 1)
1452 self.assertEqual(len(res['test'].keys()), 5)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001453
jcgregoriofd22e432006-04-27 02:00:08 +00001454 # tokens with non-alphanum
1455 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
1456 self.assertEqual(len(res.keys()), 1)
1457 self.assertEqual(len(res['t*!%#st'].keys()), 2)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001458
jcgregoriofd22e432006-04-27 02:00:08 +00001459 # quoted string with quoted pairs
1460 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
1461 self.assertEqual(len(res.keys()), 1)
1462 self.assertEqual(res['test']['realm'], 'a "test" realm')
1463
1464 def testParseWWWAuthenticateStrict(self):
1465 httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
1466 self.testParseWWWAuthenticate();
1467 httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
1468
jcgregorio2d66d4f2006-02-07 05:34:14 +00001469 def testParseWWWAuthenticateBasic(self):
1470 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
1471 basic = res['basic']
1472 self.assertEqual('me', basic['realm'])
1473
1474 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
1475 basic = res['basic']
1476 self.assertEqual('me', basic['realm'])
1477 self.assertEqual('MD5', basic['algorithm'])
1478
1479 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
1480 basic = res['basic']
1481 self.assertEqual('me', basic['realm'])
1482 self.assertEqual('MD5', basic['algorithm'])
1483
1484 def testParseWWWAuthenticateBasic2(self):
1485 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
1486 basic = res['basic']
1487 self.assertEqual('me', basic['realm'])
1488 self.assertEqual('fred', basic['other'])
1489
1490 def testParseWWWAuthenticateBasic3(self):
1491 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
1492 basic = res['basic']
1493 self.assertEqual('me', basic['realm'])
1494
1495
1496 def testParseWWWAuthenticateDigest(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001497 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001498 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
1499 digest = res['digest']
1500 self.assertEqual('testrealm@host.com', digest['realm'])
1501 self.assertEqual('auth,auth-int', digest['qop'])
1502
1503
1504 def testParseWWWAuthenticateMultiple(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001505 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001506 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
1507 digest = res['digest']
1508 self.assertEqual('testrealm@host.com', digest['realm'])
1509 self.assertEqual('auth,auth-int', digest['qop'])
1510 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1511 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1512 basic = res['basic']
1513 self.assertEqual('me', basic['realm'])
1514
1515 def testParseWWWAuthenticateMultiple2(self):
1516 # Handle an added comma between challenges, which might get thrown in if the challenges were
1517 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001518 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001519 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
1520 digest = res['digest']
1521 self.assertEqual('testrealm@host.com', digest['realm'])
1522 self.assertEqual('auth,auth-int', digest['qop'])
1523 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1524 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1525 basic = res['basic']
1526 self.assertEqual('me', basic['realm'])
1527
1528 def testParseWWWAuthenticateMultiple3(self):
1529 # Handle an added comma between challenges, which might get thrown in if the challenges were
1530 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001531 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001532 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1533 digest = res['digest']
1534 self.assertEqual('testrealm@host.com', digest['realm'])
1535 self.assertEqual('auth,auth-int', digest['qop'])
1536 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1537 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1538 basic = res['basic']
1539 self.assertEqual('me', basic['realm'])
1540 wsse = res['wsse']
1541 self.assertEqual('foo', wsse['realm'])
1542 self.assertEqual('UsernameToken', wsse['profile'])
1543
1544 def testParseWWWAuthenticateMultiple4(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001545 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1546 '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 +00001547 digest = res['digest']
1548 self.assertEqual('test-real.m@host.com', digest['realm'])
1549 self.assertEqual('\tauth,auth-int', digest['qop'])
1550 self.assertEqual('(*)&^&$%#', digest['nonce'])
1551
1552 def testParseWWWAuthenticateMoreQuoteCombos(self):
1553 res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
1554 digest = res['digest']
1555 self.assertEqual('myrealm', digest['realm'])
1556
Joe Gregorio6fa3cf22011-02-13 22:45:06 -05001557 def testParseWWWAuthenticateMalformed(self):
1558 try:
1559 res = httplib2._parse_www_authenticate({'www-authenticate':'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'})
1560 self.fail("should raise an exception")
1561 except httplib2.MalformedHeader:
1562 pass
1563
jcgregorio2d66d4f2006-02-07 05:34:14 +00001564 def testDigestObject(self):
1565 credentials = ('joe', 'password')
1566 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001567 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001568 headers = {}
1569 response = {
1570 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
1571 }
1572 content = ""
Joe Gregorio875a8b52011-06-13 14:06:23 -04001573
jcgregorio6cbab7e2006-04-21 20:35:43 +00001574 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001575 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
Joe Gregorio875a8b52011-06-13 14:06:23 -04001576 our_request = "authorization: %s" % headers['authorization']
1577 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 +00001578 self.assertEqual(our_request, working_request)
1579
Joe Gregorio03d99102011-06-22 16:55:52 -04001580 def testDigestObjectWithOpaque(self):
1581 credentials = ('joe', 'password')
1582 host = None
1583 request_uri = '/projects/httplib2/test/digest/'
1584 headers = {}
1585 response = {
1586 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", opaque="atestopaque"'
1587 }
1588 content = ""
1589
1590 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
1591 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
1592 our_request = "authorization: %s" % headers['authorization']
1593 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"'
1594 self.assertEqual(our_request, working_request)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001595
1596 def testDigestObjectStale(self):
1597 credentials = ('joe', 'password')
1598 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001599 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001600 headers = {}
1601 response = httplib2.Response({ })
1602 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1603 response.status = 401
1604 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001605 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001606 # Returns true to force a retry
1607 self.assertTrue( d.response(response, content) )
1608
1609 def testDigestObjectAuthInfo(self):
1610 credentials = ('joe', 'password')
1611 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001612 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001613 headers = {}
1614 response = httplib2.Response({ })
1615 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1616 response['authentication-info'] = 'nextnonce="fred"'
1617 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001618 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001619 # Returns true to force a retry
1620 self.assertFalse( d.response(response, content) )
1621 self.assertEqual('fred', d.challenge['nonce'])
1622 self.assertEqual(1, d.challenge['nc'])
1623
1624 def testWsseAlgorithm(self):
1625 digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
1626 expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
1627 self.assertEqual(expected, digest)
1628
jcgregoriodb8dfc82006-03-31 14:59:46 +00001629 def testEnd2End(self):
1630 # one end to end header
1631 response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
1632 end2end = httplib2._get_end2end_headers(response)
1633 self.assertTrue('content-type' in end2end)
1634 self.assertTrue('te' not in end2end)
1635 self.assertTrue('connection' not in end2end)
1636
1637 # one end to end header that gets eliminated
1638 response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
1639 end2end = httplib2._get_end2end_headers(response)
1640 self.assertTrue('content-type' not in end2end)
1641 self.assertTrue('te' not in end2end)
1642 self.assertTrue('connection' not in end2end)
1643
1644 # Degenerate case of no headers
1645 response = {}
1646 end2end = httplib2._get_end2end_headers(response)
1647 self.assertEquals(0, len(end2end))
1648
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001649 # Degenerate case of connection referrring to a header not passed in
jcgregoriodb8dfc82006-03-31 14:59:46 +00001650 response = {'connection': 'content-type'}
1651 end2end = httplib2._get_end2end_headers(response)
1652 self.assertEquals(0, len(end2end))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001653
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001654
1655class TestProxyInfo(unittest.TestCase):
1656 def setUp(self):
1657 self.orig_env = dict(os.environ)
1658
1659 def tearDown(self):
1660 os.environ.clear()
1661 os.environ.update(self.orig_env)
1662
1663 def test_from_url(self):
Joe Gregorio46546a62012-10-03 14:31:10 -04001664 pi = httplib2.proxy_info_from_url('http://myproxy.example.com')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001665 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1666 self.assertEquals(pi.proxy_port, 80)
1667 self.assertEquals(pi.proxy_user, None)
1668
1669 def test_from_url_ident(self):
Joe Gregorio46546a62012-10-03 14:31:10 -04001670 pi = httplib2.proxy_info_from_url('http://zoidberg:fish@someproxy:99')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001671 self.assertEquals(pi.proxy_host, 'someproxy')
1672 self.assertEquals(pi.proxy_port, 99)
1673 self.assertEquals(pi.proxy_user, 'zoidberg')
1674 self.assertEquals(pi.proxy_pass, 'fish')
1675
1676 def test_from_env(self):
1677 os.environ['http_proxy'] = 'http://myproxy.example.com:8080'
Joe Gregorio46546a62012-10-03 14:31:10 -04001678 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001679 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1680 self.assertEquals(pi.proxy_port, 8080)
1681 self.assertEquals(pi.bypass_hosts, [])
1682
1683 def test_from_env_no_proxy(self):
1684 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1685 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
1686 os.environ['no_proxy'] = 'localhost,otherhost.domain.local'
Joe Gregorio46546a62012-10-03 14:31:10 -04001687 pi = httplib2.proxy_info_from_environment('https')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001688 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1689 self.assertEquals(pi.proxy_port, 81)
1690 self.assertEquals(pi.bypass_hosts, ['localhost',
1691 'otherhost.domain.local'])
1692
1693 def test_from_env_none(self):
1694 os.environ.clear()
Joe Gregorio46546a62012-10-03 14:31:10 -04001695 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001696 self.assertEquals(pi, None)
1697
Jason R. Coombs43840892011-08-09 10:30:46 -04001698 def test_applies_to(self):
1699 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1700 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
Jason R. Coombs96279c52011-08-16 12:53:27 -04001701 os.environ['no_proxy'] = 'localhost,otherhost.domain.local,example.com'
Joe Gregorio46546a62012-10-03 14:31:10 -04001702 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs43840892011-08-09 10:30:46 -04001703 self.assertFalse(pi.applies_to('localhost'))
1704 self.assertTrue(pi.applies_to('www.google.com'))
Jason R. Coombs96279c52011-08-16 12:53:27 -04001705 self.assertFalse(pi.applies_to('www.example.com'))
1706
1707 def test_no_proxy_star(self):
1708 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1709 os.environ['NO_PROXY'] = '*'
Joe Gregorio46546a62012-10-03 14:31:10 -04001710 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs96279c52011-08-16 12:53:27 -04001711 for host in ('localhost', '169.254.38.192', 'www.google.com'):
1712 self.assertFalse(pi.applies_to(host))
Jason R. Coombs43840892011-08-09 10:30:46 -04001713
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001714
chris dent89f15142009-12-24 14:02:57 -06001715if __name__ == '__main__':
1716 unittest.main()