web: transform FileTooLargeError into a friendlier '413 Request Entity Too Large' error

This commit is contained in:
Brian Warner 2008-06-03 00:03:16 -07:00
parent f4496bd553
commit 32c89a8d59
3 changed files with 67 additions and 6 deletions

View File

@ -5,7 +5,8 @@ from twisted.internet import defer
from twisted.python import failure
from twisted.application import service
from allmydata import uri, dirnode
from allmydata.interfaces import IURI, IMutableFileNode, IFileNode
from allmydata.interfaces import IURI, IMutableFileNode, IFileNode, \
FileTooLargeError
from allmydata.encode import NotEnoughSharesError
from allmydata.util import log
@ -70,12 +71,18 @@ class FakeMutableFileNode:
class-level dictionary."""
implements(IMutableFileNode)
MUTABLE_SIZELIMIT = 10000
all_contents = {}
def __init__(self, client):
self.client = client
self.my_uri = make_mutable_file_uri()
self.storage_index = self.my_uri.storage_index
def create(self, initial_contents, key_generator=None):
if len(initial_contents) > self.MUTABLE_SIZELIMIT:
raise FileTooLargeError("SDMF is limited to one segment, and "
"%d > %d" % (len(initial_contents),
self.MUTABLE_SIZELIMIT))
self.all_contents[self.storage_index] = initial_contents
return defer.succeed(self)
def init_from_uri(self, myuri):
@ -100,10 +107,15 @@ class FakeMutableFileNode:
def download_best_version(self):
return defer.succeed(self.all_contents[self.storage_index])
def overwrite(self, new_contents):
if len(new_contents) > self.MUTABLE_SIZELIMIT:
raise FileTooLargeError("SDMF is limited to one segment, and "
"%d > %d" % (len(new_contents),
self.MUTABLE_SIZELIMIT))
assert not self.is_readonly()
self.all_contents[self.storage_index] = new_contents
return defer.succeed(None)
def modify(self, modifier):
# this does not implement FileTooLargeError, but the real one does
return defer.maybeDeferred(self._modify, modifier)
def _modify(self, modifier):
assert not self.is_readonly()

View File

@ -62,6 +62,7 @@ class FakeClient(service.MultiService):
d.addCallback(lambda res: n)
return d
MUTABLE_SIZELIMIT = FakeMutableFileNode.MUTABLE_SIZELIMIT
def create_mutable_file(self, contents=""):
n = FakeMutableFileNode(self)
return n.create(contents)
@ -288,12 +289,13 @@ class WebMixin(object):
res.trap(expected_failure)
if substring:
self.failUnless(substring in str(res),
"substring '%s' not in '%s'"
% (substring, str(res)))
"%s: substring '%s' not in '%s'"
% (which, substring, str(res)))
if response_substring:
self.failUnless(response_substring in res.value.response,
"response substring '%s' not in '%s'"
% (response_substring, res.value.response))
"%s: response substring '%s' not in '%s'"
% (which,
response_substring, res.value.response))
else:
self.fail("%s was supposed to raise %s, not get '%s'" %
(which, expected_failure, res))
@ -607,6 +609,15 @@ class Web(WebMixin, unittest.TestCase):
self.NEWFILE_CONTENTS))
return d
def test_PUT_NEWFILEURL_mutable_toobig(self):
d = self.shouldFail2(error.Error, "test_PUT_NEWFILEURL_mutable_toobig",
"413 Request Entity Too Large",
"SDMF is limited to one segment, and 10001 > 10000",
self.PUT,
self.public_url + "/foo/new.txt?mutable=true",
"b" * (self.s.MUTABLE_SIZELIMIT+1))
return d
def test_PUT_NEWFILEURL_replace(self):
d = self.PUT(self.public_url + "/foo/bar.txt", self.NEWFILE_CONTENTS)
# TODO: we lose the response code, so we can't check this
@ -1052,6 +1063,17 @@ class Web(WebMixin, unittest.TestCase):
d.addCallback(_check4)
return d
def test_POST_upload_no_link_mutable_toobig(self):
d = self.shouldFail2(error.Error,
"test_POST_upload_no_link_mutable_toobig",
"413 Request Entity Too Large",
"SDMF is limited to one segment, and 10001 > 10000",
self.POST,
"/uri", t="upload", mutable="true",
file=("new.txt",
"b" * (self.s.MUTABLE_SIZELIMIT+1)) )
return d
def test_POST_upload_mutable(self):
# this creates a mutable file
d = self.POST(self.public_url + "/foo", t="upload", mutable="true",
@ -1196,9 +1218,34 @@ class Web(WebMixin, unittest.TestCase):
self.failUnlessEqual(headers["content-type"], ["text/plain"])
d.addCallback(_got_headers)
# make sure that size errors are displayed correctly for overwrite
d.addCallback(lambda res:
self.shouldFail2(error.Error,
"test_POST_upload_mutable-toobig",
"413 Request Entity Too Large",
"SDMF is limited to one segment, and 10001 > 10000",
self.POST,
self.public_url + "/foo", t="upload",
mutable="true",
file=("new.txt",
"b" * (self.s.MUTABLE_SIZELIMIT+1)),
))
d.addErrback(self.dump_error)
return d
def test_POST_upload_mutable_toobig(self):
d = self.shouldFail2(error.Error,
"test_POST_upload_no_link_mutable_toobig",
"413 Request Entity Too Large",
"SDMF is limited to one segment, and 10001 > 10000",
self.POST,
self.public_url + "/foo",
t="upload", mutable="true",
file=("new.txt",
"b" * (self.s.MUTABLE_SIZELIMIT+1)) )
return d
def dump_error(self, f):
# if the web server returns an error code (like 400 Bad Request),
# web.client.getPage puts the HTTP response body into the .response

View File

@ -4,7 +4,7 @@ from zope.interface import Interface
from nevow import loaders, appserver
from nevow.inevow import IRequest
from nevow.util import resource_filename
from allmydata.interfaces import ExistingChildError
from allmydata.interfaces import ExistingChildError, FileTooLargeError
class IClient(Interface):
pass
@ -114,6 +114,8 @@ class MyExceptionHandler(appserver.DefaultExceptionHandler):
http.CONFLICT)
elif f.check(WebError):
return self.simple(ctx, f.value.text, f.value.code)
elif f.check(FileTooLargeError):
return self.simple(ctx, str(f.value), http.REQUEST_ENTITY_TOO_LARGE)
elif f.check(server.UnsupportedMethod):
# twisted.web.server.Request.render() has support for transforming
# this into an appropriate 501 NOT_IMPLEMENTED or 405 NOT_ALLOWED