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.
This commit is contained in:
Brian Warner 2012-05-13 00:41:53 -07:00
parent d437a9b33e
commit 5d404db898
4 changed files with 40 additions and 2 deletions

View File

@ -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,

View File

@ -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

View File

@ -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 ""

View File

@ -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()