blob: 2afb575a86b566184ed8c80cbe11bc8d7f2247a2 [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
190 def testGetNoCache(self):
191 # Test that can do a GET w/o the cache turned on.
192 http = httplib2.Http()
193 uri = urlparse.urljoin(base, "304/test_etag.txt")
194 (response, content) = http.request(uri, "GET")
195 self.assertEqual(response.status, 200)
jcgregorioa0713ab2006-07-01 05:21:34 +0000196 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000197
jcgregorioe4ce13e2006-04-02 03:05:08 +0000198 def testGetOnlyIfCachedCacheMiss(self):
199 # Test that can do a GET with no cache with 'only-if-cached'
jcgregorio36140b52006-06-13 02:17:52 +0000200 http = httplib2.Http()
jcgregorioe4ce13e2006-04-02 03:05:08 +0000201 uri = urlparse.urljoin(base, "304/test_etag.txt")
202 (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
203 self.assertEqual(response.fromcache, False)
jcgregorio36140b52006-06-13 02:17:52 +0000204 self.assertEqual(response.status, 200)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000205
206 def testGetOnlyIfCachedNoCacheAtAll(self):
207 # Test that can do a GET with no cache with 'only-if-cached'
208 # Of course, there might be an intermediary beyond us
209 # that responds to the 'only-if-cached', so this
210 # test can't really be guaranteed to pass.
211 http = httplib2.Http()
212 uri = urlparse.urljoin(base, "304/test_etag.txt")
213 (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
214 self.assertEqual(response.fromcache, False)
215 self.assertEqual(response.status, 200)
216
jcgregorio2d66d4f2006-02-07 05:34:14 +0000217 def testUserAgent(self):
218 # Test that we provide a default user-agent
219 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000220 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000221 self.assertEqual(response.status, 200)
222 self.assertTrue(content.startswith("Python-httplib2/"))
223
224 def testUserAgentNonDefault(self):
225 # Test that the default user-agent can be over-ridden
joe.gregoriof28536d2007-10-23 14:10:11 +0000226
jcgregorio2d66d4f2006-02-07 05:34:14 +0000227 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000228 (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000229 self.assertEqual(response.status, 200)
230 self.assertTrue(content.startswith("fred/1.0"))
231
232 def testGet300WithLocation(self):
233 # Test the we automatically follow 300 redirects if a Location: header is provided
234 uri = urlparse.urljoin(base, "300/with-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000235 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000236 self.assertEqual(response.status, 200)
237 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000238 self.assertEqual(response.previous.status, 300)
239 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000240
241 # Confirm that the intermediate 300 is not cached
jcgregorio36140b52006-06-13 02:17:52 +0000242 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000243 self.assertEqual(response.status, 200)
244 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000245 self.assertEqual(response.previous.status, 300)
246 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000247
jcgregorio2f1e1422007-05-03 13:17:33 +0000248 def testGet300WithLocationNoRedirect(self):
249 # Test the we automatically follow 300 redirects if a Location: header is provided
250 self.http.follow_redirects = False
251 uri = urlparse.urljoin(base, "300/with-location-header.asis")
252 (response, content) = self.http.request(uri, "GET")
253 self.assertEqual(response.status, 300)
254
jcgregorio2d66d4f2006-02-07 05:34:14 +0000255 def testGet300WithoutLocation(self):
256 # Not giving a Location: header in a 300 response is acceptable
257 # In which case we just return the 300 response
258 uri = urlparse.urljoin(base, "300/without-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, 300)
261 self.assertTrue(response['content-type'].startswith("text/html"))
jcgregorioa0713ab2006-07-01 05:21:34 +0000262 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000263
264 def testGet301(self):
265 # Test that we automatically follow 301 redirects
266 # and that we cache the 301 response
267 uri = urlparse.urljoin(base, "301/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000268 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000269 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000270 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000271 self.assertTrue(response.has_key('content-location'))
272 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000273 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000274 self.assertEqual(response.previous.status, 301)
275 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000276
jcgregorio36140b52006-06-13 02:17:52 +0000277 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000278 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000279 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000280 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000281 self.assertEqual(response.previous.status, 301)
282 self.assertEqual(response.previous.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000283
jcgregorio2f1e1422007-05-03 13:17:33 +0000284
285 def testGet301NoRedirect(self):
286 # Test that we automatically follow 301 redirects
287 # and that we cache the 301 response
288 self.http.follow_redirects = False
289 uri = urlparse.urljoin(base, "301/onestep.asis")
290 destination = urlparse.urljoin(base, "302/final-destination.txt")
291 (response, content) = self.http.request(uri, "GET")
292 self.assertEqual(response.status, 301)
293
294
jcgregorio2d66d4f2006-02-07 05:34:14 +0000295 def testGet302(self):
296 # Test that we automatically follow 302 redirects
297 # and that we DO NOT cache the 302 response
298 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000299 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000300 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000301 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000302 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000303 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000304 self.assertEqual(response.previous.status, 302)
305 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000306
307 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000308 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000309 self.assertEqual(response.status, 200)
310 self.assertEqual(response.fromcache, True)
jcgregorio772adc82006-11-17 21:52:34 +0000311 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000312 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000313 self.assertEqual(response.previous.status, 302)
314 self.assertEqual(response.previous.fromcache, False)
jcgregorio772adc82006-11-17 21:52:34 +0000315 self.assertEqual(response.previous['content-location'], uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000316
317 uri = urlparse.urljoin(base, "302/twostep.asis")
318
jcgregorio36140b52006-06-13 02:17:52 +0000319 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000320 self.assertEqual(response.status, 200)
321 self.assertEqual(response.fromcache, True)
322 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000323 self.assertEqual(response.previous.status, 302)
324 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000325
326 def testGet302RedirectionLimit(self):
327 # Test that we can set a lower redirection limit
328 # and that we raise an exception when we exceed
329 # that limit.
jcgregorio07a9a4a2007-03-08 21:18:39 +0000330 self.http.force_exception_to_status_code = False
331
jcgregorio2d66d4f2006-02-07 05:34:14 +0000332 uri = urlparse.urljoin(base, "302/twostep.asis")
333 try:
jcgregorio36140b52006-06-13 02:17:52 +0000334 (response, content) = self.http.request(uri, "GET", redirections = 1)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000335 self.fail("This should not happen")
336 except httplib2.RedirectLimit:
337 pass
338 except Exception, e:
339 self.fail("Threw wrong kind of exception ")
340
jcgregorio07a9a4a2007-03-08 21:18:39 +0000341 # Re-run the test with out the exceptions
342 self.http.force_exception_to_status_code = True
343
344 (response, content) = self.http.request(uri, "GET", redirections = 1)
345 self.assertEqual(response.status, 500)
346 self.assertTrue(response.reason.startswith("Redirected more"))
347 self.assertEqual("302", response['status'])
348 self.assertTrue(content.startswith("<html>"))
349 self.assertTrue(response.previous != None)
350
jcgregorio2d66d4f2006-02-07 05:34:14 +0000351 def testGet302NoLocation(self):
352 # Test that we throw an exception when we get
353 # a 302 with no Location: header.
jcgregorio07a9a4a2007-03-08 21:18:39 +0000354 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000355 uri = urlparse.urljoin(base, "302/no-location.asis")
356 try:
jcgregorio36140b52006-06-13 02:17:52 +0000357 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000358 self.fail("Should never reach here")
359 except httplib2.RedirectMissingLocation:
360 pass
361 except Exception, e:
362 self.fail("Threw wrong kind of exception ")
363
jcgregorio07a9a4a2007-03-08 21:18:39 +0000364 # Re-run the test with out the exceptions
365 self.http.force_exception_to_status_code = True
366
367 (response, content) = self.http.request(uri, "GET")
368 self.assertEqual(response.status, 500)
369 self.assertTrue(response.reason.startswith("Redirected but"))
370 self.assertEqual("302", response['status'])
371 self.assertTrue(content.startswith("This is content"))
372
jcgregorio2d66d4f2006-02-07 05:34:14 +0000373 def testGet302ViaHttps(self):
jcgregorioadbb4f82006-05-19 15:17:42 +0000374 # Google always redirects to http://google.com
jcgregorio36140b52006-06-13 02:17:52 +0000375 (response, content) = self.http.request("https://google.com", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000376 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000377 self.assertEqual(302, response.previous.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000378
379 def testGetViaHttps(self):
380 # Test that we can handle HTTPS
jcgregorio36140b52006-06-13 02:17:52 +0000381 (response, content) = self.http.request("https://google.com/adsense/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000382 self.assertEqual(200, response.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000383
384 def testGetViaHttpsSpecViolationOnLocation(self):
385 # Test that we follow redirects through HTTPS
386 # even if they violate the spec by including
387 # a relative Location: header instead of an
388 # absolute one.
jcgregorio36140b52006-06-13 02:17:52 +0000389 (response, content) = self.http.request("https://google.com/adsense", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000390 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000391 self.assertNotEqual(None, response.previous)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000392
jcgregoriode8238d2007-03-07 19:08:26 +0000393
394 def testGetViaHttpsKeyCert(self):
jcgregorio2f1e1422007-05-03 13:17:33 +0000395 # At this point I can only test
396 # that the key and cert files are passed in
397 # correctly to httplib. It would be nice to have
398 # a real https endpoint to test against.
399 http = httplib2.Http(timeout=2)
jcgregoriode8238d2007-03-07 19:08:26 +0000400
401 http.add_certificate("akeyfile", "acertfile", "bitworking.org")
402 try:
403 (response, content) = http.request("https://bitworking.org", "GET")
404 except:
405 pass
406 self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
407 self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
408
jcgregorio2f1e1422007-05-03 13:17:33 +0000409 try:
410 (response, content) = http.request("https://notthere.bitworking.org", "GET")
411 except:
412 pass
413 self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
414 self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
415
416
417
jcgregoriode8238d2007-03-07 19:08:26 +0000418
jcgregorio2d66d4f2006-02-07 05:34:14 +0000419 def testGet303(self):
420 # Do a follow-up GET on a Location: header
421 # returned from a POST that gave a 303.
422 uri = urlparse.urljoin(base, "303/303.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000423 (response, content) = self.http.request(uri, "POST", " ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000424 self.assertEqual(response.status, 200)
425 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000426 self.assertEqual(response.previous.status, 303)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000427
jcgregorio2f1e1422007-05-03 13:17:33 +0000428 def testGet303NoRedirect(self):
429 # Do a follow-up GET on a Location: header
430 # returned from a POST that gave a 303.
431 self.http.follow_redirects = False
432 uri = urlparse.urljoin(base, "303/303.cgi")
433 (response, content) = self.http.request(uri, "POST", " ")
434 self.assertEqual(response.status, 303)
435
jcgregorio2d66d4f2006-02-07 05:34:14 +0000436 def test303ForDifferentMethods(self):
437 # Test that all methods can be used
438 uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000439 for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
jcgregorio36140b52006-06-13 02:17:52 +0000440 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000441 self.assertEqual(response['x-method'], method_on_303)
442
443 def testGet304(self):
444 # Test that we use ETags properly to validate our cache
445 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000446 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000447 self.assertNotEqual(response['etag'], "")
448
jcgregorio36140b52006-06-13 02:17:52 +0000449 (response, content) = self.http.request(uri, "GET")
450 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000451 self.assertEqual(response.status, 200)
452 self.assertEqual(response.fromcache, True)
453
jcgregorio90fb4a42006-11-17 16:19:47 +0000454 cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
455 f = open(cache_file_name, "r")
456 status_line = f.readline()
457 f.close()
458
459 self.assertTrue(status_line.startswith("status:"))
460
jcgregorio36140b52006-06-13 02:17:52 +0000461 (response, content) = self.http.request(uri, "HEAD")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000462 self.assertEqual(response.status, 200)
463 self.assertEqual(response.fromcache, True)
464
jcgregorio36140b52006-06-13 02:17:52 +0000465 (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000466 self.assertEqual(response.status, 206)
467 self.assertEqual(response.fromcache, False)
468
jcgregorio25185622006-10-28 05:12:34 +0000469 def testGetIgnoreEtag(self):
470 # Test that we can forcibly ignore ETags
471 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
472 (response, content) = self.http.request(uri, "GET")
473 self.assertNotEqual(response['etag'], "")
474
475 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
476 d = self.reflector(content)
477 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
478
479 self.http.ignore_etag = True
480 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
481 d = self.reflector(content)
482 self.assertEqual(response.fromcache, False)
483 self.assertFalse(d.has_key('HTTP_IF_NONE_MATCH'))
484
jcgregorio4b145e82007-01-18 19:46:34 +0000485 def testOverrideEtag(self):
486 # Test that we can forcibly ignore ETags
487 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
488 (response, content) = self.http.request(uri, "GET")
489 self.assertNotEqual(response['etag'], "")
490
491 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
492 d = self.reflector(content)
493 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
494 self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
495
496 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0', 'if=none-match': 'fred'})
497 d = self.reflector(content)
498 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
499 self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio25185622006-10-28 05:12:34 +0000500
jcgregorio2d66d4f2006-02-07 05:34:14 +0000501 def testGet304EndToEnd(self):
502 # Test that end to end headers get overwritten in the cache
503 uri = urlparse.urljoin(base, "304/end2end.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000504 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000505 self.assertNotEqual(response['etag'], "")
506 old_date = response['date']
507 time.sleep(2)
508
jcgregorio36140b52006-06-13 02:17:52 +0000509 (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000510 # The response should be from the cache, but the Date: header should be updated.
511 new_date = response['date']
512 self.assertNotEqual(new_date, old_date)
513 self.assertEqual(response.status, 200)
514 self.assertEqual(response.fromcache, True)
515
516 def testGet304LastModified(self):
517 # Test that we can still handle a 304
518 # by only using the last-modified cache validator.
519 uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000520 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000521
522 self.assertNotEqual(response['last-modified'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000523 (response, content) = self.http.request(uri, "GET")
524 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000525 self.assertEqual(response.status, 200)
526 self.assertEqual(response.fromcache, True)
527
528 def testGet307(self):
529 # Test that we do follow 307 redirects but
530 # do not cache the 307
531 uri = urlparse.urljoin(base, "307/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000532 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000533 self.assertEqual(response.status, 200)
534 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000535 self.assertEqual(response.previous.status, 307)
536 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000537
jcgregorio36140b52006-06-13 02:17:52 +0000538 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000539 self.assertEqual(response.status, 200)
540 self.assertEqual(response.fromcache, True)
541 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000542 self.assertEqual(response.previous.status, 307)
543 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000544
545 def testGet410(self):
546 # Test that we pass 410's through
547 uri = urlparse.urljoin(base, "410/410.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000548 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000549 self.assertEqual(response.status, 410)
550
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000551 def testHeadGZip(self):
552 # Test that we don't try to decompress a HEAD response
553 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
554 (response, content) = self.http.request(uri, "HEAD")
555 self.assertEqual(response.status, 200)
556 self.assertNotEqual(int(response['content-length']), 0)
557 self.assertEqual(content, "")
558
jcgregorio2d66d4f2006-02-07 05:34:14 +0000559 def testGetGZip(self):
560 # Test that we support gzip compression
561 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000562 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000563 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000564 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000565 self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000566 self.assertEqual(content, "This is the final destination.\n")
567
568 def testGetGZipFailure(self):
569 # Test that we raise a good exception when the gzip fails
jcgregorio07a9a4a2007-03-08 21:18:39 +0000570 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000571 uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
572 try:
jcgregorio36140b52006-06-13 02:17:52 +0000573 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000574 self.fail("Should never reach here")
575 except httplib2.FailedToDecompressContent:
576 pass
577 except Exception:
578 self.fail("Threw wrong kind of exception")
579
jcgregorio07a9a4a2007-03-08 21:18:39 +0000580 # Re-run the test with out the exceptions
581 self.http.force_exception_to_status_code = True
582
583 (response, content) = self.http.request(uri, "GET")
584 self.assertEqual(response.status, 500)
585 self.assertTrue(response.reason.startswith("Content purported"))
586
587 def testTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000588 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000589 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
590 try:
591 import socket
592 socket.setdefaulttimeout(1)
593 except:
594 # Don't run the test if we can't set the timeout
595 return
596 (response, content) = self.http.request(uri)
597 self.assertEqual(response.status, 408)
598 self.assertTrue(response.reason.startswith("Request Timeout"))
599 self.assertTrue(content.startswith("Request Timeout"))
600
jcgregoriob2697912007-03-09 02:23:47 +0000601 def testIndividualTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000602 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
603 http = httplib2.Http(timeout=1)
joe.gregoriof28536d2007-10-23 14:10:11 +0000604 http.force_exception_to_status_code = True
jcgregoriob2697912007-03-09 02:23:47 +0000605
606 (response, content) = http.request(uri)
607 self.assertEqual(response.status, 408)
608 self.assertTrue(response.reason.startswith("Request Timeout"))
609 self.assertTrue(content.startswith("Request Timeout"))
610
jcgregorio07a9a4a2007-03-08 21:18:39 +0000611
jcgregorio2d66d4f2006-02-07 05:34:14 +0000612 def testGetDeflate(self):
613 # Test that we support deflate compression
614 uri = urlparse.urljoin(base, "deflate/deflated.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000615 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000616 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000617 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000618 self.assertEqual(int(response['content-length']), len("This is the final destination."))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000619 self.assertEqual(content, "This is the final destination.")
620
621 def testGetDeflateFailure(self):
622 # Test that we raise a good exception when the deflate fails
jcgregorio07a9a4a2007-03-08 21:18:39 +0000623 self.http.force_exception_to_status_code = False
624
jcgregorio2d66d4f2006-02-07 05:34:14 +0000625 uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
626 try:
jcgregorio36140b52006-06-13 02:17:52 +0000627 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000628 self.fail("Should never reach here")
629 except httplib2.FailedToDecompressContent:
630 pass
631 except Exception:
632 self.fail("Threw wrong kind of exception")
633
jcgregorio07a9a4a2007-03-08 21:18:39 +0000634 # Re-run the test with out the exceptions
635 self.http.force_exception_to_status_code = True
636
637 (response, content) = self.http.request(uri, "GET")
638 self.assertEqual(response.status, 500)
639 self.assertTrue(response.reason.startswith("Content purported"))
640
jcgregorio2d66d4f2006-02-07 05:34:14 +0000641 def testGetDuplicateHeaders(self):
642 # Test that duplicate headers get concatenated via ','
643 uri = urlparse.urljoin(base, "duplicate-headers/multilink.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000644 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000645 self.assertEqual(response.status, 200)
646 self.assertEqual(content, "This is content\n")
647 self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
648
649 def testGetCacheControlNoCache(self):
650 # Test Cache-Control: no-cache on requests
651 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000652 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000653 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000654 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000655 self.assertEqual(response.status, 200)
656 self.assertEqual(response.fromcache, True)
657
jcgregorio36140b52006-06-13 02:17:52 +0000658 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000659 self.assertEqual(response.status, 200)
660 self.assertEqual(response.fromcache, False)
661
662 def testGetCacheControlPragmaNoCache(self):
663 # Test Pragma: no-cache on requests
664 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000665 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000666 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000667 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000668 self.assertEqual(response.status, 200)
669 self.assertEqual(response.fromcache, True)
670
jcgregorio36140b52006-06-13 02:17:52 +0000671 (response, content) = self.http.request(uri, "GET", headers={'Pragma': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000672 self.assertEqual(response.status, 200)
673 self.assertEqual(response.fromcache, False)
674
675 def testGetCacheControlNoStoreRequest(self):
676 # A no-store request means that the response should not be stored.
677 uri = urlparse.urljoin(base, "304/test_etag.txt")
678
jcgregorio36140b52006-06-13 02:17:52 +0000679 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000680 self.assertEqual(response.status, 200)
681 self.assertEqual(response.fromcache, False)
682
jcgregorio36140b52006-06-13 02:17:52 +0000683 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000684 self.assertEqual(response.status, 200)
685 self.assertEqual(response.fromcache, False)
686
687 def testGetCacheControlNoStoreResponse(self):
688 # A no-store response means that the response should not be stored.
689 uri = urlparse.urljoin(base, "no-store/no-store.asis")
690
jcgregorio36140b52006-06-13 02:17:52 +0000691 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000692 self.assertEqual(response.status, 200)
693 self.assertEqual(response.fromcache, False)
694
jcgregorio36140b52006-06-13 02:17:52 +0000695 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000696 self.assertEqual(response.status, 200)
697 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000698
699 def testGetCacheControlNoCacheNoStoreRequest(self):
700 # Test that a no-store, no-cache clears the entry from the cache
701 # even if it was cached previously.
702 uri = urlparse.urljoin(base, "304/test_etag.txt")
703
jcgregorio36140b52006-06-13 02:17:52 +0000704 (response, content) = self.http.request(uri, "GET")
705 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000706 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000707 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
708 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000709 self.assertEqual(response.status, 200)
710 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000711
712 def testUpdateInvalidatesCache(self):
713 # Test that calling PUT or DELETE on a
714 # URI that is cache invalidates that cache.
715 uri = urlparse.urljoin(base, "304/test_etag.txt")
716
jcgregorio36140b52006-06-13 02:17:52 +0000717 (response, content) = self.http.request(uri, "GET")
718 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000719 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000720 (response, content) = self.http.request(uri, "DELETE")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000721 self.assertEqual(response.status, 405)
722
jcgregorio36140b52006-06-13 02:17:52 +0000723 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000724 self.assertEqual(response.fromcache, False)
725
726 def testUpdateUsesCachedETag(self):
727 # Test that we natively support http://www.w3.org/1999/04/Editing/
728 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
729
jcgregorio36140b52006-06-13 02:17:52 +0000730 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000731 self.assertEqual(response.status, 200)
732 self.assertEqual(response.fromcache, False)
jcgregorio36140b52006-06-13 02:17:52 +0000733 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000734 self.assertEqual(response.status, 200)
735 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000736 (response, content) = self.http.request(uri, "PUT")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000737 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +0000738 (response, content) = self.http.request(uri, "PUT")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000739 self.assertEqual(response.status, 412)
740
jcgregorio4b145e82007-01-18 19:46:34 +0000741 def testUpdateUsesCachedETagOverridden(self):
742 # Test that we natively support http://www.w3.org/1999/04/Editing/
743 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
744
745 (response, content) = self.http.request(uri, "GET")
746 self.assertEqual(response.status, 200)
747 self.assertEqual(response.fromcache, False)
748 (response, content) = self.http.request(uri, "GET")
749 self.assertEqual(response.status, 200)
750 self.assertEqual(response.fromcache, True)
751 (response, content) = self.http.request(uri, "PUT", headers={'if-match': 'fred'})
752 self.assertEqual(response.status, 412)
753
jcgregorio2d66d4f2006-02-07 05:34:14 +0000754 def testBasicAuth(self):
755 # Test Basic Authentication
756 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000757 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000758 self.assertEqual(response.status, 401)
759
760 uri = urlparse.urljoin(base, "basic/")
jcgregorio36140b52006-06-13 02:17:52 +0000761 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000762 self.assertEqual(response.status, 401)
763
jcgregorio36140b52006-06-13 02:17:52 +0000764 self.http.add_credentials('joe', 'password')
765 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000766 self.assertEqual(response.status, 200)
767
768 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000769 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000770 self.assertEqual(response.status, 200)
771
jcgregoriode8238d2007-03-07 19:08:26 +0000772 def testBasicAuthWithDomain(self):
773 # Test Basic Authentication
774 uri = urlparse.urljoin(base, "basic/file.txt")
775 (response, content) = self.http.request(uri, "GET")
776 self.assertEqual(response.status, 401)
777
778 uri = urlparse.urljoin(base, "basic/")
779 (response, content) = self.http.request(uri, "GET")
780 self.assertEqual(response.status, 401)
781
782 self.http.add_credentials('joe', 'password', "example.org")
783 (response, content) = self.http.request(uri, "GET")
784 self.assertEqual(response.status, 401)
785
786 uri = urlparse.urljoin(base, "basic/file.txt")
787 (response, content) = self.http.request(uri, "GET")
788 self.assertEqual(response.status, 401)
789
790 domain = urlparse.urlparse(base)[1]
791 self.http.add_credentials('joe', 'password', domain)
792 (response, content) = self.http.request(uri, "GET")
793 self.assertEqual(response.status, 200)
794
795 uri = urlparse.urljoin(base, "basic/file.txt")
796 (response, content) = self.http.request(uri, "GET")
797 self.assertEqual(response.status, 200)
798
799
800
801
802
803
jcgregorio2d66d4f2006-02-07 05:34:14 +0000804 def testBasicAuthTwoDifferentCredentials(self):
jcgregorioadbb4f82006-05-19 15:17:42 +0000805 # Test Basic Authentication with multiple sets of credentials
jcgregorio2d66d4f2006-02-07 05:34:14 +0000806 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000807 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000808 self.assertEqual(response.status, 401)
809
810 uri = urlparse.urljoin(base, "basic2/")
jcgregorio36140b52006-06-13 02:17:52 +0000811 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000812 self.assertEqual(response.status, 401)
813
jcgregorio36140b52006-06-13 02:17:52 +0000814 self.http.add_credentials('fred', 'barney')
815 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000816 self.assertEqual(response.status, 200)
817
818 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000819 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000820 self.assertEqual(response.status, 200)
821
822 def testBasicAuthNested(self):
823 # Test Basic Authentication with resources
824 # that are nested
825 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +0000826 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000827 self.assertEqual(response.status, 401)
828
829 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +0000830 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000831 self.assertEqual(response.status, 401)
832
jcgregorioadbb4f82006-05-19 15:17:42 +0000833 # Now add in credentials one at a time and test.
jcgregorio36140b52006-06-13 02:17:52 +0000834 self.http.add_credentials('joe', 'password')
jcgregorio2d66d4f2006-02-07 05:34:14 +0000835
836 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +0000837 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000838 self.assertEqual(response.status, 200)
839
840 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +0000841 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000842 self.assertEqual(response.status, 401)
843
jcgregorio36140b52006-06-13 02:17:52 +0000844 self.http.add_credentials('fred', 'barney')
jcgregorio2d66d4f2006-02-07 05:34:14 +0000845
846 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +0000847 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000848 self.assertEqual(response.status, 200)
849
850 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +0000851 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000852 self.assertEqual(response.status, 200)
853
854 def testDigestAuth(self):
855 # Test that we support Digest Authentication
856 uri = urlparse.urljoin(base, "digest/")
jcgregorio36140b52006-06-13 02:17:52 +0000857 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000858 self.assertEqual(response.status, 401)
859
jcgregorio36140b52006-06-13 02:17:52 +0000860 self.http.add_credentials('joe', 'password')
861 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000862 self.assertEqual(response.status, 200)
863
864 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000865 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000866
867 def testDigestAuthNextNonceAndNC(self):
868 # Test that if the server sets nextnonce that we reset
869 # the nonce count back to 1
870 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000871 self.http.add_credentials('joe', 'password')
872 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000873 info = httplib2._parse_www_authenticate(response, 'authentication-info')
874 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +0000875 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000876 info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
877 self.assertEqual(response.status, 200)
878
879 if info.has_key('nextnonce'):
880 self.assertEqual(info2['nc'], 1)
881
882 def testDigestAuthStale(self):
883 # Test that we can handle a nonce becoming stale
884 uri = urlparse.urljoin(base, "digest-expire/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000885 self.http.add_credentials('joe', 'password')
886 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000887 info = httplib2._parse_www_authenticate(response, 'authentication-info')
888 self.assertEqual(response.status, 200)
889
890 time.sleep(3)
891 # Sleep long enough that the nonce becomes stale
892
jcgregorio36140b52006-06-13 02:17:52 +0000893 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000894 self.assertFalse(response.fromcache)
895 self.assertTrue(response._stale_digest)
896 info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
897 self.assertEqual(response.status, 200)
898
899 def reflector(self, content):
jcgregorio25185622006-10-28 05:12:34 +0000900 return dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
jcgregorio2d66d4f2006-02-07 05:34:14 +0000901
902 def testReflector(self):
903 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000904 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000905 d = self.reflector(content)
906 self.assertTrue(d.has_key('HTTP_USER_AGENT'))
907
jcgregorio36140b52006-06-13 02:17:52 +0000908try:
909 import memcache
910 class HttpTestMemCached(HttpTest):
911 def setUp(self):
912 self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
jcgregorio47d24672006-06-29 05:18:59 +0000913 #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
jcgregorio36140b52006-06-13 02:17:52 +0000914 self.http = httplib2.Http(self.cache)
915 self.cache.flush_all()
jcgregorio47d24672006-06-29 05:18:59 +0000916 # Not exactly sure why the sleep is needed here, but
917 # if not present then some unit tests that rely on caching
918 # fail. Memcached seems to lose some sets immediately
919 # after a flush_all if the set is to a value that
920 # was previously cached. (Maybe the flush is handled async?)
921 time.sleep(1)
jcgregorio36140b52006-06-13 02:17:52 +0000922 self.http.clear_credentials()
923except:
924 pass
925
926
927
jcgregoriodb8dfc82006-03-31 14:59:46 +0000928# ------------------------------------------------------------------------
jcgregorio2d66d4f2006-02-07 05:34:14 +0000929
930class HttpPrivateTest(unittest.TestCase):
931
932 def testParseCacheControl(self):
933 # Test that we can parse the Cache-Control header
934 self.assertEqual({}, httplib2._parse_cache_control({}))
935 self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
936 cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
937 self.assertEqual(cc['no-cache'], 1)
938 self.assertEqual(cc['max-age'], '7200')
939 cc = httplib2._parse_cache_control({'cache-control': ' , '})
940 self.assertEqual(cc[''], 1)
941
942 def testNormalizeHeaders(self):
943 # Test that we normalize headers to lowercase
944 h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
945 self.assertTrue(h.has_key('cache-control'))
946 self.assertTrue(h.has_key('other'))
947 self.assertEqual('Stuff', h['other'])
948
949 def testExpirationModelTransparent(self):
950 # Test that no-cache makes our request TRANSPARENT
951 response_headers = {
952 'cache-control': 'max-age=7200'
953 }
954 request_headers = {
955 'cache-control': 'no-cache'
956 }
957 self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
958
jcgregorio45865012007-01-18 16:38:22 +0000959 def testMaxAgeNonNumeric(self):
960 # Test that no-cache makes our request TRANSPARENT
961 response_headers = {
962 'cache-control': 'max-age=fred, min-fresh=barney'
963 }
964 request_headers = {
965 }
966 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
967
968
jcgregorio2d66d4f2006-02-07 05:34:14 +0000969 def testExpirationModelNoCacheResponse(self):
970 # The date and expires point to an entry that should be
971 # FRESH, but the no-cache over-rides that.
972 now = time.time()
973 response_headers = {
974 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
975 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
976 'cache-control': 'no-cache'
977 }
978 request_headers = {
979 }
980 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
981
982 def testExpirationModelStaleRequestMustReval(self):
983 # must-revalidate forces STALE
984 self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
985
986 def testExpirationModelStaleResponseMustReval(self):
987 # must-revalidate forces STALE
988 self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
989
990 def testExpirationModelFresh(self):
991 response_headers = {
992 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
993 'cache-control': 'max-age=2'
994 }
995 request_headers = {
996 }
997 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
998 time.sleep(3)
999 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1000
1001 def testExpirationMaxAge0(self):
1002 response_headers = {
1003 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1004 'cache-control': 'max-age=0'
1005 }
1006 request_headers = {
1007 }
1008 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1009
1010 def testExpirationModelDateAndExpires(self):
1011 now = time.time()
1012 response_headers = {
1013 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1014 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1015 }
1016 request_headers = {
1017 }
1018 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1019 time.sleep(3)
1020 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1021
jcgregoriof9511052007-06-01 14:56:34 +00001022 def testExpiresZero(self):
1023 now = time.time()
1024 response_headers = {
1025 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1026 'expires': "0",
1027 }
1028 request_headers = {
1029 }
1030 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1031
jcgregorio2d66d4f2006-02-07 05:34:14 +00001032 def testExpirationModelDateOnly(self):
1033 now = time.time()
1034 response_headers = {
1035 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
1036 }
1037 request_headers = {
1038 }
1039 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1040
1041 def testExpirationModelOnlyIfCached(self):
1042 response_headers = {
1043 }
1044 request_headers = {
1045 'cache-control': 'only-if-cached',
1046 }
1047 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1048
1049 def testExpirationModelMaxAgeBoth(self):
1050 now = time.time()
1051 response_headers = {
1052 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1053 'cache-control': 'max-age=2'
1054 }
1055 request_headers = {
1056 'cache-control': 'max-age=0'
1057 }
1058 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1059
1060 def testExpirationModelDateAndExpiresMinFresh1(self):
1061 now = time.time()
1062 response_headers = {
1063 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1064 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1065 }
1066 request_headers = {
1067 'cache-control': 'min-fresh=2'
1068 }
1069 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1070
1071 def testExpirationModelDateAndExpiresMinFresh2(self):
1072 now = time.time()
1073 response_headers = {
1074 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1075 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1076 }
1077 request_headers = {
1078 'cache-control': 'min-fresh=2'
1079 }
1080 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1081
1082 def testParseWWWAuthenticateEmpty(self):
1083 res = httplib2._parse_www_authenticate({})
1084 self.assertEqual(len(res.keys()), 0)
1085
jcgregoriofd22e432006-04-27 02:00:08 +00001086 def testParseWWWAuthenticate(self):
1087 # different uses of spaces around commas
1088 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
1089 self.assertEqual(len(res.keys()), 1)
1090 self.assertEqual(len(res['test'].keys()), 5)
1091
1092 # tokens with non-alphanum
1093 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
1094 self.assertEqual(len(res.keys()), 1)
1095 self.assertEqual(len(res['t*!%#st'].keys()), 2)
1096
1097 # quoted string with quoted pairs
1098 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
1099 self.assertEqual(len(res.keys()), 1)
1100 self.assertEqual(res['test']['realm'], 'a "test" realm')
1101
1102 def testParseWWWAuthenticateStrict(self):
1103 httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
1104 self.testParseWWWAuthenticate();
1105 httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
1106
jcgregorio2d66d4f2006-02-07 05:34:14 +00001107 def testParseWWWAuthenticateBasic(self):
1108 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
1109 basic = res['basic']
1110 self.assertEqual('me', basic['realm'])
1111
1112 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
1113 basic = res['basic']
1114 self.assertEqual('me', basic['realm'])
1115 self.assertEqual('MD5', basic['algorithm'])
1116
1117 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
1118 basic = res['basic']
1119 self.assertEqual('me', basic['realm'])
1120 self.assertEqual('MD5', basic['algorithm'])
1121
1122 def testParseWWWAuthenticateBasic2(self):
1123 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
1124 basic = res['basic']
1125 self.assertEqual('me', basic['realm'])
1126 self.assertEqual('fred', basic['other'])
1127
1128 def testParseWWWAuthenticateBasic3(self):
1129 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
1130 basic = res['basic']
1131 self.assertEqual('me', basic['realm'])
1132
1133
1134 def testParseWWWAuthenticateDigest(self):
1135 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1136 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
1137 digest = res['digest']
1138 self.assertEqual('testrealm@host.com', digest['realm'])
1139 self.assertEqual('auth,auth-int', digest['qop'])
1140
1141
1142 def testParseWWWAuthenticateMultiple(self):
1143 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1144 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
1145 digest = res['digest']
1146 self.assertEqual('testrealm@host.com', digest['realm'])
1147 self.assertEqual('auth,auth-int', digest['qop'])
1148 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1149 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1150 basic = res['basic']
1151 self.assertEqual('me', basic['realm'])
1152
1153 def testParseWWWAuthenticateMultiple2(self):
1154 # Handle an added comma between challenges, which might get thrown in if the challenges were
1155 # originally sent in separate www-authenticate headers.
1156 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1157 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
1158 digest = res['digest']
1159 self.assertEqual('testrealm@host.com', digest['realm'])
1160 self.assertEqual('auth,auth-int', digest['qop'])
1161 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1162 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1163 basic = res['basic']
1164 self.assertEqual('me', basic['realm'])
1165
1166 def testParseWWWAuthenticateMultiple3(self):
1167 # Handle an added comma between challenges, which might get thrown in if the challenges were
1168 # originally sent in separate www-authenticate headers.
1169 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1170 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1171 digest = res['digest']
1172 self.assertEqual('testrealm@host.com', digest['realm'])
1173 self.assertEqual('auth,auth-int', digest['qop'])
1174 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1175 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1176 basic = res['basic']
1177 self.assertEqual('me', basic['realm'])
1178 wsse = res['wsse']
1179 self.assertEqual('foo', wsse['realm'])
1180 self.assertEqual('UsernameToken', wsse['profile'])
1181
1182 def testParseWWWAuthenticateMultiple4(self):
1183 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1184 'Digest realm="test-real.m@host.com", qop \t=\t"\tauth,auth-int", nonce="(*)&^&$%#",opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1185 digest = res['digest']
1186 self.assertEqual('test-real.m@host.com', digest['realm'])
1187 self.assertEqual('\tauth,auth-int', digest['qop'])
1188 self.assertEqual('(*)&^&$%#', digest['nonce'])
1189
1190 def testParseWWWAuthenticateMoreQuoteCombos(self):
1191 res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
1192 digest = res['digest']
1193 self.assertEqual('myrealm', digest['realm'])
1194
1195 def testDigestObject(self):
1196 credentials = ('joe', 'password')
1197 host = None
1198 request_uri = '/projects/httplib2/test/digest/'
1199 headers = {}
1200 response = {
1201 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
1202 }
1203 content = ""
1204
jcgregorio6cbab7e2006-04-21 20:35:43 +00001205 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001206 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
1207 our_request = "Authorization: %s" % headers['Authorization']
1208 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"'
1209 self.assertEqual(our_request, working_request)
1210
1211
1212 def testDigestObjectStale(self):
1213 credentials = ('joe', 'password')
1214 host = None
1215 request_uri = '/projects/httplib2/test/digest/'
1216 headers = {}
1217 response = httplib2.Response({ })
1218 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1219 response.status = 401
1220 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001221 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001222 # Returns true to force a retry
1223 self.assertTrue( d.response(response, content) )
1224
1225 def testDigestObjectAuthInfo(self):
1226 credentials = ('joe', 'password')
1227 host = None
1228 request_uri = '/projects/httplib2/test/digest/'
1229 headers = {}
1230 response = httplib2.Response({ })
1231 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1232 response['authentication-info'] = 'nextnonce="fred"'
1233 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001234 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001235 # Returns true to force a retry
1236 self.assertFalse( d.response(response, content) )
1237 self.assertEqual('fred', d.challenge['nonce'])
1238 self.assertEqual(1, d.challenge['nc'])
1239
1240 def testWsseAlgorithm(self):
1241 digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
1242 expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
1243 self.assertEqual(expected, digest)
1244
jcgregoriodb8dfc82006-03-31 14:59:46 +00001245 def testEnd2End(self):
1246 # one end to end header
1247 response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
1248 end2end = httplib2._get_end2end_headers(response)
1249 self.assertTrue('content-type' in end2end)
1250 self.assertTrue('te' not in end2end)
1251 self.assertTrue('connection' not in end2end)
1252
1253 # one end to end header that gets eliminated
1254 response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
1255 end2end = httplib2._get_end2end_headers(response)
1256 self.assertTrue('content-type' not in end2end)
1257 self.assertTrue('te' not in end2end)
1258 self.assertTrue('connection' not in end2end)
1259
1260 # Degenerate case of no headers
1261 response = {}
1262 end2end = httplib2._get_end2end_headers(response)
1263 self.assertEquals(0, len(end2end))
1264
1265 # Degenerate case of connection referrring to a header not passed in
1266 response = {'connection': 'content-type'}
1267 end2end = httplib2._get_end2end_headers(response)
1268 self.assertEquals(0, len(end2end))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001269
1270unittest.main()