backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 16 Jun 2010 14:51:17 +0200
changeset 5762 730d458ec1bf
parent 5754 51179e0bb250 (current diff)
parent 5761 02bccbc4ff1c (diff)
child 5764 ec5dbbb6a549
backport stable
devtools/devctl.py
entity.py
etwist/server.py
server/test/data/schema.py
server/test/unittest_undo.py
web/formfields.py
web/views/basecontrollers.py
web/views/treeview.py
--- a/devtools/devctl.py	Wed Jun 16 09:21:49 2010 +0200
+++ b/devtools/devctl.py	Wed Jun 16 14:51:17 2010 +0200
@@ -650,7 +650,7 @@
             except OSError, ex:
                 raise BadCommandUsage("can't open rql log file %s: %s"
                                       % (filepath, ex))
-            for lineno, line in enumerate(file):
+            for lineno, line in enumerate(stream):
                 if not ' WHERE ' in line:
                     continue
                 try:
--- a/doc/book/en/devrepo/profiling.rst	Wed Jun 16 09:21:49 2010 +0200
+++ b/doc/book/en/devrepo/profiling.rst	Wed Jun 16 14:51:17 2010 +0200
@@ -26,7 +26,7 @@
 
 .. sourcecode:: sh
 
-    $ cubicweb-ctl exlog < ~/myapp-rql.log
+    $ cubicweb-ctl exlog ~/myapp-rql.log
     0.07 50 Any A WHERE X eid %(x)s, X firstname A {}
     0.05 50 Any A WHERE X eid %(x)s, X lastname A {}
     0.01 1 Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E employees X, X modification_date AA {}
--- a/entity.py	Wed Jun 16 09:21:49 2010 +0200
+++ b/entity.py	Wed Jun 16 14:51:17 2010 +0200
@@ -781,7 +781,10 @@
             return self._cw_relation_cache(rtype, role, entities, limit)
         except KeyError:
             pass
-        assert self.has_eid()
+        if not self.has_eid():
+            if entities:
+                return []
+            return self.empty_rset()
         rql = self.cw_related_rql(rtype, role)
         rset = self._cw.execute(rql, {'x': self.eid})
         self.cw_set_relation_cache(rtype, role, rset)
--- a/etwist/server.py	Wed Jun 16 09:21:49 2010 +0200
+++ b/etwist/server.py	Wed Jun 16 14:51:17 2010 +0200
@@ -203,6 +203,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()
@@ -334,7 +339,6 @@
             d.callback(None)
         self.notifications = []
 
-
 @monkeypatch(http.Request)
 def requestReceived(self, command, path, version):
     """Called by channel when all data has been received.
@@ -359,30 +363,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')
--- a/server/test/data/schema.py	Wed Jun 16 09:21:49 2010 +0200
+++ b/server/test/data/schema.py	Wed Jun 16 14:51:17 2010 +0200
@@ -15,9 +15,7 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""
 
-"""
 from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
                             SubjectRelation, RichString, String, Int, Boolean, Datetime)
 from yams.constraints import SizeConstraint
--- a/server/test/data/sources_multi	Wed Jun 16 09:21:49 2010 +0200
+++ b/server/test/data/sources_multi	Wed Jun 16 14:51:17 2010 +0200
@@ -3,7 +3,7 @@
 db-driver   = sqlite
 db-host     = 
 adapter     = native
-db-name     = tmpdb
+db-name     = tmpdb-multi
 db-encoding = UTF-8
 db-user     = admin
 db-password = gingkow
--- a/server/test/unittest_undo.py	Wed Jun 16 09:21:49 2010 +0200
+++ b/server/test/unittest_undo.py	Wed Jun 16 14:51:17 2010 +0200
@@ -280,3 +280,7 @@
         #                    'required on CWUser (%s)' % self.toto.eid})
 
     # test implicit 'replacement' of an inlined relation
+
+if __name__ == '__main__':
+    from logilab.common.testlib import unittest_main
+    unittest_main()
--- a/web/formfields.py	Wed Jun 16 09:21:49 2010 +0200
+++ b/web/formfields.py	Wed Jun 16 14:51:17 2010 +0200
@@ -82,6 +82,8 @@
     it
     """
 
+def normalize_filename(filename):
+    return filename.split('\\')[-1]
 
 def vocab_sort(vocab):
     """sort vocabulary, considering option groups"""
@@ -742,7 +744,7 @@
             value = None
         else:
             # set filename on the Binary instance, may be used later in hooks
-            value.filename = filename
+            value.filename = normalize_filename(filename)
         return value
 
 
--- a/web/views/basecontrollers.py	Wed Jun 16 09:21:49 2010 +0200
+++ b/web/views/basecontrollers.py	Wed Jun 16 14:51:17 2010 +0200
@@ -543,12 +543,12 @@
             cookies[statename] = nodeeid
             self._cw.set_cookie(cookies, statename)
         else:
-            marked = set(filter(None, treestate.value.split(';')))
+            marked = set(filter(None, treestate.value.split(':')))
             if nodeeid in marked:
                 marked.remove(nodeeid)
             else:
                 marked.add(nodeeid)
-            cookies[statename] = ';'.join(marked)
+            cookies[statename] = ':'.join(marked)
             self._cw.set_cookie(cookies, statename)
 
     @jsonize
--- a/web/views/treeview.py	Wed Jun 16 09:21:49 2010 +0200
+++ b/web/views/treeview.py	Wed Jun 16 14:51:17 2010 +0200
@@ -216,7 +216,7 @@
         cookies = self._cw.get_cookie()
         treestate = cookies.get(treecookiename(treeid))
         if treestate:
-            return str(eeid) in treestate.value.split(';')
+            return str(eeid) in treestate.value.split(':')
         return self.default_branch_state_is_open
 
     def cell_call(self, row, col, treeid, vid='oneline', parentvid='treeview',