[hunchentoot-devel] hunchentoot-cgi and the new hunchentoot regime

Cyrus Harmon ch-tbnl at bobobeach.com
Fri Jul 11 07:20:41 UTC 2008


So... I'm trying to convert my hunchentoot-cgi over to the new 
hunchentoot and running into some problems. My old approach was to do:

      (progn
        (let* ((return-code (tbnl::return-code))
               (reason-phrase (reason-phrase return-code))
               (first-line
                (format nil "HTTP/1.1 ~D ~A" return-code reason-phrase)))
          (write-sequence (map 'list #'char-code first-line) out)
          (write-sequence tbnl::+crlf+ out)
          (tbnl::maybe-write-to-header-stream first-line))
      
        (setf tbnl::*headers-sent* t)
        (setf (tbnl::content-type) nil)
        (sb-ext::run-program path nil :output out :environment env)
        nil)


but this doesn't seem to work anymore. My new approach is to try to use 
send-headers, but with some hackery to make it optionally more cgi-friendly:
Index: headers.lisp
===================================================================
--- headers.lisp    (revision 3423)
+++ headers.lisp    (working copy)
@@ -70,6 +70,8 @@
   (:method (key value)
     (write-header-line key (princ-to-string value))))
 
+(defparameter *cgi-hack* nil)
+
 (defun start-output (&key (content nil content-provided-p)
                           (request *request*))
   "Sends all headers and maybe the content body to
@@ -84,7 +86,8 @@
   ;; Read post data to clear stream - Force binary mode to avoid 
OCTETS-TO-STRING overhead.
   (raw-post-data :force-binary t)
   (let* ((return-code (return-code))
-         (chunkedp (and (server-output-chunking-p *server*)
+         (chunkedp (and (not *cgi-hack*)
+                        (server-output-chunking-p *server*)
                         (eq (server-protocol request) :http/1.1)
                         ;; only turn chunking on if the content
                         ;; length is unknown at this point...
@@ -196,12 +199,14 @@
     ;; write all headers from the REPLY object
     (loop for (key . value) in (headers-out)
        when value
-       do (write-header-line (as-capitalized-string key) value))
+       do (unless (and *cgi-hack* (equal key :content-type))
+            (write-header-line (as-capitalized-string key) value)))
     ;; now the cookies
     (loop for (nil . cookie) in (cookies-out)
        do (write-header-line "Set-Cookie" (stringify-cookie cookie)))
     ;; all headers sent
-    (write-sequence +crlf+ *hunchentoot-stream*)
+    (unless *cgi-hack*
+      (write-sequence +crlf+ *hunchentoot-stream*))
     (maybe-write-to-header-stream "")
     ;; access log message
     (when-let (access-logger (server-access-logger *server*))



The motivation for this hack being that the CGI script wants to send the 
content-type header, so we can't finish the headers here when running a 
CGI script.

Then I can do:

(let* ((tbnl::*cgi-hack* t)             
             (stream (flexi-streams:make-flexi-stream
                      (tbnl:send-headers)
                      :external-format tbnl::+latin-1+)))
        (sb-ext::run-program path nil :output stream :environment env))


and this sort of works, but, 1) it's kind of a hack and 2) it either 
exacerbates the timeout situation or there's some other problem where 
the first request is handled promptly, but subsequent requests to 10 
seconds or so while something times out. Not sure why this would be.

any thoughts on a good way to handle this?

thanks,

Cyrus




More information about the Tbnl-devel mailing list