Merge branch 'trunk' into 9496-names-traceback

This commit is contained in:
Glyph 2020-01-09 13:21:43 -08:00 committed by GitHub
commit fecfc159fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 77 additions and 8 deletions

View File

View File

@ -873,7 +873,8 @@ class Request:
@type version: C{bytes}
@param version: The HTTP version of this request.
"""
self.content.seek(0,0)
clength = self.content.tell()
self.content.seek(0, 0)
self.args = {}
self.method, self.uri = command, path
@ -889,16 +890,16 @@ class Request:
# Argument processing
args = self.args
ctype = self.requestHeaders.getRawHeaders(b'content-type')
clength = self.requestHeaders.getRawHeaders(b'content-length')
if ctype is not None:
ctype = ctype[0]
if clength is not None:
clength = clength[0]
if self.method == b"POST" and ctype and clength:
mfd = b'multipart/form-data'
key, pdict = _parseHeader(ctype)
# This weird CONTENT-LENGTH param is required by
# cgi.parse_multipart() in some versions of Python 3.7+, see
# bpo-29979. It looks like this will be relaxed and backported, see
# https://github.com/python/cpython/pull/8530.
pdict["CONTENT-LENGTH"] = clength
if key == b'application/x-www-form-urlencoded':
args.update(parse_qs(self.content.read(), 1))

View File

@ -0,0 +1 @@
twisted.web.http.Request now correctly parses multipart-encoded form data submitted as a chunked request on Python 3.7+.

View File

@ -1426,6 +1426,73 @@ class ChunkingTests(unittest.TestCase, ResponseTestMixin):
b"Transfer-Encoding: chunked",
b"5\r\nHello\r\n6\r\nWorld!\r\n")])
def runChunkedRequest(self, httpRequest, requestFactory=None,
chunkSize=1):
"""
Execute a web request based on plain text content, chunking
the request payload.
This is a stripped-down, chunking version of ParsingTests.runRequest.
"""
channel = http.HTTPChannel()
if requestFactory:
channel.requestFactory = _makeRequestProxyFactory(requestFactory)
httpRequest = httpRequest.replace(b"\n", b"\r\n")
header, body = httpRequest.split(b"\r\n\r\n", 1)
transport = StringTransport()
channel.makeConnection(transport)
channel.dataReceived(header+b"\r\n\r\n")
for pos in range(len(body)//chunkSize+1):
if channel.transport.disconnecting:
break
channel.dataReceived(b"".join(
http.toChunk(body[pos*chunkSize:(pos+1)*chunkSize])))
channel.dataReceived(b"".join(http.toChunk(b"")))
channel.connectionLost(IOError("all done"))
return channel
def test_multipartFormData(self):
"""
Test that chunked uploads are actually processed into args.
This is essentially a copy of ParsingTests.test_multipartFormData,
just with chunking put in.
This fails as of twisted version 18.9.0 because of bug #9678.
"""
processed = []
class MyRequest(http.Request):
def process(self):
processed.append(self)
self.write(b"done")
self.finish()
req = b'''\
POST / HTTP/1.0
Content-Type: multipart/form-data; boundary=AaB03x
Transfer-Encoding: chunked
--AaB03x
Content-Type: text/plain
Content-Disposition: form-data; name="text"
Content-Transfer-Encoding: quoted-printable
abasdfg
--AaB03x--
'''
channel = self.runChunkedRequest(req, MyRequest, chunkSize=5)
self.assertEqual(channel.transport.value(),
b"HTTP/1.0 200 OK\r\n\r\ndone")
self.assertEqual(len(processed), 1)
self.assertEqual(processed[0].args, {b"text": [b"abasdfg"]})
class ParsingTests(unittest.TestCase):

View File

@ -48,9 +48,9 @@ extras =
deps =
py27-alldeps-{posix,macos}: pysqlite
; Coverage 5.0 does not work with codecov.
{withcov}: coverage<5.0
{coverage-prepare,codecov-publish}: coverage<5.0
{withcov}: coverage
{coverage-prepare,codecov-publish}: coverage
{codecov-push,codecov-publish}: codecov