From: Brian Warner Date: Sun, 13 May 2012 07:41:53 +0000 (-0700) Subject: webapi: don't allow ETags in t=info or t=rename-form, both are variable X-Git-Url: https://git.rkrishnan.org/pf/content/simplejson/about.html?a=commitdiff_plain;h=5d404db898e1e6dc334c3d125ea12a34ea58b13f;p=tahoe-lafs%2Ftahoe-lafs.git webapi: don't allow ETags in t=info or t=rename-form, both are variable t=info contains randomly-generated ophandles, and t=rename-form contains the name of the child being renamed, so neither is eligible for a short-circuiting ETag. Enhanced test_web to exercise this. Had to improve FakeCHKFileNode slightly to let it participate. Refs #443. --- diff --git a/src/allmydata/test/common.py b/src/allmydata/test/common.py index 627765a4..a914baa8 100644 --- a/src/allmydata/test/common.py +++ b/src/allmydata/test/common.py @@ -113,6 +113,8 @@ class FakeCHKFileNode: except KeyError, le: raise NotEnoughSharesError(le, 0, 3) return len(data) + def get_current_size(self): + return defer.succeed(self.get_size()) def read(self, consumer, offset=0, size=None): # we don't bother to call registerProducer/unregisterProducer, diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py index 81dbb201..1b150828 100644 --- a/src/allmydata/test/test_web.py +++ b/src/allmydata/test/test_web.py @@ -930,6 +930,10 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi (newkids, caps) = self._create_immutable_children() d = self.POST2(self.public_url + "/foo/newdir?t=mkdir-immutable", simplejson.dumps(newkids)) + def _stash_immdir_uri(uri): + self._immdir_uri = uri + return uri + d.addCallback(_stash_immdir_uri) d.addCallback(_check_etags) # Check that etags work with immutable files @@ -951,6 +955,33 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi self.failUnlessEqual(int(code), http.NOT_MODIFIED)) return d d.addCallback(_check_match) + + def _no_etag(uri, t): + target = "/uri/%s?t=%s" % (uri, t) + d = self.GET(target, return_response=True, followRedirect=True) + d.addCallback(lambda (data, code, headers): + self.failIf("etag" in headers, target)) + return d + def _yes_etag(uri, t): + target = "/uri/%s?t=%s" % (uri, t) + d = self.GET(target, return_response=True, followRedirect=True) + d.addCallback(lambda (data, code, headers): + self.failUnless("etag" in headers, target)) + return d + + d.addCallback(lambda ign: _yes_etag(self._bar_txt_uri, "")) + d.addCallback(lambda ign: _yes_etag(self._bar_txt_uri, "json")) + d.addCallback(lambda ign: _yes_etag(self._bar_txt_uri, "uri")) + d.addCallback(lambda ign: _yes_etag(self._bar_txt_uri, "readonly-uri")) + d.addCallback(lambda ign: _no_etag(self._bar_txt_uri, "info")) + + d.addCallback(lambda ign: _yes_etag(self._immdir_uri, "")) + d.addCallback(lambda ign: _yes_etag(self._immdir_uri, "json")) + d.addCallback(lambda ign: _yes_etag(self._immdir_uri, "uri")) + d.addCallback(lambda ign: _yes_etag(self._immdir_uri, "readonly-uri")) + d.addCallback(lambda ign: _no_etag(self._immdir_uri, "info")) + d.addCallback(lambda ign: _no_etag(self._immdir_uri, "rename-form")) + return d # TODO: version of this with a Unicode filename diff --git a/src/allmydata/web/directory.py b/src/allmydata/web/directory.py index 80f5aa3d..cf1d4d38 100644 --- a/src/allmydata/web/directory.py +++ b/src/allmydata/web/directory.py @@ -154,7 +154,10 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): # This is where all of the directory-related ?t=* code goes. t = get_arg(req, "t", "").strip() - if not self.node.is_mutable(): + # t=info contains variable ophandles, t=rename-form contains the name + # of the child being renamed. Neither is allowed an ETag. + FIXED_OUTPUT_TYPES = ["", "json", "uri", "readonly-uri"] + if not self.node.is_mutable() and t in FIXED_OUTPUT_TYPES: si = self.node.get_storage_index() if si and req.setETag('DIR:%s-%s' % (base32.b2a(si), t or "")): return "" diff --git a/src/allmydata/web/filenode.py b/src/allmydata/web/filenode.py index 9a1983e6..bce8e90c 100644 --- a/src/allmydata/web/filenode.py +++ b/src/allmydata/web/filenode.py @@ -158,7 +158,9 @@ class FileNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin): req = IRequest(ctx) t = get_arg(req, "t", "").strip() - if not self.node.is_mutable(): + # t=info contains variable ophandles, so is not allowed an ETag. + FIXED_OUTPUT_TYPES = ["", "json", "uri", "readonly-uri"] + if not self.node.is_mutable() and t in FIXED_OUTPUT_TYPES: # if the client already has the ETag then we can # short-circuit the whole process. si = self.node.get_storage_index()