blob: 2a8df7519b3a28090b43f3fe5e23c9ba887c765c [file] [log] [blame]
jcgregorio2d66d4f2006-02-07 05:34:14 +00001#!/usr/bin/env python2.4
2"""
3httplib2test
4
5A set of unit tests for httplib2.py.
6
7Requires Python 2.4 or later
8"""
9
10__author__ = "Joe Gregorio (joe@bitworking.org)"
11__copyright__ = "Copyright 2006, Joe Gregorio"
12__contributors__ = []
13__license__ = "MIT"
14__history__ = """ """
15__version__ = "0.1 ($Rev: 118 $)"
16
17
Joe Gregoriob6c90c42011-02-11 01:03:22 -050018import StringIO
19import base64
jcgregoriode8238d2007-03-07 19:08:26 +000020import httplib
21import httplib2
22import os
Joe Gregoriob6c90c42011-02-11 01:03:22 -050023import socket
24import sys
jcgregoriode8238d2007-03-07 19:08:26 +000025import time
Joe Gregoriob6c90c42011-02-11 01:03:22 -050026import unittest
27import urlparse
jcgregorio8421f272006-02-14 18:19:51 +000028
Joe Gregoriob53de9b2011-06-07 15:44:51 -040029try:
30 import ssl
31except ImportError:
32 pass
Joe Gregorio694a8122011-02-13 21:40:09 -050033
jcgregorio8421f272006-02-14 18:19:51 +000034# Python 2.3 support
35if not hasattr(unittest.TestCase, 'assertTrue'):
36 unittest.TestCase.assertTrue = unittest.TestCase.failUnless
37 unittest.TestCase.assertFalse = unittest.TestCase.failIf
38
jcgregorio2d66d4f2006-02-07 05:34:14 +000039# The test resources base uri
40base = 'http://bitworking.org/projects/httplib2/test/'
41#base = 'http://localhost/projects/httplib2/test/'
jcgregorio90fb4a42006-11-17 16:19:47 +000042cacheDirName = ".cache"
jcgregorio2d66d4f2006-02-07 05:34:14 +000043
jcgregoriode8238d2007-03-07 19:08:26 +000044
45class CredentialsTest(unittest.TestCase):
46 def test(self):
47 c = httplib2.Credentials()
48 c.add("joe", "password")
49 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
50 self.assertEqual(("joe", "password"), list(c.iter(""))[0])
51 c.add("fred", "password2", "wellformedweb.org")
52 self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
53 self.assertEqual(1, len(list(c.iter("bitworking.org"))))
54 self.assertEqual(2, len(list(c.iter("wellformedweb.org"))))
55 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
56 c.clear()
57 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
58 c.add("fred", "password2", "wellformedweb.org")
59 self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
60 self.assertEqual(0, len(list(c.iter("bitworking.org"))))
61 self.assertEqual(0, len(list(c.iter(""))))
62
63
jcgregorio2d66d4f2006-02-07 05:34:14 +000064class ParserTest(unittest.TestCase):
65 def testFromStd66(self):
66 self.assertEqual( ('http', 'example.com', '', None, None ), httplib2.parse_uri("http://example.com"))
67 self.assertEqual( ('https', 'example.com', '', None, None ), httplib2.parse_uri("https://example.com"))
68 self.assertEqual( ('https', 'example.com:8080', '', None, None ), httplib2.parse_uri("https://example.com:8080"))
69 self.assertEqual( ('http', 'example.com', '/', None, None ), httplib2.parse_uri("http://example.com/"))
70 self.assertEqual( ('http', 'example.com', '/path', None, None ), httplib2.parse_uri("http://example.com/path"))
71 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', None ), httplib2.parse_uri("http://example.com/path?a=1&b=2"))
72 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
73 self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
74
jcgregorio2d66d4f2006-02-07 05:34:14 +000075
jcgregorioa46fe4e2006-11-16 04:13:45 +000076class UrlNormTest(unittest.TestCase):
77 def test(self):
78 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://example.org")[-1])
79 self.assertEqual( "http://example.org/", httplib2.urlnorm("http://EXAMple.org")[-1])
80 self.assertEqual( "http://example.org/?=b", httplib2.urlnorm("http://EXAMple.org?=b")[-1])
81 self.assertEqual( "http://example.org/mypath?a=b", httplib2.urlnorm("http://EXAMple.org/mypath?a=b")[-1])
82 self.assertEqual( "http://localhost:80/", httplib2.urlnorm("http://localhost:80")[-1])
jcgregoriob4e9ab02006-11-17 15:53:15 +000083 self.assertEqual( httplib2.urlnorm("http://localhost:80/"), httplib2.urlnorm("HTTP://LOCALHOST:80"))
jcgregorio132d28e2007-01-23 16:22:53 +000084 try:
85 httplib2.urlnorm("/")
86 self.fail("Non-absolute URIs should raise an exception")
87 except httplib2.RelativeURIError:
88 pass
jcgregorioa46fe4e2006-11-16 04:13:45 +000089
90class UrlSafenameTest(unittest.TestCase):
91 def test(self):
92 # Test that different URIs end up generating different safe names
93 self.assertEqual( "example.org,fred,a=b,58489f63a7a83c3b7794a6a398ee8b1f", httplib2.safename("http://example.org/fred/?a=b"))
94 self.assertEqual( "example.org,fred,a=b,8c5946d56fec453071f43329ff0be46b", httplib2.safename("http://example.org/fred?/a=b"))
95 self.assertEqual( "www.example.org,fred,a=b,499c44b8d844a011b67ea2c015116968", httplib2.safename("http://www.example.org/fred?/a=b"))
96 self.assertEqual( httplib2.safename(httplib2.urlnorm("http://www")[-1]), httplib2.safename(httplib2.urlnorm("http://WWW")[-1]))
97 self.assertEqual( "www.example.org,fred,a=b,692e843a333484ce0095b070497ab45d", httplib2.safename("https://www.example.org/fred?/a=b"))
98 self.assertNotEqual( httplib2.safename("http://www"), httplib2.safename("https://www"))
99 # Test the max length limits
100 uri = "http://" + ("w" * 200) + ".org"
101 uri2 = "http://" + ("w" * 201) + ".org"
102 self.assertNotEqual( httplib2.safename(uri2), httplib2.safename(uri))
103 # Max length should be 200 + 1 (",") + 32
104 self.assertEqual(233, len(httplib2.safename(uri2)))
105 self.assertEqual(233, len(httplib2.safename(uri)))
106 # Unicode
jcgregoriodebceec2006-12-12 20:26:02 +0000107 if sys.version_info >= (2,3):
108 self.assertEqual( "xn--http,-4y1d.org,fred,a=b,579924c35db315e5a32e3d9963388193", httplib2.safename(u"http://\u2304.org/fred/?a=b"))
jcgregorioa46fe4e2006-11-16 04:13:45 +0000109
jcgregorio14644372007-07-30 14:13:37 +0000110class _MyResponse(StringIO.StringIO):
111 def __init__(self, body, **kwargs):
112 StringIO.StringIO.__init__(self, body)
113 self.headers = kwargs
114
115 def iteritems(self):
116 return self.headers.iteritems()
117
118
119class _MyHTTPConnection(object):
120 "This class is just a mock of httplib.HTTPConnection used for testing"
121
122 def __init__(self, host, port=None, key_file=None, cert_file=None,
joe.gregoriof28536d2007-10-23 14:10:11 +0000123 strict=None, timeout=None, proxy_info=None):
jcgregorio14644372007-07-30 14:13:37 +0000124 self.host = host
125 self.port = port
126 self.timeout = timeout
127 self.log = ""
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400128 self.sock = None
jcgregorio14644372007-07-30 14:13:37 +0000129
130 def set_debuglevel(self, level):
131 pass
132
133 def connect(self):
134 "Connect to a host on a given port."
135 pass
136
137 def close(self):
138 pass
139
140 def request(self, method, request_uri, body, headers):
141 pass
142
143 def getresponse(self):
144 return _MyResponse("the body", status="200")
jcgregorioa46fe4e2006-11-16 04:13:45 +0000145
jcgregorio90fb4a42006-11-17 16:19:47 +0000146
jcgregorio2d66d4f2006-02-07 05:34:14 +0000147class HttpTest(unittest.TestCase):
148 def setUp(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400149 if os.path.exists(cacheDirName):
jcgregorio7e3608f2006-06-15 13:01:53 +0000150 [os.remove(os.path.join(cacheDirName, file)) for file in os.listdir(cacheDirName)]
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400151
152 if sys.version_info < (2, 6):
153 disable_cert_validation = True
154 else:
155 disable_cert_validation = False
156 self.http = httplib2.Http(
157 cacheDirName,
158 disable_ssl_certificate_validation=disable_cert_validation)
jcgregorio36140b52006-06-13 02:17:52 +0000159 self.http.clear_credentials()
jcgregorio2d66d4f2006-02-07 05:34:14 +0000160
Joe Gregoriof3ee17b2011-02-13 11:59:51 -0500161 def testIPv6NoSSL(self):
162 try:
163 self.http.request("http://[::1]/")
164 except socket.gaierror:
165 self.fail("should get the address family right for IPv6")
166 except socket.error:
167 # Even if IPv6 isn't installed on a machine it should just raise socket.error
168 pass
169
170 def testIPv6SSL(self):
171 try:
172 self.http.request("https://[::1]/")
173 except socket.gaierror:
174 self.fail("should get the address family right for IPv6")
175 except socket.error:
176 # Even if IPv6 isn't installed on a machine it should just raise socket.error
177 pass
178
jcgregorio14644372007-07-30 14:13:37 +0000179 def testConnectionType(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400180 self.http.force_exception_to_status_code = False
jcgregorio14644372007-07-30 14:13:37 +0000181 response, content = self.http.request("http://bitworking.org", connection_type=_MyHTTPConnection)
182 self.assertEqual(response['content-location'], "http://bitworking.org")
183 self.assertEqual(content, "the body")
184
jcgregorio6a638172007-01-23 16:40:23 +0000185 def testGetUnknownServer(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400186 self.http.force_exception_to_status_code = False
jcgregorio6a638172007-01-23 16:40:23 +0000187 try:
188 self.http.request("http://fred.bitworking.org/")
189 self.fail("An httplib2.ServerNotFoundError Exception must be thrown on an unresolvable server.")
190 except httplib2.ServerNotFoundError:
191 pass
192
jcgregorio07a9a4a2007-03-08 21:18:39 +0000193 # Now test with exceptions turned off
194 self.http.force_exception_to_status_code = True
195
196 (response, content) = self.http.request("http://fred.bitworking.org/")
197 self.assertEqual(response['content-type'], 'text/plain')
198 self.assertTrue(content.startswith("Unable to find"))
199 self.assertEqual(response.status, 400)
200
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500201 def testGetConnectionRefused(self):
202 self.http.force_exception_to_status_code = False
203 try:
204 self.http.request("http://localhost:7777/")
205 self.fail("An socket.error exception must be thrown on Connection Refused.")
206 except socket.error:
207 pass
208
209 # Now test with exceptions turned off
210 self.http.force_exception_to_status_code = True
211
212 (response, content) = self.http.request("http://localhost:7777/")
213 self.assertEqual(response['content-type'], 'text/plain')
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400214 self.assertTrue("Connection refused" in content
215 or "actively refused" in content,
216 "Unexpected status %(content)s" % vars())
Joe Gregoriob6c90c42011-02-11 01:03:22 -0500217 self.assertEqual(response.status, 400)
218
jcgregorioa898f8f2006-12-12 17:16:55 +0000219 def testGetIRI(self):
jcgregoriodebceec2006-12-12 20:26:02 +0000220 if sys.version_info >= (2,3):
221 uri = urlparse.urljoin(base, u"reflector/reflector.cgi?d=\N{CYRILLIC CAPITAL LETTER DJE}")
222 (response, content) = self.http.request(uri, "GET")
223 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400224 self.assertTrue(d.has_key('QUERY_STRING'))
225 self.assertTrue(d['QUERY_STRING'].find('%D0%82') > 0)
226
jcgregorio2d66d4f2006-02-07 05:34:14 +0000227 def testGetIsDefaultMethod(self):
228 # Test that GET is the default method
229 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000230 (response, content) = self.http.request(uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000231 self.assertEqual(response['x-method'], "GET")
232
233 def testDifferentMethods(self):
234 # Test that all methods can be used
235 uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
236 for method in ["GET", "PUT", "DELETE", "POST"]:
jcgregorio36140b52006-06-13 02:17:52 +0000237 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000238 self.assertEqual(response['x-method'], method)
239
Joe Gregoriob628c0b2009-07-16 12:28:04 -0400240 def testHeadRead(self):
241 # Test that we don't try to read the response of a HEAD request
242 # since httplib blocks response.read() for HEAD requests.
243 # Oddly enough this doesn't appear as a problem when doing HEAD requests
244 # against Apache servers.
245 uri = "http://www.google.com/"
246 (response, content) = self.http.request(uri, "HEAD")
247 self.assertEqual(response.status, 200)
248 self.assertEqual(content, "")
249
jcgregorio2d66d4f2006-02-07 05:34:14 +0000250 def testGetNoCache(self):
251 # Test that can do a GET w/o the cache turned on.
252 http = httplib2.Http()
253 uri = urlparse.urljoin(base, "304/test_etag.txt")
254 (response, content) = http.request(uri, "GET")
255 self.assertEqual(response.status, 200)
jcgregorioa0713ab2006-07-01 05:21:34 +0000256 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000257
Joe Gregorioe202d212009-07-16 14:57:52 -0400258 def testGetOnlyIfCachedCacheHit(self):
259 # Test that can do a GET with cache and 'only-if-cached'
260 uri = urlparse.urljoin(base, "304/test_etag.txt")
261 (response, content) = self.http.request(uri, "GET")
262 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
263 self.assertEqual(response.fromcache, True)
264 self.assertEqual(response.status, 200)
265
jcgregorioe4ce13e2006-04-02 03:05:08 +0000266 def testGetOnlyIfCachedCacheMiss(self):
267 # Test that can do a GET with no cache with 'only-if-cached'
jcgregorioe4ce13e2006-04-02 03:05:08 +0000268 uri = urlparse.urljoin(base, "304/test_etag.txt")
Joe Gregorioe202d212009-07-16 14:57:52 -0400269 (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
jcgregorioe4ce13e2006-04-02 03:05:08 +0000270 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400271 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000272
273 def testGetOnlyIfCachedNoCacheAtAll(self):
274 # Test that can do a GET with no cache with 'only-if-cached'
275 # Of course, there might be an intermediary beyond us
276 # that responds to the 'only-if-cached', so this
277 # test can't really be guaranteed to pass.
278 http = httplib2.Http()
279 uri = urlparse.urljoin(base, "304/test_etag.txt")
280 (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
281 self.assertEqual(response.fromcache, False)
Joe Gregorioe202d212009-07-16 14:57:52 -0400282 self.assertEqual(response.status, 504)
jcgregorioe4ce13e2006-04-02 03:05:08 +0000283
jcgregorio2d66d4f2006-02-07 05:34:14 +0000284 def testUserAgent(self):
285 # Test that we provide a default user-agent
286 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000287 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000288 self.assertEqual(response.status, 200)
289 self.assertTrue(content.startswith("Python-httplib2/"))
290
291 def testUserAgentNonDefault(self):
292 # Test that the default user-agent can be over-ridden
joe.gregoriof28536d2007-10-23 14:10:11 +0000293
jcgregorio2d66d4f2006-02-07 05:34:14 +0000294 uri = urlparse.urljoin(base, "user-agent/test.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000295 (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000296 self.assertEqual(response.status, 200)
297 self.assertTrue(content.startswith("fred/1.0"))
298
299 def testGet300WithLocation(self):
300 # Test the we automatically follow 300 redirects if a Location: header is provided
301 uri = urlparse.urljoin(base, "300/with-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000302 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000303 self.assertEqual(response.status, 200)
304 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000305 self.assertEqual(response.previous.status, 300)
306 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000307
308 # Confirm that the intermediate 300 is not cached
jcgregorio36140b52006-06-13 02:17:52 +0000309 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000310 self.assertEqual(response.status, 200)
311 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000312 self.assertEqual(response.previous.status, 300)
313 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000314
jcgregorio2f1e1422007-05-03 13:17:33 +0000315 def testGet300WithLocationNoRedirect(self):
316 # Test the we automatically follow 300 redirects if a Location: header is provided
317 self.http.follow_redirects = False
318 uri = urlparse.urljoin(base, "300/with-location-header.asis")
319 (response, content) = self.http.request(uri, "GET")
320 self.assertEqual(response.status, 300)
321
jcgregorio2d66d4f2006-02-07 05:34:14 +0000322 def testGet300WithoutLocation(self):
323 # Not giving a Location: header in a 300 response is acceptable
324 # In which case we just return the 300 response
325 uri = urlparse.urljoin(base, "300/without-location-header.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000326 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000327 self.assertEqual(response.status, 300)
328 self.assertTrue(response['content-type'].startswith("text/html"))
jcgregorioa0713ab2006-07-01 05:21:34 +0000329 self.assertEqual(response.previous, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000330
331 def testGet301(self):
332 # Test that we automatically follow 301 redirects
333 # and that we cache the 301 response
334 uri = urlparse.urljoin(base, "301/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000335 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000336 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000337 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000338 self.assertTrue(response.has_key('content-location'))
339 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000340 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000341 self.assertEqual(response.previous.status, 301)
342 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000343
jcgregorio36140b52006-06-13 02:17:52 +0000344 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000345 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000346 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000347 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000348 self.assertEqual(response.previous.status, 301)
349 self.assertEqual(response.previous.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000350
Joe Gregorio694a8122011-02-13 21:40:09 -0500351 def testHead301(self):
352 # Test that we automatically follow 301 redirects
353 uri = urlparse.urljoin(base, "301/onestep.asis")
354 destination = urlparse.urljoin(base, "302/final-destination.txt")
355 (response, content) = self.http.request(uri, "HEAD")
356 self.assertEqual(response.status, 200)
357 self.assertEqual(response.previous.status, 301)
358 self.assertEqual(response.previous.fromcache, False)
jcgregorio2f1e1422007-05-03 13:17:33 +0000359
360 def testGet301NoRedirect(self):
361 # Test that we automatically follow 301 redirects
362 # and that we cache the 301 response
363 self.http.follow_redirects = False
364 uri = urlparse.urljoin(base, "301/onestep.asis")
365 destination = urlparse.urljoin(base, "302/final-destination.txt")
366 (response, content) = self.http.request(uri, "GET")
367 self.assertEqual(response.status, 301)
368
369
jcgregorio2d66d4f2006-02-07 05:34:14 +0000370 def testGet302(self):
371 # Test that we automatically follow 302 redirects
372 # and that we DO NOT cache the 302 response
373 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio8e300b92006-11-07 16:44:35 +0000374 destination = urlparse.urljoin(base, "302/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000375 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000376 self.assertEqual(response.status, 200)
jcgregorio772adc82006-11-17 21:52:34 +0000377 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000378 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000379 self.assertEqual(response.previous.status, 302)
380 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000381
382 uri = urlparse.urljoin(base, "302/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000383 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000384 self.assertEqual(response.status, 200)
385 self.assertEqual(response.fromcache, True)
jcgregorio772adc82006-11-17 21:52:34 +0000386 self.assertEqual(response['content-location'], destination)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000387 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000388 self.assertEqual(response.previous.status, 302)
389 self.assertEqual(response.previous.fromcache, False)
jcgregorio772adc82006-11-17 21:52:34 +0000390 self.assertEqual(response.previous['content-location'], uri)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000391
392 uri = urlparse.urljoin(base, "302/twostep.asis")
393
jcgregorio36140b52006-06-13 02:17:52 +0000394 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000395 self.assertEqual(response.status, 200)
396 self.assertEqual(response.fromcache, True)
397 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000398 self.assertEqual(response.previous.status, 302)
399 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000400
401 def testGet302RedirectionLimit(self):
402 # Test that we can set a lower redirection limit
403 # and that we raise an exception when we exceed
404 # that limit.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400405 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000406
jcgregorio2d66d4f2006-02-07 05:34:14 +0000407 uri = urlparse.urljoin(base, "302/twostep.asis")
408 try:
jcgregorio36140b52006-06-13 02:17:52 +0000409 (response, content) = self.http.request(uri, "GET", redirections = 1)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000410 self.fail("This should not happen")
411 except httplib2.RedirectLimit:
412 pass
413 except Exception, e:
414 self.fail("Threw wrong kind of exception ")
415
jcgregorio07a9a4a2007-03-08 21:18:39 +0000416 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400417 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000418
419 (response, content) = self.http.request(uri, "GET", redirections = 1)
420 self.assertEqual(response.status, 500)
421 self.assertTrue(response.reason.startswith("Redirected more"))
422 self.assertEqual("302", response['status'])
423 self.assertTrue(content.startswith("<html>"))
424 self.assertTrue(response.previous != None)
425
jcgregorio2d66d4f2006-02-07 05:34:14 +0000426 def testGet302NoLocation(self):
427 # Test that we throw an exception when we get
428 # a 302 with no Location: header.
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400429 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000430 uri = urlparse.urljoin(base, "302/no-location.asis")
431 try:
jcgregorio36140b52006-06-13 02:17:52 +0000432 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000433 self.fail("Should never reach here")
434 except httplib2.RedirectMissingLocation:
435 pass
436 except Exception, e:
437 self.fail("Threw wrong kind of exception ")
438
jcgregorio07a9a4a2007-03-08 21:18:39 +0000439 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400440 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000441
442 (response, content) = self.http.request(uri, "GET")
443 self.assertEqual(response.status, 500)
444 self.assertTrue(response.reason.startswith("Redirected but"))
445 self.assertEqual("302", response['status'])
446 self.assertTrue(content.startswith("This is content"))
Joe Gregorio84e33252011-05-03 09:09:13 -0400447
Joe Gregorioac335ff2011-11-14 12:29:03 -0500448 def testGet301ViaHttps(self):
449 # Google always redirects to https://www.google.com
450 (response, content) = self.http.request("https://code.google.com/apis/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000451 self.assertEqual(200, response.status)
Joe Gregorioac335ff2011-11-14 12:29:03 -0500452 self.assertEqual(301, response.previous.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000453
454 def testGetViaHttps(self):
455 # Test that we can handle HTTPS
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400456 (response, content) = self.http.request("https://www.google.com/adsense/", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000457 self.assertEqual(200, response.status)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000458
459 def testGetViaHttpsSpecViolationOnLocation(self):
460 # Test that we follow redirects through HTTPS
461 # even if they violate the spec by including
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400462 # a relative Location: header instead of an
jcgregorio2d66d4f2006-02-07 05:34:14 +0000463 # absolute one.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400464 (response, content) = self.http.request("https://www.google.com/adsense", "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000465 self.assertEqual(200, response.status)
jcgregorioa0713ab2006-07-01 05:21:34 +0000466 self.assertNotEqual(None, response.previous)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000467
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400468 def testSslCertValidation(self):
469 if sys.version_info >= (2, 6):
470 # Test that we get an ssl.SSLError when specifying a non-existent CA
471 # certs file.
472 http = httplib2.Http(ca_certs='/nosuchfile')
473 self.assertRaises(ssl.SSLError,
474 http.request, "https://www.google.com/", "GET")
475
476 # Test that we get a SSLHandshakeError if we try to access
477 # https;//www.google.com, using a CA cert file that doesn't contain
478 # the CA Gogole uses (i.e., simulating a cert that's not signed by a
479 # trusted CA).
480 other_ca_certs = os.path.join(
481 os.path.dirname(os.path.abspath(httplib2.__file__ )),
482 "test", "other_cacerts.txt")
483 http = httplib2.Http(ca_certs=other_ca_certs)
484 self.assertRaises(httplib2.SSLHandshakeError,
485 http.request, "https://www.google.com/", "GET")
486
Joe Gregorioc69dc782011-06-23 08:56:59 -0400487 def testSslCertValidationDoubleDots(self):
488 if sys.version_info >= (2, 6):
489 # Test that we get match a double dot cert
490 try:
491 self.http.request("https://1.www.appspot.com/", "GET")
492 except httplib2.CertificateHostnameMismatch:
493 self.fail('cert with *.*.appspot.com should not raise an exception.')
494
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400495 def testSslHostnameValidation(self):
496 if sys.version_info >= (2, 6):
497 # The SSL server at google.com:443 returns a certificate for
498 # 'www.google.com', which results in a host name mismatch.
499 # Note that this test only works because the ssl module and httplib2
500 # do not support SNI; for requests specifying a server name of
501 # 'google.com' via SNI, a matching cert would be returned.
502 self.assertRaises(httplib2.CertificateHostnameMismatch,
503 self.http.request, "https://google.com/", "GET")
504
505 def testSslCertValidationWithoutSslModuleFails(self):
506 if sys.version_info < (2, 6):
507 http = httplib2.Http(disable_ssl_certificate_validation=False)
508 self.assertRaises(httplib2.CertificateValidationUnsupported,
509 http.request, "https://www.google.com/", "GET")
jcgregoriode8238d2007-03-07 19:08:26 +0000510
511 def testGetViaHttpsKeyCert(self):
jcgregorio2f1e1422007-05-03 13:17:33 +0000512 # At this point I can only test
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400513 # that the key and cert files are passed in
514 # correctly to httplib. It would be nice to have
jcgregorio2f1e1422007-05-03 13:17:33 +0000515 # a real https endpoint to test against.
Joe Gregoriob53de9b2011-06-07 15:44:51 -0400516
517 # bitworking.org presents an certificate for a non-matching host
518 # (*.webfaction.com), so we need to disable cert checking for this test.
519 http = httplib2.Http(timeout=2, disable_ssl_certificate_validation=True)
jcgregoriode8238d2007-03-07 19:08:26 +0000520
521 http.add_certificate("akeyfile", "acertfile", "bitworking.org")
522 try:
523 (response, content) = http.request("https://bitworking.org", "GET")
524 except:
525 pass
526 self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
527 self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
528
jcgregorio2f1e1422007-05-03 13:17:33 +0000529 try:
530 (response, content) = http.request("https://notthere.bitworking.org", "GET")
531 except:
532 pass
533 self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
534 self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
535
536
537
jcgregoriode8238d2007-03-07 19:08:26 +0000538
jcgregorio2d66d4f2006-02-07 05:34:14 +0000539 def testGet303(self):
540 # Do a follow-up GET on a Location: header
541 # returned from a POST that gave a 303.
542 uri = urlparse.urljoin(base, "303/303.cgi")
jcgregorio36140b52006-06-13 02:17:52 +0000543 (response, content) = self.http.request(uri, "POST", " ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000544 self.assertEqual(response.status, 200)
545 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000546 self.assertEqual(response.previous.status, 303)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000547
jcgregorio2f1e1422007-05-03 13:17:33 +0000548 def testGet303NoRedirect(self):
549 # Do a follow-up GET on a Location: header
550 # returned from a POST that gave a 303.
551 self.http.follow_redirects = False
552 uri = urlparse.urljoin(base, "303/303.cgi")
553 (response, content) = self.http.request(uri, "POST", " ")
554 self.assertEqual(response.status, 303)
555
jcgregorio2d66d4f2006-02-07 05:34:14 +0000556 def test303ForDifferentMethods(self):
557 # Test that all methods can be used
558 uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400559 for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
jcgregorio36140b52006-06-13 02:17:52 +0000560 (response, content) = self.http.request(uri, method, body=" ")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000561 self.assertEqual(response['x-method'], method_on_303)
562
563 def testGet304(self):
564 # Test that we use ETags properly to validate our cache
565 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000566 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000567 self.assertNotEqual(response['etag'], "")
568
jcgregorio36140b52006-06-13 02:17:52 +0000569 (response, content) = self.http.request(uri, "GET")
570 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000571 self.assertEqual(response.status, 200)
572 self.assertEqual(response.fromcache, True)
573
jcgregorio90fb4a42006-11-17 16:19:47 +0000574 cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
575 f = open(cache_file_name, "r")
576 status_line = f.readline()
577 f.close()
578
579 self.assertTrue(status_line.startswith("status:"))
580
jcgregorio36140b52006-06-13 02:17:52 +0000581 (response, content) = self.http.request(uri, "HEAD")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000582 self.assertEqual(response.status, 200)
583 self.assertEqual(response.fromcache, True)
584
jcgregorio36140b52006-06-13 02:17:52 +0000585 (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000586 self.assertEqual(response.status, 206)
587 self.assertEqual(response.fromcache, False)
588
jcgregorio25185622006-10-28 05:12:34 +0000589 def testGetIgnoreEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400590 # Test that we can forcibly ignore ETags
jcgregorio25185622006-10-28 05:12:34 +0000591 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
592 (response, content) = self.http.request(uri, "GET")
593 self.assertNotEqual(response['etag'], "")
594
595 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
596 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400597 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000598
599 self.http.ignore_etag = True
600 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
601 d = self.reflector(content)
602 self.assertEqual(response.fromcache, False)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400603 self.assertFalse(d.has_key('HTTP_IF_NONE_MATCH'))
jcgregorio25185622006-10-28 05:12:34 +0000604
jcgregorio4b145e82007-01-18 19:46:34 +0000605 def testOverrideEtag(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400606 # Test that we can forcibly ignore ETags
jcgregorio4b145e82007-01-18 19:46:34 +0000607 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
608 (response, content) = self.http.request(uri, "GET")
609 self.assertNotEqual(response['etag'], "")
610
611 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0'})
612 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400613 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
614 self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio4b145e82007-01-18 19:46:34 +0000615
pilgrim00a352e2009-05-29 04:04:44 +0000616 (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'max-age=0', 'if-none-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +0000617 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400618 self.assertTrue(d.has_key('HTTP_IF_NONE_MATCH'))
619 self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
jcgregorio25185622006-10-28 05:12:34 +0000620
pilgrim00a352e2009-05-29 04:04:44 +0000621#MAP-commented this out because it consistently fails
622# def testGet304EndToEnd(self):
623# # Test that end to end headers get overwritten in the cache
624# uri = urlparse.urljoin(base, "304/end2end.cgi")
625# (response, content) = self.http.request(uri, "GET")
626# self.assertNotEqual(response['etag'], "")
627# old_date = response['date']
628# time.sleep(2)
629#
630# (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
631# # The response should be from the cache, but the Date: header should be updated.
632# new_date = response['date']
633# self.assertNotEqual(new_date, old_date)
634# self.assertEqual(response.status, 200)
635# self.assertEqual(response.fromcache, True)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000636
637 def testGet304LastModified(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400638 # Test that we can still handle a 304
jcgregorio2d66d4f2006-02-07 05:34:14 +0000639 # by only using the last-modified cache validator.
640 uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000641 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000642
643 self.assertNotEqual(response['last-modified'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000644 (response, content) = self.http.request(uri, "GET")
645 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000646 self.assertEqual(response.status, 200)
647 self.assertEqual(response.fromcache, True)
648
649 def testGet307(self):
650 # Test that we do follow 307 redirects but
651 # do not cache the 307
652 uri = urlparse.urljoin(base, "307/onestep.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000653 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000654 self.assertEqual(response.status, 200)
655 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000656 self.assertEqual(response.previous.status, 307)
657 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000658
jcgregorio36140b52006-06-13 02:17:52 +0000659 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000660 self.assertEqual(response.status, 200)
661 self.assertEqual(response.fromcache, True)
662 self.assertEqual(content, "This is the final destination.\n")
jcgregorioa0713ab2006-07-01 05:21:34 +0000663 self.assertEqual(response.previous.status, 307)
664 self.assertEqual(response.previous.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000665
666 def testGet410(self):
667 # Test that we pass 410's through
668 uri = urlparse.urljoin(base, "410/410.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000669 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000670 self.assertEqual(response.status, 410)
671
chris dent89f15142009-12-24 14:02:57 -0600672 def testVaryHeaderSimple(self):
673 """
674 RFC 2616 13.6
675 When the cache receives a subsequent request whose Request-URI
676 specifies one or more cache entries including a Vary header field,
677 the cache MUST NOT use such a cache entry to construct a response
678 to the new request unless all of the selecting request-headers
679 present in the new request match the corresponding stored
680 request-headers in the original request.
681 """
682 # test that the vary header is sent
683 uri = urlparse.urljoin(base, "vary/accept.asis")
684 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
685 self.assertEqual(response.status, 200)
686 self.assertTrue(response.has_key('vary'))
687
688 # get the resource again, from the cache since accept header in this
689 # request is the same as the request
690 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
691 self.assertEqual(response.status, 200)
692 self.assertEqual(response.fromcache, True, msg="Should be from cache")
693
694 # get the resource again, not from cache since Accept headers does not match
695 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
696 self.assertEqual(response.status, 200)
697 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
698
699 # get the resource again, without any Accept header, so again no match
700 (response, content) = self.http.request(uri, "GET")
701 self.assertEqual(response.status, 200)
702 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
703
704 def testNoVary(self):
705 # when there is no vary, a different Accept header (e.g.) should not
706 # impact if the cache is used
707 # test that the vary header is not sent
708 uri = urlparse.urljoin(base, "vary/no-vary.asis")
709 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
710 self.assertEqual(response.status, 200)
711 self.assertFalse(response.has_key('vary'))
712
713 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
714 self.assertEqual(response.status, 200)
715 self.assertEqual(response.fromcache, True, msg="Should be from cache")
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400716
chris dent89f15142009-12-24 14:02:57 -0600717 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
718 self.assertEqual(response.status, 200)
719 self.assertEqual(response.fromcache, True, msg="Should be from cache")
720
721 def testVaryHeaderDouble(self):
722 uri = urlparse.urljoin(base, "vary/accept-double.asis")
723 (response, content) = self.http.request(uri, "GET", headers={
724 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
725 self.assertEqual(response.status, 200)
726 self.assertTrue(response.has_key('vary'))
727
728 # we are from cache
729 (response, content) = self.http.request(uri, "GET", headers={
730 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
731 self.assertEqual(response.fromcache, True, msg="Should be from cache")
732
733 (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
734 self.assertEqual(response.status, 200)
735 self.assertEqual(response.fromcache, False)
736
737 # get the resource again, not from cache, varied headers don't match exact
738 (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})
739 self.assertEqual(response.status, 200)
740 self.assertEqual(response.fromcache, False, msg="Should not be from cache")
741
jcgregorio88ef89b2010-05-13 23:42:11 -0400742 def testVaryUnusedHeader(self):
743 # A header's value is not considered to vary if it's not used at all.
744 uri = urlparse.urljoin(base, "vary/unused-header.asis")
745 (response, content) = self.http.request(uri, "GET", headers={
746 'Accept': 'text/plain'})
747 self.assertEqual(response.status, 200)
748 self.assertTrue(response.has_key('vary'))
749
750 # we are from cache
751 (response, content) = self.http.request(uri, "GET", headers={
752 'Accept': 'text/plain',})
753 self.assertEqual(response.fromcache, True, msg="Should be from cache")
754
chris dent89f15142009-12-24 14:02:57 -0600755
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000756 def testHeadGZip(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400757 # Test that we don't try to decompress a HEAD response
joe.gregorio0d4a2b82007-10-23 14:28:35 +0000758 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
759 (response, content) = self.http.request(uri, "HEAD")
760 self.assertEqual(response.status, 200)
761 self.assertNotEqual(int(response['content-length']), 0)
762 self.assertEqual(content, "")
763
jcgregorio2d66d4f2006-02-07 05:34:14 +0000764 def testGetGZip(self):
765 # Test that we support gzip compression
766 uri = urlparse.urljoin(base, "gzip/final-destination.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000767 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000768 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000769 self.assertFalse(response.has_key('content-encoding'))
joe.gregorio8b6d2312007-12-16 05:42:07 +0000770 self.assertTrue(response.has_key('-content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000771 self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000772 self.assertEqual(content, "This is the final destination.\n")
773
Joe Gregoriod1137c52011-02-13 19:27:35 -0500774 def testPostAndGZipResponse(self):
775 uri = urlparse.urljoin(base, "gzip/post.cgi")
776 (response, content) = self.http.request(uri, "POST", body=" ")
777 self.assertEqual(response.status, 200)
778 self.assertFalse(response.has_key('content-encoding'))
779 self.assertTrue(response.has_key('-content-encoding'))
780
jcgregorio2d66d4f2006-02-07 05:34:14 +0000781 def testGetGZipFailure(self):
782 # Test that we raise a good exception when the gzip fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400783 self.http.force_exception_to_status_code = False
jcgregorio2d66d4f2006-02-07 05:34:14 +0000784 uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
785 try:
jcgregorio36140b52006-06-13 02:17:52 +0000786 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000787 self.fail("Should never reach here")
788 except httplib2.FailedToDecompressContent:
789 pass
790 except Exception:
791 self.fail("Threw wrong kind of exception")
792
jcgregorio07a9a4a2007-03-08 21:18:39 +0000793 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400794 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000795
796 (response, content) = self.http.request(uri, "GET")
797 self.assertEqual(response.status, 500)
798 self.assertTrue(response.reason.startswith("Content purported"))
799
800 def testTimeout(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400801 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000802 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
803 try:
804 import socket
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400805 socket.setdefaulttimeout(1)
jcgregorio07a9a4a2007-03-08 21:18:39 +0000806 except:
807 # Don't run the test if we can't set the timeout
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400808 return
jcgregorio07a9a4a2007-03-08 21:18:39 +0000809 (response, content) = self.http.request(uri)
810 self.assertEqual(response.status, 408)
811 self.assertTrue(response.reason.startswith("Request Timeout"))
812 self.assertTrue(content.startswith("Request Timeout"))
813
jcgregoriob2697912007-03-09 02:23:47 +0000814 def testIndividualTimeout(self):
jcgregoriob2697912007-03-09 02:23:47 +0000815 uri = urlparse.urljoin(base, "timeout/timeout.cgi")
816 http = httplib2.Http(timeout=1)
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400817 http.force_exception_to_status_code = True
jcgregoriob2697912007-03-09 02:23:47 +0000818
819 (response, content) = http.request(uri)
820 self.assertEqual(response.status, 408)
821 self.assertTrue(response.reason.startswith("Request Timeout"))
822 self.assertTrue(content.startswith("Request Timeout"))
823
jcgregorio07a9a4a2007-03-08 21:18:39 +0000824
Joe Gregorio1a7609f2009-07-16 10:59:44 -0400825 def testHTTPSInitTimeout(self):
826 c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
827 self.assertEqual(47, c.timeout)
828
jcgregorio2d66d4f2006-02-07 05:34:14 +0000829 def testGetDeflate(self):
830 # Test that we support deflate compression
831 uri = urlparse.urljoin(base, "deflate/deflated.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000832 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000833 self.assertEqual(response.status, 200)
jcgregorio90fb4a42006-11-17 16:19:47 +0000834 self.assertFalse(response.has_key('content-encoding'))
jcgregorio153f5882006-11-06 03:33:24 +0000835 self.assertEqual(int(response['content-length']), len("This is the final destination."))
jcgregorio2d66d4f2006-02-07 05:34:14 +0000836 self.assertEqual(content, "This is the final destination.")
837
838 def testGetDeflateFailure(self):
839 # Test that we raise a good exception when the deflate fails
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400840 self.http.force_exception_to_status_code = False
jcgregorio07a9a4a2007-03-08 21:18:39 +0000841
jcgregorio2d66d4f2006-02-07 05:34:14 +0000842 uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
843 try:
jcgregorio36140b52006-06-13 02:17:52 +0000844 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000845 self.fail("Should never reach here")
846 except httplib2.FailedToDecompressContent:
847 pass
848 except Exception:
849 self.fail("Threw wrong kind of exception")
850
jcgregorio07a9a4a2007-03-08 21:18:39 +0000851 # Re-run the test with out the exceptions
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400852 self.http.force_exception_to_status_code = True
jcgregorio07a9a4a2007-03-08 21:18:39 +0000853
854 (response, content) = self.http.request(uri, "GET")
855 self.assertEqual(response.status, 500)
856 self.assertTrue(response.reason.startswith("Content purported"))
857
jcgregorio2d66d4f2006-02-07 05:34:14 +0000858 def testGetDuplicateHeaders(self):
859 # Test that duplicate headers get concatenated via ','
860 uri = urlparse.urljoin(base, "duplicate-headers/multilink.asis")
jcgregorio36140b52006-06-13 02:17:52 +0000861 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000862 self.assertEqual(response.status, 200)
863 self.assertEqual(content, "This is content\n")
864 self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
865
866 def testGetCacheControlNoCache(self):
867 # Test Cache-Control: no-cache on requests
868 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000869 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000870 self.assertNotEqual(response['etag'], "")
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, 200)
873 self.assertEqual(response.fromcache, True)
874
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 self.assertEqual(response.status, 200)
877 self.assertEqual(response.fromcache, False)
878
879 def testGetCacheControlPragmaNoCache(self):
880 # Test Pragma: no-cache on requests
881 uri = urlparse.urljoin(base, "304/test_etag.txt")
jcgregorio36140b52006-06-13 02:17:52 +0000882 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000883 self.assertNotEqual(response['etag'], "")
jcgregorio36140b52006-06-13 02:17:52 +0000884 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000885 self.assertEqual(response.status, 200)
886 self.assertEqual(response.fromcache, True)
887
jcgregorio36140b52006-06-13 02:17:52 +0000888 (response, content) = self.http.request(uri, "GET", headers={'Pragma': 'no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000889 self.assertEqual(response.status, 200)
890 self.assertEqual(response.fromcache, False)
891
892 def testGetCacheControlNoStoreRequest(self):
893 # A no-store request means that the response should not be stored.
894 uri = urlparse.urljoin(base, "304/test_etag.txt")
895
jcgregorio36140b52006-06-13 02:17:52 +0000896 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000897 self.assertEqual(response.status, 200)
898 self.assertEqual(response.fromcache, False)
899
jcgregorio36140b52006-06-13 02:17:52 +0000900 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000901 self.assertEqual(response.status, 200)
902 self.assertEqual(response.fromcache, False)
903
904 def testGetCacheControlNoStoreResponse(self):
905 # A no-store response means that the response should not be stored.
906 uri = urlparse.urljoin(base, "no-store/no-store.asis")
907
jcgregorio36140b52006-06-13 02:17:52 +0000908 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000909 self.assertEqual(response.status, 200)
910 self.assertEqual(response.fromcache, False)
911
jcgregorio36140b52006-06-13 02:17:52 +0000912 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000913 self.assertEqual(response.status, 200)
914 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000915
916 def testGetCacheControlNoCacheNoStoreRequest(self):
917 # Test that a no-store, no-cache clears the entry from the cache
918 # even if it was cached previously.
919 uri = urlparse.urljoin(base, "304/test_etag.txt")
920
jcgregorio36140b52006-06-13 02:17:52 +0000921 (response, content) = self.http.request(uri, "GET")
922 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000923 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000924 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
925 (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
jcgregorio2d66d4f2006-02-07 05:34:14 +0000926 self.assertEqual(response.status, 200)
927 self.assertEqual(response.fromcache, False)
jcgregorio2d66d4f2006-02-07 05:34:14 +0000928
929 def testUpdateInvalidatesCache(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400930 # Test that calling PUT or DELETE on a
jcgregorio2d66d4f2006-02-07 05:34:14 +0000931 # URI that is cache invalidates that cache.
932 uri = urlparse.urljoin(base, "304/test_etag.txt")
933
jcgregorio36140b52006-06-13 02:17:52 +0000934 (response, content) = self.http.request(uri, "GET")
935 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000936 self.assertEqual(response.fromcache, True)
jcgregorio36140b52006-06-13 02:17:52 +0000937 (response, content) = self.http.request(uri, "DELETE")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000938 self.assertEqual(response.status, 405)
939
jcgregorio36140b52006-06-13 02:17:52 +0000940 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000941 self.assertEqual(response.fromcache, False)
942
943 def testUpdateUsesCachedETag(self):
Joe Gregoriobd682082011-05-24 14:06:09 -0400944 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio2d66d4f2006-02-07 05:34:14 +0000945 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
946
jcgregorio36140b52006-06-13 02:17:52 +0000947 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000948 self.assertEqual(response.status, 200)
949 self.assertEqual(response.fromcache, False)
jcgregorio36140b52006-06-13 02:17:52 +0000950 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000951 self.assertEqual(response.status, 200)
952 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -0400953 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000954 self.assertEqual(response.status, 200)
Joe Gregoriocd868102009-09-29 17:09:16 -0400955 (response, content) = self.http.request(uri, "PUT", body="foo")
jcgregorio2d66d4f2006-02-07 05:34:14 +0000956 self.assertEqual(response.status, 412)
957
Joe Gregoriobd682082011-05-24 14:06:09 -0400958 def testUpdatePatchUsesCachedETag(self):
959 # Test that we natively support http://www.w3.org/1999/04/Editing/
960 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
961
962 (response, content) = self.http.request(uri, "GET")
963 self.assertEqual(response.status, 200)
964 self.assertEqual(response.fromcache, False)
965 (response, content) = self.http.request(uri, "GET")
966 self.assertEqual(response.status, 200)
967 self.assertEqual(response.fromcache, True)
968 (response, content) = self.http.request(uri, "PATCH", body="foo")
969 self.assertEqual(response.status, 200)
970 (response, content) = self.http.request(uri, "PATCH", body="foo")
971 self.assertEqual(response.status, 412)
972
973
joe.gregorio700f04d2008-09-06 04:46:32 +0000974 def testUpdateUsesCachedETagAndOCMethod(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400975 # Test that we natively support http://www.w3.org/1999/04/Editing/
joe.gregorio700f04d2008-09-06 04:46:32 +0000976 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
977
978 (response, content) = self.http.request(uri, "GET")
979 self.assertEqual(response.status, 200)
980 self.assertEqual(response.fromcache, False)
981 (response, content) = self.http.request(uri, "GET")
982 self.assertEqual(response.status, 200)
983 self.assertEqual(response.fromcache, True)
984 self.http.optimistic_concurrency_methods.append("DELETE")
985 (response, content) = self.http.request(uri, "DELETE")
986 self.assertEqual(response.status, 200)
987
988
jcgregorio4b145e82007-01-18 19:46:34 +0000989 def testUpdateUsesCachedETagOverridden(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -0400990 # Test that we natively support http://www.w3.org/1999/04/Editing/
jcgregorio4b145e82007-01-18 19:46:34 +0000991 uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
992
993 (response, content) = self.http.request(uri, "GET")
994 self.assertEqual(response.status, 200)
995 self.assertEqual(response.fromcache, False)
996 (response, content) = self.http.request(uri, "GET")
997 self.assertEqual(response.status, 200)
998 self.assertEqual(response.fromcache, True)
Joe Gregoriocd868102009-09-29 17:09:16 -0400999 (response, content) = self.http.request(uri, "PUT", body="foo", headers={'if-match': 'fred'})
jcgregorio4b145e82007-01-18 19:46:34 +00001000 self.assertEqual(response.status, 412)
1001
jcgregorio2d66d4f2006-02-07 05:34:14 +00001002 def testBasicAuth(self):
1003 # Test Basic Authentication
1004 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001005 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001006 self.assertEqual(response.status, 401)
1007
1008 uri = urlparse.urljoin(base, "basic/")
jcgregorio36140b52006-06-13 02:17:52 +00001009 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001010 self.assertEqual(response.status, 401)
1011
jcgregorio36140b52006-06-13 02:17:52 +00001012 self.http.add_credentials('joe', 'password')
1013 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001014 self.assertEqual(response.status, 200)
1015
1016 uri = urlparse.urljoin(base, "basic/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001017 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001018 self.assertEqual(response.status, 200)
1019
jcgregoriode8238d2007-03-07 19:08:26 +00001020 def testBasicAuthWithDomain(self):
1021 # Test Basic Authentication
1022 uri = urlparse.urljoin(base, "basic/file.txt")
1023 (response, content) = self.http.request(uri, "GET")
1024 self.assertEqual(response.status, 401)
1025
1026 uri = urlparse.urljoin(base, "basic/")
1027 (response, content) = self.http.request(uri, "GET")
1028 self.assertEqual(response.status, 401)
1029
1030 self.http.add_credentials('joe', 'password', "example.org")
1031 (response, content) = self.http.request(uri, "GET")
1032 self.assertEqual(response.status, 401)
1033
1034 uri = urlparse.urljoin(base, "basic/file.txt")
1035 (response, content) = self.http.request(uri, "GET")
1036 self.assertEqual(response.status, 401)
1037
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001038 domain = urlparse.urlparse(base)[1]
jcgregoriode8238d2007-03-07 19:08:26 +00001039 self.http.add_credentials('joe', 'password', domain)
1040 (response, content) = self.http.request(uri, "GET")
1041 self.assertEqual(response.status, 200)
1042
1043 uri = urlparse.urljoin(base, "basic/file.txt")
1044 (response, content) = self.http.request(uri, "GET")
1045 self.assertEqual(response.status, 200)
1046
1047
1048
1049
1050
1051
jcgregorio2d66d4f2006-02-07 05:34:14 +00001052 def testBasicAuthTwoDifferentCredentials(self):
jcgregorioadbb4f82006-05-19 15:17:42 +00001053 # Test Basic Authentication with multiple sets of credentials
jcgregorio2d66d4f2006-02-07 05:34:14 +00001054 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001055 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001056 self.assertEqual(response.status, 401)
1057
1058 uri = urlparse.urljoin(base, "basic2/")
jcgregorio36140b52006-06-13 02:17:52 +00001059 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001060 self.assertEqual(response.status, 401)
1061
jcgregorio36140b52006-06-13 02:17:52 +00001062 self.http.add_credentials('fred', 'barney')
1063 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001064 self.assertEqual(response.status, 200)
1065
1066 uri = urlparse.urljoin(base, "basic2/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001067 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001068 self.assertEqual(response.status, 200)
1069
1070 def testBasicAuthNested(self):
1071 # Test Basic Authentication with resources
1072 # that are nested
1073 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001074 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001075 self.assertEqual(response.status, 401)
1076
1077 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001078 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001079 self.assertEqual(response.status, 401)
1080
jcgregorioadbb4f82006-05-19 15:17:42 +00001081 # Now add in credentials one at a time and test.
jcgregorio36140b52006-06-13 02:17:52 +00001082 self.http.add_credentials('joe', 'password')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001083
1084 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001085 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001086 self.assertEqual(response.status, 200)
1087
1088 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001089 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001090 self.assertEqual(response.status, 401)
1091
jcgregorio36140b52006-06-13 02:17:52 +00001092 self.http.add_credentials('fred', 'barney')
jcgregorio2d66d4f2006-02-07 05:34:14 +00001093
1094 uri = urlparse.urljoin(base, "basic-nested/")
jcgregorio36140b52006-06-13 02:17:52 +00001095 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001096 self.assertEqual(response.status, 200)
1097
1098 uri = urlparse.urljoin(base, "basic-nested/subdir")
jcgregorio36140b52006-06-13 02:17:52 +00001099 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001100 self.assertEqual(response.status, 200)
1101
1102 def testDigestAuth(self):
1103 # Test that we support Digest Authentication
1104 uri = urlparse.urljoin(base, "digest/")
jcgregorio36140b52006-06-13 02:17:52 +00001105 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001106 self.assertEqual(response.status, 401)
1107
jcgregorio36140b52006-06-13 02:17:52 +00001108 self.http.add_credentials('joe', 'password')
1109 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001110 self.assertEqual(response.status, 200)
1111
1112 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001113 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001114
1115 def testDigestAuthNextNonceAndNC(self):
1116 # Test that if the server sets nextnonce that we reset
1117 # the nonce count back to 1
1118 uri = urlparse.urljoin(base, "digest/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001119 self.http.add_credentials('joe', 'password')
1120 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001121 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1122 self.assertEqual(response.status, 200)
jcgregorio36140b52006-06-13 02:17:52 +00001123 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001124 info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
1125 self.assertEqual(response.status, 200)
1126
1127 if info.has_key('nextnonce'):
1128 self.assertEqual(info2['nc'], 1)
1129
1130 def testDigestAuthStale(self):
1131 # Test that we can handle a nonce becoming stale
1132 uri = urlparse.urljoin(base, "digest-expire/file.txt")
jcgregorio36140b52006-06-13 02:17:52 +00001133 self.http.add_credentials('joe', 'password')
1134 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001135 info = httplib2._parse_www_authenticate(response, 'authentication-info')
1136 self.assertEqual(response.status, 200)
1137
1138 time.sleep(3)
1139 # Sleep long enough that the nonce becomes stale
1140
jcgregorio36140b52006-06-13 02:17:52 +00001141 (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001142 self.assertFalse(response.fromcache)
1143 self.assertTrue(response._stale_digest)
1144 info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
1145 self.assertEqual(response.status, 200)
1146
1147 def reflector(self, content):
jcgregorio25185622006-10-28 05:12:34 +00001148 return dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
jcgregorio2d66d4f2006-02-07 05:34:14 +00001149
1150 def testReflector(self):
1151 uri = urlparse.urljoin(base, "reflector/reflector.cgi")
jcgregorio36140b52006-06-13 02:17:52 +00001152 (response, content) = self.http.request(uri, "GET")
jcgregorio2d66d4f2006-02-07 05:34:14 +00001153 d = self.reflector(content)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001154 self.assertTrue(d.has_key('HTTP_USER_AGENT'))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001155
Joe Gregorio84cc10a2009-09-01 13:02:49 -04001156 def testConnectionClose(self):
1157 uri = "http://www.google.com/"
1158 (response, content) = self.http.request(uri, "GET")
1159 for c in self.http.connections.values():
1160 self.assertNotEqual(None, c.sock)
1161 (response, content) = self.http.request(uri, "GET", headers={"connection": "close"})
1162 for c in self.http.connections.values():
1163 self.assertEqual(None, c.sock)
1164
1165
jcgregorio36140b52006-06-13 02:17:52 +00001166try:
1167 import memcache
1168 class HttpTestMemCached(HttpTest):
1169 def setUp(self):
1170 self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
jcgregorio47d24672006-06-29 05:18:59 +00001171 #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
jcgregorio36140b52006-06-13 02:17:52 +00001172 self.http = httplib2.Http(self.cache)
1173 self.cache.flush_all()
jcgregorio47d24672006-06-29 05:18:59 +00001174 # Not exactly sure why the sleep is needed here, but
1175 # if not present then some unit tests that rely on caching
1176 # fail. Memcached seems to lose some sets immediately
1177 # after a flush_all if the set is to a value that
1178 # was previously cached. (Maybe the flush is handled async?)
1179 time.sleep(1)
jcgregorio36140b52006-06-13 02:17:52 +00001180 self.http.clear_credentials()
1181except:
1182 pass
1183
1184
1185
chris dent89f15142009-12-24 14:02:57 -06001186
jcgregoriodb8dfc82006-03-31 14:59:46 +00001187# ------------------------------------------------------------------------
jcgregorio2d66d4f2006-02-07 05:34:14 +00001188
1189class HttpPrivateTest(unittest.TestCase):
1190
1191 def testParseCacheControl(self):
1192 # Test that we can parse the Cache-Control header
1193 self.assertEqual({}, httplib2._parse_cache_control({}))
1194 self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
1195 cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
1196 self.assertEqual(cc['no-cache'], 1)
1197 self.assertEqual(cc['max-age'], '7200')
1198 cc = httplib2._parse_cache_control({'cache-control': ' , '})
1199 self.assertEqual(cc[''], 1)
1200
Joe Gregorioe314e8b2009-07-16 20:11:28 -04001201 try:
1202 cc = httplib2._parse_cache_control({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'})
1203 self.assertTrue("max-age" in cc)
1204 except:
1205 self.fail("Should not throw exception")
1206
jcgregorio2d66d4f2006-02-07 05:34:14 +00001207 def testNormalizeHeaders(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001208 # Test that we normalize headers to lowercase
jcgregorio2d66d4f2006-02-07 05:34:14 +00001209 h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
1210 self.assertTrue(h.has_key('cache-control'))
1211 self.assertTrue(h.has_key('other'))
1212 self.assertEqual('Stuff', h['other'])
1213
1214 def testExpirationModelTransparent(self):
1215 # Test that no-cache makes our request TRANSPARENT
1216 response_headers = {
1217 'cache-control': 'max-age=7200'
1218 }
1219 request_headers = {
1220 'cache-control': 'no-cache'
1221 }
1222 self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
1223
jcgregorio45865012007-01-18 16:38:22 +00001224 def testMaxAgeNonNumeric(self):
1225 # Test that no-cache makes our request TRANSPARENT
1226 response_headers = {
1227 'cache-control': 'max-age=fred, min-fresh=barney'
1228 }
1229 request_headers = {
1230 }
1231 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1232
1233
jcgregorio2d66d4f2006-02-07 05:34:14 +00001234 def testExpirationModelNoCacheResponse(self):
1235 # The date and expires point to an entry that should be
1236 # FRESH, but the no-cache over-rides that.
1237 now = time.time()
1238 response_headers = {
1239 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1240 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1241 'cache-control': 'no-cache'
1242 }
1243 request_headers = {
1244 }
1245 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1246
1247 def testExpirationModelStaleRequestMustReval(self):
1248 # must-revalidate forces STALE
1249 self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
1250
1251 def testExpirationModelStaleResponseMustReval(self):
1252 # must-revalidate forces STALE
1253 self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
1254
1255 def testExpirationModelFresh(self):
1256 response_headers = {
1257 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1258 'cache-control': 'max-age=2'
1259 }
1260 request_headers = {
1261 }
1262 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1263 time.sleep(3)
1264 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1265
1266 def testExpirationMaxAge0(self):
1267 response_headers = {
1268 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
1269 'cache-control': 'max-age=0'
1270 }
1271 request_headers = {
1272 }
1273 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1274
1275 def testExpirationModelDateAndExpires(self):
1276 now = time.time()
1277 response_headers = {
1278 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1279 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1280 }
1281 request_headers = {
1282 }
1283 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1284 time.sleep(3)
1285 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1286
jcgregoriof9511052007-06-01 14:56:34 +00001287 def testExpiresZero(self):
1288 now = time.time()
1289 response_headers = {
1290 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1291 'expires': "0",
1292 }
1293 request_headers = {
1294 }
1295 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1296
jcgregorio2d66d4f2006-02-07 05:34:14 +00001297 def testExpirationModelDateOnly(self):
1298 now = time.time()
1299 response_headers = {
1300 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
1301 }
1302 request_headers = {
1303 }
1304 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1305
1306 def testExpirationModelOnlyIfCached(self):
1307 response_headers = {
1308 }
1309 request_headers = {
1310 'cache-control': 'only-if-cached',
1311 }
1312 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1313
1314 def testExpirationModelMaxAgeBoth(self):
1315 now = time.time()
1316 response_headers = {
1317 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1318 'cache-control': 'max-age=2'
1319 }
1320 request_headers = {
1321 'cache-control': 'max-age=0'
1322 }
1323 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1324
1325 def testExpirationModelDateAndExpiresMinFresh1(self):
1326 now = time.time()
1327 response_headers = {
1328 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1329 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
1330 }
1331 request_headers = {
1332 'cache-control': 'min-fresh=2'
1333 }
1334 self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
1335
1336 def testExpirationModelDateAndExpiresMinFresh2(self):
1337 now = time.time()
1338 response_headers = {
1339 'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
1340 'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
1341 }
1342 request_headers = {
1343 'cache-control': 'min-fresh=2'
1344 }
1345 self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
1346
1347 def testParseWWWAuthenticateEmpty(self):
1348 res = httplib2._parse_www_authenticate({})
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001349 self.assertEqual(len(res.keys()), 0)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001350
jcgregoriofd22e432006-04-27 02:00:08 +00001351 def testParseWWWAuthenticate(self):
1352 # different uses of spaces around commas
1353 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
1354 self.assertEqual(len(res.keys()), 1)
1355 self.assertEqual(len(res['test'].keys()), 5)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001356
jcgregoriofd22e432006-04-27 02:00:08 +00001357 # tokens with non-alphanum
1358 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
1359 self.assertEqual(len(res.keys()), 1)
1360 self.assertEqual(len(res['t*!%#st'].keys()), 2)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001361
jcgregoriofd22e432006-04-27 02:00:08 +00001362 # quoted string with quoted pairs
1363 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
1364 self.assertEqual(len(res.keys()), 1)
1365 self.assertEqual(res['test']['realm'], 'a "test" realm')
1366
1367 def testParseWWWAuthenticateStrict(self):
1368 httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
1369 self.testParseWWWAuthenticate();
1370 httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
1371
jcgregorio2d66d4f2006-02-07 05:34:14 +00001372 def testParseWWWAuthenticateBasic(self):
1373 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
1374 basic = res['basic']
1375 self.assertEqual('me', basic['realm'])
1376
1377 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
1378 basic = res['basic']
1379 self.assertEqual('me', basic['realm'])
1380 self.assertEqual('MD5', basic['algorithm'])
1381
1382 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
1383 basic = res['basic']
1384 self.assertEqual('me', basic['realm'])
1385 self.assertEqual('MD5', basic['algorithm'])
1386
1387 def testParseWWWAuthenticateBasic2(self):
1388 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
1389 basic = res['basic']
1390 self.assertEqual('me', basic['realm'])
1391 self.assertEqual('fred', basic['other'])
1392
1393 def testParseWWWAuthenticateBasic3(self):
1394 res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
1395 basic = res['basic']
1396 self.assertEqual('me', basic['realm'])
1397
1398
1399 def testParseWWWAuthenticateDigest(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001400 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001401 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
1402 digest = res['digest']
1403 self.assertEqual('testrealm@host.com', digest['realm'])
1404 self.assertEqual('auth,auth-int', digest['qop'])
1405
1406
1407 def testParseWWWAuthenticateMultiple(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001408 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001409 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
1410 digest = res['digest']
1411 self.assertEqual('testrealm@host.com', digest['realm'])
1412 self.assertEqual('auth,auth-int', digest['qop'])
1413 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1414 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1415 basic = res['basic']
1416 self.assertEqual('me', basic['realm'])
1417
1418 def testParseWWWAuthenticateMultiple2(self):
1419 # Handle an added comma between challenges, which might get thrown in if the challenges were
1420 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001421 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001422 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
1423 digest = res['digest']
1424 self.assertEqual('testrealm@host.com', digest['realm'])
1425 self.assertEqual('auth,auth-int', digest['qop'])
1426 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1427 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1428 basic = res['basic']
1429 self.assertEqual('me', basic['realm'])
1430
1431 def testParseWWWAuthenticateMultiple3(self):
1432 # Handle an added comma between challenges, which might get thrown in if the challenges were
1433 # originally sent in separate www-authenticate headers.
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001434 res = httplib2._parse_www_authenticate({ 'www-authenticate':
jcgregorio2d66d4f2006-02-07 05:34:14 +00001435 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
1436 digest = res['digest']
1437 self.assertEqual('testrealm@host.com', digest['realm'])
1438 self.assertEqual('auth,auth-int', digest['qop'])
1439 self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
1440 self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
1441 basic = res['basic']
1442 self.assertEqual('me', basic['realm'])
1443 wsse = res['wsse']
1444 self.assertEqual('foo', wsse['realm'])
1445 self.assertEqual('UsernameToken', wsse['profile'])
1446
1447 def testParseWWWAuthenticateMultiple4(self):
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001448 res = httplib2._parse_www_authenticate({ 'www-authenticate':
1449 'Digest realm="test-real.m@host.com", qop \t=\t"\tauth,auth-int", nonce="(*)&^&$%#",opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
jcgregorio2d66d4f2006-02-07 05:34:14 +00001450 digest = res['digest']
1451 self.assertEqual('test-real.m@host.com', digest['realm'])
1452 self.assertEqual('\tauth,auth-int', digest['qop'])
1453 self.assertEqual('(*)&^&$%#', digest['nonce'])
1454
1455 def testParseWWWAuthenticateMoreQuoteCombos(self):
1456 res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
1457 digest = res['digest']
1458 self.assertEqual('myrealm', digest['realm'])
1459
Joe Gregorio6fa3cf22011-02-13 22:45:06 -05001460 def testParseWWWAuthenticateMalformed(self):
1461 try:
1462 res = httplib2._parse_www_authenticate({'www-authenticate':'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'})
1463 self.fail("should raise an exception")
1464 except httplib2.MalformedHeader:
1465 pass
1466
jcgregorio2d66d4f2006-02-07 05:34:14 +00001467 def testDigestObject(self):
1468 credentials = ('joe', 'password')
1469 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001470 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001471 headers = {}
1472 response = {
1473 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
1474 }
1475 content = ""
Joe Gregorio875a8b52011-06-13 14:06:23 -04001476
jcgregorio6cbab7e2006-04-21 20:35:43 +00001477 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001478 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
Joe Gregorio875a8b52011-06-13 14:06:23 -04001479 our_request = "authorization: %s" % headers['authorization']
1480 working_request = 'authorization: Digest username="joe", realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", uri="/projects/httplib2/test/digest/", algorithm=MD5, response="97ed129401f7cdc60e5db58a80f3ea8b", qop=auth, nc=00000001, cnonce="33033375ec278a46"'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001481 self.assertEqual(our_request, working_request)
1482
Joe Gregorio03d99102011-06-22 16:55:52 -04001483 def testDigestObjectWithOpaque(self):
1484 credentials = ('joe', 'password')
1485 host = None
1486 request_uri = '/projects/httplib2/test/digest/'
1487 headers = {}
1488 response = {
1489 'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", opaque="atestopaque"'
1490 }
1491 content = ""
1492
1493 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
1494 d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
1495 our_request = "authorization: %s" % headers['authorization']
1496 working_request = 'authorization: Digest username="joe", realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", uri="/projects/httplib2/test/digest/", algorithm=MD5, response="97ed129401f7cdc60e5db58a80f3ea8b", qop=auth, nc=00000001, cnonce="33033375ec278a46", opaque="atestopaque"'
1497 self.assertEqual(our_request, working_request)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001498
1499 def testDigestObjectStale(self):
1500 credentials = ('joe', 'password')
1501 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001502 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001503 headers = {}
1504 response = httplib2.Response({ })
1505 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1506 response.status = 401
1507 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001508 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001509 # Returns true to force a retry
1510 self.assertTrue( d.response(response, content) )
1511
1512 def testDigestObjectAuthInfo(self):
1513 credentials = ('joe', 'password')
1514 host = None
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001515 request_uri = '/projects/httplib2/test/digest/'
jcgregorio2d66d4f2006-02-07 05:34:14 +00001516 headers = {}
1517 response = httplib2.Response({ })
1518 response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
1519 response['authentication-info'] = 'nextnonce="fred"'
1520 content = ""
jcgregorio6cbab7e2006-04-21 20:35:43 +00001521 d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
jcgregorio2d66d4f2006-02-07 05:34:14 +00001522 # Returns true to force a retry
1523 self.assertFalse( d.response(response, content) )
1524 self.assertEqual('fred', d.challenge['nonce'])
1525 self.assertEqual(1, d.challenge['nc'])
1526
1527 def testWsseAlgorithm(self):
1528 digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
1529 expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
1530 self.assertEqual(expected, digest)
1531
jcgregoriodb8dfc82006-03-31 14:59:46 +00001532 def testEnd2End(self):
1533 # one end to end header
1534 response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
1535 end2end = httplib2._get_end2end_headers(response)
1536 self.assertTrue('content-type' in end2end)
1537 self.assertTrue('te' not in end2end)
1538 self.assertTrue('connection' not in end2end)
1539
1540 # one end to end header that gets eliminated
1541 response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
1542 end2end = httplib2._get_end2end_headers(response)
1543 self.assertTrue('content-type' not in end2end)
1544 self.assertTrue('te' not in end2end)
1545 self.assertTrue('connection' not in end2end)
1546
1547 # Degenerate case of no headers
1548 response = {}
1549 end2end = httplib2._get_end2end_headers(response)
1550 self.assertEquals(0, len(end2end))
1551
Jason R. Coombs88c1f282011-08-09 08:53:31 -04001552 # Degenerate case of connection referrring to a header not passed in
jcgregoriodb8dfc82006-03-31 14:59:46 +00001553 response = {'connection': 'content-type'}
1554 end2end = httplib2._get_end2end_headers(response)
1555 self.assertEquals(0, len(end2end))
jcgregorio2d66d4f2006-02-07 05:34:14 +00001556
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001557
1558class TestProxyInfo(unittest.TestCase):
1559 def setUp(self):
1560 self.orig_env = dict(os.environ)
1561
1562 def tearDown(self):
1563 os.environ.clear()
1564 os.environ.update(self.orig_env)
1565
1566 def test_from_url(self):
1567 pi = httplib2.ProxyInfo.from_url('http://myproxy.example.com')
1568 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1569 self.assertEquals(pi.proxy_port, 80)
1570 self.assertEquals(pi.proxy_user, None)
1571
1572 def test_from_url_ident(self):
1573 pi = httplib2.ProxyInfo.from_url('http://zoidberg:fish@someproxy:99')
1574 self.assertEquals(pi.proxy_host, 'someproxy')
1575 self.assertEquals(pi.proxy_port, 99)
1576 self.assertEquals(pi.proxy_user, 'zoidberg')
1577 self.assertEquals(pi.proxy_pass, 'fish')
1578
1579 def test_from_env(self):
1580 os.environ['http_proxy'] = 'http://myproxy.example.com:8080'
1581 pi = httplib2.ProxyInfo.from_environment()
1582 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1583 self.assertEquals(pi.proxy_port, 8080)
1584 self.assertEquals(pi.bypass_hosts, [])
1585
1586 def test_from_env_no_proxy(self):
1587 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1588 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
1589 os.environ['no_proxy'] = 'localhost,otherhost.domain.local'
1590 pi = httplib2.ProxyInfo.from_environment('https')
1591 self.assertEquals(pi.proxy_host, 'myproxy.example.com')
1592 self.assertEquals(pi.proxy_port, 81)
1593 self.assertEquals(pi.bypass_hosts, ['localhost',
1594 'otherhost.domain.local'])
1595
1596 def test_from_env_none(self):
1597 os.environ.clear()
1598 pi = httplib2.ProxyInfo.from_environment()
1599 self.assertEquals(pi, None)
1600
Jason R. Coombs43840892011-08-09 10:30:46 -04001601 def test_applies_to(self):
1602 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1603 os.environ['https_proxy'] = 'http://myproxy.example.com:81'
Jason R. Coombs96279c52011-08-16 12:53:27 -04001604 os.environ['no_proxy'] = 'localhost,otherhost.domain.local,example.com'
Jason R. Coombs43840892011-08-09 10:30:46 -04001605 pi = httplib2.ProxyInfo.from_environment()
1606 self.assertFalse(pi.applies_to('localhost'))
1607 self.assertTrue(pi.applies_to('www.google.com'))
Jason R. Coombs96279c52011-08-16 12:53:27 -04001608 self.assertFalse(pi.applies_to('www.example.com'))
1609
1610 def test_no_proxy_star(self):
1611 os.environ['http_proxy'] = 'http://myproxy.example.com:80'
1612 os.environ['NO_PROXY'] = '*'
1613 pi = httplib2.ProxyInfo.from_environment()
1614 for host in ('localhost', '169.254.38.192', 'www.google.com'):
1615 self.assertFalse(pi.applies_to(host))
Jason R. Coombs43840892011-08-09 10:30:46 -04001616
Jason R. Coombs8a487d02011-08-09 09:35:58 -04001617
chris dent89f15142009-12-24 14:02:57 -06001618if __name__ == '__main__':
1619 unittest.main()