diff --git a/pkgs/net-doc/net/scribblings/http-client.scrbl b/pkgs/net-doc/net/scribblings/http-client.scrbl index d0ad117443..3bc71f9645 100644 --- a/pkgs/net-doc/net/scribblings/http-client.scrbl +++ b/pkgs/net-doc/net/scribblings/http-client.scrbl @@ -98,7 +98,7 @@ configured to @tech{auto-reconnect}. [#:method method (or/c bytes? string? symbol?) #"GET"] [#:close? close? boolean? #f] [#:headers headers (listof (or/c bytes? string?)) empty] - [#:content-decode decodes (listof symbol?) '(gzip)] + [#:content-decode decodes (listof symbol?) '(gzip deflate)] [#:data data (or/c false/c bytes? string? data-procedure/c) #f]) void?]{ @@ -120,15 +120,16 @@ are accepted is automatically added. If @racket[close?] is @racket[#t] and @racket[headers] does not contain a @litchar{Connection} header, then a @litchar{Connection: -close} header will be added. +close} header will be added (currently, @racket['gzip] and @racket['deflate] are supported). This function does not support requests that expect @litchar{100 (Continue)} responses. +@history[#:changed "7.6.0.9" @elem{Added support for @racket['deflate] decoding.}] } @defproc[(http-conn-recv! [hc http-conn-liveable?] - [#:content-decode decodes (listof symbol?) '(gzip)] + [#:content-decode decodes (listof symbol?) '(gzip deflate)] [#:method method (or/c bytes? string? symbol?) #"GET"] [#:close? close? boolean? #f]) (values bytes? (listof bytes?) input-port?)]{ @@ -146,7 +147,9 @@ following the response parsing. If @racket[close?] is @racket[#f], then the connection is only closed if the server instructs the client to do so. -@history[#:changed "6.1.1.6" @elem{Added the @racket[#:method] argument.}]} +@history[#:changed "6.1.1.6" @elem{Added the @racket[#:method] argument.} + #:changed "7.6.0.9" @elem{Added support for @racket['deflate] decoding.}] +} @defproc[(http-conn-sendrecv! [hc http-conn-liveable?] [uri (or/c bytes? string?)] @@ -154,12 +157,13 @@ to do so. [#:method method (or/c bytes? string? symbol?) #"GET"] [#:headers headers (listof (or/c bytes? string?)) empty] [#:data data (or/c false/c bytes? string? data-procedure/c) #f] - [#:content-decode decodes (listof symbol?) '(gzip)] + [#:content-decode decodes (listof symbol?) '(gzip deflate)] [#:close? close? boolean? #f]) (values bytes? (listof bytes?) input-port?)]{ Calls @racket[http-conn-send!] and @racket[http-conn-recv!] in sequence. +@history[#:changed "7.6.0.9" @elem{Added support for @racket['deflate] decoding.}] } @defproc[(http-sendrecv [host (or/c bytes? string?)] [uri (or/c bytes? string?)] @@ -169,7 +173,7 @@ Calls @racket[http-conn-send!] and @racket[http-conn-recv!] in sequence. [#:method method (or/c bytes? string? symbol?) #"GET"] [#:headers headers (listof (or/c bytes? string?)) empty] [#:data data (or/c false/c bytes? string? data-procedure/c) #f] - [#:content-decode decodes (listof symbol?) '(gzip)]) + [#:content-decode decodes (listof symbol?) '(gzip deflate)]) (values bytes? (listof bytes?) input-port?)]{ Calls @racket[http-conn-send!] and @racket[http-conn-recv!] in @@ -180,6 +184,7 @@ The HTTP connection is not returned, so it is always closed after one response, which is why there is no @racket[#:closed?] argument like @racket[http-conn-recv!]. +@history[#:changed "7.6.0.9" @elem{Added support for @racket['deflate] decoding.}] } @defproc[(http-conn-CONNECT-tunnel [proxy-host (or/c bytes? string?)] diff --git a/pkgs/net-doc/net/scribblings/url.scrbl b/pkgs/net-doc/net/scribblings/url.scrbl index 937b62f7d4..bfb7d20b2b 100644 --- a/pkgs/net-doc/net/scribblings/url.scrbl +++ b/pkgs/net-doc/net/scribblings/url.scrbl @@ -596,14 +596,14 @@ and @racket[host], or @racket[#f] if no proxy is to be used.} [#:method method (or/c bytes? string? symbol?) #"GET"] [#:headers headers (listof (or/c bytes? string?)) empty] [#:data data (or/c false/c bytes? string? data-procedure/c) #f] - [#:content-decode decodes (listof symbol?) '(gzip)]) + [#:content-decode decodes (listof symbol?) '(gzip deflate)]) (values bytes? (listof bytes?) input-port?)]{ Calls @racket[http-sendrecv] using @racket[u] to populate the host, URI, port, and SSL parameters. This function does not support proxies. -} +@history[#:changed "7.6.0.9" @elem{Added support for @racket['deflate] decoding.}]} @defproc[(tcp-or-tunnel-connect [scheme string?] [host string?] diff --git a/pkgs/net-test/tests/net/http-client.rkt b/pkgs/net-test/tests/net/http-client.rkt index 12ea2b1b21..12f4435491 100644 --- a/pkgs/net-test/tests/net/http-client.rkt +++ b/pkgs/net-test/tests/net/http-client.rkt @@ -81,7 +81,7 @@ (define-syntax (test stx) (syntax-case stx () - [(_ method body raw ereq estatus eheaders econtent) + [(_ method body raw ereq estatus eheaders econtent extra ...) (quasisyntax/loc stx (begin #,(syntax/loc stx @@ -93,7 +93,8 @@ #:port the-port #:method method #:headers empty - #:data body)) + #:data body + extra ...)) raw ereq estatus eheaders econtent)) #,(syntax/loc stx (test-e the-port @@ -109,7 +110,8 @@ #:method method #:headers empty #:close? #t - #:data body) + #:data body + extra ...) (begin0 (hc:http-conn-recv! c #:method method @@ -133,7 +135,8 @@ #:method method #:headers empty #:close? #t - #:data body) + #:data body + extra ...) (begin0 (hc:http-conn-recv! c #:method method @@ -150,132 +153,154 @@ (list (u:path/param "" empty)) empty #f) #:method method #:headers empty - #:data body)) + #:data body + extra ...)) raw ereq estatus eheaders econtent))))])) (tests ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n24\r\nThis is the data in the first chunk \r\n1A\r\nand this is the second one\r\n0\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 200 OK" '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") #"This is the data in the first chunk and this is the second one"] - ["GET" #f "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\nThis is the data in the first chunk and this is the second one" + ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n24\r\nThis is the data in the first chunk \r\n1A\r\nand this is the second one\r\n0\r\n" #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"HTTP/1.1 200 OK" + '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") + #"This is the data in the first chunk and this is the second one" + #:content-decode '(gzip)] + + ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n24\r\nThis is the data in the first chunk \r\n1A\r\nand this is the second one\r\n0\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"HTTP/1.1 200 OK" + '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") + #"This is the data in the first chunk and this is the second one" + #:content-decode '(deflate)] + + ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n24\r\nThis is the data in the first chunk \r\n1A\r\nand this is the second one\r\n0\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"HTTP/1.1 200 OK" + '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") + #"This is the data in the first chunk and this is the second one" + #:content-decode '()] + + ["GET" #f "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\nThis is the data in the first chunk and this is the second one" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.0 200 OK" '(#"Content-Type: text/plain") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.0 200 OK\nContent-Type: text/plain\n\nThis is the data in the first chunk and this is the second one" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.0 200 OK" '(#"Content-Type: text/plain") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 62\r\n\r\nThis is the data in the first chunk and this is the second one" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.0 200 OK" '(#"Content-Type: text/plain" #"Content-Length: 62") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\nThis is the data in the first chunk and this is the second one" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.0 200 OK" '(#"Content-Type: text/plain") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\ncontent-length: 62\r\n\r\nThis is the data in the first chunk and this is the second one" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.0 200 OK" '(#"Content-Type: text/plain" #"content-length: 62") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n20\r\nThis is the data in the first ch\r\n21\r\nand this is the second oneXXXXXXX\r\n0\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 200 OK" '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") #"This is the data in the first chand this is the second oneXXXXXXX"] ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n24\r\nThis is the data in the first chunk \r\n1A\r\nand this is the second one\r\n0\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 200 OK" '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\nThis is the data in the first chunk and this is the second one" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.0 200 OK" '(#"Content-Type: text/plain") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n20\r\nThis is the data in the first ch\r\n21\r\nand this is the second oneXXXXXXX\r\n0\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 200 OK" '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") #"This is the data in the first chand this is the second oneXXXXXXX"] ["GET" #f "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\nThis is the data in the first chunk and this is the second one\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.0 200 OK" '(#"Content-Type: text/plain") #"This is the data in the first chunk and this is the second one\r\n"] ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n24\r\nThis is the data in the first chunk \r\n1A\r\nand this is the second one\r\n0\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 200 OK" '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\nThis is the data in the first chunk and this is the second one" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.0 200 OK" '(#"Content-Type: text/plain") #"This is the data in the first chunk and this is the second one"] ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n\r\n20\r\nThis is the data in the first ch\r\n21\r\nand this is the second oneXXXXXXX\r\n0\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 200 OK" '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked") #"This is the data in the first chand this is the second oneXXXXXXX"] ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\nAnother-Header: ta-daa\r\n\r\n20\r\nThis is the data in the first ch\r\n21\r\nand this is the second oneXXXXXXX\r\n0\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 200 OK" '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked" #"Another-Header: ta-daa") #"This is the data in the first chand this is the second oneXXXXXXX"] ["GET" #f "HTTP/1.1 301 Moved Permanently\r\nLocation: http://localhost:9002/whatever\r\n\r\nstuff" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 301 Moved Permanently" '(#"Location: http://localhost:9002/whatever") #"stuff"] ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\nAnother-Header: ta-daa\r\n\r\n20\r\nThis is the data in the first ch\r\n21\r\nand this is the second oneXXXXXXX\r\n0\r\n" - #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" + #"GET / HTTP/1.1\r\nHost: localhost:REDACTED\r\nUser-Agent: Racket/REDACTED (net/http-client)\r\nAccept-Encoding: gzip,deflate\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" #"HTTP/1.1 200 OK" '(#"Content-Type: text/plain" #"Transfer-Encoding: chunked" #"Another-Header: ta-daa") #"This is the data in the first chand this is the second oneXXXXXXX"] ["GET" #f "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\nAnother-Header: ta-daa\r\n\r\nbb \r\n\n\t\t\t\t\t
\n\t\t\t\t\t