Public bug reported:
[impact]
python-twisted errors out with "'NoneType' object has no attribute
'encode' in requestReceived()" when it tries to parse a multipart mime
message and python3.7+ is used. This happens because before commit
cc3fa20 in cpython, cgi.parse_multipart ignored parts without a name
defined in "content-disposition" (or parts without headers for that
matter) but after 3.7+ the return of the function can now contain
NoneType keys, which fail to encode.
[scope]
This bug affects all releases
Fixed upstream with commit 310496249, available since 21.2.0rc1
[test case]
1. Save the following code as webserver.py
from twisted.application.internet import TCPServer
from twisted.application.service import Application
from twisted.web.resource import Resource
from twisted.web.server import Site
class Foo(Resource):
def render_POST(self, request):
newdata = request.content.getvalue()
print(newdata)
return ''
root = Resource()
root.putChild("foo", Foo())
application = Application("cgi.parse_multipart test")
TCPServer(8080, Site(root)).setServiceParent(application)
2. Save the following code as client.py (python3-httplib2 is required)
#!/usr/bin/env python
import httplib2
def http_request(url, method, body=None, headers=None, insecure=False):
"""Issue an http request."""
http = httplib2.Http(disable_ssl_certificate_validation=insecure)
if isinstance(url, bytes):
url = url.decode("ascii")
return http.request(url, method, body=body, headers=headers)
url = "http://localhost:8080"
method = "POST"
headers = {'Content-Type': 'multipart/form-data;
boundary="8825899812428059282"'}
emptyh = '--8825899812428059282\n\n--8825899812428059282--'
print("== BODY: " + emptyh + "\n")
response, content = http_request(url, method, emptyh, headers)
3. Run the server with "twistd3 -y webserver.py"
4. Run the client
5. twistd will fail to encode the key and will drop this traceback in the log
file (twistd.log)
2021-02-16T13:41:39+0100 [_GenericHTTPChannelProtocol,7,127.0.0.1] Unhandled
Error
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/twisted/python/log.py", line
103, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "/usr/lib/python3/dist-packages/twisted/python/log.py", line 86,
in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/usr/lib/python3/dist-packages/twisted/python/context.py", line
122, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/lib/python3/dist-packages/twisted/python/context.py", line
85, in callWithContext
return func(*args,**kw)
--- <exception caught here> ---
File "/usr/lib/python3/dist-packages/twisted/internet/posixbase.py",
line 614, in _doReadOrWrite
why = selectable.doRead()
File "/usr/lib/python3/dist-packages/twisted/internet/tcp.py", line
243, in doRead
return self._dataReceived(data)
File "/usr/lib/python3/dist-packages/twisted/internet/tcp.py", line
249, in _dataReceived
rval = self.protocol.dataReceived(data)
File "/usr/lib/python3/dist-packages/twisted/web/http.py", line 2952,
in dataReceived
return self._channel.dataReceived(data)
File "/usr/lib/python3/dist-packages/twisted/web/http.py", line 2245,
in dataReceived
return basic.LineReceiver.dataReceived(self, data)
File "/usr/lib/python3/dist-packages/twisted/protocols/basic.py",
line 579, in dataReceived
why = self.rawDataReceived(data)
File "/usr/lib/python3/dist-packages/twisted/web/http.py", line 2252,
in rawDataReceived
self._transferDecoder.dataReceived(data)
File "/usr/lib/python3/dist-packages/twisted/web/http.py", line 1699,
in dataReceived
finishCallback(data[contentLength:])
File "/usr/lib/python3/dist-packages/twisted/web/http.py", line 2115,
in _finishRequestBody
self.allContentReceived()
File "/usr/lib/python3/dist-packages/twisted/web/http.py", line 2224,
in allContentReceived
req.requestReceived(command, path, version)
File "/usr/lib/python3/dist-packages/twisted/web/http.py", line 898,
in requestReceived
self.args.update({
File "/usr/lib/python3/dist-packages/twisted/web/http.py", line 899,
in <dictcomp>
x.encode('iso-8859-1'): \
builtins.AttributeError: 'NoneType' object has no attribute 'encode'
[regression potential]
This affects the returned dictionaries with non-str keys, which were
discarded in python3.6 or earlier before they reached twisted, so
patching this will make its behavior consistent.
** Affects: twisted (Ubuntu)
Importance: Undecided
Status: New
** Tags: sts
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/1915819
Title:
'NoneType' object has no attribute 'encode' in requestReceived() when
multipart body doesn't include content-disposition
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/twisted/+bug/1915819/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs