From 53b8d5f3352bdc782a488d0b52a32ae15cbcbbf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Sat, 26 Sep 2015 11:04:23 +0200 Subject: [PATCH] web: Gracefully handle premature EOF when reading chunk header. * module/web/http.scm (read-chunk-header): Return 0 when 'read-line' returns EOF. --- module/web/http.scm | 25 ++++++++++++++++--------- test-suite/tests/web-http.test | 10 ++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/module/web/http.scm b/module/web/http.scm index f8aa8dbbe..623008ecb 100644 --- a/module/web/http.scm +++ b/module/web/http.scm @@ -34,6 +34,7 @@ #:use-module (srfi srfi-9) #:use-module (srfi srfi-19) #:use-module (ice-9 rdelim) + #:use-module (ice-9 match) #:use-module (ice-9 q) #:use-module (ice-9 binary-ports) #:use-module (rnrs bytevectors) @@ -1907,15 +1908,21 @@ treated specially, and is just returned as a plain string." ;; Chunked Responses (define (read-chunk-header port) - "Read a chunk header and return the chunk size." - (let* ((str (read-line port)) - (extension-start (string-index str (lambda (c) (or (char=? c #\;) - (char=? c #\return))))) - (size (string->number (if extension-start ; unnecessary? - (substring str 0 extension-start) - str) - 16))) - size)) + "Read a chunk header from PORT and return the size in bytes of the +upcoming chunk." + (match (read-line port) + ((? eof-object?) + ;; Connection closed prematurely: there's nothing left to read. + 0) + (str + (let ((extension-start (string-index str + (lambda (c) + (or (char=? c #\;) + (char=? c #\return)))))) + (string->number (if extension-start ; unnecessary? + (substring str 0 extension-start) + str) + 16))))) (define* (make-chunked-input-port port #:key (keep-alive? #f)) "Returns a new port which translates HTTP chunked transfer encoded diff --git a/test-suite/tests/web-http.test b/test-suite/tests/web-http.test index c59674f6f..7f9431564 100644 --- a/test-suite/tests/web-http.test +++ b/test-suite/tests/web-http.test @@ -414,6 +414,16 @@ (utf8->string (get-bytevector-n port 6)) (reverse requests))))) + (pass-if-equal "EOF instead of chunk header" + "Only chunk." + ;; Omit the second chunk header, leading to a premature EOF. This + ;; used to cause 'read-chunk-header' to throw to wrong-type-arg. + ;; See the backtrace at + ;; . + (let* ((str "B\r\nOnly chunk.") + (port (make-chunked-input-port (open-input-string str)))) + (get-string-all port))) + (pass-if-equal (call-with-output-string (lambda (out-raw)