(set! finished? #t) num-read) (else (let ((left (- remaining read))) (set! remaining left) (when (zero? left) ;; We're done with this chunk; read CR and LF. (get-u8 port) (get-u8 port)) (loop (- to-read read) (+ num-read read))))))))) (loop to-read 0)) (make-custom-binary-input-port "chunked input port" read! #f #f close)) (define* (make-chunked-output-port port #:key (keep-alive? #f) (buffering 1200)) "Returns a new port which translates non-encoded data into a HTTP chunked transfer encoded data and writes this to PORT. Data written to this port is buffered until the port is flushed, at which point it is all sent as one chunk. The port will otherwise be flushed every BUFFERING bytes, which defaults to 1200. Take care to close the port when done, as it will output the remaining data, and encode the final zero chunk. When the port is closed it will also close PORT, unless KEEP-ALIVE? is true." (define (q-for-each f q) (while (not (q-empty? q)) (f (deq! q)))) (define queue (make-q)) (define (%put-char c) (enq! queue c)) (define (%put-string s) (string-for-each (lambda (c) (enq! queue c)) s)) (define (flush) ;; It is important that we do _not_ write a chunk if the queue is ;; empty, since it will be treated as the final chunk. (unless (q-empty? queue) (let ((len (q-length queue))) (put-string port (number->string len 16)) (put-string port "\r\n") (q-for-each (lambda (elem) (put-char port elem)) queue) (put-string port "\r\n")))) (define (close) (flush) (put-string port "0\r\n") (force-output port) (unless keep-alive? (close-port port))) (let ((ret (make-soft-port (vector %put-char %put-string flush #f close) "w"))) (setvbuf ret 'block buffering) ret)) (define %http-proxy-port? (make-object-property)) (define (http-proxy-port? port) (%http-proxy-port? port)) (define (set-http-proxy-port?! port flag) (set! (%http-proxy-port? port) flag))