From 36dd749a41a965c9f2ce4f8d3bf610bc30ba3a79 Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Thu, 27 Apr 2023 20:56:08 +0200 Subject: [PATCH 1/2] Fix regression with FieldStorage and large payloads (#15) --- webware/WebUtils/FieldStorage.py | 3 +- .../Tests/TestFieldStorageModified.py | 80 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/webware/WebUtils/FieldStorage.py b/webware/WebUtils/FieldStorage.py index 9f6eb06..2c6e010 100644 --- a/webware/WebUtils/FieldStorage.py +++ b/webware/WebUtils/FieldStorage.py @@ -435,7 +435,8 @@ def read_binary(self): data = data.decode() except UnicodeDecodeError: self._binary_file = True - self.file = self.make_file() + if self.file is None: + self.file = self.make_file() self.file.write(data) todo -= len(data) diff --git a/webware/WebUtils/Tests/TestFieldStorageModified.py b/webware/WebUtils/Tests/TestFieldStorageModified.py index d55551f..6041f72 100644 --- a/webware/WebUtils/Tests/TestFieldStorageModified.py +++ b/webware/WebUtils/Tests/TestFieldStorageModified.py @@ -257,6 +257,86 @@ def testPostRequestWithNonUtf8TextData(self): self.assertEqual(fs.bytes_read, length) self.assertEqual(fs.file.read(), content) + def testPostRequestWithSmallPayloadWithContentLength(self): + length = 1000 # much smaller than buffer size + payload = 'x' * length + fs = FieldStorage( + fp=BytesIO(payload.encode()), + environ={'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'text/plain', + 'CONTENT_LENGTH': length}) + self.assertEqual(fs.headers, { + 'content-type': 'text/plain', + 'content-length': length}) + self.assertEqual(fs.type, 'text/plain') + self.assertEqual(fs.length, length) + self.assertEqual(fs.bytes_read, length) + self.assertEqual(fs.file.read(), payload) + + def testPostRequestWithLargeTextPayloadWithContentLength(self): + length = 25000 # much larger than buffer size + payload = 'x' * length + fs = FieldStorage( + fp=BytesIO(payload.encode()), + environ={'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'text/plain', + 'CONTENT_LENGTH': length}) + self.assertEqual(fs.headers, { + 'content-type': 'text/plain', + 'content-length': length}) + self.assertEqual(fs.type, 'text/plain') + self.assertEqual(fs.length, length) + self.assertEqual(fs.bytes_read, length) + self.assertEqual(fs.file.read(), payload) + + def testPostRequestWithLargeJsonPayloadWithContentLength(self): + # create JSON payload that is much larger than the buffer size + payload = {f'test{i}': str(i) * 5000 for i in range(5)} + payload = str(payload).replace("'", '"') + length = len(payload) + self.assertGreater(length, 25000) + fs = FieldStorage( + fp=BytesIO(payload.encode()), + environ={'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'application/json', + 'CONTENT_LENGTH': length}) + self.assertEqual(fs.headers, { + 'content-type': 'application/json', + 'content-length': length}) + self.assertEqual(fs.type, 'application/json') + self.assertEqual(fs.length, length) + self.assertEqual(fs.bytes_read, length) + # make sure that the original payload is preserved + self.assertEqual(fs.file.read(), payload) + + def testPostRequestWithSmallPayloadWithoutContentLength(self): + length = 1000 # much smaller than buffer size + payload = 'x' * length + fs = FieldStorage( + fp=BytesIO(payload.encode()), + environ={'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'text/plain'}) + self.assertEqual(fs.headers, { + 'content-type': 'text/plain'}) + self.assertEqual(fs.type, 'text/plain') + self.assertEqual(fs.length, -1) + self.assertEqual(fs.bytes_read, length) + self.assertEqual(fs.file.read(), payload) + + def testPostRequestWithLargePayloadWithoutContentLength(self): + length = 25000 # much larger than buffer size + payload = 'x' * length + fs = FieldStorage( + fp=BytesIO(payload.encode()), + environ={'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'text/plain'}) + self.assertEqual(fs.headers, { + 'content-type': 'text/plain'}) + self.assertEqual(fs.type, 'text/plain') + self.assertEqual(fs.length, -1) + self.assertEqual(fs.bytes_read, length) + self.assertEqual(fs.file.read(), payload) + def testIsBinaryType(self): self.assertIs(isBinaryType('application/json'), False) self.assertIs(isBinaryType('application/xml'), False) From a2748945dc982503048dd1486ae4876c91f48ba4 Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Thu, 27 Apr 2023 20:58:32 +0200 Subject: [PATCH 2/2] Bump version number for patch release --- docs/conf.py | 2 +- webware/Properties.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 723fb5e..def94ca 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,7 +28,7 @@ # The short X.Y version version = '3.0' # The full version, including alpha/beta/rc tags -release = '3.0.8' +release = '3.0.9' # -- General configuration --------------------------------------------------- diff --git a/webware/Properties.py b/webware/Properties.py index ca1f447..1d3d05c 100644 --- a/webware/Properties.py +++ b/webware/Properties.py @@ -1,6 +1,6 @@ name = 'Webware for Python' -version = (3, 0, 8) +version = (3, 0, 9) status = 'stable'