blob: 472424bdbcfb0ae3f56a1a308ba1f5b0b536632f [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 Gregorioc69dc782011-06-23 08:56:59 -0400514 def testSslCertValidationDoubleDots(self):
Joe Gregorio0197ec82014-03-06 14:56:29 -0500515 pass
516 # No longer a valid test.
517 #if sys.version_info >= (2, 6):
518 # Test that we get match a double dot cert
519 #try:
520 # self.http.request("https://www.appspot.com/", "GET")
521 #except httplib2.CertificateHostnameMismatch:
522 # self.fail('cert with *.*.appspot.com should not raise an exception.')
Joe Gregorioc69dc782011-06-23 08:56:59 -0400523
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400524 def testSslHostnameValidation(self):
Joe Gregorio3e563132012-03-02 10:52:45 -0500525 pass
526 # No longer a valid test.
527 #if sys.version_info >= (2, 6):
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400528 # The SSL server at google.com:443 returns a certificate for
529 # 'www.google.com', which results in a host name mismatch.
530 # Note that this test only works because the ssl module and httplib2
531 # do not support SNI; for requests specifying a server name of
532 # 'google.com' via SNI, a matching cert would be returned.
Joe Gregorio3e563132012-03-02 10:52:45 -0500533 # self.assertRaises(httplib2.CertificateHostnameMismatch,
534 # self.http.request, "https://google.com/", "GET")
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400535
536 def testSslCertValidationWithoutSslModuleFails(self):
537 if sys.version_info < (2, 6):
538 http = httplib2.Http(disable_ssl_certificate_validation=False)
539 self.assertRaises(httplib2.CertificateValidationUnsupported,
540 http.request, "https://www.google.com/", "GET")
jcgregoriode8238d2007-03-07 19:08:26 +0000541
542 def testGetViaHttpsKeyCert(self):
jcgregorio2f1e1422007-05-03 13:17:33 +0000543 # At this point I can only test
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400544 # that the key and cert files are passed in
545 # correctly to httplib. It would be nice to have
jcgregorio2f1e1422007-05-03 13:17:33 +0000546 # a real https endpoint to test against.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400547
548 # bitworking.org presents an certificate for a non-matching host
549 # (*.webfaction.com), so we need to disable cert checking for this test.
550 http = httplib2.Http(timeout=2, disable_ssl_certificate_validation=True)
jcgregoriode8238d2007-03-07 19:08:26 +0000551
552 http.add_certificate("akeyfile", "acertfile", "bitworking.org")
553 try:
554 (response, content) = http.request("https://bitworking.org", "GET")
555 except:
556 pass
557 self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
558 self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
559
jcgregorio2f1e1422007-05-03 13:17:33 +0000560 try:
561 (response, content) = http.request("https://notthere.bitworking.org", "GET")
562 except:
563 pass
564 self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
565 self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
566
567
568
jcgregoriode8238d2007-03-07 19:08:26 +0000569
jcgregorio2d66d4f2006-02-07 05:34:14 +0000570 def testGet303(self):
571 # Do a follow-up GET on a Location: header
572 # returned from a POST that gave a 303.
573 uri = urlparse.urljoin(base, "303/303.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000574 (response, content) = self.http.request(uri, "POST", " ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000575 self.assertEqual(response.status, 200)
576 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000577 self.assertEqual(response.previous.status, 303)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000578
jcgregorio2f1e1422007-05-03 13:17:33 +0000579 def testGet303NoRedirect(self):
580 # Do a follow-up GET on a Location: header
581 # returned from a POST that gave a 303.
582 self.http.follow_redirects = False
583 uri = urlparse.urljoin(base, "303/303.cgi")
584 (response, content) = self.http.request(uri, "POST", " ")
585 self.assertEqual(response.status, 303)
586
jcgregorio2d66d4f2006-02-07 05:34:14 +0000587 def test303ForDifferentMethods(self):
588 # Test that all methods can be used
589 uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400590 for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
jcgregorio36140b52006-06-13 02:17:52 +0000591 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000592 self.assertEqual(response['x-method'], method_on_303)
593
Joe Gregoriob30ed372012-07-23 14:45:17 -0400594 def test303AndForwardAuthorizationHeader(self):
595 # Test that all methods can be used
596 uri = urlparse.urljoin(base, "303/redirect-to-header-reflector.cgi")
597 headers = {'authorization': 'Bearer foo'}
598 response, content = self.http.request(uri, 'GET', body=" ",
599 headers=headers)
600 # self.assertTrue('authorization' not in content)
601 self.http.follow_all_redirects = True
602 self.http.forward_authorization_headers = True
603 response, content = self.http.request(uri, 'GET', body=" ",
604 headers=headers)
605 # Oh, how I wish Apache didn't eat the Authorization header.
606 # self.assertTrue('authorization' in content)
607
jcgregorio2d66d4f2006-02-07 05:34:14 +0000608 def testGet304(self):
609 # Test that we use ETags properly to validate our cache
610 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorio0197ec82014-03-06 14:56:29 -0500611 (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000612 self.assertNotEqual(response['etag'], "")
613
jcgregorio36140b52006-06-13 02:17:52 +0000614 (response, content) = self.http.request(uri, "GET")
615 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000616 self.assertEqual(response.status, 200)
617 self.assertEqual(response.fromcache, True)
618
jcgregorio90fb4a42006-11-17 16:19:47 +0000619 cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
620 f = open(cache_file_name, "r")
621 status_line = f.readline()
622 f.close()
623
624 self.assertTrue(status_line.startswith("status:"))
625
jcgregorio36140b52006-06-13 02:17:52 +0000626 (response, content) = self.http.request(uri, "HEAD")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000627 self.assertEqual(response.status, 200)
628 self.assertEqual(response.fromcache, True)
629
jcgregorio36140b52006-06-13 02:17:52 +0000630 (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000631 self.assertEqual(response.status, 206)
632 self.assertEqual(response.fromcache, False)
633
jcgregorio25185622006-10-28 05:12:34 +0000634 def testGetIgnoreEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400635 # Test that we can forcibly ignore ETags
jcgregorio25185622006-10-28 05:12:34 +0000636 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
Joe Gregorio0197ec82014-03-06 14:56:29 -0500637 (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
jcgregorio25185622006-10-28 05:12:34 +0000638 self.assertNotEqual(response['etag'], "")
639
Joe Gregorio0197ec82014-03-06 14:56:29 -0500640 (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})
jcgregorio25185622006-10-28 05:12:34 +0000641 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400642 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000643
644 self.http.ignore_etag = True
Joe Gregorio0197ec82014-03-06 14:56:29 -0500645 (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})
jcgregorio25185622006-10-28 05:12:34 +0000646 d = self.reflector(content)
647 self.assertEqual(response.fromcache, False)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400648 self.assertFalse(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000649
jcgregorio4b145e82007-01-18 19:46:34 +0000650 def testOverrideEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400651 # Test that we can forcibly ignore ETags
jcgregorio4b145e82007-01-18 19:46:34 +0000652 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
Joe Gregorio0197ec82014-03-06 14:56:29 -0500653 (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
jcgregorio4b145e82007-01-18 19:46:34 +0000654 self.assertNotEqual(response['etag'], "")
655
Joe Gregorio0197ec82014-03-06 14:56:29 -0500656 (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})
jcgregorio4b145e82007-01-18 19:46:34 +0000657 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400658 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
659 self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio4b145e82007-01-18 19:46:34 +0000660
Joe Gregorio0197ec82014-03-06 14:56:29 -0500661 (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0', 'if-none-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +0000662 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400663 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
664 self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio25185622006-10-28 05:12:34 +0000665
pilgrim00a352e2009-05-29 04:04:44 +0000666#MAP-commented this out because it consistently fails
667# def testGet304EndToEnd(self):
668# # Test that end to end headers get overwritten in the cache
669# uri = urlparse.urljoin(base, "304/end2end.cgi")
670# (response, content) = self.http.request(uri, "GET")
671# self.assertNotEqual(response['etag'], "")
672# old_date = response['date']
673# time.sleep(2)
674#
675# (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
676# # The response should be from the cache, but the Date: header should be updated.
677# new_date = response['date']
678# self.assertNotEqual(new_date, old_date)
679# self.assertEqual(response.status, 200)
680# self.assertEqual(response.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000681
682 def testGet304LastModified(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400683 # Test that we can still handle a 304
jcgregorio2d66d4f2006-02-07 05:34:14 +0000684 # by only using the last-modified cache validator.
685 uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000686 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000687
688 self.assertNotEqual(response['last-modified'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000689 (response, content) = self.http.request(uri, "GET")
690 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000691 self.assertEqual(response.status, 200)
692 self.assertEqual(response.fromcache, True)
693
694 def testGet307(self):
695 # Test that we do follow 307 redirects but
696 # do not cache the 307
697 uri = urlparse.urljoin(base, "307/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000698 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000699 self.assertEqual(response.status, 200)
700 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000701 self.assertEqual(response.previous.status, 307)
702 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000703
jcgregorio36140b52006-06-13 02:17:52 +0000704 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000705 self.assertEqual(response.status, 200)
706 self.assertEqual(response.fromcache, True)
707 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000708 self.assertEqual(response.previous.status, 307)
709 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000710
711 def testGet410(self):
712 # Test that we pass 410's through
713 uri = urlparse.urljoin(base, "410/410.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000714 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000715 self.assertEqual(response.status, 410)
716
chris dent89f15142009-12-24 14:02:57 -0600717 def testVaryHeaderSimple(self):
718 """
719 RFC 2616 13.6
720 When the cache receives a subsequent request whose Request-URI
721 specifies one or more cache entries including a Vary header field,
722 the cache MUST NOT use such a cache entry to construct a response
723 to the new request unless all of the selecting request-headers
724 present in the new request match the corresponding stored
725 request-headers in the original request.
726 """
727 # test that the vary header is sent
728 uri = urlparse.urljoin(base, "vary/accept.asis")
729 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
730 self.assertEqual(response.status, 200)
731 self.assertTrue(response.has_key('vary'))
732
733 # get the resource again, from the cache since accept header in this
734 # request is the same as the request
735 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
736 self.assertEqual(response.status, 200)
737 self.assertEqual(response.fromcache, True, msg="Should be from cache")
738
739 # get the resource again, not from cache since Accept headers does not match
740 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
741 self.assertEqual(response.status, 200)
742 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
743
744 # get the resource again, without any Accept header, so again no match
745 (response, content) = self.http.request(uri, "GET")
746 self.assertEqual(response.status, 200)
747 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
748
749 def testNoVary(self):
Joe Gregorio46546a62012-10-03 14:31:10 -0400750 pass
chris dent89f15142009-12-24 14:02:57 -0600751 # when there is no vary, a different Accept header (e.g.) should not
752 # impact if the cache is used
753 # test that the vary header is not sent
Joe Gregorio46546a62012-10-03 14:31:10 -0400754 # uri = urlparse.urljoin(base, "vary/no-vary.asis")
755 # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
756 # self.assertEqual(response.status, 200)
757 # self.assertFalse(response.has_key('vary'))
chris dent89f15142009-12-24 14:02:57 -0600758
Joe Gregorio46546a62012-10-03 14:31:10 -0400759 # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
760 # self.assertEqual(response.status, 200)
761 # self.assertEqual(response.fromcache, True, msg="Should be from cache")
762 #
763 # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
764 # self.assertEqual(response.status, 200)
765 # self.assertEqual(response.fromcache, True, msg="Should be from cache")
chris dent89f15142009-12-24 14:02:57 -0600766
767 def testVaryHeaderDouble(self):
768 uri = urlparse.urljoin(base, "vary/accept-double.asis")
769 (response, content) = self.http.request(uri, "GET", headers={
770 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
771 self.assertEqual(response.status, 200)
772 self.assertTrue(response.has_key('vary'))
773
774 # we are from cache
775 (response, content) = self.http.request(uri, "GET", headers={
776 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
777 self.assertEqual(response.fromcache, True, msg="Should be from cache")
778
779 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
780 self.assertEqual(response.status, 200)
781 self.assertEqual(response.fromcache, False)
782
783 # get the resource again, not from cache, varied headers don't match exact
784 (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})
785 self.assertEqual(response.status, 200)
786 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
787
jcgregorio88ef89b2010-05-13 23:42:11 -0400788 def testVaryUnusedHeader(self):
789 # A header's value is not considered to vary if it's not used at all.
790 uri = urlparse.urljoin(base, "vary/unused-header.asis")
791 (response, content) = self.http.request(uri, "GET", headers={
792 'Accept': 'text/plain'})
793 self.assertEqual(response.status, 200)
794 self.assertTrue(response.has_key('vary'))
795
796 # we are from cache
797 (response, content) = self.http.request(uri, "GET", headers={
798 'Accept': 'text/plain',})
799 self.assertEqual(response.fromcache, True, msg="Should be from cache")
800
chris dent89f15142009-12-24 14:02:57 -0600801
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000802 def testHeadGZip(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400803 # Test that we don't try to decompress a HEAD response
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000804 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
805 (response, content) = self.http.request(uri, "HEAD")
806 self.assertEqual(response.status, 200)
807 self.assertNotEqual(int(response['content-length']), 0)
808 self.assertEqual(content, "")
809
jcgregorio2d66d4f2006-02-07 05:34:14 +0000810 def testGetGZip(self):
811 # Test that we support gzip compression
812 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000813 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000814 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000815 self.assertFalse(response.has_key('content-encoding'))
joe.gregorio8b6d2312007-12-16 05:42:07 +0000816 self.assertTrue(response.has_key('-content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000817 self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000818 self.assertEqual(content, "This is the final destination.\n")
819
Joe Gregoriod1137c52011-02-13 19:27:35 -0500820 def testPostAndGZipResponse(self):
821 uri = urlparse.urljoin(base, "gzip/post.cgi")
822 (response, content) = self.http.request(uri, "POST", body=" ")
823 self.assertEqual(response.status, 200)
824 self.assertFalse(response.has_key('content-encoding'))
825 self.assertTrue(response.has_key('-content-encoding'))
826
jcgregorio2d66d4f2006-02-07 05:34:14 +0000827 def testGetGZipFailure(self):
828 # Test that we raise a good exception when the gzip fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400829 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000830 uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
831 try:
jcgregorio36140b52006-06-13 02:17:52 +0000832 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000833 self.fail("Should never reach here")
834 except httplib2.FailedToDecompressContent:
835 pass
836 except Exception:
837 self.fail("Threw wrong kind of exception")
838
jcgregorio07a9a4a2007-03-08 21:18:39 +0000839 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400840 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000841
842 (response, content) = self.http.request(uri, "GET")
843 self.assertEqual(response.status, 500)
844 self.assertTrue(response.reason.startswith("Content purported"))
845
846 def testTimeout(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400847 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000848 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
849 try:
850 import socket
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400851 socket.setdefaulttimeout(1)
jcgregorio07a9a4a2007-03-08 21:18:39 +0000852 except:
853 # Don't run the test if we can't set the timeout
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400854 return
jcgregorio07a9a4a2007-03-08 21:18:39 +0000855 (response, content) = self.http.request(uri)
856 self.assertEqual(response.status, 408)
857 self.assertTrue(response.reason.startswith("Request Timeout"))
858 self.assertTrue(content.startswith("Request Timeout"))
859
jcgregoriob2697912007-03-09 02:23:47 +0000860 def testIndividualTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000861 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
862 http = httplib2.Http(timeout=1)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400863 http.force_exception_to_status_code = True
jcgregoriob2697912007-03-09 02:23:47 +0000864
865 (response, content) = http.request(uri)
866 self.assertEqual(response.status, 408)
867 self.assertTrue(response.reason.startswith("Request Timeout"))
868 self.assertTrue(content.startswith("Request Timeout"))
869
jcgregorio07a9a4a2007-03-08 21:18:39 +0000870
Joe Gregorio1a7609f2009-07-16 10:59:44 -0400871 def testHTTPSInitTimeout(self):
872 c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
873 self.assertEqual(47, c.timeout)
874
jcgregorio2d66d4f2006-02-07 05:34:14 +0000875 def testGetDeflate(self):
876 # Test that we support deflate compression
877 uri = urlparse.urljoin(base, "deflate/deflated.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000878 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000879 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000880 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000881 self.assertEqual(int(response['content-length']), len("This is the final destination."))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000882 self.assertEqual(content, "This is the final destination.")
883
884 def testGetDeflateFailure(self):
885 # Test that we raise a good exception when the deflate fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400886 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000887
jcgregorio2d66d4f2006-02-07 05:34:14 +0000888 uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
889 try:
jcgregorio36140b52006-06-13 02:17:52 +0000890 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000891 self.fail("Should never reach here")
892 except httplib2.FailedToDecompressContent:
893 pass
894 except Exception:
895 self.fail("Threw wrong kind of exception")
896
jcgregorio07a9a4a2007-03-08 21:18:39 +0000897 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400898 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000899
900 (response, content) = self.http.request(uri, "GET")
901 self.assertEqual(response.status, 500)
902 self.assertTrue(response.reason.startswith("Content purported"))
903
jcgregorio2d66d4f2006-02-07 05:34:14 +0000904 def testGetDuplicateHeaders(self):
905 # Test that duplicate headers get concatenated via ','
906 uri = urlparse.urljoin(base, "duplicate-headers/multilink.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000907 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000908 self.assertEqual(response.status, 200)
909 self.assertEqual(content, "This is content\n")
910 self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
911
912 def testGetCacheControlNoCache(self):
913 # Test Cache-Control: no-cache on requests
914 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorio0197ec82014-03-06 14:56:29 -0500915 (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000916 self.assertNotEqual(response['etag'], "")
Joe Gregorio0197ec82014-03-06 14:56:29 -0500917 (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000918 self.assertEqual(response.status, 200)
919 self.assertEqual(response.fromcache, True)
920
Joe Gregorio0197ec82014-03-06 14:56:29 -0500921 (response, content) = self.http.request(uri, "GET", headers={'accept-encoding': 'identity', 'Cache-Control': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000922 self.assertEqual(response.status, 200)
923 self.assertEqual(response.fromcache, False)
924
925 def testGetCacheControlPragmaNoCache(self):
926 # Test Pragma: no-cache on requests
927 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorio0197ec82014-03-06 14:56:29 -0500928 (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000929 self.assertNotEqual(response['etag'], "")
Joe Gregorio0197ec82014-03-06 14:56:29 -0500930 (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000931 self.assertEqual(response.status, 200)
932 self.assertEqual(response.fromcache, True)
933
Joe Gregorio0197ec82014-03-06 14:56:29 -0500934 (response, content) = self.http.request(uri, "GET", headers={'accept-encoding': 'identity', 'Pragma': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000935 self.assertEqual(response.status, 200)
936 self.assertEqual(response.fromcache, False)
937
938 def testGetCacheControlNoStoreRequest(self):
939 # A no-store request means that the response should not be stored.
940 uri = urlparse.urljoin(base, "304/test_etag.txt")
941
jcgregorio36140b52006-06-13 02:17:52 +0000942 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000943 self.assertEqual(response.status, 200)
944 self.assertEqual(response.fromcache, False)
945
jcgregorio36140b52006-06-13 02:17:52 +0000946 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000947 self.assertEqual(response.status, 200)
948 self.assertEqual(response.fromcache, False)
949
950 def testGetCacheControlNoStoreResponse(self):
951 # A no-store response means that the response should not be stored.
952 uri = urlparse.urljoin(base, "no-store/no-store.asis")
953
jcgregorio36140b52006-06-13 02:17:52 +0000954 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000955 self.assertEqual(response.status, 200)
956 self.assertEqual(response.fromcache, False)
957
jcgregorio36140b52006-06-13 02:17:52 +0000958 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000959 self.assertEqual(response.status, 200)
960 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000961
962 def testGetCacheControlNoCacheNoStoreRequest(self):
963 # Test that a no-store, no-cache clears the entry from the cache
964 # even if it was cached previously.
965 uri = urlparse.urljoin(base, "304/test_etag.txt")
966
jcgregorio36140b52006-06-13 02:17:52 +0000967 (response, content) = self.http.request(uri, "GET")
968 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000969 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000970 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
971 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000972 self.assertEqual(response.status, 200)
973 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000974
975 def testUpdateInvalidatesCache(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400976 # Test that calling PUT or DELETE on a
jcgregorio2d66d4f2006-02-07 05:34:14 +0000977 # URI that is cache invalidates that cache.
978 uri = urlparse.urljoin(base, "304/test_etag.txt")
979
jcgregorio36140b52006-06-13 02:17:52 +0000980 (response, content) = self.http.request(uri, "GET")
981 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000982 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000983 (response, content) = self.http.request(uri, "DELETE")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000984 self.assertEqual(response.status, 405)
985
jcgregorio36140b52006-06-13 02:17:52 +0000986 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000987 self.assertEqual(response.fromcache, False)
988
989 def testUpdateUsesCachedETag(self):
Joe Gregoriobd682082011-05-24 14:06:09 -0400990 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio2d66d4f2006-02-07 05:34:14 +0000991 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
992
jcgregorio36140b52006-06-13 02:17:52 +0000993 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000994 self.assertEqual(response.status, 200)
995 self.assertEqual(response.fromcache, False)
jcgregorio36140b52006-06-13 02:17:52 +0000996 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000997 self.assertEqual(response.status, 200)
998 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -0400999 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001000 self.assertEqual(response.status, 200)
Joe Gregoriocd868102009-09-29 17:09:16 -04001001 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001002 self.assertEqual(response.status, 412)
1003
Joe Gregoriobd682082011-05-24 14:06:09 -04001004 def testUpdatePatchUsesCachedETag(self):
1005 # Test that we natively support http://www.w3.org/1999/04/Editing/
1006 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
1007
1008 (response, content) = self.http.request(uri, "GET")
1009 self.assertEqual(response.status, 200)
1010 self.assertEqual(response.fromcache, False)
1011 (response, content) = self.http.request(uri, "GET")
1012 self.assertEqual(response.status, 200)
1013 self.assertEqual(response.fromcache, True)
1014 (response, content) = self.http.request(uri, "PATCH", body="foo")
1015 self.assertEqual(response.status, 200)
1016 (response, content) = self.http.request(uri, "PATCH", body="foo")
1017 self.assertEqual(response.status, 412)
1018
1019
joe.gregorio700f04d2008-09-06 04:46:32 +00001020 def testUpdateUsesCachedETagAndOCMethod(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001021 # Test that we natively support http://www.w3.org/1999/04/Editing/
joe.gregorio700f04d2008-09-06 04:46:32 +00001022 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
1023
1024 (response, content) = self.http.request(uri, "GET")
1025 self.assertEqual(response.status, 200)
1026 self.assertEqual(response.fromcache, False)
1027 (response, content) = self.http.request(uri, "GET")
1028 self.assertEqual(response.status, 200)
1029 self.assertEqual(response.fromcache, True)
1030 self.http.optimistic_concurrency_methods.append("DELETE")
1031 (response, content) = self.http.request(uri, "DELETE")
1032 self.assertEqual(response.status, 200)
1033
1034
jcgregorio4b145e82007-01-18 19:46:34 +00001035 def testUpdateUsesCachedETagOverridden(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001036 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio4b145e82007-01-18 19:46:34 +00001037 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
1038
1039 (response, content) = self.http.request(uri, "GET")
1040 self.assertEqual(response.status, 200)
1041 self.assertEqual(response.fromcache, False)
1042 (response, content) = self.http.request(uri, "GET")
1043 self.assertEqual(response.status, 200)
1044 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -04001045 (response, content) = self.http.request(uri, "PUT", body="foo", headers={'if-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +00001046 self.assertEqual(response.status, 412)
1047
jcgregorio2d66d4f2006-02-07 05:34:14 +00001048 def testBasicAuth(self):
1049 # Test Basic Authentication
1050 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001051 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001052 self.assertEqual(response.status, 401)
1053
1054 uri = urlparse.urljoin(base, "basic/")
jcgregorio36140b52006-06-13 02:17:52 +00001055 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001056 self.assertEqual(response.status, 401)
1057
jcgregorio36140b52006-06-13 02:17:52 +00001058 self.http.add_credentials('joe', 'password')
1059 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001060 self.assertEqual(response.status, 200)
1061
1062 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001063 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001064 self.assertEqual(response.status, 200)
1065
jcgregoriode8238d2007-03-07 19:08:26 +00001066 def testBasicAuthWithDomain(self):
1067 # Test Basic Authentication
1068 uri = urlparse.urljoin(base, "basic/file.txt")
1069 (response, content) = self.http.request(uri, "GET")
1070 self.assertEqual(response.status, 401)
1071
1072 uri = urlparse.urljoin(base, "basic/")
1073 (response, content) = self.http.request(uri, "GET")
1074 self.assertEqual(response.status, 401)
1075
1076 self.http.add_credentials('joe', 'password', "example.org")
1077 (response, content) = self.http.request(uri, "GET")
1078 self.assertEqual(response.status, 401)
1079
1080 uri = urlparse.urljoin(base, "basic/file.txt")
1081 (response, content) = self.http.request(uri, "GET")
1082 self.assertEqual(response.status, 401)
1083
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001084 domain = urlparse.urlparse(base)[1]
jcgregoriode8238d2007-03-07 19:08:26 +00001085 self.http.add_credentials('joe', 'password', domain)
1086 (response, content) = self.http.request(uri, "GET")
1087 self.assertEqual(response.status, 200)
1088
1089 uri = urlparse.urljoin(base, "basic/file.txt")
1090 (response, content) = self.http.request(uri, "GET")
1091 self.assertEqual(response.status, 200)
1092
1093
1094
1095
1096
1097
jcgregorio2d66d4f2006-02-07 05:34:14 +00001098 def testBasicAuthTwoDifferentCredentials(self):
jcgregorioadbb4f82006-05-19 15:17:42 +00001099 # Test Basic Authentication with multiple sets of credentials
jcgregorio2d66d4f2006-02-07 05:34:14 +00001100 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001101 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001102 self.assertEqual(response.status, 401)
1103
1104 uri = urlparse.urljoin(base, "basic2/")
jcgregorio36140b52006-06-13 02:17:52 +00001105 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001106 self.assertEqual(response.status, 401)
1107
jcgregorio36140b52006-06-13 02:17:52 +00001108 self.http.add_credentials('fred', 'barney')
1109 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001110 self.assertEqual(response.status, 200)
1111
1112 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001113 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001114 self.assertEqual(response.status, 200)
1115
1116 def testBasicAuthNested(self):
1117 # Test Basic Authentication with resources
1118 # that are nested
1119 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001120 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001121 self.assertEqual(response.status, 401)
1122
1123 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001124 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001125 self.assertEqual(response.status, 401)
1126
jcgregorioadbb4f82006-05-19 15:17:42 +00001127 # Now add in credentials one at a time and test.
jcgregorio36140b52006-06-13 02:17:52 +00001128 self.http.add_credentials('joe', 'password')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001129
1130 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001131 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001132 self.assertEqual(response.status, 200)
1133
1134 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001135 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001136 self.assertEqual(response.status, 401)
1137
jcgregorio36140b52006-06-13 02:17:52 +00001138 self.http.add_credentials('fred', 'barney')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001139
1140 uri = urlparse.urljoin(base, "basic-nested/")
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, 200)
1143
1144 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001145 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001146 self.assertEqual(response.status, 200)
1147
1148 def testDigestAuth(self):
1149 # Test that we support Digest Authentication
1150 uri = urlparse.urljoin(base, "digest/")
jcgregorio36140b52006-06-13 02:17:52 +00001151 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001152 self.assertEqual(response.status, 401)
1153
jcgregorio36140b52006-06-13 02:17:52 +00001154 self.http.add_credentials('joe', 'password')
1155 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001156 self.assertEqual(response.status, 200)
1157
1158 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001159 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001160
1161 def testDigestAuthNextNonceAndNC(self):
1162 # Test that if the server sets nextnonce that we reset
1163 # the nonce count back to 1
1164 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001165 self.http.add_credentials('joe', 'password')
1166 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001167 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1168 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +00001169 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001170 info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
1171 self.assertEqual(response.status, 200)
1172
1173 if info.has_key('nextnonce'):
1174 self.assertEqual(info2['nc'], 1)
1175
1176 def testDigestAuthStale(self):
1177 # Test that we can handle a nonce becoming stale
1178 uri = urlparse.urljoin(base, "digest-expire/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001179 self.http.add_credentials('joe', 'password')
1180 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001181 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1182 self.assertEqual(response.status, 200)
1183
1184 time.sleep(3)
1185 # Sleep long enough that the nonce becomes stale
1186
jcgregorio36140b52006-06-13 02:17:52 +00001187 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001188 self.assertFalse(response.fromcache)
1189 self.assertTrue(response._stale_digest)
1190 info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
1191 self.assertEqual(response.status, 200)
1192
1193 def reflector(self, content):
jcgregorio25185622006-10-28 05:12:34 +00001194 return dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
jcgregorio2d66d4f2006-02-07 05:34:14 +00001195
1196 def testReflector(self):
1197 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +00001198 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001199 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001200 self.assertTrue(d.has_key('HTTP_USER_AGENT'))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001201
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001202 def testConnectionClose(self):
1203 uri = "http://www.google.com/"
1204 (response, content) = self.http.request(uri, "GET")
1205 for c in self.http.connections.values():
1206 self.assertNotEqual(None, c.sock)
1207 (response, content) = self.http.request(uri, "GET", headers={"connection": "close"})
1208 for c in self.http.connections.values():
1209 self.assertEqual(None, c.sock)
1210
Joe Gregorio46546a62012-10-03 14:31:10 -04001211 def testPickleHttp(self):
1212 pickled_http = pickle.dumps(self.http)
1213 new_http = pickle.loads(pickled_http)
1214
1215 self.assertEqual(sorted(new_http.__dict__.keys()),
1216 sorted(self.http.__dict__.keys()))
1217 for key in new_http.__dict__:
1218 if key in ('certificates', 'credentials'):
1219 self.assertEqual(new_http.__dict__[key].credentials,
1220 self.http.__dict__[key].credentials)
1221 elif key == 'cache':
1222 self.assertEqual(new_http.__dict__[key].cache,
1223 self.http.__dict__[key].cache)
1224 else:
1225 self.assertEqual(new_http.__dict__[key],
1226 self.http.__dict__[key])
1227
1228 def testPickleHttpWithConnection(self):
1229 self.http.request('http://bitworking.org',
1230 connection_type=_MyHTTPConnection)
1231 pickled_http = pickle.dumps(self.http)
1232 new_http = pickle.loads(pickled_http)
1233
1234 self.assertEqual(self.http.connections.keys(), ['http:bitworking.org'])
1235 self.assertEqual(new_http.connections, {})
1236
1237 def testPickleCustomRequestHttp(self):
1238 def dummy_request(*args, **kwargs):
1239 return new_request(*args, **kwargs)
1240 dummy_request.dummy_attr = 'dummy_value'
1241
1242 self.http.request = dummy_request
1243 pickled_http = pickle.dumps(self.http)
1244 self.assertFalse("S'request'" in pickled_http)
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001245
jcgregorio36140b52006-06-13 02:17:52 +00001246try:
1247 import memcache
1248 class HttpTestMemCached(HttpTest):
1249 def setUp(self):
1250 self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
jcgregorio47d24672006-06-29 05:18:59 +00001251 #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
jcgregorio36140b52006-06-13 02:17:52 +00001252 self.http = httplib2.Http(self.cache)
1253 self.cache.flush_all()
jcgregorio47d24672006-06-29 05:18:59 +00001254 # Not exactly sure why the sleep is needed here, but
1255 # if not present then some unit tests that rely on caching
1256 # fail. Memcached seems to lose some sets immediately
1257 # after a flush_all if the set is to a value that
1258 # was previously cached. (Maybe the flush is handled async?)
1259 time.sleep(1)
jcgregorio36140b52006-06-13 02:17:52 +00001260 self.http.clear_credentials()
1261except:
1262 pass
1263
1264
1265
chris dent89f15142009-12-24 14:02:57 -06001266
jcgregoriodb8dfc82006-03-31 14:59:46 +00001267# ------------------------------------------------------------------------
jcgregorio2d66d4f2006-02-07 05:34:14 +00001268
1269class HttpPrivateTest(unittest.TestCase):
1270
1271 def testParseCacheControl(self):
1272 # Test that we can parse the Cache-Control header
1273 self.assertEqual({}, httplib2._parse_cache_control({}))
1274 self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
1275 cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
1276 self.assertEqual(cc['no-cache'], 1)
1277 self.assertEqual(cc['max-age'], '7200')
1278 cc = httplib2._parse_cache_control({'cache-control': ' , '})
1279 self.assertEqual(cc[''], 1)
1280
Joe Gregorioe314e8b2009-07-16 20:11:28 -04001281 try:
1282 cc = httplib2._parse_cache_control({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'})
1283 self.assertTrue("max-age" in cc)
1284 except:
1285 self.fail("Should not throw exception")
1286
jcgregorio2d66d4f2006-02-07 05:34:14 +00001287 def testNormalizeHeaders(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001288 # Test that we normalize headers to lowercase
jcgregorio2d66d4f2006-02-07 05:34:14 +00001289 h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
1290 self.assertTrue(h.has_key('cache-control'))
1291 self.assertTrue(h.has_key('other'))
1292 self.assertEqual('Stuff', h['other'])
1293
1294 def testExpirationModelTransparent(self):
1295 # Test that no-cache makes our request TRANSPARENT
1296 response_headers = {
1297 'cache-control': 'max-age=7200'
1298 }
1299 request_headers = {
1300 'cache-control': 'no-cache'
1301 }
1302 self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
1303
jcgregorio45865012007-01-18 16:38:22 +00001304 def testMaxAgeNonNumeric(self):
1305 # Test that no-cache makes our request TRANSPARENT
1306 response_headers = {
1307 'cache-control': 'max-age=fred, min-fresh=barney'
1308 }
1309 request_headers = {
1310 }
1311 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1312
1313
jcgregorio2d66d4f2006-02-07 05:34:14 +00001314 def testExpirationModelNoCacheResponse(self):
1315 # The date and expires point to an entry that should be
1316 # FRESH, but the no-cache over-rides that.
1317 now = time.time()
1318 response_headers = {
1319 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1320 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1321 'cache-control': 'no-cache'
1322 }
1323 request_headers = {
1324 }
1325 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1326
1327 def testExpirationModelStaleRequestMustReval(self):
1328 # must-revalidate forces STALE
1329 self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
1330
1331 def testExpirationModelStaleResponseMustReval(self):
1332 # must-revalidate forces STALE
1333 self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
1334
1335 def testExpirationModelFresh(self):
1336 response_headers = {
1337 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1338 'cache-control': 'max-age=2'
1339 }
1340 request_headers = {
1341 }
1342 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1343 time.sleep(3)
1344 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1345
1346 def testExpirationMaxAge0(self):
1347 response_headers = {
1348 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1349 'cache-control': 'max-age=0'
1350 }
1351 request_headers = {
1352 }
1353 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1354
1355 def testExpirationModelDateAndExpires(self):
1356 now = time.time()
1357 response_headers = {
1358 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1359 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1360 }
1361 request_headers = {
1362 }
1363 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1364 time.sleep(3)
1365 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1366
jcgregoriof9511052007-06-01 14:56:34 +00001367 def testExpiresZero(self):
1368 now = time.time()
1369 response_headers = {
1370 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1371 'expires': "0",
1372 }
1373 request_headers = {
1374 }
1375 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1376
jcgregorio2d66d4f2006-02-07 05:34:14 +00001377 def testExpirationModelDateOnly(self):
1378 now = time.time()
1379 response_headers = {
1380 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
1381 }
1382 request_headers = {
1383 }
1384 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1385
1386 def testExpirationModelOnlyIfCached(self):
1387 response_headers = {
1388 }
1389 request_headers = {
1390 'cache-control': 'only-if-cached',
1391 }
1392 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1393
1394 def testExpirationModelMaxAgeBoth(self):
1395 now = time.time()
1396 response_headers = {
1397 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1398 'cache-control': 'max-age=2'
1399 }
1400 request_headers = {
1401 'cache-control': 'max-age=0'
1402 }
1403 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1404
1405 def testExpirationModelDateAndExpiresMinFresh1(self):
1406 now = time.time()
1407 response_headers = {
1408 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1409 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1410 }
1411 request_headers = {
1412 'cache-control': 'min-fresh=2'
1413 }
1414 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1415
1416 def testExpirationModelDateAndExpiresMinFresh2(self):
1417 now = time.time()
1418 response_headers = {
1419 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1420 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1421 }
1422 request_headers = {
1423 'cache-control': 'min-fresh=2'
1424 }
1425 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1426
1427 def testParseWWWAuthenticateEmpty(self):
1428 res = httplib2._parse_www_authenticate({})
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001429 self.assertEqual(len(res.keys()), 0)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001430
jcgregoriofd22e432006-04-27 02:00:08 +00001431 def testParseWWWAuthenticate(self):
1432 # different uses of spaces around commas
1433 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
1434 self.assertEqual(len(res.keys()), 1)
1435 self.assertEqual(len(res['test'].keys()), 5)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001436
jcgregoriofd22e432006-04-27 02:00:08 +00001437 # tokens with non-alphanum
1438 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
1439 self.assertEqual(len(res.keys()), 1)
1440 self.assertEqual(len(res['t*!%#st'].keys()), 2)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001441
jcgregoriofd22e432006-04-27 02:00:08 +00001442 # quoted string with quoted pairs
1443 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
1444 self.assertEqual(len(res.keys()), 1)
1445 self.assertEqual(res['test']['realm'], 'a "test" realm')
1446
1447 def testParseWWWAuthenticateStrict(self):
1448 httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
1449 self.testParseWWWAuthenticate();
1450 httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
1451
jcgregorio2d66d4f2006-02-07 05:34:14 +00001452 def testParseWWWAuthenticateBasic(self):
1453 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
1454 basic = res['basic']
1455 self.assertEqual('me', basic['realm'])
1456
1457 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
1458 basic = res['basic']
1459 self.assertEqual('me', basic['realm'])
1460 self.assertEqual('MD5', basic['algorithm'])
1461
1462 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
1463 basic = res['basic']
1464 self.assertEqual('me', basic['realm'])
1465 self.assertEqual('MD5', basic['algorithm'])
1466
1467 def testParseWWWAuthenticateBasic2(self):
1468 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
1469 basic = res['basic']
1470 self.assertEqual('me', basic['realm'])
1471 self.assertEqual('fred', basic['other'])
1472
1473 def testParseWWWAuthenticateBasic3(self):
1474 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
1475 basic = res['basic']
1476 self.assertEqual('me', basic['realm'])
1477
1478
1479 def testParseWWWAuthenticateDigest(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001480 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001481 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
1482 digest = res['digest']
1483 self.assertEqual('testrealm@host.com', digest['realm'])
1484 self.assertEqual('auth,auth-int', digest['qop'])
1485
1486
1487 def testParseWWWAuthenticateMultiple(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001488 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001489 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
1490 digest = res['digest']
1491 self.assertEqual('testrealm@host.com', digest['realm'])
1492 self.assertEqual('auth,auth-int', digest['qop'])
1493 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1494 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1495 basic = res['basic']
1496 self.assertEqual('me', basic['realm'])
1497
1498 def testParseWWWAuthenticateMultiple2(self):
1499 # Handle an added comma between challenges, which might get thrown in if the challenges were
1500 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001501 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001502 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
1503 digest = res['digest']
1504 self.assertEqual('testrealm@host.com', digest['realm'])
1505 self.assertEqual('auth,auth-int', digest['qop'])
1506 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1507 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1508 basic = res['basic']
1509 self.assertEqual('me', basic['realm'])
1510
1511 def testParseWWWAuthenticateMultiple3(self):
1512 # Handle an added comma between challenges, which might get thrown in if the challenges were
1513 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001514 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001515 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1516 digest = res['digest']
1517 self.assertEqual('testrealm@host.com', digest['realm'])
1518 self.assertEqual('auth,auth-int', digest['qop'])
1519 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1520 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1521 basic = res['basic']
1522 self.assertEqual('me', basic['realm'])
1523 wsse = res['wsse']
1524 self.assertEqual('foo', wsse['realm'])
1525 self.assertEqual('UsernameToken', wsse['profile'])
1526
1527 def testParseWWWAuthenticateMultiple4(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001528 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1529 '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 +00001530 digest = res['digest']
1531 self.assertEqual('test-real.m@host.com', digest['realm'])
1532 self.assertEqual('\tauth,auth-int', digest['qop'])
1533 self.assertEqual('(*)&^&$%#', digest['nonce'])
1534
1535 def testParseWWWAuthenticateMoreQuoteCombos(self):
1536 res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
1537 digest = res['digest']
1538 self.assertEqual('myrealm', digest['realm'])
1539
Joe Gregorio6fa3cf22011-02-13 22:45:06 -05001540 def testParseWWWAuthenticateMalformed(self):
1541 try:
1542 res = httplib2._parse_www_authenticate({'www-authenticate':'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'})
1543 self.fail("should raise an exception")
1544 except httplib2.MalformedHeader:
1545 pass
1546
jcgregorio2d66d4f2006-02-07 05:34:14 +00001547 def testDigestObject(self):
1548 credentials = ('joe', 'password')
1549 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001550 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001551 headers = {}
1552 response = {
1553 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
1554 }
1555 content = ""
Joe Gregorio875a8b52011-06-13 14:06:23 -04001556
jcgregorio6cbab7e2006-04-21 20:35:43 +00001557 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001558 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
Joe Gregorio875a8b52011-06-13 14:06:23 -04001559 our_request = "authorization: %s" % headers['authorization']
1560 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 +00001561 self.assertEqual(our_request, working_request)
1562
Joe Gregorio03d99102011-06-22 16:55:52 -04001563 def testDigestObjectWithOpaque(self):
1564 credentials = ('joe', 'password')
1565 host = None
1566 request_uri = '/projects/httplib2/test/digest/'
1567 headers = {}
1568 response = {
1569 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", opaque="atestopaque"'
1570 }
1571 content = ""
1572
1573 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
1574 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
1575 our_request = "authorization: %s" % headers['authorization']
1576 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"'
1577 self.assertEqual(our_request, working_request)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001578
1579 def testDigestObjectStale(self):
1580 credentials = ('joe', 'password')
1581 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001582 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001583 headers = {}
1584 response = httplib2.Response({ })
1585 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1586 response.status = 401
1587 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001588 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001589 # Returns true to force a retry
1590 self.assertTrue( d.response(response, content) )
1591
1592 def testDigestObjectAuthInfo(self):
1593 credentials = ('joe', 'password')
1594 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001595 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001596 headers = {}
1597 response = httplib2.Response({ })
1598 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1599 response['authentication-info'] = 'nextnonce="fred"'
1600 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001601 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001602 # Returns true to force a retry
1603 self.assertFalse( d.response(response, content) )
1604 self.assertEqual('fred', d.challenge['nonce'])
1605 self.assertEqual(1, d.challenge['nc'])
1606
1607 def testWsseAlgorithm(self):
1608 digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
1609 expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
1610 self.assertEqual(expected, digest)
1611
jcgregoriodb8dfc82006-03-31 14:59:46 +00001612 def testEnd2End(self):
1613 # one end to end header
1614 response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
1615 end2end = httplib2._get_end2end_headers(response)
1616 self.assertTrue('content-type' in end2end)
1617 self.assertTrue('te' not in end2end)
1618 self.assertTrue('connection' not in end2end)
1619
1620 # one end to end header that gets eliminated
1621 response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
1622 end2end = httplib2._get_end2end_headers(response)
1623 self.assertTrue('content-type' not in end2end)
1624 self.assertTrue('te' not in end2end)
1625 self.assertTrue('connection' not in end2end)
1626
1627 # Degenerate case of no headers
1628 response = {}
1629 end2end = httplib2._get_end2end_headers(response)
1630 self.assertEquals(0, len(end2end))
1631
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001632 # Degenerate case of connection referrring to a header not passed in
jcgregoriodb8dfc82006-03-31 14:59:46 +00001633 response = {'connection': 'content-type'}
1634 end2end = httplib2._get_end2end_headers(response)
1635 self.assertEquals(0, len(end2end))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001636
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001637
1638class TestProxyInfo(unittest.TestCase):
1639 def setUp(self):
1640 self.orig_env = dict(os.environ)
1641
1642 def tearDown(self):
1643 os.environ.clear()
1644 os.environ.update(self.orig_env)
1645
1646 def test_from_url(self):
Joe Gregorio46546a62012-10-03 14:31:10 -04001647 pi = httplib2.proxy_info_from_url('http://myproxy.example.com')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001648 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1649 self.assertEquals(pi.proxy_port, 80)
1650 self.assertEquals(pi.proxy_user, None)
1651
1652 def test_from_url_ident(self):
Joe Gregorio46546a62012-10-03 14:31:10 -04001653 pi = httplib2.proxy_info_from_url('http://zoidberg:fish@someproxy:99')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001654 self.assertEquals(pi.proxy_host, 'someproxy')
1655 self.assertEquals(pi.proxy_port, 99)
1656 self.assertEquals(pi.proxy_user, 'zoidberg')
1657 self.assertEquals(pi.proxy_pass, 'fish')
1658
1659 def test_from_env(self):
1660 os.environ['http_proxy'] = 'http://myproxy.example.com:8080'
Joe Gregorio46546a62012-10-03 14:31:10 -04001661 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001662 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1663 self.assertEquals(pi.proxy_port, 8080)
1664 self.assertEquals(pi.bypass_hosts, [])
1665
1666 def test_from_env_no_proxy(self):
1667 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1668 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
1669 os.environ['no_proxy'] = 'localhost,otherhost.domain.local'
Joe Gregorio46546a62012-10-03 14:31:10 -04001670 pi = httplib2.proxy_info_from_environment('https')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001671 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1672 self.assertEquals(pi.proxy_port, 81)
1673 self.assertEquals(pi.bypass_hosts, ['localhost',
1674 'otherhost.domain.local'])
1675
1676 def test_from_env_none(self):
1677 os.environ.clear()
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, None)
1680
Jason R. Coombs43840892011-08-09 10:30:46 -04001681 def test_applies_to(self):
1682 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1683 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
Jason R. Coombs96279c52011-08-16 12:53:27 -04001684 os.environ['no_proxy'] = 'localhost,otherhost.domain.local,example.com'
Joe Gregorio46546a62012-10-03 14:31:10 -04001685 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs43840892011-08-09 10:30:46 -04001686 self.assertFalse(pi.applies_to('localhost'))
1687 self.assertTrue(pi.applies_to('www.google.com'))
Jason R. Coombs96279c52011-08-16 12:53:27 -04001688 self.assertFalse(pi.applies_to('www.example.com'))
1689
1690 def test_no_proxy_star(self):
1691 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1692 os.environ['NO_PROXY'] = '*'
Joe Gregorio46546a62012-10-03 14:31:10 -04001693 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs96279c52011-08-16 12:53:27 -04001694 for host in ('localhost', '169.254.38.192', 'www.google.com'):
1695 self.assertFalse(pi.applies_to(host))
Jason R. Coombs43840892011-08-09 10:30:46 -04001696
Martin Carroll5ccd2602016-09-03 01:03:00 -04001697 def test_proxy_headers(self):
1698 headers = {'key0': 'val0', 'key1': 'val1'}
1699 pi = httplib2.ProxyInfo(httplib2.socks.PROXY_TYPE_HTTP, 'localhost', 1234, proxy_headers = headers)
1700 self.assertEquals(pi.proxy_headers, headers)
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001701
chris dent89f15142009-12-24 14:02:57 -06001702if __name__ == '__main__':
1703 unittest.main()