etwist/server.py
branchstable
changeset 5759 5db529e0a3ee
parent 5660 97343804414b
child 5762 730d458ec1bf
--- a/etwist/server.py	Wed Jun 16 12:24:11 2010 +0200
+++ b/etwist/server.py	Wed Jun 16 12:24:12 2010 +0200
@@ -197,6 +197,11 @@
 
     def render_request(self, request):
         try:
+            # processing HUGE files (hundred of megabytes) in http.processReceived
+            # blocks other HTTP requests processing
+            # due to the clumsy & slow parsing algorithm of cgi.FieldStorage
+            # so we deferred that part to the cubicweb thread
+            request.process_multipart()
             return self._render_request(request)
         except:
             errorstream = StringIO()
@@ -328,7 +333,6 @@
             d.callback(None)
         self.notifications = []
 
-
 @monkeypatch(http.Request)
 def requestReceived(self, command, path, version):
     """Called by channel when all data has been received.
@@ -353,30 +357,38 @@
     self.host = self.channel.transport.getHost()
     # Argument processing
     ctype = self.getHeader('content-type')
+    self._do_process_multipart = False
     if self.method == "POST" and ctype:
         key, pdict = parse_header(ctype)
         if key == 'application/x-www-form-urlencoded':
             self.args.update(http.parse_qs(self.content.read(), 1))
         elif key == 'multipart/form-data':
-            self.content.seek(0, 0)
-            form = FieldStorage(self.content, self.received_headers,
-                                environ={'REQUEST_METHOD': 'POST'},
-                                keep_blank_values=1,
-                                strict_parsing=1)
-            for key in form:
-                value = form[key]
-                if isinstance(value, list):
-                    self.args[key] = [v.value for v in value]
-                elif value.filename:
-                    if value.done != -1: # -1 is transfer has been interrupted
-                        self.files[key] = (value.filename, value.file)
-                    else:
-                        self.files[key] = (None, None)
-                else:
-                    self.args[key] = value.value
+            # defer this as it can be extremely time consumming
+            # with big files
+            self._do_process_multipart = True
     self.process()
 
 
+@monkeypatch(http.Request)
+def process_multipart(self):
+    if not self._do_process_multipart:
+        return
+    form = FieldStorage(self.content, self.received_headers,
+                        environ={'REQUEST_METHOD': 'POST'},
+                        keep_blank_values=1,
+                        strict_parsing=1)
+    for key in form:
+        value = form[key]
+        if isinstance(value, list):
+            self.args[key] = [v.value for v in value]
+        elif value.filename:
+            if value.done != -1: # -1 is transfer has been interrupted
+                self.files[key] = (value.filename, value.file)
+            else:
+                self.files[key] = (None, None)
+        else:
+            self.args[key] = value.value
+
 from logging import getLogger
 from cubicweb import set_log_methods
 LOGGER = getLogger('cubicweb.twisted')