SVN: r25536 - trunk/quixote

Neil Schemenauer <nascheme-fVcApmY9cLvQ3/1i3zOLAti2O/[email protected]> Thu, 4 Nov 2004 18:30:53 -0500
Newsgroups gmane.comp.web.quixote.cvs
Message-ID <[email protected]>
Author: nascheme
Date: 2004-11-04 18:30:44 -0500 (Thu, 04 Nov 2004)
New Revision: 25536

Modified:
   trunk/quixote/http_response.py
   trunk/quixote/publish.py
Log:
Move page compression functionality to http_response module.


Modified: trunk/quixote/http_response.py
===================================================================
--- trunk/quixote/http_response.py	2004-11-04 23:21:40 UTC (rev 25535)
+++ trunk/quixote/http_response.py	2004-11-04 23:30:44 UTC (rev 25536)
@@ -6,6 +6,11 @@
 """
 
 import time
+try:
+    import zlib
+except ImportError:
+    pass
+import struct
 from rfc822 import formatdate
 from quixote.html import stringify
 
@@ -58,7 +63,14 @@
     507: 'Insufficient Storage',
 }
 
+_GZIP_HEADER = ("\037\213" # magic
+                "\010" # compression method
+                "\000" # flags
+                "\000\000\000\000" # time, who cares?
+                "\002"
+                "\377")
 
+
 class HTTPResponse:
     """
     An object representation of an HTTP response.
@@ -199,16 +211,37 @@
         else:
             return chunk.encode(self.charset)
             
-    def set_body(self, body):
-        """(body : any)
-
-        Sets the response body equal to the argument "body".
+    def _compress_body(self, body):
+        """(body: str) -> str
         """
-        if isinstance(body, Stream):
-            self.body = body
+        n = len(body)
+        co = zlib.compressobj(6, zlib.DEFLATED, -zlib.MAX_WBITS,
+                              zlib.DEF_MEM_LEVEL, 0)
+        chunks = [_GZIP_HEADER,
+                  co.compress(body),
+                  co.flush(),
+                  struct.pack("<ll", zlib.crc32(body), n)]
+        compressed_body = "".join(chunks)
+        ratio = float(n) / len(compressed_body)
+        #print "gzip original size %d, ratio %.1f" % (n, ratio)
+        if ratio > 1.1:
+            self.set_header("Content-Encoding", "gzip")
+            return compressed_body
         else:
-            self.body = self._encode_chunk(stringify(body))
+            return body
 
+    def set_body(self, body, compress=False):
+        """(body : any, compress : bool = False)
+
+        Sets the response body equal to the argument 'body'.  If 'compress'
+        is true then the body may be compressed using 'gzip'.
+        """
+        if not isinstance(body, Stream):
+            body = self._encode_chunk(stringify(body))
+            if compress:
+                body = self._compress_body(body)
+        self.body = body
+
     def expire_cookie(self, name, **attrs):
         """
         Cause an HTTP cookie to be removed from the browser

Modified: trunk/quixote/publish.py
===================================================================
--- trunk/quixote/publish.py	2004-11-04 23:21:40 UTC (rev 25535)
+++ trunk/quixote/publish.py	2004-11-04 23:30:44 UTC (rev 25536)
@@ -9,7 +9,6 @@
 
 import sys, traceback, cStringIO
 import time, re
-import struct
 import urlparse
 import cgitb
 try:
@@ -265,41 +264,10 @@
         self.finish_successful_request()
         return output
 
-    _GZIP_HEADER = ("\037\213" # magic
-                    "\010" # compression method
-                    "\000" # flags
-                    "\000\000\000\000" # time, who cares?
-                    "\002"
-                    "\377")
-
-    _GZIP_THRESHOLD = 200 # responses smaller than this are not compressed
-
-    def compress_output(self, request, output):
-        encoding = request.get_encoding(["gzip", "x-gzip"])
-        n = len(output)
-        if n > self._GZIP_THRESHOLD and encoding:
-            co = zlib.compressobj(6, zlib.DEFLATED, -zlib.MAX_WBITS,
-                                  zlib.DEF_MEM_LEVEL, 0)
-            chunks = [self._GZIP_HEADER,
-                      co.compress(output),
-                      co.flush(),
-                      struct.pack("<ll", zlib.crc32(output), len(output))]
-            output = "".join(chunks)
-            #self.log("gzip (original size %d, ratio %.1f)" %
-            #           (n, float(n)/len(output)))
-            request.response.set_header("Content-Encoding", encoding)
-        return output
-
     def filter_output(self, request, output):
         """Hook for post processing the output.  Subclasses may wish to
         override (e.g. check HTML syntax).
         """
-        if 0:
-            # XXX need to use charset from response
-            if (output and
-                    self.config.compress_pages and
-                    not isinstance(output, Stream)):
-                output = self.compress_output(request, str(output))
         return output
 
     def process_request(self, request):
@@ -332,7 +300,11 @@
         output = self.filter_output(request, output)
         self.logger.log_request(request, start_time)
         if output:
-            request.response.set_body(output)
+            if self.config.compress_pages and request.get_encoding(["gzip"]):
+                compress = True
+            else:
+                compress = False
+            request.response.set_body(output, compress)
         self._clear_request()
         return request.response