[Checkins] SVN: z3c.extfile/trunk/ see CHANGES.txt

Bernd Dorn bernd.dorn at lovelysystems.com
Sat Jan 19 07:06:52 EST 2008


Log message for revision 82949:
  see CHANGES.txt

Changed:
  U   z3c.extfile/trunk/CHANGES.txt
  U   z3c.extfile/trunk/src/z3c/extfile/filter.py
  U   z3c.extfile/trunk/src/z3c/extfile/filter.txt
  U   z3c.extfile/trunk/src/z3c/extfile/testing.py
  U   z3c.extfile/trunk/src/z3c/extfile/testing.txt

-=-
Modified: z3c.extfile/trunk/CHANGES.txt
===================================================================
--- z3c.extfile/trunk/CHANGES.txt	2008-01-18 15:49:30 UTC (rev 82948)
+++ z3c.extfile/trunk/CHANGES.txt	2008-01-19 12:06:51 UTC (rev 82949)
@@ -5,7 +5,7 @@
 After
 =====
 
-- TODO: set content-type in wsgi filter if info is present when
+- set content-type and length in wsgi filter if info is present when
   delivering files
 
 - tell and abort methods on WriteFile

Modified: z3c.extfile/trunk/src/z3c/extfile/filter.py
===================================================================
--- z3c.extfile/trunk/src/z3c/extfile/filter.py	2008-01-18 15:49:30 UTC (rev 82948)
+++ z3c.extfile/trunk/src/z3c/extfile/filter.py	2008-01-19 12:06:51 UTC (rev 82949)
@@ -21,31 +21,33 @@
         self.hd = hashdir.HashDir(self.dir)
 
     def __call__(self, env, start_response):
-        if env.get('X-EXTFILE-HANDLE') and env.get('REQUEST_METHOD')=='POST' and \
-           env.get('CONTENT_TYPE','').startswith('multipart/form-data;'):
-            fp = env['wsgi.input']
-            out = StringIO()
-            proc = processor.Processor(
-                self.hd,
-                contentInfo=env.has_key('X-EXTFILE-INFO'),
-                allowedTypes=env.get('X-EXTFILE-TYPES'),
-                )
-            cl = env.get('CONTENT_LENGTH')
-            if not cl:
-                raise RuntimeError, "No content-length header found"
-            cl = int(cl)
-            try:
-                proc.pushInput(fp, out, cl)
-            except interfaces.TypeNotAllowed:
-                start_response("400 Bad Request", [
-                    ('Content-Type', 'text/plain')])
-                return []
-            env['CONTENT_LENGTH'] = out.tell()
-            out.seek(0)
-            env['wsgi.input'] = out
-        elif env.get('REQUEST_METHOD') in ('GET',):
-            resp = FileResponse(self.app, self.hd)
-            return resp(env, start_response)
+        method = env.get('REQUEST_METHOD')
+        if env.get('X-EXTFILE-HANDLE'):
+            if method=='POST' and \
+                   env.get('CONTENT_TYPE','').startswith('multipart/form-data;'):
+                fp = env['wsgi.input']
+                out = StringIO()
+                proc = processor.Processor(
+                    self.hd,
+                    contentInfo=env.has_key('X-EXTFILE-INFO'),
+                    allowedTypes=env.get('X-EXTFILE-TYPES'),
+                    )
+                cl = env.get('CONTENT_LENGTH')
+                if not cl:
+                    raise RuntimeError, "No content-length header found"
+                cl = int(cl)
+                try:
+                    proc.pushInput(fp, out, cl)
+                except interfaces.TypeNotAllowed:
+                    start_response("400 Bad Request", [
+                        ('Content-Type', 'text/plain')])
+                    return []
+                env['CONTENT_LENGTH'] = out.tell()
+                out.seek(0)
+                env['wsgi.input'] = out
+            elif method == 'GET':
+                resp = FileResponse(self.app, self.hd)
+                return resp(env, start_response)
         return self.app(env, start_response)
 
 
@@ -58,6 +60,15 @@
 
     def start_response(self, status, headers_out, exc_info=None):
         """Intercept the response start from the filtered app."""
+        self.doHandle = False
+        if '200' in status:
+            for n,v in headers_out:
+                # the length is digest(40) + len(z3c.extfile.digest)
+                # we do not now how long the info is getting but it should
+                # be under 100
+                if n.lower()=='content-length' and len(v)<3:
+                    self.doHandle = True
+                    break
         self.status      = status
         self.headers_out = headers_out
         self.exc_info    = exc_info
@@ -66,60 +77,44 @@
         """Facilitate WSGI API by providing a callable hook."""
         self.env        = env
         self.real_start = start_response
-        return self.__iter__()
-
-    def __iter__(self):
-
-        result = self.app(self.env, self.start_response)
-        result_iter  = result.__iter__()
-        doHandle = False
-        for n,v in self.headers_out:
-            # the length is digest(40) + len(z3c.extfile.digest)
-            if n.lower()=='content-length' and v=='59':
-                doHandle = True
-                break
-        if not doHandle:
-            # this is not for us
-            headers_out = self.headers_out
-            iter_out = result_iter
+        self.response = self.app(self.env, self.start_response)
+        if self.doHandle is False:
+            return self._orgStart()
+        body = "".join(self.response)
+        if not body.startswith('z3c.extfile.digest:'):
+            return self._orgStart()
+        parts = body.split(':')
+        contentType = contentLength = None
+        if len(parts)==2:
+            digest = parts[1]
+        elif len(parts)==4:
+            digest, contentType, contentLength = parts[1:]
         else:
-            headers_out = dict(
-                [(k.lower(),v) for k,v in self.headers_out]
-                )
+            return self._orgStart()
+        try:
+            f = self.hd.open(digest)
+        except KeyError:
+            # no such digest
+            return self._orgStart()
+        headers_out = dict(
+            [(k.lower(),v) for k,v in self.headers_out]
+            )
+        if contentType:
+            headers_out['content-type'] = contentType
+        if contentLength:
+            headers_out['content-length'] = contentLength
+        else:
+            headers_out['content-length'] = str(len(f))
+        headers_out = headers_out.items()
+        fw = self.env.get('wsgi.file_wrapper')
+        self.real_start(self.status, headers_out, self.exc_info)
+        return f.__iter__()
+#    return fw(f, BLOCK_SIZE)
 
-            body = "".join(result_iter)
-            if body.startswith('z3c.extfile.digest:'):
-                digest = body[19:]
-            else:
-                digest = None
-            # do we have to handle the content. type?
-            # zope sniffs if it has no extension, so we get an unknown
-            # text content-type for our digest
-            filename = self.env['PATH_INFO']
-            content_type, content_encoding =mimetypes.guess_type(filename)
-            if content_type and not 'unknown' in \
-                   headers_out.get('content-type','unknown'):
-                headers_out['content-type'] = content_type
-            if content_encoding and not 'content-encoding' in headers_out:
-                headers_out['content-encoding'] = content_encoding
-            if digest is not None:
-                try:
-                    size = self.hd.getSize(digest)
-                    headers_out['content-length'] = size
-                    f = self.hd.open(digest)
-                    fw = self.env.get('wsgi.file_wrapper')
-                    iter_out = fw(f, BLOCK_SIZE)
-                except KeyError:
-                    # no such digest available, just return the body
-                    iter_out = body.__iter__()
-            else:
-                # we have no digest so return body
-                iter_out = body.__iter__()
-            headers_out = headers_out.items()
-        self.real_start(self.status, headers_out, exc_info=self.exc_info)
-        return iter_out
+    def _orgStart(self):
+        self.real_start(self.status, self.headers_out, self.exc_info)
+        return self.response
 
-
 def filter_factory(global_conf, **local_conf):
     if local_conf.has_key('directory'):
         local_conf['directory'] = os.path.join(

Modified: z3c.extfile/trunk/src/z3c/extfile/filter.txt
===================================================================
--- z3c.extfile/trunk/src/z3c/extfile/filter.txt	2008-01-18 15:49:30 UTC (rev 82948)
+++ z3c.extfile/trunk/src/z3c/extfile/filter.txt	2008-01-19 12:06:51 UTC (rev 82949)
@@ -132,3 +132,55 @@
     z3c...:3641323866cd50dd809a926cee773849cb6c8a85:application/x-gzip:4552
     ...
 
+GET Requests
+============
+
+The also replaces the extfile info with the real file. Our test
+application behind the filter returns the path on GET request, so we
+can just set the body we want.
+
+Here is an example.
+
+    >>> app.get('/abc').body
+    'abc'
+
+So let us request a file that we uploaded previously. If the header is
+not set nothing is done.
+
+
+    >>> info = 'z3c.extfile.digest:9a2e5260cd0001b96b623d25b01194ca7d8008db:text/html:126'
+    >>> app.get('/%s' % info).body == info
+    True
+
+Let us enable the filter by setting the environment.
+
+    >>> env = {'X-EXTFILE-HANDLE':'on'}
+    >>> res = app.get('/%s' % info, extra_environ=env)
+    >>> print res.body
+    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+    <head>
+    <title>Title</title>
+    <BLANKLINE>
+    <body>
+     body
+    </body>
+    </html>
+    <BLANKLINE>
+    >>> res.headers
+    [('content-length', '126'), ('content-type', 'text/html')]
+
+    >>> info='z3c.extfile.digest:4934828cf300711df0af9879b0b479c1c18e5707:video/mp4:1026603'
+
+    >>> res = app.get('/%s' % info, extra_environ=env)
+    >>> res.headers
+    [('content-length', '1026603'), ('content-type', 'video/mp4')]
+    >>> len(res.body)
+    1026603
+
+If we have no info the content-type is not modified. The length is taken
+from the files size.
+
+    >>> info='z3c.extfile.digest:4934828cf300711df0af9879b0b479c1c18e5707'
+    >>> res = app.get('/%s' % info, extra_environ=env)
+    >>> res.headers
+    [('content-length', '1026603'), ('content-type', 'text/plain')]

Modified: z3c.extfile/trunk/src/z3c/extfile/testing.py
===================================================================
--- z3c.extfile/trunk/src/z3c/extfile/testing.py	2008-01-18 15:49:30 UTC (rev 82948)
+++ z3c.extfile/trunk/src/z3c/extfile/testing.py	2008-01-19 12:06:51 UTC (rev 82949)
@@ -28,10 +28,17 @@
     returns the input stream
     """
     def __call__(self, environ, start_response):
-        #import pdb;pdb.set_trace()
-        start_response("200 OK", [('Content-Type', 'text/plain')])
-        for l in environ.get('wsgi.input'):
-            yield l
+        method = environ.get('REQUEST_METHOD')
+        if method=='POST':
+            start_response("200 OK", [('Content-Type', 'text/plain')])
+            return [l for l in environ.get('wsgi.input')]
+        else:
+            path = environ.get('PATH_INFO')[1:]
+            start_response("200 OK", [('Content-Type', 'text/plain'),
+                                      ('Content-Length', str(len(path))),
+                                      ])
+            return [path]
 
+
 def app_factory(global_conf, **local_conf):
     return In2OutApplication()

Modified: z3c.extfile/trunk/src/z3c/extfile/testing.txt
===================================================================
--- z3c.extfile/trunk/src/z3c/extfile/testing.txt	2008-01-18 15:49:30 UTC (rev 82948)
+++ z3c.extfile/trunk/src/z3c/extfile/testing.txt	2008-01-19 12:06:51 UTC (rev 82949)
@@ -18,6 +18,6 @@
 and we have the environment vaiable set
 
   >>> import os
-  >>> os.environ['EXTFILE_STORAGEDIR'] == oldEnv
+  >>> os.environ.get('EXTFILE_STORAGEDIR') == oldEnv
   False
 



More information about the Checkins mailing list