I've been troubled with a weird problem in read-response-body for a long time. I think read-response-body never return the received data when any break happens. No matter the break caused by connection problem or user interruption. The only possible read-response-body returns data is connection never down and all the data have been received even if I want to download a 2G file. Or there's no chance to write any data to the disk. When break occurs, all the received data will evaporate. Considering my terrible network, I decide not to pray for good luck when I establish connection with our web module. So here's a patch to fix it.
The new read-response-body will add the received data to the exceptional information which used by "throw", if read-response-body can't continue to work anymore, the received data will return with throw. And there's a useful helper function to write this data to the disk ==> (output-received-response-body e port) However, add received data to the exceptions will cause troubles when tracing or REPL throw exceptional information, because received data(as a bytevector) is usually huge. So there's another helper function to get rid of the received data after you handle the received data in your way. It will re-throw the original information in case other program need to catch it. ==> (throw-from-response-body-break e) It's easy to use them, but you must catch anything when your code contains read-response-body: ----------------------------cut------------------------- (catch #t (lambda () .....do some work with read-response-body...) (lambda e (output-received-response-body e port) ;; write received-data to the disk or you may decide to store it to other place. ... ... (throw-from-response-body-break e))) ;; re-throw the original information in the last step. ---------------------------end--------------------------- Anyway, one may use it in his/her own way if he/she checkout their implementation. The helper functions are not always necessary. But I do think read-response-body should return the received data when it breaks. Any comments? Regards.
From 6b6aef2192769ce12a2962b02d103a019f4bc9c6 Mon Sep 17 00:00:00 2001 From: NalaGinrut <nalagin...@gmail.com> Date: Sun, 11 Mar 2012 23:02:07 +0800 Subject: [PATCH] read-response-body should return received data in any break --- module/web/response.scm | 52 +++++++++++++++++++++++++++++++++++++++------- 1 files changed, 44 insertions(+), 8 deletions(-) diff --git a/module/web/response.scm b/module/web/response.scm index 07e1245..e3ea0a6 100644 --- a/module/web/response.scm +++ b/module/web/response.scm @@ -21,6 +21,7 @@ (define-module (web response) #:use-module (rnrs bytevectors) + #:autoload (rnrs) (call-with-port) #:use-module (ice-9 binary-ports) #:use-module (ice-9 rdelim) #:use-module (srfi srfi-9) @@ -38,6 +39,8 @@ response-must-not-include-body? read-response-body + output-received-response-body + throw-from-response-body-break write-response-body ;; General headers @@ -224,16 +227,49 @@ This is true for some response types, like those with code 304." (= (response-code r) 204) (= (response-code r) 304))) -(define (read-response-body r) +(define* (read-response-body r #:key (block 4096)) "Reads the response body from @var{r}, as a bytevector. Returns @code{#f} if there was no response body." - (let ((nbytes (response-content-length r))) - (and nbytes - (let ((bv (get-bytevector-n (response-port r) nbytes))) - (if (= (bytevector-length bv) nbytes) - bv - (bad-response "EOF while reading response body: ~a bytes of ~a" - (bytevector-length bv) nbytes)))))) + (let* ((nbytes (response-content-length r)) + (bv (and nbytes (make-bytevector nbytes))) + (start 0)) + (catch #t + (lambda () + (let lp((buf (get-bytevector-n (response-port r) block))) + (if (eof-object? buf) + bv + (let ((len (bytevector-length buf))) + (cond + ((<= len block) + (bytevector-copy! buf 0 bv start len) + (set! start (+ start len)) + (lp (get-bytevector-n (response-port r) block))) + (else + (bad-response "EOF while reading response body: ~a bytes of ~a" + start nbytes))))))) + (lambda (k . e) + (let ((received (call-with-port + (open-bytevector-input-port bv) + (lambda (port) + (get-bytevector-n port start))))) + (throw k `(,@e (body ,@received))) ;; return the received data + ))))) + +;; output the received data if there is, or do nothing +(define (output-received-response-body e port) + (let ((received (assoc-ref (cadr e) 'body))) + (if received + (begin + (put-bytevector port received) + (force-output port))))) + +;; Exceptional information contains the received bytevector added from the +;; read-response-body if any exception had been caught. +;; If received data ware huge(it always does), it'd be a trouble during the tracing. +;; This helper function could get rid of the received data from exceptional info, +;; and re-throw it. +(define (throw-from-response-body-break e) + (throw (car e) (list-head (cdr e) (1- (length (cdr e)))))) (define (write-response-body r bv) "Write @var{bv}, a bytevector, to the port corresponding to the HTTP -- 1.7.0.4