[hunchentoot-devel] Re: Publishing stream data?

Volkan YAZICI yazicivo at ttnet.net.tr
Fri Sep 28 16:41:57 UTC 2007


Nicolas Neuss <neuss at math.uni-karlsruhe.de> writes:
> I want to return some data in CSV format (or also PDF format in another
> application).  At the moment I am using something like
>
> (let ((file "output.csv"))
>   (with-open-file (stream file :direction :output :if-exists :supersede)
>     (csv-output stream ...))
>   (handle-static-file file)
>   (delete-file file))
>
> However, this is clearly not good in a multiprocessing situation, and I
> would like to get rid of the intermediate file.  Is it possible to publish
> the stream output directly?

If I were you, I'd start with looking at the source code of
HANDLE-STATIC-FILE:

(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))))
    (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)
            (content-length) (file-length file))
      (let ((out (send-headers)))
        (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))))))

The trick is to send the will be transfered content to the stream
returned by call to SEND-HEADERS. Also, don't forget to check the
SEND-HEADERS documentation from the Hunchentoot manual:

  ... Returns a flexi stream to which the body of the reply can be
  written. Once this function has been called, further changes to
  *REPLY* don't have any effect. Also, automatic handling of errors
  (i.e. sending the corresponding status code to the browser, etc.) is
  turned off for this request. ...

(More is in the documentation.)


Regards.



More information about the Tbnl-devel mailing list