changeset 69:4b260d4ca1d4

added etag support
author Atul Varma <avarma@mozilla.com>
date Tue, 29 Jun 2010 21:45:47 -0700
parents 5c3f592522ea
children 09c95c2549f3
files summitidp/app.py tests/test_app.py
diffstat 2 files changed, 48 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/summitidp/app.py	Tue Jun 29 21:18:44 2010 -0700
+++ b/summitidp/app.py	Tue Jun 29 21:45:47 2010 -0700
@@ -40,9 +40,12 @@
         except ValueError:
             self.length = 0
 
-    def json_response(self, status, obj):
-        self.start_response(status,
-                            [('Content-Type', 'application/json')])
+    def json_response(self, status, obj, headers=None):
+        final_headers = [('Content-Type', 'application/json')]
+        if headers is not None:
+            for name, value in headers.items():
+                final_headers.append((name, value))
+        self.start_response(status, final_headers)
         return [json.dumps(obj)]
 
     def get_body(self):
@@ -200,6 +203,14 @@
                         '400 Bad Request',
                         {'error': 'invalid or expired token'}
                         )
+                if 'HTTP_IF_NONE_MATCH' in req.environ:
+                    try:
+                        rev = int(req.environ['HTTP_IF_NONE_MATCH'][1:-1])
+                    except ValueError:
+                        rev = -1
+                    if self.profiles.rev == rev:
+                        req.start_response('304 Not Modified', [])
+                        return []
                 try:
                     since_rev = int(req.qargs.get('since_rev', 0))
                 except ValueError:
@@ -210,7 +221,8 @@
                 profile = self.profiles.get(since_rev)
                 return req.json_response('200 OK',
                                          {'rev': self.profiles.rev,
-                                          'contents': profile})
+                                          'contents': profile},
+                                         {'ETag': '"%s"' % self.profiles.rev})
             elif req.method == 'POST':
                 body = req.get_body()
                 if body and 'token' in body and 'contents' in body:
--- a/tests/test_app.py	Tue Jun 29 21:18:44 2010 -0700
+++ b/tests/test_app.py	Tue Jun 29 21:45:47 2010 -0700
@@ -164,6 +164,38 @@
             status=400)
 
 @apptest
+def test_get_profile_includes_etag():
+    token = server.auth_tokens.create(email='bob@foo.com',
+                                      user_id=0)
+    resp = app.get('%s?token=%s' % (server.profile_path, token))
+    assert resp.headers['ETag'] == '"0"'
+
+    post_json(server.profile_path,
+              {'token': token,
+               'contents': {'name': 'bob jones'}})
+    resp = app.get('%s?token=%s' % (server.profile_path, token))
+    assert resp.headers['ETag'] == '"1"'
+
+    # Ensure If-None-Match is ignored if it's not the latest rev.
+
+    resp = app.get('%s?token=%s' % (server.profile_path, token),
+                   headers={'If-None-Match': '"0"'},
+                   status=200)
+
+    # Ensure 304's are issued when appropriate.
+
+    resp = app.get('%s?token=%s' % (server.profile_path, token),
+                   headers={'If-None-Match': '"1"'},
+                   status=304)
+
+    # Ensure invalid If-None-Matches are ignored (not sure if
+    # this is actually the right behavior or not, though...)
+
+    resp = app.get('%s?token=%s' % (server.profile_path, token),
+                   headers={'If-None-Match': '"meh"'},
+                   status=200)
+
+@apptest
 def test_get_profile_with_invalid_since_rev():
     token = server.auth_tokens.create(email='bob@foo.com',
                                       user_id=0)