summaryrefslogtreecommitdiff
path: root/python2
diff options
context:
space:
mode:
authorchris dent <chris.dent@gmail.com>2009-12-24 14:02:57 -0600
committerchris dent <chris.dent@gmail.com>2009-12-24 14:02:57 -0600
commit89f1514bff479bf72adc5f82f3287167447d0423 (patch)
tree8fa11473de3a6d4ddeb705681be15b23514d6d84 /python2
parent25dffefd19323728d8dea13e798d56ae4347884b (diff)
downloadhttplib2-89f1514bff479bf72adc5f82f3287167447d0423.tar.gz
Add support for Vary header
Diffstat (limited to 'python2')
-rw-r--r--python2/httplib2/__init__.py24
-rwxr-xr-xpython2/httplib2test.py75
2 files changed, 98 insertions, 1 deletions
diff --git a/python2/httplib2/__init__.py b/python2/httplib2/__init__.py
index 7980ca7..d2abdb4 100644
--- a/python2/httplib2/__init__.py
+++ b/python2/httplib2/__init__.py
@@ -370,6 +370,18 @@ def _updateCache(request_headers, response_headers, content, cache, cachekey):
if key not in ['status','content-encoding','transfer-encoding']:
info[key] = value
+ # Add annotations to the cache to indicate what headers
+ # are variant for this request.
+ vary = response_headers.get('vary', None)
+ if vary:
+ vary_headers = vary.lower().replace(' ', '').split(',')
+ for header in vary_headers:
+ key = '-varied-%s' % header
+ try:
+ info[key] = request_headers[header]
+ except KeyError:
+ pass
+
status = response_headers.status
if status == 304:
status = 200
@@ -1036,6 +1048,18 @@ a string that contains the response entity body.
# RFC 2616 Section 13.10
self.cache.delete(cachekey)
+ # Check the vary header in the cache to see if this request
+ # matches what varies in the cache.
+ if method in ['GET', 'HEAD'] and 'vary' in info:
+ vary = info['vary']
+ vary_headers = vary.lower().replace(' ', '').split(',')
+ for header in vary_headers:
+ key = '-varied-%s' % header
+ value = info[key]
+ if headers.get(header, '') != value:
+ cached_value = None
+ break
+
if cached_value and method in ["GET", "HEAD"] and self.cache and 'range' not in headers:
if info.has_key('-x-permanent-redirect-url'):
# Should cached permanent redirects be counted in our redirection count? For now, yes.
diff --git a/python2/httplib2test.py b/python2/httplib2test.py
index 5bab45e..3bfde31 100755
--- a/python2/httplib2test.py
+++ b/python2/httplib2test.py
@@ -573,6 +573,77 @@ class HttpTest(unittest.TestCase):
(response, content) = self.http.request(uri, "GET")
self.assertEqual(response.status, 410)
+ def testVaryHeaderSimple(self):
+ """
+ RFC 2616 13.6
+ When the cache receives a subsequent request whose Request-URI
+ specifies one or more cache entries including a Vary header field,
+ the cache MUST NOT use such a cache entry to construct a response
+ to the new request unless all of the selecting request-headers
+ present in the new request match the corresponding stored
+ request-headers in the original request.
+ """
+ # test that the vary header is sent
+ uri = urlparse.urljoin(base, "vary/accept.asis")
+ (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+ self.assertEqual(response.status, 200)
+ self.assertTrue(response.has_key('vary'))
+
+ # get the resource again, from the cache since accept header in this
+ # request is the same as the request
+ (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.fromcache, True, msg="Should be from cache")
+
+ # get the resource again, not from cache since Accept headers does not match
+ (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.fromcache, False, msg="Should not be from cache")
+
+ # get the resource again, without any Accept header, so again no match
+ (response, content) = self.http.request(uri, "GET")
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.fromcache, False, msg="Should not be from cache")
+
+ def testNoVary(self):
+ # when there is no vary, a different Accept header (e.g.) should not
+ # impact if the cache is used
+ # test that the vary header is not sent
+ uri = urlparse.urljoin(base, "vary/no-vary.asis")
+ (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+ self.assertEqual(response.status, 200)
+ self.assertFalse(response.has_key('vary'))
+
+ (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.fromcache, True, msg="Should be from cache")
+
+ (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.fromcache, True, msg="Should be from cache")
+
+ def testVaryHeaderDouble(self):
+ uri = urlparse.urljoin(base, "vary/accept-double.asis")
+ (response, content) = self.http.request(uri, "GET", headers={
+ 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
+ self.assertEqual(response.status, 200)
+ self.assertTrue(response.has_key('vary'))
+
+ # we are from cache
+ (response, content) = self.http.request(uri, "GET", headers={
+ 'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
+ self.assertEqual(response.fromcache, True, msg="Should be from cache")
+
+ (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.fromcache, False)
+
+ # get the resource again, not from cache, varied headers don't match exact
+ (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.fromcache, False, msg="Should not be from cache")
+
+
def testHeadGZip(self):
# Test that we don't try to decompress a HEAD response
uri = urlparse.urljoin(base, "gzip/final-destination.txt")
@@ -980,6 +1051,7 @@ except:
+
# ------------------------------------------------------------------------
class HttpPrivateTest(unittest.TestCase):
@@ -1328,4 +1400,5 @@ class HttpPrivateTest(unittest.TestCase):
end2end = httplib2._get_end2end_headers(response)
self.assertEquals(0, len(end2end))
-unittest.main()
+if __name__ == '__main__':
+ unittest.main()