blob: b2cbb020b9ad5e43fd8d5bdee8989b7723e0f84e [file] [log] [blame]
jcgregorio2d66d4f2006-02-07 05:34:14 +00001#!/usr/bin/env python2.4
2"""
3httplib2test
4
5A set of unit tests for httplib2.py.
6
7Requires Python 2.4 or later
8"""
9
10__author__ = "Joe Gregorio (joe@bitworking.org)"
11__copyright__ = "Copyright 2006, Joe Gregorio"
12__contributors__ = []
13__license__ = "MIT"
14__history__ = """ """
15__version__ = "0.1 ($Rev: 118 $)"
16
17
Joe Gregoriob6c90c42011-02-11 01:03:22 -050018import StringIO
19import base64
jcgregoriode8238d2007-03-07 19:08:26 +000020import httplib
21import httplib2
22import os
Joe Gregoriob6c90c42011-02-11 01:03:22 -050023import socket
24import sys
jcgregoriode8238d2007-03-07 19:08:26 +000025import time
Joe Gregoriob6c90c42011-02-11 01:03:22 -050026import unittest
27import urlparse
jcgregorio8421f272006-02-14 18:19:51 +000028
Joe Gregoriob53de9b2011-06-07 15:44:51 -040029try:
30 import ssl
31except ImportError:
32 pass
Joe Gregorio694a8122011-02-13 21:40:09 -050033
jcgregorio8421f272006-02-14 18:19:51 +000034# Python 2.3 support
35if not hasattr(unittest.TestCase, 'assertTrue'):
36 unittest.TestCase.assertTrue = unittest.TestCase.failUnless
37 unittest.TestCase.assertFalse = unittest.TestCase.failIf
38
jcgregorio2d66d4f2006-02-07 05:34:14 +000039# The test resources base uri
40base = 'http://bitworking.org/projects/httplib2/test/'
41#base = 'http://localhost/projects/httplib2/test/'
jcgregorio90fb4a42006-11-17 16:19:47 +000042cacheDirName = ".cache"
jcgregorio2d66d4f2006-02-07 05:34:14 +000043
jcgregoriode8238d2007-03-07 19:08:26 +000044
45class CredentialsTest(unittest.TestCase):
46 def test(self):
47 c = httplib2.Credentials()
48 c.add("joe", "password")
49 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
50 self.assertEqual(("joe", "password"), list(c.iter(""))[0])
51 c.add("fred", "password2", "wellformedweb.org")
52 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
53 self.assertEqual(1, len(list(c.iter("bitworking.org"))))
54 self.assertEqual(2, len(list(c.iter("wellformedweb.org"))))
55 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
56 c.clear()
57 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
58 c.add("fred", "password2", "wellformedweb.org")
59 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
60 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
61 self.assertEqual(0, len(list(c.iter(""))))
62
63
jcgregorio2d66d4f2006-02-07 05:34:14 +000064class ParserTest(unittest.TestCase):
65 def testFromStd66(self):
66 self.assertEqual( ('http', 'example.com', '', None, None ), httplib2.parse_uri("http://example.com"))
67 self.assertEqual( ('https', 'example.com', '', None, None ), httplib2.parse_uri("https://example.com"))
68 self.assertEqual( ('https', 'example.com:8080', '', None, None ), httplib2.parse_uri("https://example.com:8080"))
69 self.assertEqual( ('http', 'example.com', '/', None, None ), httplib2.parse_uri("http://example.com/"))
70 self.assertEqual( ('http', 'example.com', '/path', None, None ), httplib2.parse_uri("http://example.com/path"))
71 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', None ), httplib2.parse_uri("http://example.com/path?a=1&b=2"))
72 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
73 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
74
jcgregorio2d66d4f2006-02-07 05:34:14 +000075
jcgregorioa46fe4e2006-11-16 04:13:45 +000076class UrlNormTest(unittest.TestCase):
77 def test(self):
78 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://example.org")[-1])
79 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://EXAMple.org")[-1])
80 self.assertEqual( "http://example.org/?=b", httplib2.urlnorm("http://EXAMple.org?=b")[-1])
81 self.assertEqual( "http://example.org/mypath?a=b", httplib2.urlnorm("http://EXAMple.org/mypath?a=b")[-1])
82 self.assertEqual( "http://localhost:80/", httplib2.urlnorm("http://localhost:80")[-1])
jcgregoriob4e9ab02006-11-17 15:53:15 +000083 self.assertEqual( httplib2.urlnorm("http://localhost:80/"), httplib2.urlnorm("HTTP://LOCALHOST:80"))
jcgregorio132d28e2007-01-23 16:22:53 +000084 try:
85 httplib2.urlnorm("/")
86 self.fail("Non-absolute URIs should raise an exception")
87 except httplib2.RelativeURIError:
88 pass
jcgregorioa46fe4e2006-11-16 04:13:45 +000089
90class UrlSafenameTest(unittest.TestCase):
91 def test(self):
92 # Test that different URIs end up generating different safe names
93 self.assertEqual( "example.org,fred,a=b,58489f63a7a83c3b7794a6a398ee8b1f", httplib2.safename("http://example.org/fred/?a=b"))
94 self.assertEqual( "example.org,fred,a=b,8c5946d56fec453071f43329ff0be46b", httplib2.safename("http://example.org/fred?/a=b"))
95 self.assertEqual( "www.example.org,fred,a=b,499c44b8d844a011b67ea2c015116968", httplib2.safename("http://www.example.org/fred?/a=b"))
96 self.assertEqual( httplib2.safename(httplib2.urlnorm("http://www")[-1]), httplib2.safename(httplib2.urlnorm("http://WWW")[-1]))
97 self.assertEqual( "www.example.org,fred,a=b,692e843a333484ce0095b070497ab45d", httplib2.safename("https://www.example.org/fred?/a=b"))
98 self.assertNotEqual( httplib2.safename("http://www"), httplib2.safename("https://www"))
99 # Test the max length limits
100 uri = "http://" + ("w" * 200) + ".org"
101 uri2 = "http://" + ("w" * 201) + ".org"
102 self.assertNotEqual( httplib2.safename(uri2), httplib2.safename(uri))
103 # Max length should be 200 + 1 (",") + 32
104 self.assertEqual(233, len(httplib2.safename(uri2)))
105 self.assertEqual(233, len(httplib2.safename(uri)))
106 # Unicode
jcgregoriodebceec2006-12-12 20:26:02 +0000107 if sys.version_info >= (2,3):
108 self.assertEqual( "xn--http,-4y1d.org,fred,a=b,579924c35db315e5a32e3d9963388193", httplib2.safename(u"http://\u2304.org/fred/?a=b"))
jcgregorioa46fe4e2006-11-16 04:13:45 +0000109
jcgregorio14644372007-07-30 14:13:37 +0000110class _MyResponse(StringIO.StringIO):
111 def __init__(self, body, **kwargs):
112 StringIO.StringIO.__init__(self, body)
113 self.headers = kwargs
114
115 def iteritems(self):
116 return self.headers.iteritems()
117
118
119class _MyHTTPConnection(object):
120 "This class is just a mock of httplib.HTTPConnection used for testing"
121
122 def __init__(self, host, port=None, key_file=None, cert_file=None,
joe.gregoriof28536d2007-10-23 14:10:11 +0000123 strict=None, timeout=None, proxy_info=None):
jcgregorio14644372007-07-30 14:13:37 +0000124 self.host = host
125 self.port = port
126 self.timeout = timeout
127 self.log = ""
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400128 self.sock = None
jcgregorio14644372007-07-30 14:13:37 +0000129
130 def set_debuglevel(self, level):
131 pass
132
133 def connect(self):
134 "Connect to a host on a given port."
135 pass
136
137 def close(self):
138 pass
139
140 def request(self, method, request_uri, body, headers):
141 pass
142
143 def getresponse(self):
144 return _MyResponse("the body", status="200")
jcgregorioa46fe4e2006-11-16 04:13:45 +0000145
jcgregorio90fb4a42006-11-17 16:19:47 +0000146
jcgregorio2d66d4f2006-02-07 05:34:14 +0000147class HttpTest(unittest.TestCase):
148 def setUp(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400149 if os.path.exists(cacheDirName):
jcgregorio7e3608f2006-06-15 13:01:53 +0000150 [os.remove(os.path.join(cacheDirName, file)) for file in os.listdir(cacheDirName)]
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400151
152 if sys.version_info < (2, 6):
153 disable_cert_validation = True
154 else:
155 disable_cert_validation = False
156 self.http = httplib2.Http(
157 cacheDirName,
158 disable_ssl_certificate_validation=disable_cert_validation)
jcgregorio36140b52006-06-13 02:17:52 +0000159 self.http.clear_credentials()
jcgregorio2d66d4f2006-02-07 05:34:14 +0000160
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500161 def testIPv6NoSSL(self):
162 try:
163 self.http.request("http://[::1]/")
164 except socket.gaierror:
165 self.fail("should get the address family right for IPv6")
166 except socket.error:
167 # Even if IPv6 isn't installed on a machine it should just raise socket.error
168 pass
169
170 def testIPv6SSL(self):
171 try:
172 self.http.request("https://[::1]/")
173 except socket.gaierror:
174 self.fail("should get the address family right for IPv6")
Jason R. Coombscee15da2011-08-09 09:13:34 -0400175 except httplib2.CertificateHostnameMismatch:
176 # We connected and verified that the certificate doesn't match
177 # the name. Good enough.
178 pass
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500179 except socket.error:
180 # Even if IPv6 isn't installed on a machine it should just raise socket.error
181 pass
182
jcgregorio14644372007-07-30 14:13:37 +0000183 def testConnectionType(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400184 self.http.force_exception_to_status_code = False
jcgregorio14644372007-07-30 14:13:37 +0000185 response, content = self.http.request("http://bitworking.org", connection_type=_MyHTTPConnection)
186 self.assertEqual(response['content-location'], "http://bitworking.org")
187 self.assertEqual(content, "the body")
188
jcgregorio6a638172007-01-23 16:40:23 +0000189 def testGetUnknownServer(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400190 self.http.force_exception_to_status_code = False
jcgregorio6a638172007-01-23 16:40:23 +0000191 try:
192 self.http.request("http://fred.bitworking.org/")
193 self.fail("An httplib2.ServerNotFoundError Exception must be thrown on an unresolvable server.")
194 except httplib2.ServerNotFoundError:
195 pass
196
jcgregorio07a9a4a2007-03-08 21:18:39 +0000197 # Now test with exceptions turned off
198 self.http.force_exception_to_status_code = True
199
200 (response, content) = self.http.request("http://fred.bitworking.org/")
201 self.assertEqual(response['content-type'], 'text/plain')
202 self.assertTrue(content.startswith("Unable to find"))
203 self.assertEqual(response.status, 400)
204
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500205 def testGetConnectionRefused(self):
206 self.http.force_exception_to_status_code = False
207 try:
208 self.http.request("http://localhost:7777/")
209 self.fail("An socket.error exception must be thrown on Connection Refused.")
210 except socket.error:
211 pass
212
213 # Now test with exceptions turned off
214 self.http.force_exception_to_status_code = True
215
216 (response, content) = self.http.request("http://localhost:7777/")
217 self.assertEqual(response['content-type'], 'text/plain')
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400218 self.assertTrue("Connection refused" in content
219 or "actively refused" in content,
220 "Unexpected status %(content)s" % vars())
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500221 self.assertEqual(response.status, 400)
222
jcgregorioa898f8f2006-12-12 17:16:55 +0000223 def testGetIRI(self):
jcgregoriodebceec2006-12-12 20:26:02 +0000224 if sys.version_info >= (2,3):
225 uri = urlparse.urljoin(base, u"reflector/reflector.cgi?d=\N{CYRILLIC CAPITAL LETTER DJE}")
226 (response, content) = self.http.request(uri, "GET")
227 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400228 self.assertTrue(d.has_key('QUERY_STRING'))
229 self.assertTrue(d['QUERY_STRING'].find('%D0%82') > 0)
230
jcgregorio2d66d4f2006-02-07 05:34:14 +0000231 def testGetIsDefaultMethod(self):
232 # Test that GET is the default method
233 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000234 (response, content) = self.http.request(uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000235 self.assertEqual(response['x-method'], "GET")
236
237 def testDifferentMethods(self):
238 # Test that all methods can be used
239 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
240 for method in ["GET", "PUT", "DELETE", "POST"]:
jcgregorio36140b52006-06-13 02:17:52 +0000241 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000242 self.assertEqual(response['x-method'], method)
243
Joe Gregoriob628c0b2009-07-16 12:28:04 -0400244 def testHeadRead(self):
245 # Test that we don't try to read the response of a HEAD request
246 # since httplib blocks response.read() for HEAD requests.
247 # Oddly enough this doesn't appear as a problem when doing HEAD requests
248 # against Apache servers.
249 uri = "http://www.google.com/"
250 (response, content) = self.http.request(uri, "HEAD")
251 self.assertEqual(response.status, 200)
252 self.assertEqual(content, "")
253
jcgregorio2d66d4f2006-02-07 05:34:14 +0000254 def testGetNoCache(self):
255 # Test that can do a GET w/o the cache turned on.
256 http = httplib2.Http()
257 uri = urlparse.urljoin(base, "304/test_etag.txt")
258 (response, content) = http.request(uri, "GET")
259 self.assertEqual(response.status, 200)
jcgregorioa0713ab2006-07-01 05:21:34 +0000260 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000261
Joe Gregorioe202d212009-07-16 14:57:52 -0400262 def testGetOnlyIfCachedCacheHit(self):
263 # Test that can do a GET with cache and 'only-if-cached'
264 uri = urlparse.urljoin(base, "304/test_etag.txt")
265 (response, content) = self.http.request(uri, "GET")
266 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
267 self.assertEqual(response.fromcache, True)
268 self.assertEqual(response.status, 200)
269
jcgregorioe4ce13e2006-04-02 03:05:08 +0000270 def testGetOnlyIfCachedCacheMiss(self):
271 # Test that can do a GET with no cache with 'only-if-cached'
jcgregorioe4ce13e2006-04-02 03:05:08 +0000272 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorioe202d212009-07-16 14:57:52 -0400273 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
jcgregorioe4ce13e2006-04-02 03:05:08 +0000274 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400275 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000276
277 def testGetOnlyIfCachedNoCacheAtAll(self):
278 # Test that can do a GET with no cache with 'only-if-cached'
279 # Of course, there might be an intermediary beyond us
280 # that responds to the 'only-if-cached', so this
281 # test can't really be guaranteed to pass.
282 http = httplib2.Http()
283 uri = urlparse.urljoin(base, "304/test_etag.txt")
284 (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
285 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400286 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000287
jcgregorio2d66d4f2006-02-07 05:34:14 +0000288 def testUserAgent(self):
289 # Test that we provide a default user-agent
290 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000291 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000292 self.assertEqual(response.status, 200)
293 self.assertTrue(content.startswith("Python-httplib2/"))
294
295 def testUserAgentNonDefault(self):
296 # Test that the default user-agent can be over-ridden
joe.gregoriof28536d2007-10-23 14:10:11 +0000297
jcgregorio2d66d4f2006-02-07 05:34:14 +0000298 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000299 (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000300 self.assertEqual(response.status, 200)
301 self.assertTrue(content.startswith("fred/1.0"))
302
303 def testGet300WithLocation(self):
304 # Test the we automatically follow 300 redirects if a Location: header is provided
305 uri = urlparse.urljoin(base, "300/with-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000306 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000307 self.assertEqual(response.status, 200)
308 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000309 self.assertEqual(response.previous.status, 300)
310 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000311
312 # Confirm that the intermediate 300 is not cached
jcgregorio36140b52006-06-13 02:17:52 +0000313 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000314 self.assertEqual(response.status, 200)
315 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000316 self.assertEqual(response.previous.status, 300)
317 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000318
jcgregorio2f1e1422007-05-03 13:17:33 +0000319 def testGet300WithLocationNoRedirect(self):
320 # Test the we automatically follow 300 redirects if a Location: header is provided
321 self.http.follow_redirects = False
322 uri = urlparse.urljoin(base, "300/with-location-header.asis")
323 (response, content) = self.http.request(uri, "GET")
324 self.assertEqual(response.status, 300)
325
jcgregorio2d66d4f2006-02-07 05:34:14 +0000326 def testGet300WithoutLocation(self):
327 # Not giving a Location: header in a 300 response is acceptable
328 # In which case we just return the 300 response
329 uri = urlparse.urljoin(base, "300/without-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000330 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000331 self.assertEqual(response.status, 300)
332 self.assertTrue(response['content-type'].startswith("text/html"))
jcgregorioa0713ab2006-07-01 05:21:34 +0000333 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000334
335 def testGet301(self):
336 # Test that we automatically follow 301 redirects
337 # and that we cache the 301 response
338 uri = urlparse.urljoin(base, "301/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000339 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000340 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000341 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000342 self.assertTrue(response.has_key('content-location'))
343 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000344 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000345 self.assertEqual(response.previous.status, 301)
346 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000347
jcgregorio36140b52006-06-13 02:17:52 +0000348 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000349 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000350 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000351 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000352 self.assertEqual(response.previous.status, 301)
353 self.assertEqual(response.previous.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000354
Joe Gregorio694a8122011-02-13 21:40:09 -0500355 def testHead301(self):
356 # Test that we automatically follow 301 redirects
357 uri = urlparse.urljoin(base, "301/onestep.asis")
358 destination = urlparse.urljoin(base, "302/final-destination.txt")
359 (response, content) = self.http.request(uri, "HEAD")
360 self.assertEqual(response.status, 200)
361 self.assertEqual(response.previous.status, 301)
362 self.assertEqual(response.previous.fromcache, False)
jcgregorio2f1e1422007-05-03 13:17:33 +0000363
364 def testGet301NoRedirect(self):
365 # Test that we automatically follow 301 redirects
366 # and that we cache the 301 response
367 self.http.follow_redirects = False
368 uri = urlparse.urljoin(base, "301/onestep.asis")
369 destination = urlparse.urljoin(base, "302/final-destination.txt")
370 (response, content) = self.http.request(uri, "GET")
371 self.assertEqual(response.status, 301)
372
373
jcgregorio2d66d4f2006-02-07 05:34:14 +0000374 def testGet302(self):
375 # Test that we automatically follow 302 redirects
376 # and that we DO NOT cache the 302 response
377 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000378 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000379 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000380 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000381 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000382 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000383 self.assertEqual(response.previous.status, 302)
384 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000385
386 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000387 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000388 self.assertEqual(response.status, 200)
389 self.assertEqual(response.fromcache, True)
jcgregorio772adc82006-11-17 21:52:34 +0000390 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000391 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000392 self.assertEqual(response.previous.status, 302)
393 self.assertEqual(response.previous.fromcache, False)
jcgregorio772adc82006-11-17 21:52:34 +0000394 self.assertEqual(response.previous['content-location'], uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000395
396 uri = urlparse.urljoin(base, "302/twostep.asis")
397
jcgregorio36140b52006-06-13 02:17:52 +0000398 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000399 self.assertEqual(response.status, 200)
400 self.assertEqual(response.fromcache, True)
401 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000402 self.assertEqual(response.previous.status, 302)
403 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000404
405 def testGet302RedirectionLimit(self):
406 # Test that we can set a lower redirection limit
407 # and that we raise an exception when we exceed
408 # that limit.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400409 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000410
jcgregorio2d66d4f2006-02-07 05:34:14 +0000411 uri = urlparse.urljoin(base, "302/twostep.asis")
412 try:
jcgregorio36140b52006-06-13 02:17:52 +0000413 (response, content) = self.http.request(uri, "GET", redirections = 1)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000414 self.fail("This should not happen")
415 except httplib2.RedirectLimit:
416 pass
417 except Exception, e:
418 self.fail("Threw wrong kind of exception ")
419
jcgregorio07a9a4a2007-03-08 21:18:39 +0000420 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400421 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000422
423 (response, content) = self.http.request(uri, "GET", redirections = 1)
424 self.assertEqual(response.status, 500)
425 self.assertTrue(response.reason.startswith("Redirected more"))
426 self.assertEqual("302", response['status'])
427 self.assertTrue(content.startswith("<html>"))
428 self.assertTrue(response.previous != None)
429
jcgregorio2d66d4f2006-02-07 05:34:14 +0000430 def testGet302NoLocation(self):
431 # Test that we throw an exception when we get
432 # a 302 with no Location: header.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400433 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000434 uri = urlparse.urljoin(base, "302/no-location.asis")
435 try:
jcgregorio36140b52006-06-13 02:17:52 +0000436 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000437 self.fail("Should never reach here")
438 except httplib2.RedirectMissingLocation:
439 pass
440 except Exception, e:
441 self.fail("Threw wrong kind of exception ")
442
jcgregorio07a9a4a2007-03-08 21:18:39 +0000443 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400444 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000445
446 (response, content) = self.http.request(uri, "GET")
447 self.assertEqual(response.status, 500)
448 self.assertTrue(response.reason.startswith("Redirected but"))
449 self.assertEqual("302", response['status'])
450 self.assertTrue(content.startswith("This is content"))
Joe Gregorio84e33252011-05-03 09:09:13 -0400451
Joe Gregorioac335ff2011-11-14 12:29:03 -0500452 def testGet301ViaHttps(self):
453 # Google always redirects to https://www.google.com
454 (response, content) = self.http.request("https://code.google.com/apis/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000455 self.assertEqual(200, response.status)
Joe Gregorioac335ff2011-11-14 12:29:03 -0500456 self.assertEqual(301, response.previous.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000457
458 def testGetViaHttps(self):
459 # Test that we can handle HTTPS
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400460 (response, content) = self.http.request("https://www.google.com/adsense/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000461 self.assertEqual(200, response.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000462
463 def testGetViaHttpsSpecViolationOnLocation(self):
464 # Test that we follow redirects through HTTPS
465 # even if they violate the spec by including
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400466 # a relative Location: header instead of an
jcgregorio2d66d4f2006-02-07 05:34:14 +0000467 # absolute one.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400468 (response, content) = self.http.request("https://www.google.com/adsense", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000469 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000470 self.assertNotEqual(None, response.previous)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000471
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400472 def testSslCertValidation(self):
473 if sys.version_info >= (2, 6):
474 # Test that we get an ssl.SSLError when specifying a non-existent CA
475 # certs file.
476 http = httplib2.Http(ca_certs='/nosuchfile')
477 self.assertRaises(ssl.SSLError,
478 http.request, "https://www.google.com/", "GET")
479
480 # Test that we get a SSLHandshakeError if we try to access
481 # https;//www.google.com, using a CA cert file that doesn't contain
482 # the CA Gogole uses (i.e., simulating a cert that's not signed by a
483 # trusted CA).
484 other_ca_certs = os.path.join(
485 os.path.dirname(os.path.abspath(httplib2.__file__ )),
486 "test", "other_cacerts.txt")
487 http = httplib2.Http(ca_certs=other_ca_certs)
488 self.assertRaises(httplib2.SSLHandshakeError,
489 http.request, "https://www.google.com/", "GET")
490
Joe Gregorioc69dc782011-06-23 08:56:59 -0400491 def testSslCertValidationDoubleDots(self):
492 if sys.version_info >= (2, 6):
493 # Test that we get match a double dot cert
494 try:
495 self.http.request("https://1.www.appspot.com/", "GET")
496 except httplib2.CertificateHostnameMismatch:
497 self.fail('cert with *.*.appspot.com should not raise an exception.')
498
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400499 def testSslHostnameValidation(self):
Joe Gregorio3e563132012-03-02 10:52:45 -0500500 pass
501 # No longer a valid test.
502 #if sys.version_info >= (2, 6):
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400503 # The SSL server at google.com:443 returns a certificate for
504 # 'www.google.com', which results in a host name mismatch.
505 # Note that this test only works because the ssl module and httplib2
506 # do not support SNI; for requests specifying a server name of
507 # 'google.com' via SNI, a matching cert would be returned.
Joe Gregorio3e563132012-03-02 10:52:45 -0500508 # self.assertRaises(httplib2.CertificateHostnameMismatch,
509 # self.http.request, "https://google.com/", "GET")
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400510
511 def testSslCertValidationWithoutSslModuleFails(self):
512 if sys.version_info < (2, 6):
513 http = httplib2.Http(disable_ssl_certificate_validation=False)
514 self.assertRaises(httplib2.CertificateValidationUnsupported,
515 http.request, "https://www.google.com/", "GET")
jcgregoriode8238d2007-03-07 19:08:26 +0000516
517 def testGetViaHttpsKeyCert(self):
jcgregorio2f1e1422007-05-03 13:17:33 +0000518 # At this point I can only test
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400519 # that the key and cert files are passed in
520 # correctly to httplib. It would be nice to have
jcgregorio2f1e1422007-05-03 13:17:33 +0000521 # a real https endpoint to test against.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400522
523 # bitworking.org presents an certificate for a non-matching host
524 # (*.webfaction.com), so we need to disable cert checking for this test.
525 http = httplib2.Http(timeout=2, disable_ssl_certificate_validation=True)
jcgregoriode8238d2007-03-07 19:08:26 +0000526
527 http.add_certificate("akeyfile", "acertfile", "bitworking.org")
528 try:
529 (response, content) = http.request("https://bitworking.org", "GET")
530 except:
531 pass
532 self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
533 self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
534
jcgregorio2f1e1422007-05-03 13:17:33 +0000535 try:
536 (response, content) = http.request("https://notthere.bitworking.org", "GET")
537 except:
538 pass
539 self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
540 self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
541
542
543
jcgregoriode8238d2007-03-07 19:08:26 +0000544
jcgregorio2d66d4f2006-02-07 05:34:14 +0000545 def testGet303(self):
546 # Do a follow-up GET on a Location: header
547 # returned from a POST that gave a 303.
548 uri = urlparse.urljoin(base, "303/303.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000549 (response, content) = self.http.request(uri, "POST", " ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000550 self.assertEqual(response.status, 200)
551 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000552 self.assertEqual(response.previous.status, 303)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000553
jcgregorio2f1e1422007-05-03 13:17:33 +0000554 def testGet303NoRedirect(self):
555 # Do a follow-up GET on a Location: header
556 # returned from a POST that gave a 303.
557 self.http.follow_redirects = False
558 uri = urlparse.urljoin(base, "303/303.cgi")
559 (response, content) = self.http.request(uri, "POST", " ")
560 self.assertEqual(response.status, 303)
561
jcgregorio2d66d4f2006-02-07 05:34:14 +0000562 def test303ForDifferentMethods(self):
563 # Test that all methods can be used
564 uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400565 for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
jcgregorio36140b52006-06-13 02:17:52 +0000566 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000567 self.assertEqual(response['x-method'], method_on_303)
568
569 def testGet304(self):
570 # Test that we use ETags properly to validate our cache
571 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000572 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000573 self.assertNotEqual(response['etag'], "")
574
jcgregorio36140b52006-06-13 02:17:52 +0000575 (response, content) = self.http.request(uri, "GET")
576 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000577 self.assertEqual(response.status, 200)
578 self.assertEqual(response.fromcache, True)
579
jcgregorio90fb4a42006-11-17 16:19:47 +0000580 cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
581 f = open(cache_file_name, "r")
582 status_line = f.readline()
583 f.close()
584
585 self.assertTrue(status_line.startswith("status:"))
586
jcgregorio36140b52006-06-13 02:17:52 +0000587 (response, content) = self.http.request(uri, "HEAD")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000588 self.assertEqual(response.status, 200)
589 self.assertEqual(response.fromcache, True)
590
jcgregorio36140b52006-06-13 02:17:52 +0000591 (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000592 self.assertEqual(response.status, 206)
593 self.assertEqual(response.fromcache, False)
594
jcgregorio25185622006-10-28 05:12:34 +0000595 def testGetIgnoreEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400596 # Test that we can forcibly ignore ETags
jcgregorio25185622006-10-28 05:12:34 +0000597 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
598 (response, content) = self.http.request(uri, "GET")
599 self.assertNotEqual(response['etag'], "")
600
601 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
602 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400603 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000604
605 self.http.ignore_etag = True
606 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
607 d = self.reflector(content)
608 self.assertEqual(response.fromcache, False)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400609 self.assertFalse(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000610
jcgregorio4b145e82007-01-18 19:46:34 +0000611 def testOverrideEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400612 # Test that we can forcibly ignore ETags
jcgregorio4b145e82007-01-18 19:46:34 +0000613 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
614 (response, content) = self.http.request(uri, "GET")
615 self.assertNotEqual(response['etag'], "")
616
617 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
618 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400619 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
620 self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio4b145e82007-01-18 19:46:34 +0000621
pilgrim00a352e2009-05-29 04:04:44 +0000622 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0', 'if-none-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +0000623 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400624 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
625 self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio25185622006-10-28 05:12:34 +0000626
pilgrim00a352e2009-05-29 04:04:44 +0000627#MAP-commented this out because it consistently fails
628# def testGet304EndToEnd(self):
629# # Test that end to end headers get overwritten in the cache
630# uri = urlparse.urljoin(base, "304/end2end.cgi")
631# (response, content) = self.http.request(uri, "GET")
632# self.assertNotEqual(response['etag'], "")
633# old_date = response['date']
634# time.sleep(2)
635#
636# (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
637# # The response should be from the cache, but the Date: header should be updated.
638# new_date = response['date']
639# self.assertNotEqual(new_date, old_date)
640# self.assertEqual(response.status, 200)
641# self.assertEqual(response.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000642
643 def testGet304LastModified(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400644 # Test that we can still handle a 304
jcgregorio2d66d4f2006-02-07 05:34:14 +0000645 # by only using the last-modified cache validator.
646 uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000647 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000648
649 self.assertNotEqual(response['last-modified'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000650 (response, content) = self.http.request(uri, "GET")
651 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000652 self.assertEqual(response.status, 200)
653 self.assertEqual(response.fromcache, True)
654
655 def testGet307(self):
656 # Test that we do follow 307 redirects but
657 # do not cache the 307
658 uri = urlparse.urljoin(base, "307/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000659 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000660 self.assertEqual(response.status, 200)
661 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000662 self.assertEqual(response.previous.status, 307)
663 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000664
jcgregorio36140b52006-06-13 02:17:52 +0000665 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000666 self.assertEqual(response.status, 200)
667 self.assertEqual(response.fromcache, True)
668 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000669 self.assertEqual(response.previous.status, 307)
670 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000671
672 def testGet410(self):
673 # Test that we pass 410's through
674 uri = urlparse.urljoin(base, "410/410.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000675 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000676 self.assertEqual(response.status, 410)
677
chris dent89f15142009-12-24 14:02:57 -0600678 def testVaryHeaderSimple(self):
679 """
680 RFC 2616 13.6
681 When the cache receives a subsequent request whose Request-URI
682 specifies one or more cache entries including a Vary header field,
683 the cache MUST NOT use such a cache entry to construct a response
684 to the new request unless all of the selecting request-headers
685 present in the new request match the corresponding stored
686 request-headers in the original request.
687 """
688 # test that the vary header is sent
689 uri = urlparse.urljoin(base, "vary/accept.asis")
690 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
691 self.assertEqual(response.status, 200)
692 self.assertTrue(response.has_key('vary'))
693
694 # get the resource again, from the cache since accept header in this
695 # request is the same as the request
696 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
697 self.assertEqual(response.status, 200)
698 self.assertEqual(response.fromcache, True, msg="Should be from cache")
699
700 # get the resource again, not from cache since Accept headers does not match
701 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
702 self.assertEqual(response.status, 200)
703 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
704
705 # get the resource again, without any Accept header, so again no match
706 (response, content) = self.http.request(uri, "GET")
707 self.assertEqual(response.status, 200)
708 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
709
710 def testNoVary(self):
711 # when there is no vary, a different Accept header (e.g.) should not
712 # impact if the cache is used
713 # test that the vary header is not sent
714 uri = urlparse.urljoin(base, "vary/no-vary.asis")
715 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
716 self.assertEqual(response.status, 200)
717 self.assertFalse(response.has_key('vary'))
718
719 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
720 self.assertEqual(response.status, 200)
721 self.assertEqual(response.fromcache, True, msg="Should be from cache")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400722
chris dent89f15142009-12-24 14:02:57 -0600723 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
724 self.assertEqual(response.status, 200)
725 self.assertEqual(response.fromcache, True, msg="Should be from cache")
726
727 def testVaryHeaderDouble(self):
728 uri = urlparse.urljoin(base, "vary/accept-double.asis")
729 (response, content) = self.http.request(uri, "GET", headers={
730 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
731 self.assertEqual(response.status, 200)
732 self.assertTrue(response.has_key('vary'))
733
734 # we are from cache
735 (response, content) = self.http.request(uri, "GET", headers={
736 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
737 self.assertEqual(response.fromcache, True, msg="Should be from cache")
738
739 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
740 self.assertEqual(response.status, 200)
741 self.assertEqual(response.fromcache, False)
742
743 # get the resource again, not from cache, varied headers don't match exact
744 (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})
745 self.assertEqual(response.status, 200)
746 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
747
jcgregorio88ef89b2010-05-13 23:42:11 -0400748 def testVaryUnusedHeader(self):
749 # A header's value is not considered to vary if it's not used at all.
750 uri = urlparse.urljoin(base, "vary/unused-header.asis")
751 (response, content) = self.http.request(uri, "GET", headers={
752 'Accept': 'text/plain'})
753 self.assertEqual(response.status, 200)
754 self.assertTrue(response.has_key('vary'))
755
756 # we are from cache
757 (response, content) = self.http.request(uri, "GET", headers={
758 'Accept': 'text/plain',})
759 self.assertEqual(response.fromcache, True, msg="Should be from cache")
760
chris dent89f15142009-12-24 14:02:57 -0600761
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000762 def testHeadGZip(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400763 # Test that we don't try to decompress a HEAD response
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000764 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
765 (response, content) = self.http.request(uri, "HEAD")
766 self.assertEqual(response.status, 200)
767 self.assertNotEqual(int(response['content-length']), 0)
768 self.assertEqual(content, "")
769
jcgregorio2d66d4f2006-02-07 05:34:14 +0000770 def testGetGZip(self):
771 # Test that we support gzip compression
772 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000773 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000774 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000775 self.assertFalse(response.has_key('content-encoding'))
joe.gregorio8b6d2312007-12-16 05:42:07 +0000776 self.assertTrue(response.has_key('-content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000777 self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000778 self.assertEqual(content, "This is the final destination.\n")
779
Joe Gregoriod1137c52011-02-13 19:27:35 -0500780 def testPostAndGZipResponse(self):
781 uri = urlparse.urljoin(base, "gzip/post.cgi")
782 (response, content) = self.http.request(uri, "POST", body=" ")
783 self.assertEqual(response.status, 200)
784 self.assertFalse(response.has_key('content-encoding'))
785 self.assertTrue(response.has_key('-content-encoding'))
786
jcgregorio2d66d4f2006-02-07 05:34:14 +0000787 def testGetGZipFailure(self):
788 # Test that we raise a good exception when the gzip fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400789 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000790 uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
791 try:
jcgregorio36140b52006-06-13 02:17:52 +0000792 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000793 self.fail("Should never reach here")
794 except httplib2.FailedToDecompressContent:
795 pass
796 except Exception:
797 self.fail("Threw wrong kind of exception")
798
jcgregorio07a9a4a2007-03-08 21:18:39 +0000799 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400800 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000801
802 (response, content) = self.http.request(uri, "GET")
803 self.assertEqual(response.status, 500)
804 self.assertTrue(response.reason.startswith("Content purported"))
805
806 def testTimeout(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400807 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000808 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
809 try:
810 import socket
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400811 socket.setdefaulttimeout(1)
jcgregorio07a9a4a2007-03-08 21:18:39 +0000812 except:
813 # Don't run the test if we can't set the timeout
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400814 return
jcgregorio07a9a4a2007-03-08 21:18:39 +0000815 (response, content) = self.http.request(uri)
816 self.assertEqual(response.status, 408)
817 self.assertTrue(response.reason.startswith("Request Timeout"))
818 self.assertTrue(content.startswith("Request Timeout"))
819
jcgregoriob2697912007-03-09 02:23:47 +0000820 def testIndividualTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000821 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
822 http = httplib2.Http(timeout=1)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400823 http.force_exception_to_status_code = True
jcgregoriob2697912007-03-09 02:23:47 +0000824
825 (response, content) = http.request(uri)
826 self.assertEqual(response.status, 408)
827 self.assertTrue(response.reason.startswith("Request Timeout"))
828 self.assertTrue(content.startswith("Request Timeout"))
829
jcgregorio07a9a4a2007-03-08 21:18:39 +0000830
Joe Gregorio1a7609f2009-07-16 10:59:44 -0400831 def testHTTPSInitTimeout(self):
832 c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
833 self.assertEqual(47, c.timeout)
834
jcgregorio2d66d4f2006-02-07 05:34:14 +0000835 def testGetDeflate(self):
836 # Test that we support deflate compression
837 uri = urlparse.urljoin(base, "deflate/deflated.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000838 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000839 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000840 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000841 self.assertEqual(int(response['content-length']), len("This is the final destination."))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000842 self.assertEqual(content, "This is the final destination.")
843
844 def testGetDeflateFailure(self):
845 # Test that we raise a good exception when the deflate fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400846 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000847
jcgregorio2d66d4f2006-02-07 05:34:14 +0000848 uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
849 try:
jcgregorio36140b52006-06-13 02:17:52 +0000850 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000851 self.fail("Should never reach here")
852 except httplib2.FailedToDecompressContent:
853 pass
854 except Exception:
855 self.fail("Threw wrong kind of exception")
856
jcgregorio07a9a4a2007-03-08 21:18:39 +0000857 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400858 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000859
860 (response, content) = self.http.request(uri, "GET")
861 self.assertEqual(response.status, 500)
862 self.assertTrue(response.reason.startswith("Content purported"))
863
jcgregorio2d66d4f2006-02-07 05:34:14 +0000864 def testGetDuplicateHeaders(self):
865 # Test that duplicate headers get concatenated via ','
866 uri = urlparse.urljoin(base, "duplicate-headers/multilink.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000867 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000868 self.assertEqual(response.status, 200)
869 self.assertEqual(content, "This is content\n")
870 self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
871
872 def testGetCacheControlNoCache(self):
873 # Test Cache-Control: no-cache on requests
874 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000875 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000876 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000877 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000878 self.assertEqual(response.status, 200)
879 self.assertEqual(response.fromcache, True)
880
jcgregorio36140b52006-06-13 02:17:52 +0000881 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000882 self.assertEqual(response.status, 200)
883 self.assertEqual(response.fromcache, False)
884
885 def testGetCacheControlPragmaNoCache(self):
886 # Test Pragma: no-cache on requests
887 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000888 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000889 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000890 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000891 self.assertEqual(response.status, 200)
892 self.assertEqual(response.fromcache, True)
893
jcgregorio36140b52006-06-13 02:17:52 +0000894 (response, content) = self.http.request(uri, "GET", headers={'Pragma': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000895 self.assertEqual(response.status, 200)
896 self.assertEqual(response.fromcache, False)
897
898 def testGetCacheControlNoStoreRequest(self):
899 # A no-store request means that the response should not be stored.
900 uri = urlparse.urljoin(base, "304/test_etag.txt")
901
jcgregorio36140b52006-06-13 02:17:52 +0000902 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000903 self.assertEqual(response.status, 200)
904 self.assertEqual(response.fromcache, False)
905
jcgregorio36140b52006-06-13 02:17:52 +0000906 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000907 self.assertEqual(response.status, 200)
908 self.assertEqual(response.fromcache, False)
909
910 def testGetCacheControlNoStoreResponse(self):
911 # A no-store response means that the response should not be stored.
912 uri = urlparse.urljoin(base, "no-store/no-store.asis")
913
jcgregorio36140b52006-06-13 02:17:52 +0000914 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000915 self.assertEqual(response.status, 200)
916 self.assertEqual(response.fromcache, False)
917
jcgregorio36140b52006-06-13 02:17:52 +0000918 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000919 self.assertEqual(response.status, 200)
920 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000921
922 def testGetCacheControlNoCacheNoStoreRequest(self):
923 # Test that a no-store, no-cache clears the entry from the cache
924 # even if it was cached previously.
925 uri = urlparse.urljoin(base, "304/test_etag.txt")
926
jcgregorio36140b52006-06-13 02:17:52 +0000927 (response, content) = self.http.request(uri, "GET")
928 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000929 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000930 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
931 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000932 self.assertEqual(response.status, 200)
933 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000934
935 def testUpdateInvalidatesCache(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400936 # Test that calling PUT or DELETE on a
jcgregorio2d66d4f2006-02-07 05:34:14 +0000937 # URI that is cache invalidates that cache.
938 uri = urlparse.urljoin(base, "304/test_etag.txt")
939
jcgregorio36140b52006-06-13 02:17:52 +0000940 (response, content) = self.http.request(uri, "GET")
941 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000942 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000943 (response, content) = self.http.request(uri, "DELETE")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000944 self.assertEqual(response.status, 405)
945
jcgregorio36140b52006-06-13 02:17:52 +0000946 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000947 self.assertEqual(response.fromcache, False)
948
949 def testUpdateUsesCachedETag(self):
Joe Gregoriobd682082011-05-24 14:06:09 -0400950 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio2d66d4f2006-02-07 05:34:14 +0000951 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
952
jcgregorio36140b52006-06-13 02:17:52 +0000953 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000954 self.assertEqual(response.status, 200)
955 self.assertEqual(response.fromcache, False)
jcgregorio36140b52006-06-13 02:17:52 +0000956 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000957 self.assertEqual(response.status, 200)
958 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -0400959 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000960 self.assertEqual(response.status, 200)
Joe Gregoriocd868102009-09-29 17:09:16 -0400961 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000962 self.assertEqual(response.status, 412)
963
Joe Gregoriobd682082011-05-24 14:06:09 -0400964 def testUpdatePatchUsesCachedETag(self):
965 # Test that we natively support http://www.w3.org/1999/04/Editing/
966 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
967
968 (response, content) = self.http.request(uri, "GET")
969 self.assertEqual(response.status, 200)
970 self.assertEqual(response.fromcache, False)
971 (response, content) = self.http.request(uri, "GET")
972 self.assertEqual(response.status, 200)
973 self.assertEqual(response.fromcache, True)
974 (response, content) = self.http.request(uri, "PATCH", body="foo")
975 self.assertEqual(response.status, 200)
976 (response, content) = self.http.request(uri, "PATCH", body="foo")
977 self.assertEqual(response.status, 412)
978
979
joe.gregorio700f04d2008-09-06 04:46:32 +0000980 def testUpdateUsesCachedETagAndOCMethod(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400981 # Test that we natively support http://www.w3.org/1999/04/Editing/
joe.gregorio700f04d2008-09-06 04:46:32 +0000982 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 self.http.optimistic_concurrency_methods.append("DELETE")
991 (response, content) = self.http.request(uri, "DELETE")
992 self.assertEqual(response.status, 200)
993
994
jcgregorio4b145e82007-01-18 19:46:34 +0000995 def testUpdateUsesCachedETagOverridden(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400996 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio4b145e82007-01-18 19:46:34 +0000997 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
998
999 (response, content) = self.http.request(uri, "GET")
1000 self.assertEqual(response.status, 200)
1001 self.assertEqual(response.fromcache, False)
1002 (response, content) = self.http.request(uri, "GET")
1003 self.assertEqual(response.status, 200)
1004 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -04001005 (response, content) = self.http.request(uri, "PUT", body="foo", headers={'if-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +00001006 self.assertEqual(response.status, 412)
1007
jcgregorio2d66d4f2006-02-07 05:34:14 +00001008 def testBasicAuth(self):
1009 # Test Basic Authentication
1010 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001011 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001012 self.assertEqual(response.status, 401)
1013
1014 uri = urlparse.urljoin(base, "basic/")
jcgregorio36140b52006-06-13 02:17:52 +00001015 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001016 self.assertEqual(response.status, 401)
1017
jcgregorio36140b52006-06-13 02:17:52 +00001018 self.http.add_credentials('joe', 'password')
1019 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001020 self.assertEqual(response.status, 200)
1021
1022 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001023 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001024 self.assertEqual(response.status, 200)
1025
jcgregoriode8238d2007-03-07 19:08:26 +00001026 def testBasicAuthWithDomain(self):
1027 # Test Basic Authentication
1028 uri = urlparse.urljoin(base, "basic/file.txt")
1029 (response, content) = self.http.request(uri, "GET")
1030 self.assertEqual(response.status, 401)
1031
1032 uri = urlparse.urljoin(base, "basic/")
1033 (response, content) = self.http.request(uri, "GET")
1034 self.assertEqual(response.status, 401)
1035
1036 self.http.add_credentials('joe', 'password', "example.org")
1037 (response, content) = self.http.request(uri, "GET")
1038 self.assertEqual(response.status, 401)
1039
1040 uri = urlparse.urljoin(base, "basic/file.txt")
1041 (response, content) = self.http.request(uri, "GET")
1042 self.assertEqual(response.status, 401)
1043
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001044 domain = urlparse.urlparse(base)[1]
jcgregoriode8238d2007-03-07 19:08:26 +00001045 self.http.add_credentials('joe', 'password', domain)
1046 (response, content) = self.http.request(uri, "GET")
1047 self.assertEqual(response.status, 200)
1048
1049 uri = urlparse.urljoin(base, "basic/file.txt")
1050 (response, content) = self.http.request(uri, "GET")
1051 self.assertEqual(response.status, 200)
1052
1053
1054
1055
1056
1057
jcgregorio2d66d4f2006-02-07 05:34:14 +00001058 def testBasicAuthTwoDifferentCredentials(self):
jcgregorioadbb4f82006-05-19 15:17:42 +00001059 # Test Basic Authentication with multiple sets of credentials
jcgregorio2d66d4f2006-02-07 05:34:14 +00001060 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001061 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001062 self.assertEqual(response.status, 401)
1063
1064 uri = urlparse.urljoin(base, "basic2/")
jcgregorio36140b52006-06-13 02:17:52 +00001065 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001066 self.assertEqual(response.status, 401)
1067
jcgregorio36140b52006-06-13 02:17:52 +00001068 self.http.add_credentials('fred', 'barney')
1069 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001070 self.assertEqual(response.status, 200)
1071
1072 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001073 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001074 self.assertEqual(response.status, 200)
1075
1076 def testBasicAuthNested(self):
1077 # Test Basic Authentication with resources
1078 # that are nested
1079 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001080 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001081 self.assertEqual(response.status, 401)
1082
1083 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001084 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001085 self.assertEqual(response.status, 401)
1086
jcgregorioadbb4f82006-05-19 15:17:42 +00001087 # Now add in credentials one at a time and test.
jcgregorio36140b52006-06-13 02:17:52 +00001088 self.http.add_credentials('joe', 'password')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001089
1090 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001091 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001092 self.assertEqual(response.status, 200)
1093
1094 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001095 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001096 self.assertEqual(response.status, 401)
1097
jcgregorio36140b52006-06-13 02:17:52 +00001098 self.http.add_credentials('fred', 'barney')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001099
1100 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001101 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001102 self.assertEqual(response.status, 200)
1103
1104 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001105 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001106 self.assertEqual(response.status, 200)
1107
1108 def testDigestAuth(self):
1109 # Test that we support Digest Authentication
1110 uri = urlparse.urljoin(base, "digest/")
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('joe', 'password')
1115 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001116 self.assertEqual(response.status, 200)
1117
1118 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001119 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001120
1121 def testDigestAuthNextNonceAndNC(self):
1122 # Test that if the server sets nextnonce that we reset
1123 # the nonce count back to 1
1124 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001125 self.http.add_credentials('joe', 'password')
1126 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001127 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1128 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +00001129 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001130 info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
1131 self.assertEqual(response.status, 200)
1132
1133 if info.has_key('nextnonce'):
1134 self.assertEqual(info2['nc'], 1)
1135
1136 def testDigestAuthStale(self):
1137 # Test that we can handle a nonce becoming stale
1138 uri = urlparse.urljoin(base, "digest-expire/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001139 self.http.add_credentials('joe', 'password')
1140 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001141 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1142 self.assertEqual(response.status, 200)
1143
1144 time.sleep(3)
1145 # Sleep long enough that the nonce becomes stale
1146
jcgregorio36140b52006-06-13 02:17:52 +00001147 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001148 self.assertFalse(response.fromcache)
1149 self.assertTrue(response._stale_digest)
1150 info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
1151 self.assertEqual(response.status, 200)
1152
1153 def reflector(self, content):
jcgregorio25185622006-10-28 05:12:34 +00001154 return dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
jcgregorio2d66d4f2006-02-07 05:34:14 +00001155
1156 def testReflector(self):
1157 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +00001158 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001159 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001160 self.assertTrue(d.has_key('HTTP_USER_AGENT'))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001161
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001162 def testConnectionClose(self):
1163 uri = "http://www.google.com/"
1164 (response, content) = self.http.request(uri, "GET")
1165 for c in self.http.connections.values():
1166 self.assertNotEqual(None, c.sock)
1167 (response, content) = self.http.request(uri, "GET", headers={"connection": "close"})
1168 for c in self.http.connections.values():
1169 self.assertEqual(None, c.sock)
1170
1171
jcgregorio36140b52006-06-13 02:17:52 +00001172try:
1173 import memcache
1174 class HttpTestMemCached(HttpTest):
1175 def setUp(self):
1176 self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
jcgregorio47d24672006-06-29 05:18:59 +00001177 #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
jcgregorio36140b52006-06-13 02:17:52 +00001178 self.http = httplib2.Http(self.cache)
1179 self.cache.flush_all()
jcgregorio47d24672006-06-29 05:18:59 +00001180 # Not exactly sure why the sleep is needed here, but
1181 # if not present then some unit tests that rely on caching
1182 # fail. Memcached seems to lose some sets immediately
1183 # after a flush_all if the set is to a value that
1184 # was previously cached. (Maybe the flush is handled async?)
1185 time.sleep(1)
jcgregorio36140b52006-06-13 02:17:52 +00001186 self.http.clear_credentials()
1187except:
1188 pass
1189
1190
1191
chris dent89f15142009-12-24 14:02:57 -06001192
jcgregoriodb8dfc82006-03-31 14:59:46 +00001193# ------------------------------------------------------------------------
jcgregorio2d66d4f2006-02-07 05:34:14 +00001194
1195class HttpPrivateTest(unittest.TestCase):
1196
1197 def testParseCacheControl(self):
1198 # Test that we can parse the Cache-Control header
1199 self.assertEqual({}, httplib2._parse_cache_control({}))
1200 self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
1201 cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
1202 self.assertEqual(cc['no-cache'], 1)
1203 self.assertEqual(cc['max-age'], '7200')
1204 cc = httplib2._parse_cache_control({'cache-control': ' , '})
1205 self.assertEqual(cc[''], 1)
1206
Joe Gregorioe314e8b2009-07-16 20:11:28 -04001207 try:
1208 cc = httplib2._parse_cache_control({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'})
1209 self.assertTrue("max-age" in cc)
1210 except:
1211 self.fail("Should not throw exception")
1212
jcgregorio2d66d4f2006-02-07 05:34:14 +00001213 def testNormalizeHeaders(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001214 # Test that we normalize headers to lowercase
jcgregorio2d66d4f2006-02-07 05:34:14 +00001215 h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
1216 self.assertTrue(h.has_key('cache-control'))
1217 self.assertTrue(h.has_key('other'))
1218 self.assertEqual('Stuff', h['other'])
1219
1220 def testExpirationModelTransparent(self):
1221 # Test that no-cache makes our request TRANSPARENT
1222 response_headers = {
1223 'cache-control': 'max-age=7200'
1224 }
1225 request_headers = {
1226 'cache-control': 'no-cache'
1227 }
1228 self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
1229
jcgregorio45865012007-01-18 16:38:22 +00001230 def testMaxAgeNonNumeric(self):
1231 # Test that no-cache makes our request TRANSPARENT
1232 response_headers = {
1233 'cache-control': 'max-age=fred, min-fresh=barney'
1234 }
1235 request_headers = {
1236 }
1237 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1238
1239
jcgregorio2d66d4f2006-02-07 05:34:14 +00001240 def testExpirationModelNoCacheResponse(self):
1241 # The date and expires point to an entry that should be
1242 # FRESH, but the no-cache over-rides that.
1243 now = time.time()
1244 response_headers = {
1245 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1246 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1247 'cache-control': 'no-cache'
1248 }
1249 request_headers = {
1250 }
1251 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1252
1253 def testExpirationModelStaleRequestMustReval(self):
1254 # must-revalidate forces STALE
1255 self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
1256
1257 def testExpirationModelStaleResponseMustReval(self):
1258 # must-revalidate forces STALE
1259 self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
1260
1261 def testExpirationModelFresh(self):
1262 response_headers = {
1263 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1264 'cache-control': 'max-age=2'
1265 }
1266 request_headers = {
1267 }
1268 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1269 time.sleep(3)
1270 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1271
1272 def testExpirationMaxAge0(self):
1273 response_headers = {
1274 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1275 'cache-control': 'max-age=0'
1276 }
1277 request_headers = {
1278 }
1279 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1280
1281 def testExpirationModelDateAndExpires(self):
1282 now = time.time()
1283 response_headers = {
1284 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1285 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1286 }
1287 request_headers = {
1288 }
1289 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1290 time.sleep(3)
1291 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1292
jcgregoriof9511052007-06-01 14:56:34 +00001293 def testExpiresZero(self):
1294 now = time.time()
1295 response_headers = {
1296 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1297 'expires': "0",
1298 }
1299 request_headers = {
1300 }
1301 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1302
jcgregorio2d66d4f2006-02-07 05:34:14 +00001303 def testExpirationModelDateOnly(self):
1304 now = time.time()
1305 response_headers = {
1306 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
1307 }
1308 request_headers = {
1309 }
1310 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1311
1312 def testExpirationModelOnlyIfCached(self):
1313 response_headers = {
1314 }
1315 request_headers = {
1316 'cache-control': 'only-if-cached',
1317 }
1318 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1319
1320 def testExpirationModelMaxAgeBoth(self):
1321 now = time.time()
1322 response_headers = {
1323 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1324 'cache-control': 'max-age=2'
1325 }
1326 request_headers = {
1327 'cache-control': 'max-age=0'
1328 }
1329 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1330
1331 def testExpirationModelDateAndExpiresMinFresh1(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 'cache-control': 'min-fresh=2'
1339 }
1340 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1341
1342 def testExpirationModelDateAndExpiresMinFresh2(self):
1343 now = time.time()
1344 response_headers = {
1345 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1346 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1347 }
1348 request_headers = {
1349 'cache-control': 'min-fresh=2'
1350 }
1351 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1352
1353 def testParseWWWAuthenticateEmpty(self):
1354 res = httplib2._parse_www_authenticate({})
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001355 self.assertEqual(len(res.keys()), 0)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001356
jcgregoriofd22e432006-04-27 02:00:08 +00001357 def testParseWWWAuthenticate(self):
1358 # different uses of spaces around commas
1359 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
1360 self.assertEqual(len(res.keys()), 1)
1361 self.assertEqual(len(res['test'].keys()), 5)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001362
jcgregoriofd22e432006-04-27 02:00:08 +00001363 # tokens with non-alphanum
1364 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
1365 self.assertEqual(len(res.keys()), 1)
1366 self.assertEqual(len(res['t*!%#st'].keys()), 2)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001367
jcgregoriofd22e432006-04-27 02:00:08 +00001368 # quoted string with quoted pairs
1369 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
1370 self.assertEqual(len(res.keys()), 1)
1371 self.assertEqual(res['test']['realm'], 'a "test" realm')
1372
1373 def testParseWWWAuthenticateStrict(self):
1374 httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
1375 self.testParseWWWAuthenticate();
1376 httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
1377
jcgregorio2d66d4f2006-02-07 05:34:14 +00001378 def testParseWWWAuthenticateBasic(self):
1379 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
1380 basic = res['basic']
1381 self.assertEqual('me', basic['realm'])
1382
1383 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
1384 basic = res['basic']
1385 self.assertEqual('me', basic['realm'])
1386 self.assertEqual('MD5', basic['algorithm'])
1387
1388 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
1389 basic = res['basic']
1390 self.assertEqual('me', basic['realm'])
1391 self.assertEqual('MD5', basic['algorithm'])
1392
1393 def testParseWWWAuthenticateBasic2(self):
1394 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
1395 basic = res['basic']
1396 self.assertEqual('me', basic['realm'])
1397 self.assertEqual('fred', basic['other'])
1398
1399 def testParseWWWAuthenticateBasic3(self):
1400 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
1401 basic = res['basic']
1402 self.assertEqual('me', basic['realm'])
1403
1404
1405 def testParseWWWAuthenticateDigest(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001406 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001407 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
1408 digest = res['digest']
1409 self.assertEqual('testrealm@host.com', digest['realm'])
1410 self.assertEqual('auth,auth-int', digest['qop'])
1411
1412
1413 def testParseWWWAuthenticateMultiple(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001414 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001415 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
1416 digest = res['digest']
1417 self.assertEqual('testrealm@host.com', digest['realm'])
1418 self.assertEqual('auth,auth-int', digest['qop'])
1419 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1420 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1421 basic = res['basic']
1422 self.assertEqual('me', basic['realm'])
1423
1424 def testParseWWWAuthenticateMultiple2(self):
1425 # Handle an added comma between challenges, which might get thrown in if the challenges were
1426 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001427 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001428 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
1429 digest = res['digest']
1430 self.assertEqual('testrealm@host.com', digest['realm'])
1431 self.assertEqual('auth,auth-int', digest['qop'])
1432 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1433 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1434 basic = res['basic']
1435 self.assertEqual('me', basic['realm'])
1436
1437 def testParseWWWAuthenticateMultiple3(self):
1438 # Handle an added comma between challenges, which might get thrown in if the challenges were
1439 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001440 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001441 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1442 digest = res['digest']
1443 self.assertEqual('testrealm@host.com', digest['realm'])
1444 self.assertEqual('auth,auth-int', digest['qop'])
1445 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1446 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1447 basic = res['basic']
1448 self.assertEqual('me', basic['realm'])
1449 wsse = res['wsse']
1450 self.assertEqual('foo', wsse['realm'])
1451 self.assertEqual('UsernameToken', wsse['profile'])
1452
1453 def testParseWWWAuthenticateMultiple4(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001454 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1455 '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 +00001456 digest = res['digest']
1457 self.assertEqual('test-real.m@host.com', digest['realm'])
1458 self.assertEqual('\tauth,auth-int', digest['qop'])
1459 self.assertEqual('(*)&^&$%#', digest['nonce'])
1460
1461 def testParseWWWAuthenticateMoreQuoteCombos(self):
1462 res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
1463 digest = res['digest']
1464 self.assertEqual('myrealm', digest['realm'])
1465
Joe Gregorio6fa3cf22011-02-13 22:45:06 -05001466 def testParseWWWAuthenticateMalformed(self):
1467 try:
1468 res = httplib2._parse_www_authenticate({'www-authenticate':'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'})
1469 self.fail("should raise an exception")
1470 except httplib2.MalformedHeader:
1471 pass
1472
jcgregorio2d66d4f2006-02-07 05:34:14 +00001473 def testDigestObject(self):
1474 credentials = ('joe', 'password')
1475 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001476 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001477 headers = {}
1478 response = {
1479 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
1480 }
1481 content = ""
Joe Gregorio875a8b52011-06-13 14:06:23 -04001482
jcgregorio6cbab7e2006-04-21 20:35:43 +00001483 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001484 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
Joe Gregorio875a8b52011-06-13 14:06:23 -04001485 our_request = "authorization: %s" % headers['authorization']
1486 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 +00001487 self.assertEqual(our_request, working_request)
1488
Joe Gregorio03d99102011-06-22 16:55:52 -04001489 def testDigestObjectWithOpaque(self):
1490 credentials = ('joe', 'password')
1491 host = None
1492 request_uri = '/projects/httplib2/test/digest/'
1493 headers = {}
1494 response = {
1495 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", opaque="atestopaque"'
1496 }
1497 content = ""
1498
1499 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
1500 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
1501 our_request = "authorization: %s" % headers['authorization']
1502 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"'
1503 self.assertEqual(our_request, working_request)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001504
1505 def testDigestObjectStale(self):
1506 credentials = ('joe', 'password')
1507 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001508 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001509 headers = {}
1510 response = httplib2.Response({ })
1511 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1512 response.status = 401
1513 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001514 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001515 # Returns true to force a retry
1516 self.assertTrue( d.response(response, content) )
1517
1518 def testDigestObjectAuthInfo(self):
1519 credentials = ('joe', 'password')
1520 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001521 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001522 headers = {}
1523 response = httplib2.Response({ })
1524 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1525 response['authentication-info'] = 'nextnonce="fred"'
1526 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001527 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001528 # Returns true to force a retry
1529 self.assertFalse( d.response(response, content) )
1530 self.assertEqual('fred', d.challenge['nonce'])
1531 self.assertEqual(1, d.challenge['nc'])
1532
1533 def testWsseAlgorithm(self):
1534 digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
1535 expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
1536 self.assertEqual(expected, digest)
1537
jcgregoriodb8dfc82006-03-31 14:59:46 +00001538 def testEnd2End(self):
1539 # one end to end header
1540 response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
1541 end2end = httplib2._get_end2end_headers(response)
1542 self.assertTrue('content-type' in end2end)
1543 self.assertTrue('te' not in end2end)
1544 self.assertTrue('connection' not in end2end)
1545
1546 # one end to end header that gets eliminated
1547 response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
1548 end2end = httplib2._get_end2end_headers(response)
1549 self.assertTrue('content-type' not in end2end)
1550 self.assertTrue('te' not in end2end)
1551 self.assertTrue('connection' not in end2end)
1552
1553 # Degenerate case of no headers
1554 response = {}
1555 end2end = httplib2._get_end2end_headers(response)
1556 self.assertEquals(0, len(end2end))
1557
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001558 # Degenerate case of connection referrring to a header not passed in
jcgregoriodb8dfc82006-03-31 14:59:46 +00001559 response = {'connection': 'content-type'}
1560 end2end = httplib2._get_end2end_headers(response)
1561 self.assertEquals(0, len(end2end))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001562
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001563
1564class TestProxyInfo(unittest.TestCase):
1565 def setUp(self):
1566 self.orig_env = dict(os.environ)
1567
1568 def tearDown(self):
1569 os.environ.clear()
1570 os.environ.update(self.orig_env)
1571
1572 def test_from_url(self):
1573 pi = httplib2.ProxyInfo.from_url('http://myproxy.example.com')
1574 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1575 self.assertEquals(pi.proxy_port, 80)
1576 self.assertEquals(pi.proxy_user, None)
1577
1578 def test_from_url_ident(self):
1579 pi = httplib2.ProxyInfo.from_url('http://zoidberg:fish@someproxy:99')
1580 self.assertEquals(pi.proxy_host, 'someproxy')
1581 self.assertEquals(pi.proxy_port, 99)
1582 self.assertEquals(pi.proxy_user, 'zoidberg')
1583 self.assertEquals(pi.proxy_pass, 'fish')
1584
1585 def test_from_env(self):
1586 os.environ['http_proxy'] = 'http://myproxy.example.com:8080'
1587 pi = httplib2.ProxyInfo.from_environment()
1588 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1589 self.assertEquals(pi.proxy_port, 8080)
1590 self.assertEquals(pi.bypass_hosts, [])
1591
1592 def test_from_env_no_proxy(self):
1593 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1594 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
1595 os.environ['no_proxy'] = 'localhost,otherhost.domain.local'
1596 pi = httplib2.ProxyInfo.from_environment('https')
1597 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1598 self.assertEquals(pi.proxy_port, 81)
1599 self.assertEquals(pi.bypass_hosts, ['localhost',
1600 'otherhost.domain.local'])
1601
1602 def test_from_env_none(self):
1603 os.environ.clear()
1604 pi = httplib2.ProxyInfo.from_environment()
1605 self.assertEquals(pi, None)
1606
Jason R. Coombs43840892011-08-09 10:30:46 -04001607 def test_applies_to(self):
1608 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1609 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
Jason R. Coombs96279c52011-08-16 12:53:27 -04001610 os.environ['no_proxy'] = 'localhost,otherhost.domain.local,example.com'
Jason R. Coombs43840892011-08-09 10:30:46 -04001611 pi = httplib2.ProxyInfo.from_environment()
1612 self.assertFalse(pi.applies_to('localhost'))
1613 self.assertTrue(pi.applies_to('www.google.com'))
Jason R. Coombs96279c52011-08-16 12:53:27 -04001614 self.assertFalse(pi.applies_to('www.example.com'))
1615
1616 def test_no_proxy_star(self):
1617 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1618 os.environ['NO_PROXY'] = '*'
1619 pi = httplib2.ProxyInfo.from_environment()
1620 for host in ('localhost', '169.254.38.192', 'www.google.com'):
1621 self.assertFalse(pi.applies_to(host))
Jason R. Coombs43840892011-08-09 10:30:46 -04001622
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001623
chris dent89f15142009-12-24 14:02:57 -06001624if __name__ == '__main__':
1625 unittest.main()