From 4c6750286a487a988bec24275e1570ae64ff9093 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Mon, 9 Nov 2015 20:04:50 -0700 Subject: [PATCH] net/http-client: avoid race between EOF and collection close The race condition can result in an "input port is closed" error when a connection is used again. --- racket/collects/net/http-client.rkt | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/racket/collects/net/http-client.rkt b/racket/collects/net/http-client.rkt index b243241944..79d7de5ddf 100644 --- a/racket/collects/net/http-client.rkt +++ b/racket/collects/net/http-client.rkt @@ -184,9 +184,7 @@ (define (http-conn-response-port/chunked! hc #:close? [close? #f]) (define (http-pipe-chunk ip op) - (define (done) - (flush-output op) - (close-output-port op)) + (define (done) (void)) (define crlf-bytes (make-bytes 2)) (let loop ([last-bytes #f]) (define in-v (read-line ip eol-type)) @@ -248,11 +246,12 @@ (or (equal? method-bss #"HEAD") (equal? method-bss "HEAD") (equal? method-bss 'HEAD))) - (define raw-response-port + (define-values (raw-response-port wait-for-close?) (cond - [head? (open-input-bytes #"")] + [head? (values (open-input-bytes #"") #f)] [(regexp-member #rx#"^(?i:Transfer-Encoding: +chunked)$" headers) - (http-conn-response-port/chunked! hc #:close? #t)] + (values (http-conn-response-port/chunked! hc #:close? #t) + #t)] [(ormap (λ (h) (match (regexp-match #rx#"^(?i:Content-Length:) +(.+)$" h) [#f #f] @@ -262,9 +261,10 @@ headers) => (λ (count) - (http-conn-response-port/length! hc count #:close? close?))] + (values (http-conn-response-port/length! hc count #:close? close?) + close?))] [else - (http-conn-response-port/rest! hc)])) + (values (http-conn-response-port/rest! hc) #t)])) (define decoded-response-port (cond [head? raw-response-port] @@ -276,9 +276,13 @@ (thread (λ () (gunzip-through-ports raw-response-port out)))) - (thread + (thread (λ () (thread-wait gunzip-t) + (when wait-for-close? + ;; Wait for an EOF from the raw port before we + ;; send an output on the decoding pipe: + (copy-port raw-response-port (open-output-nowhere))) (close-output-port out))) in] [else