[hunchentoot-devel] gzip-encoding

Mac Chan emailmac at gmail.com
Sat May 26 10:24:31 UTC 2007


With this web 2.0 thing, nowadays it's not uncommon to have javascript
library weighting over 500k (with extreme case like dojo which adds up
to several megabytes).

If you google a bit you'll find that this doesn't concern the toolkit
authors because they'll say that if you minimize (eliminate
whitespaces) the javascript file and turn on gzip encoding it's a
non-issue.

It was a low-hanging fruit to add gzip-encoding to hunchentoot since
the hard work has already been done by Edi's (flexi-stream), Zach
(Salza 1) and Sean Ross (gzip-stream 2).

In fact it was only a few lines of changes.

Using the network monitor in FireBug , my initial testing (with a 790
KB javascript file) shows that the response time is  slower with gzip
turned on (I'm guessing that it might be related to flexi-stream.)

262 KB	828ms	875ms	735ms	703ms	719ms	593ms	734ms

790 KB	625ms	359ms	672ms	328ms	610ms	641ms	594ms	

Since I'm testing with the loopback interface, there's virtually no
network overhead.

So I launch another firefox in vmware and limit the download rate of
the network interface to 150k (the most common DSL speed offered in
the states)

262 KB	1.72s	1.72s	1.64s	1.79s

790 KB	5.16s	5.21s	5.11s	5.21s

Now we're talking.  And we can't ignore the 56k line users, can't we?

262 KB	8.39s	5.07s	4.97s	5.07s

790 KB	15.36s … point taken, I don't want to repeat this :-)


So now, the questions remain:

Should we add this to hunchentoot or make it an extension module?
(this will introduce two new dependencies to hunchentoot)

If we add this to hunchentoot, should we add a flag to turn on/off
gzip encoding? (probably yes)

And again, since there's flexi-stream overhead (my guess), should we
add a flag to control what content-type we should disable gzip
encoding? (probably wasting cpu cycle to gzip jpeg, mp3 and png, etc).

Suggestions?

-- Mac

1: http://www.cliki.net/Salza

2: http://common-lisp.net/project/gzip-stream/


(defun handle-static-file (path &optional content-type)
  "A function which acts like a Hunchentoot handler for the file
denoted by PATH.  Send a content type header corresponding to
CONTENT-TYPE or \(if that is NIL) tries to determine the content
type via the file's suffix."
  (unless (or (pathname-name path)
              (pathname-type path))
    ;; not a file
    (setf (return-code) +http-bad-request+)
    (throw 'handler-done nil))
  (unless (probe-file path)
    ;; does not exist
    (setf (return-code) +http-not-found+)
    (throw 'handler-done nil))
  (let ((time (or (file-write-date path) (get-universal-time)))
        (accept-gzip-p (search "gzip" (header-in :accept-encoding))))
    (setf (content-type) (or content-type
                             (mime-type path)
                             "application/octet-stream"))
    (handle-if-modified-since time)
    (with-open-file (file path
                     :direction :input
                     :element-type '(unsigned-byte 8)
                     :if-does-not-exist nil)
      (setf (header-out "Last-Modified") (rfc-1123-date time))
      (if accept-gzip-p
          (setf (header-out "Content-Encoding") "gzip")
          (setf (content-length) (file-length file)))
      (let ((out (send-headers)))
        (when accept-gzip-p
          (setq out (gzip-stream:make-gzip-output-stream out)))
        (loop with buf = (make-array +buffer-length+ :element-type
'(unsigned-byte 8))
              for pos = (read-sequence buf file)
              until (zerop pos)
              do (write-sequence buf out :end pos)
              (finish-output out))))))



More information about the Tbnl-devel mailing list