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
ubuntu-bugs@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to