1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-29 19:30:36 +02:00

web: Don't hide missing data in the chunked input port.

This port is of limited use if it cannot be used reliably. Rather than
behaving as if the input has finished when it ends unexpectedly, instead
raise an exception.

* module/web/http.scm (make-chunked-input-port): Raise an exception on
premature termination.
(&chunked-input-ended-prematurely): New exception type.
(chunked-input-ended-prematurely-error?): New procedure.
* test-suite/tests/web-http.test (pass-if-named-exception): Rename to
pass-if-named-exception.
(pass-if-named-exception): New syntax.
("Exception on premature chunk end"): New test for this behaviour.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
Christopher Baines 2022-06-30 19:15:54 +01:00 committed by Ludovic Courtès
parent 9a3353a993
commit baa1424335
3 changed files with 36 additions and 10 deletions

View file

@ -1117,6 +1117,9 @@ Returns a new port, that transparently reads and decodes chunk-encoded
data from @var{port}. If no more chunk-encoded data is available, it
returns the end-of-file object. When the port is closed, @var{port} will
also be closed, unless @var{keep-alive?} is true.
If the chunked input ends prematurely, a
@code{&chunked-input-ended-promaturely} exception will be raised.
@end deffn
@example

View file

@ -38,6 +38,7 @@
#:use-module (ice-9 q)
#:use-module (ice-9 binary-ports)
#:use-module (ice-9 textual-ports)
#:use-module (ice-9 exceptions)
#:use-module (rnrs bytevectors)
#:use-module (web uri)
#:export (string->header
@ -67,6 +68,8 @@
read-response-line
write-response-line
&chunked-input-error-prematurely
chunked-input-ended-prematurely-error?
make-chunked-input-port
make-chunked-output-port
@ -1945,6 +1948,17 @@ treated specially, and is just returned as a plain string."
;; Chunked Responses
(define &chunked-input-ended-prematurely
(make-exception-type '&chunked-input-error-prematurely
&external-error
'()))
(define make-chunked-input-ended-prematurely-error
(record-constructor &chunked-input-ended-prematurely))
(define chunked-input-ended-prematurely-error?
(record-predicate &chunked-input-ended-prematurely))
(define (read-chunk-header port)
"Read a chunk header from PORT and return the size in bytes of the
upcoming chunk."
@ -1997,8 +2011,8 @@ closed it will also close PORT, unless the KEEP-ALIVE? is true."
ask-for)))
(cond
((eof-object? read) ;premature termination
(set! finished? #t)
num-read)
(raise-exception
(make-chunked-input-ended-prematurely-error)))
(else
(let ((left (- remaining read)))
(set! remaining left)

View file

@ -28,16 +28,19 @@
#:use-module (test-suite lib))
(define-syntax pass-if-named-exception
(define-syntax pass-if-expected-exception
(syntax-rules ()
((_ name k pat exp)
((_ name exception-predicate? exp)
(pass-if name
(catch 'k
(lambda () exp (error "expected exception" 'k))
(lambda (k message args)
(if (string-match pat message)
#t
(error "unexpected exception" message args))))))))
(with-exception-handler
(lambda (exn)
(if (exception-predicate? exn)
#t
(error "unexpected exception" exn)))
(lambda ()
exp
#f)
#:unwind? #t)))))
(define-syntax pass-if-only-parse
(syntax-rules ()
@ -491,6 +494,12 @@
(port (make-chunked-input-port (open-input-string str))))
(get-string-all port)))
(pass-if-expected-exception "Exception on premature chunk end"
chunked-input-ended-prematurely-error?
(let* ((str "b\r\nFirst chunk\r\nc\r\nSecond chun")
(port (make-chunked-input-port (open-input-string str))))
(get-string-all port)))
(pass-if-equal
(call-with-output-string
(lambda (out-raw)