blob: a0b4dc50d8aa98e50cd4839c0a3c2d2af7216342 [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
jcgregoriode8238d2007-03-07 19:08:26 +000018import sys
19import unittest
20import httplib
21import httplib2
22import os
23import urlparse
24import time
25import base64
jcgregorio14644372007-07-30 14:13:37 +000026import StringIO
jcgregorio8421f272006-02-14 18:19:51 +000027
28# Python 2.3 support
29if not hasattr(unittest.TestCase, 'assertTrue'):
30 unittest.TestCase.assertTrue = unittest.TestCase.failUnless
31 unittest.TestCase.assertFalse = unittest.TestCase.failIf
32
jcgregorio2d66d4f2006-02-07 05:34:14 +000033# The test resources base uri
34base = 'http://bitworking.org/projects/httplib2/test/'
35#base = 'http://localhost/projects/httplib2/test/'
jcgregorio90fb4a42006-11-17 16:19:47 +000036cacheDirName = ".cache"
jcgregorio2d66d4f2006-02-07 05:34:14 +000037
jcgregoriode8238d2007-03-07 19:08:26 +000038
39class CredentialsTest(unittest.TestCase):
40 def test(self):
41 c = httplib2.Credentials()
42 c.add("joe", "password")
43 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
44 self.assertEqual(("joe", "password"), list(c.iter(""))[0])
45 c.add("fred", "password2", "wellformedweb.org")
46 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
47 self.assertEqual(1, len(list(c.iter("bitworking.org"))))
48 self.assertEqual(2, len(list(c.iter("wellformedweb.org"))))
49 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
50 c.clear()
51 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
52 c.add("fred", "password2", "wellformedweb.org")
53 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
54 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
55 self.assertEqual(0, len(list(c.iter(""))))
56
57
jcgregorio2d66d4f2006-02-07 05:34:14 +000058class ParserTest(unittest.TestCase):
59 def testFromStd66(self):
60 self.assertEqual( ('http', 'example.com', '', None, None ), httplib2.parse_uri("http://example.com"))
61 self.assertEqual( ('https', 'example.com', '', None, None ), httplib2.parse_uri("https://example.com"))
62 self.assertEqual( ('https', 'example.com:8080', '', None, None ), httplib2.parse_uri("https://example.com:8080"))
63 self.assertEqual( ('http', 'example.com', '/', None, None ), httplib2.parse_uri("http://example.com/"))
64 self.assertEqual( ('http', 'example.com', '/path', None, None ), httplib2.parse_uri("http://example.com/path"))
65 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', None ), httplib2.parse_uri("http://example.com/path?a=1&b=2"))
66 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
67 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
68
jcgregorio2d66d4f2006-02-07 05:34:14 +000069
jcgregorioa46fe4e2006-11-16 04:13:45 +000070class UrlNormTest(unittest.TestCase):
71 def test(self):
72 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://example.org")[-1])
73 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://EXAMple.org")[-1])
74 self.assertEqual( "http://example.org/?=b", httplib2.urlnorm("http://EXAMple.org?=b")[-1])
75 self.assertEqual( "http://example.org/mypath?a=b", httplib2.urlnorm("http://EXAMple.org/mypath?a=b")[-1])
76 self.assertEqual( "http://localhost:80/", httplib2.urlnorm("http://localhost:80")[-1])
jcgregoriob4e9ab02006-11-17 15:53:15 +000077 self.assertEqual( httplib2.urlnorm("http://localhost:80/"), httplib2.urlnorm("HTTP://LOCALHOST:80"))
jcgregorio132d28e2007-01-23 16:22:53 +000078 try:
79 httplib2.urlnorm("/")
80 self.fail("Non-absolute URIs should raise an exception")
81 except httplib2.RelativeURIError:
82 pass
jcgregorioa46fe4e2006-11-16 04:13:45 +000083
84class UrlSafenameTest(unittest.TestCase):
85 def test(self):
86 # Test that different URIs end up generating different safe names
87 self.assertEqual( "example.org,fred,a=b,58489f63a7a83c3b7794a6a398ee8b1f", httplib2.safename("http://example.org/fred/?a=b"))
88 self.assertEqual( "example.org,fred,a=b,8c5946d56fec453071f43329ff0be46b", httplib2.safename("http://example.org/fred?/a=b"))
89 self.assertEqual( "www.example.org,fred,a=b,499c44b8d844a011b67ea2c015116968", httplib2.safename("http://www.example.org/fred?/a=b"))
90 self.assertEqual( httplib2.safename(httplib2.urlnorm("http://www")[-1]), httplib2.safename(httplib2.urlnorm("http://WWW")[-1]))
91 self.assertEqual( "www.example.org,fred,a=b,692e843a333484ce0095b070497ab45d", httplib2.safename("https://www.example.org/fred?/a=b"))
92 self.assertNotEqual( httplib2.safename("http://www"), httplib2.safename("https://www"))
93 # Test the max length limits
94 uri = "http://" + ("w" * 200) + ".org"
95 uri2 = "http://" + ("w" * 201) + ".org"
96 self.assertNotEqual( httplib2.safename(uri2), httplib2.safename(uri))
97 # Max length should be 200 + 1 (",") + 32
98 self.assertEqual(233, len(httplib2.safename(uri2)))
99 self.assertEqual(233, len(httplib2.safename(uri)))
100 # Unicode
jcgregoriodebceec2006-12-12 20:26:02 +0000101 if sys.version_info >= (2,3):
102 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 +0000103
jcgregorio14644372007-07-30 14:13:37 +0000104class _MyResponse(StringIO.StringIO):
105 def __init__(self, body, **kwargs):
106 StringIO.StringIO.__init__(self, body)
107 self.headers = kwargs
108
109 def iteritems(self):
110 return self.headers.iteritems()
111
112
113class _MyHTTPConnection(object):
114 "This class is just a mock of httplib.HTTPConnection used for testing"
115
116 def __init__(self, host, port=None, key_file=None, cert_file=None,
joe.gregoriof28536d2007-10-23 14:10:11 +0000117 strict=None, timeout=None, proxy_info=None):
jcgregorio14644372007-07-30 14:13:37 +0000118 self.host = host
119 self.port = port
120 self.timeout = timeout
121 self.log = ""
122
123 def set_debuglevel(self, level):
124 pass
125
126 def connect(self):
127 "Connect to a host on a given port."
128 pass
129
130 def close(self):
131 pass
132
133 def request(self, method, request_uri, body, headers):
134 pass
135
136 def getresponse(self):
137 return _MyResponse("the body", status="200")
jcgregorioa46fe4e2006-11-16 04:13:45 +0000138
jcgregorio90fb4a42006-11-17 16:19:47 +0000139
jcgregorio2d66d4f2006-02-07 05:34:14 +0000140class HttpTest(unittest.TestCase):
141 def setUp(self):
jcgregorio7e3608f2006-06-15 13:01:53 +0000142 if os.path.exists(cacheDirName):
143 [os.remove(os.path.join(cacheDirName, file)) for file in os.listdir(cacheDirName)]
144 self.http = httplib2.Http(cacheDirName)
jcgregorio36140b52006-06-13 02:17:52 +0000145 self.http.clear_credentials()
jcgregorio2d66d4f2006-02-07 05:34:14 +0000146
jcgregorio14644372007-07-30 14:13:37 +0000147 def testConnectionType(self):
joe.gregoriof28536d2007-10-23 14:10:11 +0000148 self.http.force_exception_to_status_code = False
jcgregorio14644372007-07-30 14:13:37 +0000149 response, content = self.http.request("http://bitworking.org", connection_type=_MyHTTPConnection)
150 self.assertEqual(response['content-location'], "http://bitworking.org")
151 self.assertEqual(content, "the body")
152
jcgregorio6a638172007-01-23 16:40:23 +0000153 def testGetUnknownServer(self):
jcgregorio07a9a4a2007-03-08 21:18:39 +0000154 self.http.force_exception_to_status_code = False
jcgregorio6a638172007-01-23 16:40:23 +0000155 try:
156 self.http.request("http://fred.bitworking.org/")
157 self.fail("An httplib2.ServerNotFoundError Exception must be thrown on an unresolvable server.")
158 except httplib2.ServerNotFoundError:
159 pass
160
jcgregorio07a9a4a2007-03-08 21:18:39 +0000161 # Now test with exceptions turned off
162 self.http.force_exception_to_status_code = True
163
164 (response, content) = self.http.request("http://fred.bitworking.org/")
165 self.assertEqual(response['content-type'], 'text/plain')
166 self.assertTrue(content.startswith("Unable to find"))
167 self.assertEqual(response.status, 400)
168
jcgregorioa898f8f2006-12-12 17:16:55 +0000169 def testGetIRI(self):
jcgregoriodebceec2006-12-12 20:26:02 +0000170 if sys.version_info >= (2,3):
171 uri = urlparse.urljoin(base, u"reflector/reflector.cgi?d=\N{CYRILLIC CAPITAL LETTER DJE}")
172 (response, content) = self.http.request(uri, "GET")
173 d = self.reflector(content)
174 self.assertTrue(d.has_key('QUERY_STRING'))
175 self.assertTrue(d['QUERY_STRING'].find('%D0%82') > 0)
jcgregorioa898f8f2006-12-12 17:16:55 +0000176
jcgregorio2d66d4f2006-02-07 05:34:14 +0000177 def testGetIsDefaultMethod(self):
178 # Test that GET is the default method
179 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000180 (response, content) = self.http.request(uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000181 self.assertEqual(response['x-method'], "GET")
182
183 def testDifferentMethods(self):
184 # Test that all methods can be used
185 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
186 for method in ["GET", "PUT", "DELETE", "POST"]:
jcgregorio36140b52006-06-13 02:17:52 +0000187 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000188 self.assertEqual(response['x-method'], method)
189
Joe Gregoriob628c0b2009-07-16 12:28:04 -0400190 def testHeadRead(self):
191 # Test that we don't try to read the response of a HEAD request
192 # since httplib blocks response.read() for HEAD requests.
193 # Oddly enough this doesn't appear as a problem when doing HEAD requests
194 # against Apache servers.
195 uri = "http://www.google.com/"
196 (response, content) = self.http.request(uri, "HEAD")
197 self.assertEqual(response.status, 200)
198 self.assertEqual(content, "")
199
jcgregorio2d66d4f2006-02-07 05:34:14 +0000200 def testGetNoCache(self):
201 # Test that can do a GET w/o the cache turned on.
202 http = httplib2.Http()
203 uri = urlparse.urljoin(base, "304/test_etag.txt")
204 (response, content) = http.request(uri, "GET")
205 self.assertEqual(response.status, 200)
jcgregorioa0713ab2006-07-01 05:21:34 +0000206 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000207
Joe Gregorioe202d212009-07-16 14:57:52 -0400208 def testGetOnlyIfCachedCacheHit(self):
209 # Test that can do a GET with cache and 'only-if-cached'
210 uri = urlparse.urljoin(base, "304/test_etag.txt")
211 (response, content) = self.http.request(uri, "GET")
212 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
213 self.assertEqual(response.fromcache, True)
214 self.assertEqual(response.status, 200)
215
216 def testGetOnlyIfCachedCacheMissCache(self):
217 # Test that can do a GET with cache and 'only-if-cached'
218 uri = urlparse.urljoin(base, "304/test_etag.txt")
219 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
220 self.assertEqual(response.fromcache, False)
221 self.assertEqual(response.status, 504)
222
jcgregorioe4ce13e2006-04-02 03:05:08 +0000223 def testGetOnlyIfCachedCacheMiss(self):
224 # Test that can do a GET with no cache with 'only-if-cached'
jcgregorioe4ce13e2006-04-02 03:05:08 +0000225 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorioe202d212009-07-16 14:57:52 -0400226 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
jcgregorioe4ce13e2006-04-02 03:05:08 +0000227 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400228 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000229
230 def testGetOnlyIfCachedNoCacheAtAll(self):
231 # Test that can do a GET with no cache with 'only-if-cached'
232 # Of course, there might be an intermediary beyond us
233 # that responds to the 'only-if-cached', so this
234 # test can't really be guaranteed to pass.
235 http = httplib2.Http()
236 uri = urlparse.urljoin(base, "304/test_etag.txt")
237 (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
238 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400239 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000240
jcgregorio2d66d4f2006-02-07 05:34:14 +0000241 def testUserAgent(self):
242 # Test that we provide a default user-agent
243 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000244 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000245 self.assertEqual(response.status, 200)
246 self.assertTrue(content.startswith("Python-httplib2/"))
247
248 def testUserAgentNonDefault(self):
249 # Test that the default user-agent can be over-ridden
joe.gregoriof28536d2007-10-23 14:10:11 +0000250
jcgregorio2d66d4f2006-02-07 05:34:14 +0000251 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000252 (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000253 self.assertEqual(response.status, 200)
254 self.assertTrue(content.startswith("fred/1.0"))
255
256 def testGet300WithLocation(self):
257 # Test the we automatically follow 300 redirects if a Location: header is provided
258 uri = urlparse.urljoin(base, "300/with-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000259 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000260 self.assertEqual(response.status, 200)
261 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000262 self.assertEqual(response.previous.status, 300)
263 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000264
265 # Confirm that the intermediate 300 is not cached
jcgregorio36140b52006-06-13 02:17:52 +0000266 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000267 self.assertEqual(response.status, 200)
268 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000269 self.assertEqual(response.previous.status, 300)
270 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000271
jcgregorio2f1e1422007-05-03 13:17:33 +0000272 def testGet300WithLocationNoRedirect(self):
273 # Test the we automatically follow 300 redirects if a Location: header is provided
274 self.http.follow_redirects = False
275 uri = urlparse.urljoin(base, "300/with-location-header.asis")
276 (response, content) = self.http.request(uri, "GET")
277 self.assertEqual(response.status, 300)
278
jcgregorio2d66d4f2006-02-07 05:34:14 +0000279 def testGet300WithoutLocation(self):
280 # Not giving a Location: header in a 300 response is acceptable
281 # In which case we just return the 300 response
282 uri = urlparse.urljoin(base, "300/without-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000283 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000284 self.assertEqual(response.status, 300)
285 self.assertTrue(response['content-type'].startswith("text/html"))
jcgregorioa0713ab2006-07-01 05:21:34 +0000286 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000287
288 def testGet301(self):
289 # Test that we automatically follow 301 redirects
290 # and that we cache the 301 response
291 uri = urlparse.urljoin(base, "301/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000292 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000293 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000294 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000295 self.assertTrue(response.has_key('content-location'))
296 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000297 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000298 self.assertEqual(response.previous.status, 301)
299 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000300
jcgregorio36140b52006-06-13 02:17:52 +0000301 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000302 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000303 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000304 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000305 self.assertEqual(response.previous.status, 301)
306 self.assertEqual(response.previous.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000307
jcgregorio2f1e1422007-05-03 13:17:33 +0000308
309 def testGet301NoRedirect(self):
310 # Test that we automatically follow 301 redirects
311 # and that we cache the 301 response
312 self.http.follow_redirects = False
313 uri = urlparse.urljoin(base, "301/onestep.asis")
314 destination = urlparse.urljoin(base, "302/final-destination.txt")
315 (response, content) = self.http.request(uri, "GET")
316 self.assertEqual(response.status, 301)
317
318
jcgregorio2d66d4f2006-02-07 05:34:14 +0000319 def testGet302(self):
320 # Test that we automatically follow 302 redirects
321 # and that we DO NOT cache the 302 response
322 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000323 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000324 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000325 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000326 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000327 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000328 self.assertEqual(response.previous.status, 302)
329 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000330
331 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000332 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000333 self.assertEqual(response.status, 200)
334 self.assertEqual(response.fromcache, True)
jcgregorio772adc82006-11-17 21:52:34 +0000335 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000336 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000337 self.assertEqual(response.previous.status, 302)
338 self.assertEqual(response.previous.fromcache, False)
jcgregorio772adc82006-11-17 21:52:34 +0000339 self.assertEqual(response.previous['content-location'], uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000340
341 uri = urlparse.urljoin(base, "302/twostep.asis")
342
jcgregorio36140b52006-06-13 02:17:52 +0000343 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000344 self.assertEqual(response.status, 200)
345 self.assertEqual(response.fromcache, True)
346 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000347 self.assertEqual(response.previous.status, 302)
348 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000349
350 def testGet302RedirectionLimit(self):
351 # Test that we can set a lower redirection limit
352 # and that we raise an exception when we exceed
353 # that limit.
jcgregorio07a9a4a2007-03-08 21:18:39 +0000354 self.http.force_exception_to_status_code = False
355
jcgregorio2d66d4f2006-02-07 05:34:14 +0000356 uri = urlparse.urljoin(base, "302/twostep.asis")
357 try:
jcgregorio36140b52006-06-13 02:17:52 +0000358 (response, content) = self.http.request(uri, "GET", redirections = 1)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000359 self.fail("This should not happen")
360 except httplib2.RedirectLimit:
361 pass
362 except Exception, e:
363 self.fail("Threw wrong kind of exception ")
364
jcgregorio07a9a4a2007-03-08 21:18:39 +0000365 # Re-run the test with out the exceptions
366 self.http.force_exception_to_status_code = True
367
368 (response, content) = self.http.request(uri, "GET", redirections = 1)
369 self.assertEqual(response.status, 500)
370 self.assertTrue(response.reason.startswith("Redirected more"))
371 self.assertEqual("302", response['status'])
372 self.assertTrue(content.startswith("<html>"))
373 self.assertTrue(response.previous != None)
374
jcgregorio2d66d4f2006-02-07 05:34:14 +0000375 def testGet302NoLocation(self):
376 # Test that we throw an exception when we get
377 # a 302 with no Location: header.
jcgregorio07a9a4a2007-03-08 21:18:39 +0000378 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000379 uri = urlparse.urljoin(base, "302/no-location.asis")
380 try:
jcgregorio36140b52006-06-13 02:17:52 +0000381 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000382 self.fail("Should never reach here")
383 except httplib2.RedirectMissingLocation:
384 pass
385 except Exception, e:
386 self.fail("Threw wrong kind of exception ")
387
jcgregorio07a9a4a2007-03-08 21:18:39 +0000388 # Re-run the test with out the exceptions
389 self.http.force_exception_to_status_code = True
390
391 (response, content) = self.http.request(uri, "GET")
392 self.assertEqual(response.status, 500)
393 self.assertTrue(response.reason.startswith("Redirected but"))
394 self.assertEqual("302", response['status'])
395 self.assertTrue(content.startswith("This is content"))
396
jcgregorio2d66d4f2006-02-07 05:34:14 +0000397 def testGet302ViaHttps(self):
jcgregorioadbb4f82006-05-19 15:17:42 +0000398 # Google always redirects to http://google.com
jcgregorio36140b52006-06-13 02:17:52 +0000399 (response, content) = self.http.request("https://google.com", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000400 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000401 self.assertEqual(302, response.previous.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000402
403 def testGetViaHttps(self):
404 # Test that we can handle HTTPS
jcgregorio36140b52006-06-13 02:17:52 +0000405 (response, content) = self.http.request("https://google.com/adsense/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000406 self.assertEqual(200, response.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000407
408 def testGetViaHttpsSpecViolationOnLocation(self):
409 # Test that we follow redirects through HTTPS
410 # even if they violate the spec by including
411 # a relative Location: header instead of an
412 # absolute one.
jcgregorio36140b52006-06-13 02:17:52 +0000413 (response, content) = self.http.request("https://google.com/adsense", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000414 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000415 self.assertNotEqual(None, response.previous)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000416
jcgregoriode8238d2007-03-07 19:08:26 +0000417
418 def testGetViaHttpsKeyCert(self):
jcgregorio2f1e1422007-05-03 13:17:33 +0000419 # At this point I can only test
420 # that the key and cert files are passed in
421 # correctly to httplib. It would be nice to have
422 # a real https endpoint to test against.
423 http = httplib2.Http(timeout=2)
jcgregoriode8238d2007-03-07 19:08:26 +0000424
425 http.add_certificate("akeyfile", "acertfile", "bitworking.org")
426 try:
427 (response, content) = http.request("https://bitworking.org", "GET")
428 except:
429 pass
430 self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
431 self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
432
jcgregorio2f1e1422007-05-03 13:17:33 +0000433 try:
434 (response, content) = http.request("https://notthere.bitworking.org", "GET")
435 except:
436 pass
437 self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
438 self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
439
440
441
jcgregoriode8238d2007-03-07 19:08:26 +0000442
jcgregorio2d66d4f2006-02-07 05:34:14 +0000443 def testGet303(self):
444 # Do a follow-up GET on a Location: header
445 # returned from a POST that gave a 303.
446 uri = urlparse.urljoin(base, "303/303.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000447 (response, content) = self.http.request(uri, "POST", " ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000448 self.assertEqual(response.status, 200)
449 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000450 self.assertEqual(response.previous.status, 303)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000451
jcgregorio2f1e1422007-05-03 13:17:33 +0000452 def testGet303NoRedirect(self):
453 # Do a follow-up GET on a Location: header
454 # returned from a POST that gave a 303.
455 self.http.follow_redirects = False
456 uri = urlparse.urljoin(base, "303/303.cgi")
457 (response, content) = self.http.request(uri, "POST", " ")
458 self.assertEqual(response.status, 303)
459
jcgregorio2d66d4f2006-02-07 05:34:14 +0000460 def test303ForDifferentMethods(self):
461 # Test that all methods can be used
462 uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000463 for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
jcgregorio36140b52006-06-13 02:17:52 +0000464 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000465 self.assertEqual(response['x-method'], method_on_303)
466
467 def testGet304(self):
468 # Test that we use ETags properly to validate our cache
469 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000470 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000471 self.assertNotEqual(response['etag'], "")
472
jcgregorio36140b52006-06-13 02:17:52 +0000473 (response, content) = self.http.request(uri, "GET")
474 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000475 self.assertEqual(response.status, 200)
476 self.assertEqual(response.fromcache, True)
477
jcgregorio90fb4a42006-11-17 16:19:47 +0000478 cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
479 f = open(cache_file_name, "r")
480 status_line = f.readline()
481 f.close()
482
483 self.assertTrue(status_line.startswith("status:"))
484
jcgregorio36140b52006-06-13 02:17:52 +0000485 (response, content) = self.http.request(uri, "HEAD")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000486 self.assertEqual(response.status, 200)
487 self.assertEqual(response.fromcache, True)
488
jcgregorio36140b52006-06-13 02:17:52 +0000489 (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000490 self.assertEqual(response.status, 206)
491 self.assertEqual(response.fromcache, False)
492
jcgregorio25185622006-10-28 05:12:34 +0000493 def testGetIgnoreEtag(self):
494 # Test that we can forcibly ignore ETags
495 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
496 (response, content) = self.http.request(uri, "GET")
497 self.assertNotEqual(response['etag'], "")
498
499 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
500 d = self.reflector(content)
501 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
502
503 self.http.ignore_etag = True
504 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
505 d = self.reflector(content)
506 self.assertEqual(response.fromcache, False)
507 self.assertFalse(d.has_key('HTTP_IF_NONE_MATCH'))
508
jcgregorio4b145e82007-01-18 19:46:34 +0000509 def testOverrideEtag(self):
510 # Test that we can forcibly ignore ETags
511 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
512 (response, content) = self.http.request(uri, "GET")
513 self.assertNotEqual(response['etag'], "")
514
515 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
516 d = self.reflector(content)
517 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
518 self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
519
pilgrim00a352e2009-05-29 04:04:44 +0000520 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0', 'if-none-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +0000521 d = self.reflector(content)
522 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
523 self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio25185622006-10-28 05:12:34 +0000524
pilgrim00a352e2009-05-29 04:04:44 +0000525#MAP-commented this out because it consistently fails
526# def testGet304EndToEnd(self):
527# # Test that end to end headers get overwritten in the cache
528# uri = urlparse.urljoin(base, "304/end2end.cgi")
529# (response, content) = self.http.request(uri, "GET")
530# self.assertNotEqual(response['etag'], "")
531# old_date = response['date']
532# time.sleep(2)
533#
534# (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
535# # The response should be from the cache, but the Date: header should be updated.
536# new_date = response['date']
537# self.assertNotEqual(new_date, old_date)
538# self.assertEqual(response.status, 200)
539# self.assertEqual(response.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000540
541 def testGet304LastModified(self):
542 # Test that we can still handle a 304
543 # by only using the last-modified cache validator.
544 uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000545 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000546
547 self.assertNotEqual(response['last-modified'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000548 (response, content) = self.http.request(uri, "GET")
549 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000550 self.assertEqual(response.status, 200)
551 self.assertEqual(response.fromcache, True)
552
553 def testGet307(self):
554 # Test that we do follow 307 redirects but
555 # do not cache the 307
556 uri = urlparse.urljoin(base, "307/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000557 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000558 self.assertEqual(response.status, 200)
559 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000560 self.assertEqual(response.previous.status, 307)
561 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000562
jcgregorio36140b52006-06-13 02:17:52 +0000563 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000564 self.assertEqual(response.status, 200)
565 self.assertEqual(response.fromcache, True)
566 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000567 self.assertEqual(response.previous.status, 307)
568 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000569
570 def testGet410(self):
571 # Test that we pass 410's through
572 uri = urlparse.urljoin(base, "410/410.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000573 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000574 self.assertEqual(response.status, 410)
575
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000576 def testHeadGZip(self):
577 # Test that we don't try to decompress a HEAD response
578 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
579 (response, content) = self.http.request(uri, "HEAD")
580 self.assertEqual(response.status, 200)
581 self.assertNotEqual(int(response['content-length']), 0)
582 self.assertEqual(content, "")
583
jcgregorio2d66d4f2006-02-07 05:34:14 +0000584 def testGetGZip(self):
585 # Test that we support gzip compression
586 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000587 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000588 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000589 self.assertFalse(response.has_key('content-encoding'))
joe.gregorio8b6d2312007-12-16 05:42:07 +0000590 self.assertTrue(response.has_key('-content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000591 self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000592 self.assertEqual(content, "This is the final destination.\n")
593
594 def testGetGZipFailure(self):
595 # Test that we raise a good exception when the gzip fails
jcgregorio07a9a4a2007-03-08 21:18:39 +0000596 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000597 uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
598 try:
jcgregorio36140b52006-06-13 02:17:52 +0000599 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000600 self.fail("Should never reach here")
601 except httplib2.FailedToDecompressContent:
602 pass
603 except Exception:
604 self.fail("Threw wrong kind of exception")
605
jcgregorio07a9a4a2007-03-08 21:18:39 +0000606 # Re-run the test with out the exceptions
607 self.http.force_exception_to_status_code = True
608
609 (response, content) = self.http.request(uri, "GET")
610 self.assertEqual(response.status, 500)
611 self.assertTrue(response.reason.startswith("Content purported"))
612
613 def testTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000614 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000615 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
616 try:
617 import socket
618 socket.setdefaulttimeout(1)
619 except:
620 # Don't run the test if we can't set the timeout
621 return
622 (response, content) = self.http.request(uri)
623 self.assertEqual(response.status, 408)
624 self.assertTrue(response.reason.startswith("Request Timeout"))
625 self.assertTrue(content.startswith("Request Timeout"))
626
jcgregoriob2697912007-03-09 02:23:47 +0000627 def testIndividualTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000628 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
629 http = httplib2.Http(timeout=1)
joe.gregoriof28536d2007-10-23 14:10:11 +0000630 http.force_exception_to_status_code = True
jcgregoriob2697912007-03-09 02:23:47 +0000631
632 (response, content) = http.request(uri)
633 self.assertEqual(response.status, 408)
634 self.assertTrue(response.reason.startswith("Request Timeout"))
635 self.assertTrue(content.startswith("Request Timeout"))
636
jcgregorio07a9a4a2007-03-08 21:18:39 +0000637
Joe Gregorio1a7609f2009-07-16 10:59:44 -0400638 def testHTTPSInitTimeout(self):
639 c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
640 self.assertEqual(47, c.timeout)
641
jcgregorio2d66d4f2006-02-07 05:34:14 +0000642 def testGetDeflate(self):
643 # Test that we support deflate compression
644 uri = urlparse.urljoin(base, "deflate/deflated.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000645 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000646 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000647 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000648 self.assertEqual(int(response['content-length']), len("This is the final destination."))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000649 self.assertEqual(content, "This is the final destination.")
650
651 def testGetDeflateFailure(self):
652 # Test that we raise a good exception when the deflate fails
jcgregorio07a9a4a2007-03-08 21:18:39 +0000653 self.http.force_exception_to_status_code = False
654
jcgregorio2d66d4f2006-02-07 05:34:14 +0000655 uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
656 try:
jcgregorio36140b52006-06-13 02:17:52 +0000657 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000658 self.fail("Should never reach here")
659 except httplib2.FailedToDecompressContent:
660 pass
661 except Exception:
662 self.fail("Threw wrong kind of exception")
663
jcgregorio07a9a4a2007-03-08 21:18:39 +0000664 # Re-run the test with out the exceptions
665 self.http.force_exception_to_status_code = True
666
667 (response, content) = self.http.request(uri, "GET")
668 self.assertEqual(response.status, 500)
669 self.assertTrue(response.reason.startswith("Content purported"))
670
jcgregorio2d66d4f2006-02-07 05:34:14 +0000671 def testGetDuplicateHeaders(self):
672 # Test that duplicate headers get concatenated via ','
673 uri = urlparse.urljoin(base, "duplicate-headers/multilink.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 content\n")
677 self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
678
679 def testGetCacheControlNoCache(self):
680 # Test Cache-Control: no-cache on requests
681 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000682 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000683 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000684 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000685 self.assertEqual(response.status, 200)
686 self.assertEqual(response.fromcache, True)
687
jcgregorio36140b52006-06-13 02:17:52 +0000688 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000689 self.assertEqual(response.status, 200)
690 self.assertEqual(response.fromcache, False)
691
692 def testGetCacheControlPragmaNoCache(self):
693 # Test Pragma: no-cache on requests
694 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000695 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000696 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000697 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000698 self.assertEqual(response.status, 200)
699 self.assertEqual(response.fromcache, True)
700
jcgregorio36140b52006-06-13 02:17:52 +0000701 (response, content) = self.http.request(uri, "GET", headers={'Pragma': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000702 self.assertEqual(response.status, 200)
703 self.assertEqual(response.fromcache, False)
704
705 def testGetCacheControlNoStoreRequest(self):
706 # A no-store request means that the response should not be stored.
707 uri = urlparse.urljoin(base, "304/test_etag.txt")
708
jcgregorio36140b52006-06-13 02:17:52 +0000709 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000710 self.assertEqual(response.status, 200)
711 self.assertEqual(response.fromcache, False)
712
jcgregorio36140b52006-06-13 02:17:52 +0000713 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000714 self.assertEqual(response.status, 200)
715 self.assertEqual(response.fromcache, False)
716
717 def testGetCacheControlNoStoreResponse(self):
718 # A no-store response means that the response should not be stored.
719 uri = urlparse.urljoin(base, "no-store/no-store.asis")
720
jcgregorio36140b52006-06-13 02:17:52 +0000721 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000722 self.assertEqual(response.status, 200)
723 self.assertEqual(response.fromcache, False)
724
jcgregorio36140b52006-06-13 02:17:52 +0000725 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000726 self.assertEqual(response.status, 200)
727 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000728
729 def testGetCacheControlNoCacheNoStoreRequest(self):
730 # Test that a no-store, no-cache clears the entry from the cache
731 # even if it was cached previously.
732 uri = urlparse.urljoin(base, "304/test_etag.txt")
733
jcgregorio36140b52006-06-13 02:17:52 +0000734 (response, content) = self.http.request(uri, "GET")
735 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000736 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000737 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
738 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000739 self.assertEqual(response.status, 200)
740 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000741
742 def testUpdateInvalidatesCache(self):
743 # Test that calling PUT or DELETE on a
744 # URI that is cache invalidates that cache.
745 uri = urlparse.urljoin(base, "304/test_etag.txt")
746
jcgregorio36140b52006-06-13 02:17:52 +0000747 (response, content) = self.http.request(uri, "GET")
748 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000749 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000750 (response, content) = self.http.request(uri, "DELETE")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000751 self.assertEqual(response.status, 405)
752
jcgregorio36140b52006-06-13 02:17:52 +0000753 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000754 self.assertEqual(response.fromcache, False)
755
756 def testUpdateUsesCachedETag(self):
757 # Test that we natively support http://www.w3.org/1999/04/Editing/
758 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
759
jcgregorio36140b52006-06-13 02:17:52 +0000760 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000761 self.assertEqual(response.status, 200)
762 self.assertEqual(response.fromcache, False)
jcgregorio36140b52006-06-13 02:17:52 +0000763 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000764 self.assertEqual(response.status, 200)
765 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000766 (response, content) = self.http.request(uri, "PUT")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000767 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +0000768 (response, content) = self.http.request(uri, "PUT")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000769 self.assertEqual(response.status, 412)
770
joe.gregorio700f04d2008-09-06 04:46:32 +0000771 def testUpdateUsesCachedETagAndOCMethod(self):
772 # Test that we natively support http://www.w3.org/1999/04/Editing/
773 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
774
775 (response, content) = self.http.request(uri, "GET")
776 self.assertEqual(response.status, 200)
777 self.assertEqual(response.fromcache, False)
778 (response, content) = self.http.request(uri, "GET")
779 self.assertEqual(response.status, 200)
780 self.assertEqual(response.fromcache, True)
781 self.http.optimistic_concurrency_methods.append("DELETE")
782 (response, content) = self.http.request(uri, "DELETE")
783 self.assertEqual(response.status, 200)
784
785
jcgregorio4b145e82007-01-18 19:46:34 +0000786 def testUpdateUsesCachedETagOverridden(self):
787 # Test that we natively support http://www.w3.org/1999/04/Editing/
788 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
789
790 (response, content) = self.http.request(uri, "GET")
791 self.assertEqual(response.status, 200)
792 self.assertEqual(response.fromcache, False)
793 (response, content) = self.http.request(uri, "GET")
794 self.assertEqual(response.status, 200)
795 self.assertEqual(response.fromcache, True)
796 (response, content) = self.http.request(uri, "PUT", headers={'if-match': 'fred'})
797 self.assertEqual(response.status, 412)
798
jcgregorio2d66d4f2006-02-07 05:34:14 +0000799 def testBasicAuth(self):
800 # Test Basic Authentication
801 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000802 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000803 self.assertEqual(response.status, 401)
804
805 uri = urlparse.urljoin(base, "basic/")
jcgregorio36140b52006-06-13 02:17:52 +0000806 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000807 self.assertEqual(response.status, 401)
808
jcgregorio36140b52006-06-13 02:17:52 +0000809 self.http.add_credentials('joe', 'password')
810 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000811 self.assertEqual(response.status, 200)
812
813 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000814 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000815 self.assertEqual(response.status, 200)
816
jcgregoriode8238d2007-03-07 19:08:26 +0000817 def testBasicAuthWithDomain(self):
818 # Test Basic Authentication
819 uri = urlparse.urljoin(base, "basic/file.txt")
820 (response, content) = self.http.request(uri, "GET")
821 self.assertEqual(response.status, 401)
822
823 uri = urlparse.urljoin(base, "basic/")
824 (response, content) = self.http.request(uri, "GET")
825 self.assertEqual(response.status, 401)
826
827 self.http.add_credentials('joe', 'password', "example.org")
828 (response, content) = self.http.request(uri, "GET")
829 self.assertEqual(response.status, 401)
830
831 uri = urlparse.urljoin(base, "basic/file.txt")
832 (response, content) = self.http.request(uri, "GET")
833 self.assertEqual(response.status, 401)
834
835 domain = urlparse.urlparse(base)[1]
836 self.http.add_credentials('joe', 'password', domain)
837 (response, content) = self.http.request(uri, "GET")
838 self.assertEqual(response.status, 200)
839
840 uri = urlparse.urljoin(base, "basic/file.txt")
841 (response, content) = self.http.request(uri, "GET")
842 self.assertEqual(response.status, 200)
843
844
845
846
847
848
jcgregorio2d66d4f2006-02-07 05:34:14 +0000849 def testBasicAuthTwoDifferentCredentials(self):
jcgregorioadbb4f82006-05-19 15:17:42 +0000850 # Test Basic Authentication with multiple sets of credentials
jcgregorio2d66d4f2006-02-07 05:34:14 +0000851 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000852 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000853 self.assertEqual(response.status, 401)
854
855 uri = urlparse.urljoin(base, "basic2/")
jcgregorio36140b52006-06-13 02:17:52 +0000856 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000857 self.assertEqual(response.status, 401)
858
jcgregorio36140b52006-06-13 02:17:52 +0000859 self.http.add_credentials('fred', 'barney')
860 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000861 self.assertEqual(response.status, 200)
862
863 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000864 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000865 self.assertEqual(response.status, 200)
866
867 def testBasicAuthNested(self):
868 # Test Basic Authentication with resources
869 # that are nested
870 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +0000871 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000872 self.assertEqual(response.status, 401)
873
874 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +0000875 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000876 self.assertEqual(response.status, 401)
877
jcgregorioadbb4f82006-05-19 15:17:42 +0000878 # Now add in credentials one at a time and test.
jcgregorio36140b52006-06-13 02:17:52 +0000879 self.http.add_credentials('joe', 'password')
jcgregorio2d66d4f2006-02-07 05:34:14 +0000880
881 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +0000882 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000883 self.assertEqual(response.status, 200)
884
885 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +0000886 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000887 self.assertEqual(response.status, 401)
888
jcgregorio36140b52006-06-13 02:17:52 +0000889 self.http.add_credentials('fred', 'barney')
jcgregorio2d66d4f2006-02-07 05:34:14 +0000890
891 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +0000892 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000893 self.assertEqual(response.status, 200)
894
895 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +0000896 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000897 self.assertEqual(response.status, 200)
898
899 def testDigestAuth(self):
900 # Test that we support Digest Authentication
901 uri = urlparse.urljoin(base, "digest/")
jcgregorio36140b52006-06-13 02:17:52 +0000902 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000903 self.assertEqual(response.status, 401)
904
jcgregorio36140b52006-06-13 02:17:52 +0000905 self.http.add_credentials('joe', 'password')
906 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000907 self.assertEqual(response.status, 200)
908
909 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000910 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000911
912 def testDigestAuthNextNonceAndNC(self):
913 # Test that if the server sets nextnonce that we reset
914 # the nonce count back to 1
915 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000916 self.http.add_credentials('joe', 'password')
917 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000918 info = httplib2._parse_www_authenticate(response, 'authentication-info')
919 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +0000920 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000921 info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
922 self.assertEqual(response.status, 200)
923
924 if info.has_key('nextnonce'):
925 self.assertEqual(info2['nc'], 1)
926
927 def testDigestAuthStale(self):
928 # Test that we can handle a nonce becoming stale
929 uri = urlparse.urljoin(base, "digest-expire/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000930 self.http.add_credentials('joe', 'password')
931 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000932 info = httplib2._parse_www_authenticate(response, 'authentication-info')
933 self.assertEqual(response.status, 200)
934
935 time.sleep(3)
936 # Sleep long enough that the nonce becomes stale
937
jcgregorio36140b52006-06-13 02:17:52 +0000938 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000939 self.assertFalse(response.fromcache)
940 self.assertTrue(response._stale_digest)
941 info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
942 self.assertEqual(response.status, 200)
943
944 def reflector(self, content):
jcgregorio25185622006-10-28 05:12:34 +0000945 return dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
jcgregorio2d66d4f2006-02-07 05:34:14 +0000946
947 def testReflector(self):
948 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000949 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000950 d = self.reflector(content)
951 self.assertTrue(d.has_key('HTTP_USER_AGENT'))
952
jcgregorio36140b52006-06-13 02:17:52 +0000953try:
954 import memcache
955 class HttpTestMemCached(HttpTest):
956 def setUp(self):
957 self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
jcgregorio47d24672006-06-29 05:18:59 +0000958 #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
jcgregorio36140b52006-06-13 02:17:52 +0000959 self.http = httplib2.Http(self.cache)
960 self.cache.flush_all()
jcgregorio47d24672006-06-29 05:18:59 +0000961 # Not exactly sure why the sleep is needed here, but
962 # if not present then some unit tests that rely on caching
963 # fail. Memcached seems to lose some sets immediately
964 # after a flush_all if the set is to a value that
965 # was previously cached. (Maybe the flush is handled async?)
966 time.sleep(1)
jcgregorio36140b52006-06-13 02:17:52 +0000967 self.http.clear_credentials()
968except:
969 pass
970
971
972
jcgregoriodb8dfc82006-03-31 14:59:46 +0000973# ------------------------------------------------------------------------
jcgregorio2d66d4f2006-02-07 05:34:14 +0000974
975class HttpPrivateTest(unittest.TestCase):
976
977 def testParseCacheControl(self):
978 # Test that we can parse the Cache-Control header
979 self.assertEqual({}, httplib2._parse_cache_control({}))
980 self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
981 cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
982 self.assertEqual(cc['no-cache'], 1)
983 self.assertEqual(cc['max-age'], '7200')
984 cc = httplib2._parse_cache_control({'cache-control': ' , '})
985 self.assertEqual(cc[''], 1)
986
987 def testNormalizeHeaders(self):
988 # Test that we normalize headers to lowercase
989 h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
990 self.assertTrue(h.has_key('cache-control'))
991 self.assertTrue(h.has_key('other'))
992 self.assertEqual('Stuff', h['other'])
993
994 def testExpirationModelTransparent(self):
995 # Test that no-cache makes our request TRANSPARENT
996 response_headers = {
997 'cache-control': 'max-age=7200'
998 }
999 request_headers = {
1000 'cache-control': 'no-cache'
1001 }
1002 self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
1003
jcgregorio45865012007-01-18 16:38:22 +00001004 def testMaxAgeNonNumeric(self):
1005 # Test that no-cache makes our request TRANSPARENT
1006 response_headers = {
1007 'cache-control': 'max-age=fred, min-fresh=barney'
1008 }
1009 request_headers = {
1010 }
1011 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1012
1013
jcgregorio2d66d4f2006-02-07 05:34:14 +00001014 def testExpirationModelNoCacheResponse(self):
1015 # The date and expires point to an entry that should be
1016 # FRESH, but the no-cache over-rides that.
1017 now = time.time()
1018 response_headers = {
1019 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1020 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1021 'cache-control': 'no-cache'
1022 }
1023 request_headers = {
1024 }
1025 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1026
1027 def testExpirationModelStaleRequestMustReval(self):
1028 # must-revalidate forces STALE
1029 self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
1030
1031 def testExpirationModelStaleResponseMustReval(self):
1032 # must-revalidate forces STALE
1033 self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
1034
1035 def testExpirationModelFresh(self):
1036 response_headers = {
1037 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1038 'cache-control': 'max-age=2'
1039 }
1040 request_headers = {
1041 }
1042 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1043 time.sleep(3)
1044 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1045
1046 def testExpirationMaxAge0(self):
1047 response_headers = {
1048 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1049 'cache-control': 'max-age=0'
1050 }
1051 request_headers = {
1052 }
1053 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1054
1055 def testExpirationModelDateAndExpires(self):
1056 now = time.time()
1057 response_headers = {
1058 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1059 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1060 }
1061 request_headers = {
1062 }
1063 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1064 time.sleep(3)
1065 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1066
jcgregoriof9511052007-06-01 14:56:34 +00001067 def testExpiresZero(self):
1068 now = time.time()
1069 response_headers = {
1070 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1071 'expires': "0",
1072 }
1073 request_headers = {
1074 }
1075 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1076
jcgregorio2d66d4f2006-02-07 05:34:14 +00001077 def testExpirationModelDateOnly(self):
1078 now = time.time()
1079 response_headers = {
1080 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
1081 }
1082 request_headers = {
1083 }
1084 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1085
1086 def testExpirationModelOnlyIfCached(self):
1087 response_headers = {
1088 }
1089 request_headers = {
1090 'cache-control': 'only-if-cached',
1091 }
1092 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1093
1094 def testExpirationModelMaxAgeBoth(self):
1095 now = time.time()
1096 response_headers = {
1097 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1098 'cache-control': 'max-age=2'
1099 }
1100 request_headers = {
1101 'cache-control': 'max-age=0'
1102 }
1103 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1104
1105 def testExpirationModelDateAndExpiresMinFresh1(self):
1106 now = time.time()
1107 response_headers = {
1108 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1109 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1110 }
1111 request_headers = {
1112 'cache-control': 'min-fresh=2'
1113 }
1114 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1115
1116 def testExpirationModelDateAndExpiresMinFresh2(self):
1117 now = time.time()
1118 response_headers = {
1119 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1120 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1121 }
1122 request_headers = {
1123 'cache-control': 'min-fresh=2'
1124 }
1125 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1126
1127 def testParseWWWAuthenticateEmpty(self):
1128 res = httplib2._parse_www_authenticate({})
1129 self.assertEqual(len(res.keys()), 0)
1130
jcgregoriofd22e432006-04-27 02:00:08 +00001131 def testParseWWWAuthenticate(self):
1132 # different uses of spaces around commas
1133 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
1134 self.assertEqual(len(res.keys()), 1)
1135 self.assertEqual(len(res['test'].keys()), 5)
1136
1137 # tokens with non-alphanum
1138 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
1139 self.assertEqual(len(res.keys()), 1)
1140 self.assertEqual(len(res['t*!%#st'].keys()), 2)
1141
1142 # quoted string with quoted pairs
1143 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
1144 self.assertEqual(len(res.keys()), 1)
1145 self.assertEqual(res['test']['realm'], 'a "test" realm')
1146
1147 def testParseWWWAuthenticateStrict(self):
1148 httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
1149 self.testParseWWWAuthenticate();
1150 httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
1151
jcgregorio2d66d4f2006-02-07 05:34:14 +00001152 def testParseWWWAuthenticateBasic(self):
1153 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
1154 basic = res['basic']
1155 self.assertEqual('me', basic['realm'])
1156
1157 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
1158 basic = res['basic']
1159 self.assertEqual('me', basic['realm'])
1160 self.assertEqual('MD5', basic['algorithm'])
1161
1162 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
1163 basic = res['basic']
1164 self.assertEqual('me', basic['realm'])
1165 self.assertEqual('MD5', basic['algorithm'])
1166
1167 def testParseWWWAuthenticateBasic2(self):
1168 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
1169 basic = res['basic']
1170 self.assertEqual('me', basic['realm'])
1171 self.assertEqual('fred', basic['other'])
1172
1173 def testParseWWWAuthenticateBasic3(self):
1174 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
1175 basic = res['basic']
1176 self.assertEqual('me', basic['realm'])
1177
1178
1179 def testParseWWWAuthenticateDigest(self):
1180 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1181 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
1182 digest = res['digest']
1183 self.assertEqual('testrealm@host.com', digest['realm'])
1184 self.assertEqual('auth,auth-int', digest['qop'])
1185
1186
1187 def testParseWWWAuthenticateMultiple(self):
1188 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1189 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
1190 digest = res['digest']
1191 self.assertEqual('testrealm@host.com', digest['realm'])
1192 self.assertEqual('auth,auth-int', digest['qop'])
1193 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1194 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1195 basic = res['basic']
1196 self.assertEqual('me', basic['realm'])
1197
1198 def testParseWWWAuthenticateMultiple2(self):
1199 # Handle an added comma between challenges, which might get thrown in if the challenges were
1200 # originally sent in separate www-authenticate headers.
1201 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1202 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
1203 digest = res['digest']
1204 self.assertEqual('testrealm@host.com', digest['realm'])
1205 self.assertEqual('auth,auth-int', digest['qop'])
1206 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1207 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1208 basic = res['basic']
1209 self.assertEqual('me', basic['realm'])
1210
1211 def testParseWWWAuthenticateMultiple3(self):
1212 # Handle an added comma between challenges, which might get thrown in if the challenges were
1213 # originally sent in separate www-authenticate headers.
1214 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1215 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1216 digest = res['digest']
1217 self.assertEqual('testrealm@host.com', digest['realm'])
1218 self.assertEqual('auth,auth-int', digest['qop'])
1219 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1220 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1221 basic = res['basic']
1222 self.assertEqual('me', basic['realm'])
1223 wsse = res['wsse']
1224 self.assertEqual('foo', wsse['realm'])
1225 self.assertEqual('UsernameToken', wsse['profile'])
1226
1227 def testParseWWWAuthenticateMultiple4(self):
1228 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1229 'Digest realm="test-real.m@host.com", qop \t=\t"\tauth,auth-int", nonce="(*)&^&$%#",opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1230 digest = res['digest']
1231 self.assertEqual('test-real.m@host.com', digest['realm'])
1232 self.assertEqual('\tauth,auth-int', digest['qop'])
1233 self.assertEqual('(*)&^&$%#', digest['nonce'])
1234
1235 def testParseWWWAuthenticateMoreQuoteCombos(self):
1236 res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
1237 digest = res['digest']
1238 self.assertEqual('myrealm', digest['realm'])
1239
1240 def testDigestObject(self):
1241 credentials = ('joe', 'password')
1242 host = None
1243 request_uri = '/projects/httplib2/test/digest/'
1244 headers = {}
1245 response = {
1246 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
1247 }
1248 content = ""
1249
jcgregorio6cbab7e2006-04-21 20:35:43 +00001250 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001251 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
1252 our_request = "Authorization: %s" % headers['Authorization']
1253 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"'
1254 self.assertEqual(our_request, working_request)
1255
1256
1257 def testDigestObjectStale(self):
1258 credentials = ('joe', 'password')
1259 host = None
1260 request_uri = '/projects/httplib2/test/digest/'
1261 headers = {}
1262 response = httplib2.Response({ })
1263 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1264 response.status = 401
1265 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001266 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001267 # Returns true to force a retry
1268 self.assertTrue( d.response(response, content) )
1269
1270 def testDigestObjectAuthInfo(self):
1271 credentials = ('joe', 'password')
1272 host = None
1273 request_uri = '/projects/httplib2/test/digest/'
1274 headers = {}
1275 response = httplib2.Response({ })
1276 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1277 response['authentication-info'] = 'nextnonce="fred"'
1278 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001279 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001280 # Returns true to force a retry
1281 self.assertFalse( d.response(response, content) )
1282 self.assertEqual('fred', d.challenge['nonce'])
1283 self.assertEqual(1, d.challenge['nc'])
1284
1285 def testWsseAlgorithm(self):
1286 digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
1287 expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
1288 self.assertEqual(expected, digest)
1289
jcgregoriodb8dfc82006-03-31 14:59:46 +00001290 def testEnd2End(self):
1291 # one end to end header
1292 response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
1293 end2end = httplib2._get_end2end_headers(response)
1294 self.assertTrue('content-type' in end2end)
1295 self.assertTrue('te' not in end2end)
1296 self.assertTrue('connection' not in end2end)
1297
1298 # one end to end header that gets eliminated
1299 response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
1300 end2end = httplib2._get_end2end_headers(response)
1301 self.assertTrue('content-type' not in end2end)
1302 self.assertTrue('te' not in end2end)
1303 self.assertTrue('connection' not in end2end)
1304
1305 # Degenerate case of no headers
1306 response = {}
1307 end2end = httplib2._get_end2end_headers(response)
1308 self.assertEquals(0, len(end2end))
1309
1310 # Degenerate case of connection referrring to a header not passed in
1311 response = {'connection': 'content-type'}
1312 end2end = httplib2._get_end2end_headers(response)
1313 self.assertEquals(0, len(end2end))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001314
1315unittest.main()