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