blob: 3802879a53864a82727bf8feefa025340fd574e5 [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
jcgregorio90fb4a42006-11-17 16:19:47 +0000147
jcgregorio2d66d4f2006-02-07 05:34:14 +0000148class HttpTest(unittest.TestCase):
149 def setUp(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400150 if os.path.exists(cacheDirName):
jcgregorio7e3608f2006-06-15 13:01:53 +0000151 [os.remove(os.path.join(cacheDirName, file)) for file in os.listdir(cacheDirName)]
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400152
153 if sys.version_info < (2, 6):
154 disable_cert_validation = True
155 else:
156 disable_cert_validation = False
157 self.http = httplib2.Http(
158 cacheDirName,
159 disable_ssl_certificate_validation=disable_cert_validation)
jcgregorio36140b52006-06-13 02:17:52 +0000160 self.http.clear_credentials()
jcgregorio2d66d4f2006-02-07 05:34:14 +0000161
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500162 def testIPv6NoSSL(self):
163 try:
164 self.http.request("http://[::1]/")
165 except socket.gaierror:
166 self.fail("should get the address family right for IPv6")
167 except socket.error:
168 # Even if IPv6 isn't installed on a machine it should just raise socket.error
169 pass
170
171 def testIPv6SSL(self):
172 try:
173 self.http.request("https://[::1]/")
174 except socket.gaierror:
175 self.fail("should get the address family right for IPv6")
Jason R. Coombscee15da2011-08-09 09:13:34 -0400176 except httplib2.CertificateHostnameMismatch:
177 # We connected and verified that the certificate doesn't match
178 # the name. Good enough.
179 pass
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500180 except socket.error:
181 # Even if IPv6 isn't installed on a machine it should just raise socket.error
182 pass
183
jcgregorio14644372007-07-30 14:13:37 +0000184 def testConnectionType(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400185 self.http.force_exception_to_status_code = False
jcgregorio14644372007-07-30 14:13:37 +0000186 response, content = self.http.request("http://bitworking.org", connection_type=_MyHTTPConnection)
187 self.assertEqual(response['content-location'], "http://bitworking.org")
188 self.assertEqual(content, "the body")
189
jcgregorio6a638172007-01-23 16:40:23 +0000190 def testGetUnknownServer(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400191 self.http.force_exception_to_status_code = False
jcgregorio6a638172007-01-23 16:40:23 +0000192 try:
193 self.http.request("http://fred.bitworking.org/")
194 self.fail("An httplib2.ServerNotFoundError Exception must be thrown on an unresolvable server.")
195 except httplib2.ServerNotFoundError:
196 pass
197
jcgregorio07a9a4a2007-03-08 21:18:39 +0000198 # Now test with exceptions turned off
199 self.http.force_exception_to_status_code = True
200
201 (response, content) = self.http.request("http://fred.bitworking.org/")
202 self.assertEqual(response['content-type'], 'text/plain')
203 self.assertTrue(content.startswith("Unable to find"))
204 self.assertEqual(response.status, 400)
205
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500206 def testGetConnectionRefused(self):
207 self.http.force_exception_to_status_code = False
208 try:
209 self.http.request("http://localhost:7777/")
210 self.fail("An socket.error exception must be thrown on Connection Refused.")
211 except socket.error:
212 pass
213
214 # Now test with exceptions turned off
215 self.http.force_exception_to_status_code = True
216
217 (response, content) = self.http.request("http://localhost:7777/")
218 self.assertEqual(response['content-type'], 'text/plain')
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400219 self.assertTrue("Connection refused" in content
220 or "actively refused" in content,
221 "Unexpected status %(content)s" % vars())
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500222 self.assertEqual(response.status, 400)
223
jcgregorioa898f8f2006-12-12 17:16:55 +0000224 def testGetIRI(self):
jcgregoriodebceec2006-12-12 20:26:02 +0000225 if sys.version_info >= (2,3):
226 uri = urlparse.urljoin(base, u"reflector/reflector.cgi?d=\N{CYRILLIC CAPITAL LETTER DJE}")
227 (response, content) = self.http.request(uri, "GET")
228 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400229 self.assertTrue(d.has_key('QUERY_STRING'))
230 self.assertTrue(d['QUERY_STRING'].find('%D0%82') > 0)
231
jcgregorio2d66d4f2006-02-07 05:34:14 +0000232 def testGetIsDefaultMethod(self):
233 # Test that GET is the default method
234 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000235 (response, content) = self.http.request(uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000236 self.assertEqual(response['x-method'], "GET")
237
238 def testDifferentMethods(self):
239 # Test that all methods can be used
240 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
241 for method in ["GET", "PUT", "DELETE", "POST"]:
jcgregorio36140b52006-06-13 02:17:52 +0000242 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000243 self.assertEqual(response['x-method'], method)
244
Joe Gregoriob628c0b2009-07-16 12:28:04 -0400245 def testHeadRead(self):
246 # Test that we don't try to read the response of a HEAD request
247 # since httplib blocks response.read() for HEAD requests.
248 # Oddly enough this doesn't appear as a problem when doing HEAD requests
249 # against Apache servers.
250 uri = "http://www.google.com/"
251 (response, content) = self.http.request(uri, "HEAD")
252 self.assertEqual(response.status, 200)
253 self.assertEqual(content, "")
254
jcgregorio2d66d4f2006-02-07 05:34:14 +0000255 def testGetNoCache(self):
256 # Test that can do a GET w/o the cache turned on.
257 http = httplib2.Http()
258 uri = urlparse.urljoin(base, "304/test_etag.txt")
259 (response, content) = http.request(uri, "GET")
260 self.assertEqual(response.status, 200)
jcgregorioa0713ab2006-07-01 05:21:34 +0000261 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000262
Joe Gregorioe202d212009-07-16 14:57:52 -0400263 def testGetOnlyIfCachedCacheHit(self):
264 # Test that can do a GET with cache and 'only-if-cached'
265 uri = urlparse.urljoin(base, "304/test_etag.txt")
266 (response, content) = self.http.request(uri, "GET")
267 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
268 self.assertEqual(response.fromcache, True)
269 self.assertEqual(response.status, 200)
270
jcgregorioe4ce13e2006-04-02 03:05:08 +0000271 def testGetOnlyIfCachedCacheMiss(self):
272 # Test that can do a GET with no cache with 'only-if-cached'
jcgregorioe4ce13e2006-04-02 03:05:08 +0000273 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorioe202d212009-07-16 14:57:52 -0400274 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
jcgregorioe4ce13e2006-04-02 03:05:08 +0000275 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400276 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000277
278 def testGetOnlyIfCachedNoCacheAtAll(self):
279 # Test that can do a GET with no cache with 'only-if-cached'
280 # Of course, there might be an intermediary beyond us
281 # that responds to the 'only-if-cached', so this
282 # test can't really be guaranteed to pass.
283 http = httplib2.Http()
284 uri = urlparse.urljoin(base, "304/test_etag.txt")
285 (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
286 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400287 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000288
jcgregorio2d66d4f2006-02-07 05:34:14 +0000289 def testUserAgent(self):
290 # Test that we provide a default user-agent
291 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000292 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000293 self.assertEqual(response.status, 200)
294 self.assertTrue(content.startswith("Python-httplib2/"))
295
296 def testUserAgentNonDefault(self):
297 # Test that the default user-agent can be over-ridden
joe.gregoriof28536d2007-10-23 14:10:11 +0000298
jcgregorio2d66d4f2006-02-07 05:34:14 +0000299 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000300 (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000301 self.assertEqual(response.status, 200)
302 self.assertTrue(content.startswith("fred/1.0"))
303
304 def testGet300WithLocation(self):
305 # Test the we automatically follow 300 redirects if a Location: header is provided
306 uri = urlparse.urljoin(base, "300/with-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000307 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000308 self.assertEqual(response.status, 200)
309 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000310 self.assertEqual(response.previous.status, 300)
311 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000312
313 # Confirm that the intermediate 300 is not cached
jcgregorio36140b52006-06-13 02:17:52 +0000314 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000315 self.assertEqual(response.status, 200)
316 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000317 self.assertEqual(response.previous.status, 300)
318 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000319
jcgregorio2f1e1422007-05-03 13:17:33 +0000320 def testGet300WithLocationNoRedirect(self):
321 # Test the we automatically follow 300 redirects if a Location: header is provided
322 self.http.follow_redirects = False
323 uri = urlparse.urljoin(base, "300/with-location-header.asis")
324 (response, content) = self.http.request(uri, "GET")
325 self.assertEqual(response.status, 300)
326
jcgregorio2d66d4f2006-02-07 05:34:14 +0000327 def testGet300WithoutLocation(self):
328 # Not giving a Location: header in a 300 response is acceptable
329 # In which case we just return the 300 response
330 uri = urlparse.urljoin(base, "300/without-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000331 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000332 self.assertEqual(response.status, 300)
333 self.assertTrue(response['content-type'].startswith("text/html"))
jcgregorioa0713ab2006-07-01 05:21:34 +0000334 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000335
336 def testGet301(self):
337 # Test that we automatically follow 301 redirects
338 # and that we cache the 301 response
339 uri = urlparse.urljoin(base, "301/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000340 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000341 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000342 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000343 self.assertTrue(response.has_key('content-location'))
344 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000345 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000346 self.assertEqual(response.previous.status, 301)
347 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000348
jcgregorio36140b52006-06-13 02:17:52 +0000349 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000350 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000351 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000352 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000353 self.assertEqual(response.previous.status, 301)
354 self.assertEqual(response.previous.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000355
Joe Gregorio694a8122011-02-13 21:40:09 -0500356 def testHead301(self):
357 # Test that we automatically follow 301 redirects
358 uri = urlparse.urljoin(base, "301/onestep.asis")
359 destination = urlparse.urljoin(base, "302/final-destination.txt")
360 (response, content) = self.http.request(uri, "HEAD")
361 self.assertEqual(response.status, 200)
362 self.assertEqual(response.previous.status, 301)
363 self.assertEqual(response.previous.fromcache, False)
jcgregorio2f1e1422007-05-03 13:17:33 +0000364
365 def testGet301NoRedirect(self):
366 # Test that we automatically follow 301 redirects
367 # and that we cache the 301 response
368 self.http.follow_redirects = False
369 uri = urlparse.urljoin(base, "301/onestep.asis")
370 destination = urlparse.urljoin(base, "302/final-destination.txt")
371 (response, content) = self.http.request(uri, "GET")
372 self.assertEqual(response.status, 301)
373
374
jcgregorio2d66d4f2006-02-07 05:34:14 +0000375 def testGet302(self):
376 # Test that we automatically follow 302 redirects
377 # and that we DO NOT cache the 302 response
378 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000379 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000380 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000381 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000382 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000383 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000384 self.assertEqual(response.previous.status, 302)
385 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000386
387 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000388 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000389 self.assertEqual(response.status, 200)
390 self.assertEqual(response.fromcache, True)
jcgregorio772adc82006-11-17 21:52:34 +0000391 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000392 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000393 self.assertEqual(response.previous.status, 302)
394 self.assertEqual(response.previous.fromcache, False)
jcgregorio772adc82006-11-17 21:52:34 +0000395 self.assertEqual(response.previous['content-location'], uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000396
397 uri = urlparse.urljoin(base, "302/twostep.asis")
398
jcgregorio36140b52006-06-13 02:17:52 +0000399 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000400 self.assertEqual(response.status, 200)
401 self.assertEqual(response.fromcache, True)
402 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000403 self.assertEqual(response.previous.status, 302)
404 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000405
406 def testGet302RedirectionLimit(self):
407 # Test that we can set a lower redirection limit
408 # and that we raise an exception when we exceed
409 # that limit.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400410 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000411
jcgregorio2d66d4f2006-02-07 05:34:14 +0000412 uri = urlparse.urljoin(base, "302/twostep.asis")
413 try:
jcgregorio36140b52006-06-13 02:17:52 +0000414 (response, content) = self.http.request(uri, "GET", redirections = 1)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000415 self.fail("This should not happen")
416 except httplib2.RedirectLimit:
417 pass
418 except Exception, e:
419 self.fail("Threw wrong kind of exception ")
420
jcgregorio07a9a4a2007-03-08 21:18:39 +0000421 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400422 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000423
424 (response, content) = self.http.request(uri, "GET", redirections = 1)
425 self.assertEqual(response.status, 500)
426 self.assertTrue(response.reason.startswith("Redirected more"))
427 self.assertEqual("302", response['status'])
428 self.assertTrue(content.startswith("<html>"))
429 self.assertTrue(response.previous != None)
430
jcgregorio2d66d4f2006-02-07 05:34:14 +0000431 def testGet302NoLocation(self):
432 # Test that we throw an exception when we get
433 # a 302 with no Location: header.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400434 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000435 uri = urlparse.urljoin(base, "302/no-location.asis")
436 try:
jcgregorio36140b52006-06-13 02:17:52 +0000437 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000438 self.fail("Should never reach here")
439 except httplib2.RedirectMissingLocation:
440 pass
441 except Exception, e:
442 self.fail("Threw wrong kind of exception ")
443
jcgregorio07a9a4a2007-03-08 21:18:39 +0000444 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400445 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000446
447 (response, content) = self.http.request(uri, "GET")
448 self.assertEqual(response.status, 500)
449 self.assertTrue(response.reason.startswith("Redirected but"))
450 self.assertEqual("302", response['status'])
451 self.assertTrue(content.startswith("This is content"))
Joe Gregorio84e33252011-05-03 09:09:13 -0400452
Joe Gregorioac335ff2011-11-14 12:29:03 -0500453 def testGet301ViaHttps(self):
454 # Google always redirects to https://www.google.com
455 (response, content) = self.http.request("https://code.google.com/apis/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000456 self.assertEqual(200, response.status)
Joe Gregorioac335ff2011-11-14 12:29:03 -0500457 self.assertEqual(301, response.previous.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000458
459 def testGetViaHttps(self):
460 # Test that we can handle HTTPS
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400461 (response, content) = self.http.request("https://www.google.com/adsense/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000462 self.assertEqual(200, response.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000463
464 def testGetViaHttpsSpecViolationOnLocation(self):
465 # Test that we follow redirects through HTTPS
466 # even if they violate the spec by including
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400467 # a relative Location: header instead of an
jcgregorio2d66d4f2006-02-07 05:34:14 +0000468 # absolute one.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400469 (response, content) = self.http.request("https://www.google.com/adsense", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000470 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000471 self.assertNotEqual(None, response.previous)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000472
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400473 def testSslCertValidation(self):
474 if sys.version_info >= (2, 6):
475 # Test that we get an ssl.SSLError when specifying a non-existent CA
476 # certs file.
477 http = httplib2.Http(ca_certs='/nosuchfile')
478 self.assertRaises(ssl.SSLError,
479 http.request, "https://www.google.com/", "GET")
480
481 # Test that we get a SSLHandshakeError if we try to access
482 # https;//www.google.com, using a CA cert file that doesn't contain
483 # the CA Gogole uses (i.e., simulating a cert that's not signed by a
484 # trusted CA).
485 other_ca_certs = os.path.join(
486 os.path.dirname(os.path.abspath(httplib2.__file__ )),
487 "test", "other_cacerts.txt")
488 http = httplib2.Http(ca_certs=other_ca_certs)
489 self.assertRaises(httplib2.SSLHandshakeError,
490 http.request, "https://www.google.com/", "GET")
491
Joe Gregorioc69dc782011-06-23 08:56:59 -0400492 def testSslCertValidationDoubleDots(self):
493 if sys.version_info >= (2, 6):
494 # Test that we get match a double dot cert
495 try:
496 self.http.request("https://1.www.appspot.com/", "GET")
497 except httplib2.CertificateHostnameMismatch:
498 self.fail('cert with *.*.appspot.com should not raise an exception.')
499
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400500 def testSslHostnameValidation(self):
Joe Gregorio3e563132012-03-02 10:52:45 -0500501 pass
502 # No longer a valid test.
503 #if sys.version_info >= (2, 6):
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400504 # The SSL server at google.com:443 returns a certificate for
505 # 'www.google.com', which results in a host name mismatch.
506 # Note that this test only works because the ssl module and httplib2
507 # do not support SNI; for requests specifying a server name of
508 # 'google.com' via SNI, a matching cert would be returned.
Joe Gregorio3e563132012-03-02 10:52:45 -0500509 # self.assertRaises(httplib2.CertificateHostnameMismatch,
510 # self.http.request, "https://google.com/", "GET")
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400511
512 def testSslCertValidationWithoutSslModuleFails(self):
513 if sys.version_info < (2, 6):
514 http = httplib2.Http(disable_ssl_certificate_validation=False)
515 self.assertRaises(httplib2.CertificateValidationUnsupported,
516 http.request, "https://www.google.com/", "GET")
jcgregoriode8238d2007-03-07 19:08:26 +0000517
518 def testGetViaHttpsKeyCert(self):
jcgregorio2f1e1422007-05-03 13:17:33 +0000519 # At this point I can only test
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400520 # that the key and cert files are passed in
521 # correctly to httplib. It would be nice to have
jcgregorio2f1e1422007-05-03 13:17:33 +0000522 # a real https endpoint to test against.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400523
524 # bitworking.org presents an certificate for a non-matching host
525 # (*.webfaction.com), so we need to disable cert checking for this test.
526 http = httplib2.Http(timeout=2, disable_ssl_certificate_validation=True)
jcgregoriode8238d2007-03-07 19:08:26 +0000527
528 http.add_certificate("akeyfile", "acertfile", "bitworking.org")
529 try:
530 (response, content) = http.request("https://bitworking.org", "GET")
531 except:
532 pass
533 self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
534 self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
535
jcgregorio2f1e1422007-05-03 13:17:33 +0000536 try:
537 (response, content) = http.request("https://notthere.bitworking.org", "GET")
538 except:
539 pass
540 self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
541 self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
542
543
544
jcgregoriode8238d2007-03-07 19:08:26 +0000545
jcgregorio2d66d4f2006-02-07 05:34:14 +0000546 def testGet303(self):
547 # Do a follow-up GET on a Location: header
548 # returned from a POST that gave a 303.
549 uri = urlparse.urljoin(base, "303/303.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000550 (response, content) = self.http.request(uri, "POST", " ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000551 self.assertEqual(response.status, 200)
552 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000553 self.assertEqual(response.previous.status, 303)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000554
jcgregorio2f1e1422007-05-03 13:17:33 +0000555 def testGet303NoRedirect(self):
556 # Do a follow-up GET on a Location: header
557 # returned from a POST that gave a 303.
558 self.http.follow_redirects = False
559 uri = urlparse.urljoin(base, "303/303.cgi")
560 (response, content) = self.http.request(uri, "POST", " ")
561 self.assertEqual(response.status, 303)
562
jcgregorio2d66d4f2006-02-07 05:34:14 +0000563 def test303ForDifferentMethods(self):
564 # Test that all methods can be used
565 uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400566 for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
jcgregorio36140b52006-06-13 02:17:52 +0000567 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000568 self.assertEqual(response['x-method'], method_on_303)
569
Joe Gregoriob30ed372012-07-23 14:45:17 -0400570 def test303AndForwardAuthorizationHeader(self):
571 # Test that all methods can be used
572 uri = urlparse.urljoin(base, "303/redirect-to-header-reflector.cgi")
573 headers = {'authorization': 'Bearer foo'}
574 response, content = self.http.request(uri, 'GET', body=" ",
575 headers=headers)
576 # self.assertTrue('authorization' not in content)
577 self.http.follow_all_redirects = True
578 self.http.forward_authorization_headers = True
579 response, content = self.http.request(uri, 'GET', body=" ",
580 headers=headers)
581 # Oh, how I wish Apache didn't eat the Authorization header.
582 # self.assertTrue('authorization' in content)
583
jcgregorio2d66d4f2006-02-07 05:34:14 +0000584 def testGet304(self):
585 # Test that we use ETags properly to validate our cache
586 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000587 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000588 self.assertNotEqual(response['etag'], "")
589
jcgregorio36140b52006-06-13 02:17:52 +0000590 (response, content) = self.http.request(uri, "GET")
591 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000592 self.assertEqual(response.status, 200)
593 self.assertEqual(response.fromcache, True)
594
jcgregorio90fb4a42006-11-17 16:19:47 +0000595 cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
596 f = open(cache_file_name, "r")
597 status_line = f.readline()
598 f.close()
599
600 self.assertTrue(status_line.startswith("status:"))
601
jcgregorio36140b52006-06-13 02:17:52 +0000602 (response, content) = self.http.request(uri, "HEAD")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000603 self.assertEqual(response.status, 200)
604 self.assertEqual(response.fromcache, True)
605
jcgregorio36140b52006-06-13 02:17:52 +0000606 (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000607 self.assertEqual(response.status, 206)
608 self.assertEqual(response.fromcache, False)
609
jcgregorio25185622006-10-28 05:12:34 +0000610 def testGetIgnoreEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400611 # Test that we can forcibly ignore ETags
jcgregorio25185622006-10-28 05:12:34 +0000612 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
613 (response, content) = self.http.request(uri, "GET")
614 self.assertNotEqual(response['etag'], "")
615
616 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
617 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400618 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000619
620 self.http.ignore_etag = True
621 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
622 d = self.reflector(content)
623 self.assertEqual(response.fromcache, False)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400624 self.assertFalse(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000625
jcgregorio4b145e82007-01-18 19:46:34 +0000626 def testOverrideEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400627 # Test that we can forcibly ignore ETags
jcgregorio4b145e82007-01-18 19:46:34 +0000628 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
629 (response, content) = self.http.request(uri, "GET")
630 self.assertNotEqual(response['etag'], "")
631
632 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
633 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400634 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
635 self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio4b145e82007-01-18 19:46:34 +0000636
pilgrim00a352e2009-05-29 04:04:44 +0000637 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0', 'if-none-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +0000638 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400639 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
640 self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio25185622006-10-28 05:12:34 +0000641
pilgrim00a352e2009-05-29 04:04:44 +0000642#MAP-commented this out because it consistently fails
643# def testGet304EndToEnd(self):
644# # Test that end to end headers get overwritten in the cache
645# uri = urlparse.urljoin(base, "304/end2end.cgi")
646# (response, content) = self.http.request(uri, "GET")
647# self.assertNotEqual(response['etag'], "")
648# old_date = response['date']
649# time.sleep(2)
650#
651# (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
652# # The response should be from the cache, but the Date: header should be updated.
653# new_date = response['date']
654# self.assertNotEqual(new_date, old_date)
655# self.assertEqual(response.status, 200)
656# self.assertEqual(response.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000657
658 def testGet304LastModified(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400659 # Test that we can still handle a 304
jcgregorio2d66d4f2006-02-07 05:34:14 +0000660 # by only using the last-modified cache validator.
661 uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000662 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000663
664 self.assertNotEqual(response['last-modified'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000665 (response, content) = self.http.request(uri, "GET")
666 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000667 self.assertEqual(response.status, 200)
668 self.assertEqual(response.fromcache, True)
669
670 def testGet307(self):
671 # Test that we do follow 307 redirects but
672 # do not cache the 307
673 uri = urlparse.urljoin(base, "307/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000674 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000675 self.assertEqual(response.status, 200)
676 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000677 self.assertEqual(response.previous.status, 307)
678 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000679
jcgregorio36140b52006-06-13 02:17:52 +0000680 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000681 self.assertEqual(response.status, 200)
682 self.assertEqual(response.fromcache, True)
683 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000684 self.assertEqual(response.previous.status, 307)
685 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000686
687 def testGet410(self):
688 # Test that we pass 410's through
689 uri = urlparse.urljoin(base, "410/410.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000690 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000691 self.assertEqual(response.status, 410)
692
chris dent89f15142009-12-24 14:02:57 -0600693 def testVaryHeaderSimple(self):
694 """
695 RFC 2616 13.6
696 When the cache receives a subsequent request whose Request-URI
697 specifies one or more cache entries including a Vary header field,
698 the cache MUST NOT use such a cache entry to construct a response
699 to the new request unless all of the selecting request-headers
700 present in the new request match the corresponding stored
701 request-headers in the original request.
702 """
703 # test that the vary header is sent
704 uri = urlparse.urljoin(base, "vary/accept.asis")
705 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
706 self.assertEqual(response.status, 200)
707 self.assertTrue(response.has_key('vary'))
708
709 # get the resource again, from the cache since accept header in this
710 # request is the same as the request
711 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
712 self.assertEqual(response.status, 200)
713 self.assertEqual(response.fromcache, True, msg="Should be from cache")
714
715 # get the resource again, not from cache since Accept headers does not match
716 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
717 self.assertEqual(response.status, 200)
718 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
719
720 # get the resource again, without any Accept header, so again no match
721 (response, content) = self.http.request(uri, "GET")
722 self.assertEqual(response.status, 200)
723 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
724
725 def testNoVary(self):
Joe Gregorio46546a62012-10-03 14:31:10 -0400726 pass
chris dent89f15142009-12-24 14:02:57 -0600727 # when there is no vary, a different Accept header (e.g.) should not
728 # impact if the cache is used
729 # test that the vary header is not sent
Joe Gregorio46546a62012-10-03 14:31:10 -0400730 # uri = urlparse.urljoin(base, "vary/no-vary.asis")
731 # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
732 # self.assertEqual(response.status, 200)
733 # self.assertFalse(response.has_key('vary'))
chris dent89f15142009-12-24 14:02:57 -0600734
Joe Gregorio46546a62012-10-03 14:31:10 -0400735 # (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 # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
740 # self.assertEqual(response.status, 200)
741 # self.assertEqual(response.fromcache, True, msg="Should be from cache")
chris dent89f15142009-12-24 14:02:57 -0600742
743 def testVaryHeaderDouble(self):
744 uri = urlparse.urljoin(base, "vary/accept-double.asis")
745 (response, content) = self.http.request(uri, "GET", headers={
746 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
747 self.assertEqual(response.status, 200)
748 self.assertTrue(response.has_key('vary'))
749
750 # we are from cache
751 (response, content) = self.http.request(uri, "GET", headers={
752 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
753 self.assertEqual(response.fromcache, True, msg="Should be from cache")
754
755 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
756 self.assertEqual(response.status, 200)
757 self.assertEqual(response.fromcache, False)
758
759 # get the resource again, not from cache, varied headers don't match exact
760 (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})
761 self.assertEqual(response.status, 200)
762 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
763
jcgregorio88ef89b2010-05-13 23:42:11 -0400764 def testVaryUnusedHeader(self):
765 # A header's value is not considered to vary if it's not used at all.
766 uri = urlparse.urljoin(base, "vary/unused-header.asis")
767 (response, content) = self.http.request(uri, "GET", headers={
768 'Accept': 'text/plain'})
769 self.assertEqual(response.status, 200)
770 self.assertTrue(response.has_key('vary'))
771
772 # we are from cache
773 (response, content) = self.http.request(uri, "GET", headers={
774 'Accept': 'text/plain',})
775 self.assertEqual(response.fromcache, True, msg="Should be from cache")
776
chris dent89f15142009-12-24 14:02:57 -0600777
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000778 def testHeadGZip(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400779 # Test that we don't try to decompress a HEAD response
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000780 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
781 (response, content) = self.http.request(uri, "HEAD")
782 self.assertEqual(response.status, 200)
783 self.assertNotEqual(int(response['content-length']), 0)
784 self.assertEqual(content, "")
785
jcgregorio2d66d4f2006-02-07 05:34:14 +0000786 def testGetGZip(self):
787 # Test that we support gzip compression
788 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000789 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000790 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000791 self.assertFalse(response.has_key('content-encoding'))
joe.gregorio8b6d2312007-12-16 05:42:07 +0000792 self.assertTrue(response.has_key('-content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000793 self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000794 self.assertEqual(content, "This is the final destination.\n")
795
Joe Gregoriod1137c52011-02-13 19:27:35 -0500796 def testPostAndGZipResponse(self):
797 uri = urlparse.urljoin(base, "gzip/post.cgi")
798 (response, content) = self.http.request(uri, "POST", body=" ")
799 self.assertEqual(response.status, 200)
800 self.assertFalse(response.has_key('content-encoding'))
801 self.assertTrue(response.has_key('-content-encoding'))
802
jcgregorio2d66d4f2006-02-07 05:34:14 +0000803 def testGetGZipFailure(self):
804 # Test that we raise a good exception when the gzip fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400805 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000806 uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
807 try:
jcgregorio36140b52006-06-13 02:17:52 +0000808 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000809 self.fail("Should never reach here")
810 except httplib2.FailedToDecompressContent:
811 pass
812 except Exception:
813 self.fail("Threw wrong kind of exception")
814
jcgregorio07a9a4a2007-03-08 21:18:39 +0000815 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400816 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000817
818 (response, content) = self.http.request(uri, "GET")
819 self.assertEqual(response.status, 500)
820 self.assertTrue(response.reason.startswith("Content purported"))
821
822 def testTimeout(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400823 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000824 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
825 try:
826 import socket
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400827 socket.setdefaulttimeout(1)
jcgregorio07a9a4a2007-03-08 21:18:39 +0000828 except:
829 # Don't run the test if we can't set the timeout
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400830 return
jcgregorio07a9a4a2007-03-08 21:18:39 +0000831 (response, content) = self.http.request(uri)
832 self.assertEqual(response.status, 408)
833 self.assertTrue(response.reason.startswith("Request Timeout"))
834 self.assertTrue(content.startswith("Request Timeout"))
835
jcgregoriob2697912007-03-09 02:23:47 +0000836 def testIndividualTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000837 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
838 http = httplib2.Http(timeout=1)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400839 http.force_exception_to_status_code = True
jcgregoriob2697912007-03-09 02:23:47 +0000840
841 (response, content) = http.request(uri)
842 self.assertEqual(response.status, 408)
843 self.assertTrue(response.reason.startswith("Request Timeout"))
844 self.assertTrue(content.startswith("Request Timeout"))
845
jcgregorio07a9a4a2007-03-08 21:18:39 +0000846
Joe Gregorio1a7609f2009-07-16 10:59:44 -0400847 def testHTTPSInitTimeout(self):
848 c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
849 self.assertEqual(47, c.timeout)
850
jcgregorio2d66d4f2006-02-07 05:34:14 +0000851 def testGetDeflate(self):
852 # Test that we support deflate compression
853 uri = urlparse.urljoin(base, "deflate/deflated.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000854 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000855 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000856 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000857 self.assertEqual(int(response['content-length']), len("This is the final destination."))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000858 self.assertEqual(content, "This is the final destination.")
859
860 def testGetDeflateFailure(self):
861 # Test that we raise a good exception when the deflate fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400862 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000863
jcgregorio2d66d4f2006-02-07 05:34:14 +0000864 uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
865 try:
jcgregorio36140b52006-06-13 02:17:52 +0000866 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000867 self.fail("Should never reach here")
868 except httplib2.FailedToDecompressContent:
869 pass
870 except Exception:
871 self.fail("Threw wrong kind of exception")
872
jcgregorio07a9a4a2007-03-08 21:18:39 +0000873 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400874 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000875
876 (response, content) = self.http.request(uri, "GET")
877 self.assertEqual(response.status, 500)
878 self.assertTrue(response.reason.startswith("Content purported"))
879
jcgregorio2d66d4f2006-02-07 05:34:14 +0000880 def testGetDuplicateHeaders(self):
881 # Test that duplicate headers get concatenated via ','
882 uri = urlparse.urljoin(base, "duplicate-headers/multilink.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000883 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000884 self.assertEqual(response.status, 200)
885 self.assertEqual(content, "This is content\n")
886 self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
887
888 def testGetCacheControlNoCache(self):
889 # Test Cache-Control: no-cache on requests
890 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000891 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000892 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000893 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000894 self.assertEqual(response.status, 200)
895 self.assertEqual(response.fromcache, True)
896
jcgregorio36140b52006-06-13 02:17:52 +0000897 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000898 self.assertEqual(response.status, 200)
899 self.assertEqual(response.fromcache, False)
900
901 def testGetCacheControlPragmaNoCache(self):
902 # Test Pragma: no-cache on requests
903 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000904 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000905 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000906 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000907 self.assertEqual(response.status, 200)
908 self.assertEqual(response.fromcache, True)
909
jcgregorio36140b52006-06-13 02:17:52 +0000910 (response, content) = self.http.request(uri, "GET", headers={'Pragma': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000911 self.assertEqual(response.status, 200)
912 self.assertEqual(response.fromcache, False)
913
914 def testGetCacheControlNoStoreRequest(self):
915 # A no-store request means that the response should not be stored.
916 uri = urlparse.urljoin(base, "304/test_etag.txt")
917
jcgregorio36140b52006-06-13 02:17:52 +0000918 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000919 self.assertEqual(response.status, 200)
920 self.assertEqual(response.fromcache, False)
921
jcgregorio36140b52006-06-13 02:17:52 +0000922 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000923 self.assertEqual(response.status, 200)
924 self.assertEqual(response.fromcache, False)
925
926 def testGetCacheControlNoStoreResponse(self):
927 # A no-store response means that the response should not be stored.
928 uri = urlparse.urljoin(base, "no-store/no-store.asis")
929
jcgregorio36140b52006-06-13 02:17:52 +0000930 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000931 self.assertEqual(response.status, 200)
932 self.assertEqual(response.fromcache, False)
933
jcgregorio36140b52006-06-13 02:17:52 +0000934 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000935 self.assertEqual(response.status, 200)
936 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000937
938 def testGetCacheControlNoCacheNoStoreRequest(self):
939 # Test that a no-store, no-cache clears the entry from the cache
940 # even if it was cached previously.
941 uri = urlparse.urljoin(base, "304/test_etag.txt")
942
jcgregorio36140b52006-06-13 02:17:52 +0000943 (response, content) = self.http.request(uri, "GET")
944 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000945 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000946 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
947 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000948 self.assertEqual(response.status, 200)
949 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000950
951 def testUpdateInvalidatesCache(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400952 # Test that calling PUT or DELETE on a
jcgregorio2d66d4f2006-02-07 05:34:14 +0000953 # URI that is cache invalidates that cache.
954 uri = urlparse.urljoin(base, "304/test_etag.txt")
955
jcgregorio36140b52006-06-13 02:17:52 +0000956 (response, content) = self.http.request(uri, "GET")
957 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000958 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000959 (response, content) = self.http.request(uri, "DELETE")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000960 self.assertEqual(response.status, 405)
961
jcgregorio36140b52006-06-13 02:17:52 +0000962 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000963 self.assertEqual(response.fromcache, False)
964
965 def testUpdateUsesCachedETag(self):
Joe Gregoriobd682082011-05-24 14:06:09 -0400966 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio2d66d4f2006-02-07 05:34:14 +0000967 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
968
jcgregorio36140b52006-06-13 02:17:52 +0000969 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000970 self.assertEqual(response.status, 200)
971 self.assertEqual(response.fromcache, False)
jcgregorio36140b52006-06-13 02:17:52 +0000972 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000973 self.assertEqual(response.status, 200)
974 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -0400975 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000976 self.assertEqual(response.status, 200)
Joe Gregoriocd868102009-09-29 17:09:16 -0400977 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000978 self.assertEqual(response.status, 412)
979
Joe Gregoriobd682082011-05-24 14:06:09 -0400980 def testUpdatePatchUsesCachedETag(self):
981 # Test that we natively support http://www.w3.org/1999/04/Editing/
982 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
983
984 (response, content) = self.http.request(uri, "GET")
985 self.assertEqual(response.status, 200)
986 self.assertEqual(response.fromcache, False)
987 (response, content) = self.http.request(uri, "GET")
988 self.assertEqual(response.status, 200)
989 self.assertEqual(response.fromcache, True)
990 (response, content) = self.http.request(uri, "PATCH", body="foo")
991 self.assertEqual(response.status, 200)
992 (response, content) = self.http.request(uri, "PATCH", body="foo")
993 self.assertEqual(response.status, 412)
994
995
joe.gregorio700f04d2008-09-06 04:46:32 +0000996 def testUpdateUsesCachedETagAndOCMethod(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400997 # Test that we natively support http://www.w3.org/1999/04/Editing/
joe.gregorio700f04d2008-09-06 04:46:32 +0000998 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
999
1000 (response, content) = self.http.request(uri, "GET")
1001 self.assertEqual(response.status, 200)
1002 self.assertEqual(response.fromcache, False)
1003 (response, content) = self.http.request(uri, "GET")
1004 self.assertEqual(response.status, 200)
1005 self.assertEqual(response.fromcache, True)
1006 self.http.optimistic_concurrency_methods.append("DELETE")
1007 (response, content) = self.http.request(uri, "DELETE")
1008 self.assertEqual(response.status, 200)
1009
1010
jcgregorio4b145e82007-01-18 19:46:34 +00001011 def testUpdateUsesCachedETagOverridden(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001012 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio4b145e82007-01-18 19:46:34 +00001013 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
1014
1015 (response, content) = self.http.request(uri, "GET")
1016 self.assertEqual(response.status, 200)
1017 self.assertEqual(response.fromcache, False)
1018 (response, content) = self.http.request(uri, "GET")
1019 self.assertEqual(response.status, 200)
1020 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -04001021 (response, content) = self.http.request(uri, "PUT", body="foo", headers={'if-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +00001022 self.assertEqual(response.status, 412)
1023
jcgregorio2d66d4f2006-02-07 05:34:14 +00001024 def testBasicAuth(self):
1025 # Test Basic Authentication
1026 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001027 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001028 self.assertEqual(response.status, 401)
1029
1030 uri = urlparse.urljoin(base, "basic/")
jcgregorio36140b52006-06-13 02:17:52 +00001031 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001032 self.assertEqual(response.status, 401)
1033
jcgregorio36140b52006-06-13 02:17:52 +00001034 self.http.add_credentials('joe', 'password')
1035 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001036 self.assertEqual(response.status, 200)
1037
1038 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001039 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001040 self.assertEqual(response.status, 200)
1041
jcgregoriode8238d2007-03-07 19:08:26 +00001042 def testBasicAuthWithDomain(self):
1043 # Test Basic Authentication
1044 uri = urlparse.urljoin(base, "basic/file.txt")
1045 (response, content) = self.http.request(uri, "GET")
1046 self.assertEqual(response.status, 401)
1047
1048 uri = urlparse.urljoin(base, "basic/")
1049 (response, content) = self.http.request(uri, "GET")
1050 self.assertEqual(response.status, 401)
1051
1052 self.http.add_credentials('joe', 'password', "example.org")
1053 (response, content) = self.http.request(uri, "GET")
1054 self.assertEqual(response.status, 401)
1055
1056 uri = urlparse.urljoin(base, "basic/file.txt")
1057 (response, content) = self.http.request(uri, "GET")
1058 self.assertEqual(response.status, 401)
1059
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001060 domain = urlparse.urlparse(base)[1]
jcgregoriode8238d2007-03-07 19:08:26 +00001061 self.http.add_credentials('joe', 'password', domain)
1062 (response, content) = self.http.request(uri, "GET")
1063 self.assertEqual(response.status, 200)
1064
1065 uri = urlparse.urljoin(base, "basic/file.txt")
1066 (response, content) = self.http.request(uri, "GET")
1067 self.assertEqual(response.status, 200)
1068
1069
1070
1071
1072
1073
jcgregorio2d66d4f2006-02-07 05:34:14 +00001074 def testBasicAuthTwoDifferentCredentials(self):
jcgregorioadbb4f82006-05-19 15:17:42 +00001075 # Test Basic Authentication with multiple sets of credentials
jcgregorio2d66d4f2006-02-07 05:34:14 +00001076 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001077 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001078 self.assertEqual(response.status, 401)
1079
1080 uri = urlparse.urljoin(base, "basic2/")
jcgregorio36140b52006-06-13 02:17:52 +00001081 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001082 self.assertEqual(response.status, 401)
1083
jcgregorio36140b52006-06-13 02:17:52 +00001084 self.http.add_credentials('fred', 'barney')
1085 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001086 self.assertEqual(response.status, 200)
1087
1088 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001089 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001090 self.assertEqual(response.status, 200)
1091
1092 def testBasicAuthNested(self):
1093 # Test Basic Authentication with resources
1094 # that are nested
1095 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001096 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001097 self.assertEqual(response.status, 401)
1098
1099 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001100 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001101 self.assertEqual(response.status, 401)
1102
jcgregorioadbb4f82006-05-19 15:17:42 +00001103 # Now add in credentials one at a time and test.
jcgregorio36140b52006-06-13 02:17:52 +00001104 self.http.add_credentials('joe', 'password')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001105
1106 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001107 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001108 self.assertEqual(response.status, 200)
1109
1110 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001111 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001112 self.assertEqual(response.status, 401)
1113
jcgregorio36140b52006-06-13 02:17:52 +00001114 self.http.add_credentials('fred', 'barney')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001115
1116 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001117 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001118 self.assertEqual(response.status, 200)
1119
1120 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001121 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001122 self.assertEqual(response.status, 200)
1123
1124 def testDigestAuth(self):
1125 # Test that we support Digest Authentication
1126 uri = urlparse.urljoin(base, "digest/")
jcgregorio36140b52006-06-13 02:17:52 +00001127 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001128 self.assertEqual(response.status, 401)
1129
jcgregorio36140b52006-06-13 02:17:52 +00001130 self.http.add_credentials('joe', 'password')
1131 (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, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001135 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001136
1137 def testDigestAuthNextNonceAndNC(self):
1138 # Test that if the server sets nextnonce that we reset
1139 # the nonce count back to 1
1140 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001141 self.http.add_credentials('joe', 'password')
1142 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001143 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1144 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +00001145 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001146 info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
1147 self.assertEqual(response.status, 200)
1148
1149 if info.has_key('nextnonce'):
1150 self.assertEqual(info2['nc'], 1)
1151
1152 def testDigestAuthStale(self):
1153 # Test that we can handle a nonce becoming stale
1154 uri = urlparse.urljoin(base, "digest-expire/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001155 self.http.add_credentials('joe', 'password')
1156 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001157 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1158 self.assertEqual(response.status, 200)
1159
1160 time.sleep(3)
1161 # Sleep long enough that the nonce becomes stale
1162
jcgregorio36140b52006-06-13 02:17:52 +00001163 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001164 self.assertFalse(response.fromcache)
1165 self.assertTrue(response._stale_digest)
1166 info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
1167 self.assertEqual(response.status, 200)
1168
1169 def reflector(self, content):
jcgregorio25185622006-10-28 05:12:34 +00001170 return dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
jcgregorio2d66d4f2006-02-07 05:34:14 +00001171
1172 def testReflector(self):
1173 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +00001174 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001175 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001176 self.assertTrue(d.has_key('HTTP_USER_AGENT'))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001177
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001178 def testConnectionClose(self):
1179 uri = "http://www.google.com/"
1180 (response, content) = self.http.request(uri, "GET")
1181 for c in self.http.connections.values():
1182 self.assertNotEqual(None, c.sock)
1183 (response, content) = self.http.request(uri, "GET", headers={"connection": "close"})
1184 for c in self.http.connections.values():
1185 self.assertEqual(None, c.sock)
1186
Joe Gregorio46546a62012-10-03 14:31:10 -04001187 def testPickleHttp(self):
1188 pickled_http = pickle.dumps(self.http)
1189 new_http = pickle.loads(pickled_http)
1190
1191 self.assertEqual(sorted(new_http.__dict__.keys()),
1192 sorted(self.http.__dict__.keys()))
1193 for key in new_http.__dict__:
1194 if key in ('certificates', 'credentials'):
1195 self.assertEqual(new_http.__dict__[key].credentials,
1196 self.http.__dict__[key].credentials)
1197 elif key == 'cache':
1198 self.assertEqual(new_http.__dict__[key].cache,
1199 self.http.__dict__[key].cache)
1200 else:
1201 self.assertEqual(new_http.__dict__[key],
1202 self.http.__dict__[key])
1203
1204 def testPickleHttpWithConnection(self):
1205 self.http.request('http://bitworking.org',
1206 connection_type=_MyHTTPConnection)
1207 pickled_http = pickle.dumps(self.http)
1208 new_http = pickle.loads(pickled_http)
1209
1210 self.assertEqual(self.http.connections.keys(), ['http:bitworking.org'])
1211 self.assertEqual(new_http.connections, {})
1212
1213 def testPickleCustomRequestHttp(self):
1214 def dummy_request(*args, **kwargs):
1215 return new_request(*args, **kwargs)
1216 dummy_request.dummy_attr = 'dummy_value'
1217
1218 self.http.request = dummy_request
1219 pickled_http = pickle.dumps(self.http)
1220 self.assertFalse("S'request'" in pickled_http)
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001221
jcgregorio36140b52006-06-13 02:17:52 +00001222try:
1223 import memcache
1224 class HttpTestMemCached(HttpTest):
1225 def setUp(self):
1226 self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
jcgregorio47d24672006-06-29 05:18:59 +00001227 #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
jcgregorio36140b52006-06-13 02:17:52 +00001228 self.http = httplib2.Http(self.cache)
1229 self.cache.flush_all()
jcgregorio47d24672006-06-29 05:18:59 +00001230 # Not exactly sure why the sleep is needed here, but
1231 # if not present then some unit tests that rely on caching
1232 # fail. Memcached seems to lose some sets immediately
1233 # after a flush_all if the set is to a value that
1234 # was previously cached. (Maybe the flush is handled async?)
1235 time.sleep(1)
jcgregorio36140b52006-06-13 02:17:52 +00001236 self.http.clear_credentials()
1237except:
1238 pass
1239
1240
1241
chris dent89f15142009-12-24 14:02:57 -06001242
jcgregoriodb8dfc82006-03-31 14:59:46 +00001243# ------------------------------------------------------------------------
jcgregorio2d66d4f2006-02-07 05:34:14 +00001244
1245class HttpPrivateTest(unittest.TestCase):
1246
1247 def testParseCacheControl(self):
1248 # Test that we can parse the Cache-Control header
1249 self.assertEqual({}, httplib2._parse_cache_control({}))
1250 self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
1251 cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
1252 self.assertEqual(cc['no-cache'], 1)
1253 self.assertEqual(cc['max-age'], '7200')
1254 cc = httplib2._parse_cache_control({'cache-control': ' , '})
1255 self.assertEqual(cc[''], 1)
1256
Joe Gregorioe314e8b2009-07-16 20:11:28 -04001257 try:
1258 cc = httplib2._parse_cache_control({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'})
1259 self.assertTrue("max-age" in cc)
1260 except:
1261 self.fail("Should not throw exception")
1262
jcgregorio2d66d4f2006-02-07 05:34:14 +00001263 def testNormalizeHeaders(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001264 # Test that we normalize headers to lowercase
jcgregorio2d66d4f2006-02-07 05:34:14 +00001265 h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
1266 self.assertTrue(h.has_key('cache-control'))
1267 self.assertTrue(h.has_key('other'))
1268 self.assertEqual('Stuff', h['other'])
1269
1270 def testExpirationModelTransparent(self):
1271 # Test that no-cache makes our request TRANSPARENT
1272 response_headers = {
1273 'cache-control': 'max-age=7200'
1274 }
1275 request_headers = {
1276 'cache-control': 'no-cache'
1277 }
1278 self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
1279
jcgregorio45865012007-01-18 16:38:22 +00001280 def testMaxAgeNonNumeric(self):
1281 # Test that no-cache makes our request TRANSPARENT
1282 response_headers = {
1283 'cache-control': 'max-age=fred, min-fresh=barney'
1284 }
1285 request_headers = {
1286 }
1287 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1288
1289
jcgregorio2d66d4f2006-02-07 05:34:14 +00001290 def testExpirationModelNoCacheResponse(self):
1291 # The date and expires point to an entry that should be
1292 # FRESH, but the no-cache over-rides that.
1293 now = time.time()
1294 response_headers = {
1295 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1296 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1297 'cache-control': 'no-cache'
1298 }
1299 request_headers = {
1300 }
1301 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1302
1303 def testExpirationModelStaleRequestMustReval(self):
1304 # must-revalidate forces STALE
1305 self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
1306
1307 def testExpirationModelStaleResponseMustReval(self):
1308 # must-revalidate forces STALE
1309 self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
1310
1311 def testExpirationModelFresh(self):
1312 response_headers = {
1313 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1314 'cache-control': 'max-age=2'
1315 }
1316 request_headers = {
1317 }
1318 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1319 time.sleep(3)
1320 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1321
1322 def testExpirationMaxAge0(self):
1323 response_headers = {
1324 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1325 'cache-control': 'max-age=0'
1326 }
1327 request_headers = {
1328 }
1329 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1330
1331 def testExpirationModelDateAndExpires(self):
1332 now = time.time()
1333 response_headers = {
1334 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1335 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1336 }
1337 request_headers = {
1338 }
1339 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1340 time.sleep(3)
1341 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1342
jcgregoriof9511052007-06-01 14:56:34 +00001343 def testExpiresZero(self):
1344 now = time.time()
1345 response_headers = {
1346 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1347 'expires': "0",
1348 }
1349 request_headers = {
1350 }
1351 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1352
jcgregorio2d66d4f2006-02-07 05:34:14 +00001353 def testExpirationModelDateOnly(self):
1354 now = time.time()
1355 response_headers = {
1356 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
1357 }
1358 request_headers = {
1359 }
1360 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1361
1362 def testExpirationModelOnlyIfCached(self):
1363 response_headers = {
1364 }
1365 request_headers = {
1366 'cache-control': 'only-if-cached',
1367 }
1368 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1369
1370 def testExpirationModelMaxAgeBoth(self):
1371 now = time.time()
1372 response_headers = {
1373 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1374 'cache-control': 'max-age=2'
1375 }
1376 request_headers = {
1377 'cache-control': 'max-age=0'
1378 }
1379 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1380
1381 def testExpirationModelDateAndExpiresMinFresh1(self):
1382 now = time.time()
1383 response_headers = {
1384 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1385 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1386 }
1387 request_headers = {
1388 'cache-control': 'min-fresh=2'
1389 }
1390 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1391
1392 def testExpirationModelDateAndExpiresMinFresh2(self):
1393 now = time.time()
1394 response_headers = {
1395 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1396 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1397 }
1398 request_headers = {
1399 'cache-control': 'min-fresh=2'
1400 }
1401 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1402
1403 def testParseWWWAuthenticateEmpty(self):
1404 res = httplib2._parse_www_authenticate({})
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001405 self.assertEqual(len(res.keys()), 0)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001406
jcgregoriofd22e432006-04-27 02:00:08 +00001407 def testParseWWWAuthenticate(self):
1408 # different uses of spaces around commas
1409 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
1410 self.assertEqual(len(res.keys()), 1)
1411 self.assertEqual(len(res['test'].keys()), 5)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001412
jcgregoriofd22e432006-04-27 02:00:08 +00001413 # tokens with non-alphanum
1414 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
1415 self.assertEqual(len(res.keys()), 1)
1416 self.assertEqual(len(res['t*!%#st'].keys()), 2)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001417
jcgregoriofd22e432006-04-27 02:00:08 +00001418 # quoted string with quoted pairs
1419 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
1420 self.assertEqual(len(res.keys()), 1)
1421 self.assertEqual(res['test']['realm'], 'a "test" realm')
1422
1423 def testParseWWWAuthenticateStrict(self):
1424 httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
1425 self.testParseWWWAuthenticate();
1426 httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
1427
jcgregorio2d66d4f2006-02-07 05:34:14 +00001428 def testParseWWWAuthenticateBasic(self):
1429 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
1430 basic = res['basic']
1431 self.assertEqual('me', basic['realm'])
1432
1433 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
1434 basic = res['basic']
1435 self.assertEqual('me', basic['realm'])
1436 self.assertEqual('MD5', basic['algorithm'])
1437
1438 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
1439 basic = res['basic']
1440 self.assertEqual('me', basic['realm'])
1441 self.assertEqual('MD5', basic['algorithm'])
1442
1443 def testParseWWWAuthenticateBasic2(self):
1444 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
1445 basic = res['basic']
1446 self.assertEqual('me', basic['realm'])
1447 self.assertEqual('fred', basic['other'])
1448
1449 def testParseWWWAuthenticateBasic3(self):
1450 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
1451 basic = res['basic']
1452 self.assertEqual('me', basic['realm'])
1453
1454
1455 def testParseWWWAuthenticateDigest(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001456 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001457 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
1458 digest = res['digest']
1459 self.assertEqual('testrealm@host.com', digest['realm'])
1460 self.assertEqual('auth,auth-int', digest['qop'])
1461
1462
1463 def testParseWWWAuthenticateMultiple(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001464 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001465 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
1466 digest = res['digest']
1467 self.assertEqual('testrealm@host.com', digest['realm'])
1468 self.assertEqual('auth,auth-int', digest['qop'])
1469 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1470 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1471 basic = res['basic']
1472 self.assertEqual('me', basic['realm'])
1473
1474 def testParseWWWAuthenticateMultiple2(self):
1475 # Handle an added comma between challenges, which might get thrown in if the challenges were
1476 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001477 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001478 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
1479 digest = res['digest']
1480 self.assertEqual('testrealm@host.com', digest['realm'])
1481 self.assertEqual('auth,auth-int', digest['qop'])
1482 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1483 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1484 basic = res['basic']
1485 self.assertEqual('me', basic['realm'])
1486
1487 def testParseWWWAuthenticateMultiple3(self):
1488 # Handle an added comma between challenges, which might get thrown in if the challenges were
1489 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001490 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001491 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1492 digest = res['digest']
1493 self.assertEqual('testrealm@host.com', digest['realm'])
1494 self.assertEqual('auth,auth-int', digest['qop'])
1495 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1496 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1497 basic = res['basic']
1498 self.assertEqual('me', basic['realm'])
1499 wsse = res['wsse']
1500 self.assertEqual('foo', wsse['realm'])
1501 self.assertEqual('UsernameToken', wsse['profile'])
1502
1503 def testParseWWWAuthenticateMultiple4(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001504 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1505 '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 +00001506 digest = res['digest']
1507 self.assertEqual('test-real.m@host.com', digest['realm'])
1508 self.assertEqual('\tauth,auth-int', digest['qop'])
1509 self.assertEqual('(*)&^&$%#', digest['nonce'])
1510
1511 def testParseWWWAuthenticateMoreQuoteCombos(self):
1512 res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
1513 digest = res['digest']
1514 self.assertEqual('myrealm', digest['realm'])
1515
Joe Gregorio6fa3cf22011-02-13 22:45:06 -05001516 def testParseWWWAuthenticateMalformed(self):
1517 try:
1518 res = httplib2._parse_www_authenticate({'www-authenticate':'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'})
1519 self.fail("should raise an exception")
1520 except httplib2.MalformedHeader:
1521 pass
1522
jcgregorio2d66d4f2006-02-07 05:34:14 +00001523 def testDigestObject(self):
1524 credentials = ('joe', 'password')
1525 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001526 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001527 headers = {}
1528 response = {
1529 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
1530 }
1531 content = ""
Joe Gregorio875a8b52011-06-13 14:06:23 -04001532
jcgregorio6cbab7e2006-04-21 20:35:43 +00001533 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001534 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
Joe Gregorio875a8b52011-06-13 14:06:23 -04001535 our_request = "authorization: %s" % headers['authorization']
1536 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 +00001537 self.assertEqual(our_request, working_request)
1538
Joe Gregorio03d99102011-06-22 16:55:52 -04001539 def testDigestObjectWithOpaque(self):
1540 credentials = ('joe', 'password')
1541 host = None
1542 request_uri = '/projects/httplib2/test/digest/'
1543 headers = {}
1544 response = {
1545 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", opaque="atestopaque"'
1546 }
1547 content = ""
1548
1549 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
1550 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
1551 our_request = "authorization: %s" % headers['authorization']
1552 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"'
1553 self.assertEqual(our_request, working_request)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001554
1555 def testDigestObjectStale(self):
1556 credentials = ('joe', 'password')
1557 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001558 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001559 headers = {}
1560 response = httplib2.Response({ })
1561 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1562 response.status = 401
1563 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001564 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001565 # Returns true to force a retry
1566 self.assertTrue( d.response(response, content) )
1567
1568 def testDigestObjectAuthInfo(self):
1569 credentials = ('joe', 'password')
1570 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001571 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001572 headers = {}
1573 response = httplib2.Response({ })
1574 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1575 response['authentication-info'] = 'nextnonce="fred"'
1576 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001577 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001578 # Returns true to force a retry
1579 self.assertFalse( d.response(response, content) )
1580 self.assertEqual('fred', d.challenge['nonce'])
1581 self.assertEqual(1, d.challenge['nc'])
1582
1583 def testWsseAlgorithm(self):
1584 digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
1585 expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
1586 self.assertEqual(expected, digest)
1587
jcgregoriodb8dfc82006-03-31 14:59:46 +00001588 def testEnd2End(self):
1589 # one end to end header
1590 response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
1591 end2end = httplib2._get_end2end_headers(response)
1592 self.assertTrue('content-type' in end2end)
1593 self.assertTrue('te' not in end2end)
1594 self.assertTrue('connection' not in end2end)
1595
1596 # one end to end header that gets eliminated
1597 response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
1598 end2end = httplib2._get_end2end_headers(response)
1599 self.assertTrue('content-type' not in end2end)
1600 self.assertTrue('te' not in end2end)
1601 self.assertTrue('connection' not in end2end)
1602
1603 # Degenerate case of no headers
1604 response = {}
1605 end2end = httplib2._get_end2end_headers(response)
1606 self.assertEquals(0, len(end2end))
1607
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001608 # Degenerate case of connection referrring to a header not passed in
jcgregoriodb8dfc82006-03-31 14:59:46 +00001609 response = {'connection': 'content-type'}
1610 end2end = httplib2._get_end2end_headers(response)
1611 self.assertEquals(0, len(end2end))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001612
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001613
1614class TestProxyInfo(unittest.TestCase):
1615 def setUp(self):
1616 self.orig_env = dict(os.environ)
1617
1618 def tearDown(self):
1619 os.environ.clear()
1620 os.environ.update(self.orig_env)
1621
1622 def test_from_url(self):
Joe Gregorio46546a62012-10-03 14:31:10 -04001623 pi = httplib2.proxy_info_from_url('http://myproxy.example.com')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001624 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1625 self.assertEquals(pi.proxy_port, 80)
1626 self.assertEquals(pi.proxy_user, None)
1627
1628 def test_from_url_ident(self):
Joe Gregorio46546a62012-10-03 14:31:10 -04001629 pi = httplib2.proxy_info_from_url('http://zoidberg:fish@someproxy:99')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001630 self.assertEquals(pi.proxy_host, 'someproxy')
1631 self.assertEquals(pi.proxy_port, 99)
1632 self.assertEquals(pi.proxy_user, 'zoidberg')
1633 self.assertEquals(pi.proxy_pass, 'fish')
1634
1635 def test_from_env(self):
1636 os.environ['http_proxy'] = 'http://myproxy.example.com:8080'
Joe Gregorio46546a62012-10-03 14:31:10 -04001637 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001638 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1639 self.assertEquals(pi.proxy_port, 8080)
1640 self.assertEquals(pi.bypass_hosts, [])
1641
1642 def test_from_env_no_proxy(self):
1643 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1644 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
1645 os.environ['no_proxy'] = 'localhost,otherhost.domain.local'
Joe Gregorio46546a62012-10-03 14:31:10 -04001646 pi = httplib2.proxy_info_from_environment('https')
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001647 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1648 self.assertEquals(pi.proxy_port, 81)
1649 self.assertEquals(pi.bypass_hosts, ['localhost',
1650 'otherhost.domain.local'])
1651
1652 def test_from_env_none(self):
1653 os.environ.clear()
Joe Gregorio46546a62012-10-03 14:31:10 -04001654 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001655 self.assertEquals(pi, None)
1656
Jason R. Coombs43840892011-08-09 10:30:46 -04001657 def test_applies_to(self):
1658 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1659 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
Jason R. Coombs96279c52011-08-16 12:53:27 -04001660 os.environ['no_proxy'] = 'localhost,otherhost.domain.local,example.com'
Joe Gregorio46546a62012-10-03 14:31:10 -04001661 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs43840892011-08-09 10:30:46 -04001662 self.assertFalse(pi.applies_to('localhost'))
1663 self.assertTrue(pi.applies_to('www.google.com'))
Jason R. Coombs96279c52011-08-16 12:53:27 -04001664 self.assertFalse(pi.applies_to('www.example.com'))
1665
1666 def test_no_proxy_star(self):
1667 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1668 os.environ['NO_PROXY'] = '*'
Joe Gregorio46546a62012-10-03 14:31:10 -04001669 pi = httplib2.proxy_info_from_environment()
Jason R. Coombs96279c52011-08-16 12:53:27 -04001670 for host in ('localhost', '169.254.38.192', 'www.google.com'):
1671 self.assertFalse(pi.applies_to(host))
Jason R. Coombs43840892011-08-09 10:30:46 -04001672
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001673
chris dent89f15142009-12-24 14:02:57 -06001674if __name__ == '__main__':
1675 unittest.main()