diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py index c3965645a..2d9ef25ff 100644 --- a/src/allmydata/webish.py +++ b/src/allmydata/webish.py @@ -44,6 +44,42 @@ from .web.storage_plugins import ( StoragePlugins, ) + +if PY2: + FileUploadFieldStorage = FieldStorage +else: + class FileUploadFieldStorage(FieldStorage): + """ + Do terrible things to ensure files are still bytes. + + On Python 2, uploaded files were always bytes. On Python 3, there's a + heuristic: if the filename is set on a field, it's assumed to be a file + upload and therefore bytes. If no filename is set, it's Unicode. + + Unfortunately, we always want it to be bytes, and Tahoe-LAFS also + enables setting the filename not via the MIME filename, but via a + separate field called "name". + + Thus we need to do this ridiculous workaround. + + Source for idea: + https://mail.python.org/pipermail/python-dev/2017-February/147402.html + """ + @property + def filename(self): + if self.name == "file" and not self._mime_filename: + # We use the file field to upload files, see directory.py's + # _POST_upload. Lack of _mime_filename means we need to trick + # FieldStorage into thinking there is a filename so it'll + # return bytes. + return "unknown-filename" + return self._mime_filename + + @filename.setter + def filename(self, value): + self._mime_filename = value + + class TahoeLAFSRequest(Request, object): """ ``TahoeLAFSRequest`` adds several features to a Twisted Web ``Request`` @@ -94,7 +130,8 @@ class TahoeLAFSRequest(Request, object): headers['content-length'] = str(self.content.tell()) self.content.seek(0) - self.fields = FieldStorage(self.content, headers, environ={'REQUEST_METHOD': 'POST'}) + self.fields = FileUploadFieldStorage( + self.content, headers, environ={'REQUEST_METHOD': 'POST'}) self.content.seek(0) self._tahoeLAFSSecurityPolicy()