mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-20 17:52:50 +00:00
web: transform FileTooLargeError into a friendlier '413 Request Entity Too Large' error
This commit is contained in:
parent
f4496bd553
commit
32c89a8d59
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user