HTTP.jl Documentation
HTTP.jl is a Julia library for HTTP Messages.
HTTP.request sends a HTTP Request Message and returns a Response Message.
r = HTTP.request("GET", "http://httpbin.org/ip")
println(r.status)
println(String(r.body))HTTP.open sends a HTTP Request Message and opens an IO stream from which the Response can be read.
HTTP.open("GET", "https://tinyurl.com/bach-cello-suite-1-ogg") do http
open(`vlc -q --play-and-exit --intf dummy -`, "w") do vlc
write(vlc, http)
end
endRequests
HTTP.request — Method.HTTP.request(method, url [, headers [, body]]; <keyword arguments>]) -> HTTP.ResponseSend a HTTP Request Message and recieve a HTTP Response Message.
e.g.
r = HTTP.request("GET", "http://httpbin.org/ip")
println(r.status)
println(String(r.body))headers can be any collection where [string(k) => string(v) for (k,v) in headers] yields Vector{Pair}. e.g. a Dict(), a Vector{Tuple}, a Vector{Pair} or an iterator.
body can take a number of forms:
a
String, aVector{UInt8}or anyTaccepted bywrite(::IO, ::T)a collection of
StringorAbstractVector{UInt8}orIOstreams or items of any typeTaccepted bywrite(::IO, ::T...)a readable
IOstream or anyIO-like typeTfor whicheof(T)andreadavailable(T)are defined.
The HTTP.Response struct contains:
status::Int16e.g.200headers::Vector{Pair{String,String}}e.g. ["Server" => "Apache", "Content-Type" => "text/html"]body::Vector{UInt8}, the Response Body bytes (empty if aresponse_streamwas specified in therequest).
Functions HTTP.get, HTTP.put, HTTP.post and HTTP.head are defined as shorthand for HTTP.request("GET", ...), etc.
HTTP.request and HTTP.open also accept optional keyword parameters.
e.g.
HTTP.request("GET", "http://httpbin.org/ip"; retries=4, cookies=true)
HTTP.get("http://s3.us-east-1.amazonaws.com/"; aws_authorization=true)
conf = (readtimeout = 10,
pipeline_limit = 4,
retry = false,
redirect = false)
HTTP.get("http://httpbin.org/ip"; conf..)
HTTP.put("http://httpbin.org/put", [], "Hello"; conf..)URL options
query = nothing, replaces the query part ofurl.
Streaming options
response_stream = nothing, a writeableIOstream or anyIO-like typeTfor whichwrite(T, AbstractVector{UInt8})is defined.verbose = 0, set to1or2for extra message logging.
Connection Pool options
connection_limit = 8, number of concurrent connections to each host:port.pipeline_limit = 16, number of concurrent requests per connection.reuse_limit = nolimit, number of times a connection is reused after the first request.socket_type = TCPSocket
Timeout options
readtimeout = 60, close the connection if no data is recieved for this many seconds. Usereadtimeout = 0to disable.
Retry options
retry = true, retry idempotent requests in case of error.retries = 4, number of times to retry.retry_non_idempotent = false, retry non-idempotent requests too. e.g. POST.
Redirect options
redirect = true, follow 3xx redirect responses.redirect_limit = 3, number of times to redirect.forwardheaders = true, forward original headers on redirect.
Status Exception options
status_exception = true, throwHTTP.StatusErrorfor response status >= 300.
SSLContext options
require_ssl_verification = false, passMBEDTLS_SSL_VERIFY_REQUIREDto the mbed TLS library. "... peer must present a valid certificate, handshake is aborted if verification failed."sslconfig = SSLConfig(require_ssl_verification)
Basic Authenticaiton options
basic_authorization=false, add
Authorization: Basicheader using credentials from url userinfo.
AWS Authenticaiton options
aws_authorization = false, enable AWS4 Authentication.aws_service = split(url.host, ".")[1]aws_region = split(url.host, ".")[2]aws_access_key_id = ENV["AWS_ACCESS_KEY_ID"]aws_secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]aws_session_token = get(ENV, "AWS_SESSION_TOKEN", "")body_sha256 = digest(MD_SHA256, body),body_md5 = digest(MD_MD5, body),
Cookie options
cookies = false, enable cookies.cookiejar::Dict{String, Set{Cookie}}=default_cookiejar
Cananoincalization options
canonicalize_headers = false, rewrite request and response headers in Canonical-Camel-Dash-Format.
Request Body Examples
String body:
HTTP.request("POST", "http://httpbin.org/post", [], "post body data")Stream body from file:
io = open("post_data.txt", "r")
HTTP.request("POST", "http://httpbin.org/post", [], io)Generator body:
chunks = ("chunk$i" for i in 1:1000)
HTTP.request("POST", "http://httpbin.org/post", [], chunks)Collection body:
chunks = [preamble_chunk, data_chunk, checksum(data_chunk)]
HTTP.request("POST", "http://httpbin.org/post", [], chunks)open() do io body:
HTTP.open("POST", "http://httpbin.org/post") do io
write(io, preamble_chunk)
write(io, data_chunk)
write(io, checksum(data_chunk))
endResponse Body Examples
String body:
r = HTTP.request("GET", "http://httpbin.org/get")
println(String(r.body))Stream body to file:
io = open("get_data.txt", "w")
r = HTTP.request("GET", "http://httpbin.org/get", response_stream=io)
close(io)
println(read("get_data.txt"))Stream body through buffer:
io = Base.BufferStream()
@async while !eof(io)
bytes = readavailable(io))
println("GET data: $bytes")
end
r = HTTP.request("GET", "http://httpbin.org/get", response_stream=io)
close(io)Stream body through open() do io:
r = HTTP.open("GET", "http://httpbin.org/stream/10") do io
while !eof(io)
println(String(readavailable(io)))
end
end
using HTTP.IOExtras
HTTP.open("GET", "https://tinyurl.com/bach-cello-suite-1-ogg") do http
n = 0
r = startread(http)
l = parse(Int, header(r, "Content-Length"))
open(`vlc -q --play-and-exit --intf dummy -`, "w") do vlc
while !eof(http)
bytes = readavailable(http)
write(vlc, bytes)
n += length(bytes)
println("streamed $n-bytes $((100*n)÷l)%\u1b[1A")
end
end
endRequest and Response Body Examples
String bodies:
r = HTTP.request("POST", "http://httpbin.org/post", [], "post body data")
println(String(r.body))Stream bodies from and to files:
in = open("foo.png", "r")
out = open("foo.jpg", "w")
HTTP.request("POST", "http://convert.com/png2jpg", [], in, response_stream=out)Stream bodies through: open() do io:
using HTTP.IOExtras
HTTP.open("POST", "http://music.com/play") do io
write(io, JSON.json([
"auth" => "12345XXXX",
"song_id" => 7,
]))
r = startread(io)
@show r.status
while !eof(io)
bytes = readavailable(io))
play_audio(bytes)
end
endHTTP.open — Function.HTTP.open(method, url, [,headers]) do io
write(io, body)
[startread(io) -> HTTP.Response]
while !eof(io)
readavailable(io) -> AbstractVector{UInt8}
end
end -> HTTP.ResponseThe HTTP.open API allows the Request Body to be written to (and/or the Response Body to be read from) an IO stream.
e.g. Streaming an audio file to the vlc player:
HTTP.open("GET", "https://tinyurl.com/bach-cello-suite-1-ogg") do http
open(`vlc -q --play-and-exit --intf dummy -`, "w") do vlc
write(vlc, http)
end
endHTTP.get — Function.HTTP.get(url [, headers]; <keyword arguments>) -> HTTP.ResponseShorthand for HTTP.request("GET", ...). See HTTP.request.
HTTP.put — Function.HTTP.put(url, headers, body; <keyword arguments>) -> HTTP.ResponseShorthand for HTTP.request("PUT", ...). See HTTP.request.
HTTP.post — Function.HTTP.post(url, headers, body; <keyword arguments>) -> HTTP.ResponseShorthand for HTTP.request("POST", ...). See HTTP.request.
HTTP.head — Function.HTTP.head(url; <keyword arguments>) -> HTTP.ResponseShorthand for HTTP.request("HEAD", ...). See HTTP.request.
Request functions may throw the following exceptions:
The Response has a 4xx, 5xx or unrecognised status code.
Fields:
status::Int16, the response status code.responsetheHTTP.Response
HTTP.Parsers.ParseError — Type.Parser input was invalid.
Fields:
code, error codebytes, the offending input.
HTTP.IOExtras.IOError — Type.The request terminated with due to an IO-related error.
Fields:
e, the error.
Sockets.DNSErrorServer / Handlers
HTTP.Servers.listen — Function.HTTP.listen([host=Sockets.localhost[, port=8081]]; <keyword arguments>) do http
...
endListen for HTTP connections and execute the do function for each request.
Optional keyword arguments:
ssl::Bool = false, use https.require_ssl_verification = true, passMBEDTLS_SSL_VERIFY_REQUIREDto the mbed TLS library. "... peer must present a valid certificate, handshake is aborted if verification failed."sslconfig = SSLConfig(require_ssl_verification)pipeline_limit = 16, number of concurrent requests per connection.reuse_limit = nolimit, number of times a connection is allowed to be reused after the first request.tcpisvalid::Function (::TCPSocket) -> Bool, check accepted connection before processing requests. e.g. to implement source IP filtering, rate-limiting, etc.tcpref::Ref{Base.IOServer}, this reference is set to the underlyingIOServer. e.g. to allow closing the server.
e.g.
HTTP.listen() do http::HTTP.Stream
@show http.message
@show HTTP.header(http, "Content-Type")
while !eof(http)
println("body data: ", String(readavailable(http)))
end
setstatus(http, 404)
setheader(http, "Foo-Header" => "bar")
startwrite(http)
write(http, "response body")
write(http, "more response body")
end
HTTP.listen() do request::HTTP.Request
@show HTTP.header(request, "Content-Type")
@show HTTP.payload(request)
return HTTP.Response(404)
endHTTP.Servers.serve — Function.HTTP.serve([server,] host::Union{IPAddr, String}, port::Integer; verbose::Bool=true, kwargs...)
HTTP.serve([server,] host::InetAddr; verbose::Bool=true, kwargs...)
HTTP.serve([server,] host::String; verbose::Bool=true, kwargs...)Start a server listening on the provided host:port. verbose indicates whether server activity should be logged. Optional keyword arguments allow construction of Server on the fly if the server argument isn't provided directly. See ?HTTP.Server for more details on server construction and supported keyword arguments. By default, HTTP.serve aims to "never die", catching and recovering from all internal errors. Two methods for stopping HTTP.serve include interrupting (ctrl/cmd+c) if blocking on the main task, or sending the kill signal via the server's in channel (put!(server.in, HTTP.Servers.KILL)).
HTTP.Servers.Server — Type.Server(handler, logger::IO=stdout; kwargs...)An http/https server. Supports listening on a host and port via the HTTP.serve(server, host, port) function. handler is a function of the form f(::Request, ::Response) -> HTTP.Response, i.e. it takes both a Request and pre-built Response objects as inputs and returns the, potentially modified, Response. logger indicates where logging output should be directed. When HTTP.serve is called, it aims to "never die", catching and recovering from all internal errors. To forcefully stop, one can obviously kill the julia process, interrupt (ctrl/cmd+c) if main task, or send the kill signal over a server in channel like: put!(server.in, HTTP.Servers.KILL).
Supported keyword arguments include:
cert: if https, the cert file to use, as passed toHTTP.MbedTLS.SSLConfig(cert, key)key: if https, the key file to use, as passed toHTTP.MbedTLS.SSLConfig(cert, key)sslconfig: pass in an already-constructedHTTP.MbedTLS.SSLConfiginstancereadtimeout: how long a client connection will be left open without receiving any bytesratelimit: aRational{Int}of the form5//1indicating how manymessages//secondshould be allowed per client IP address; requests exceeding the rate limit will be droppedsupport100continue: aBoolindicating whetherExpect: 100-continueheaders should be supported for delayed request body sending; default =truelogbody: whether the Response body should be logged whenverbose=truelogging is enabled; default =true
HTTP.Handlers.Handler — Type.Abstract type representing an object that knows how to "handle" a server request.
Types of handlers include HandlerFunction (a julia function of the form f(request) and Router (which pattern matches request url paths to other specific Handler types).
HTTP.Handlers.HandlerFunction — Type.HandlerFunction(f::Function)
A Function-wrapper type that is a subtype of Handler. Takes a single Function as an argument. The provided argument should be of the form f(request) => Response, i.e. it accepts a Request returns a Response.
HTTP.Handlers.Router — Type.Router(h::Handler) Router(f::Function) Router()
An HTTP.Handler type that supports mapping request url paths to other HTTP.Handler types. Can accept a default Handler or Function that will be used in case no other handlers match; by default, a 404 response handler is used. Paths can be mapped to a handler via HTTP.register!(r::Router, path, handler), see ?HTTP.register! for more details.
HTTP.Handlers.register! — Function.HTTP.register!(r::Router, url, handler) HTTP.register!(r::Router, m::String, url, handler)
Function to map request urls matching url and an optional method m to another handler::HTTP.Handler. URLs are registered one at a time, and multiple urls can map to the same handler. The URL can be passed as a String or HTTP.URI object directly. Requests can be routed based on: method, scheme, hostname, or path. The following examples show how various urls will direct how a request is routed by a server:
"http://*": match all HTTP requests, regardless of path"https://*": match all HTTPS requests, regardless of path"google": regardless of scheme, match requests to the hostname "google""google/gmail": match requests to hostname "google", and path starting with "gmail""/gmail": regardless of scheme or host, match any request with a path starting with "gmail""/gmail/userId/*/inbox: match any request matching the path pattern, "*" is used as a wildcard that matches any value between the two "/"
URIs
HTTP.URIs.URI — Type.HTTP.URI(; scheme="", host="", port="", etc...)
HTTP.URI(str) = parse(HTTP.URI, str::String)A type representing a valid uri. Can be constructed from distinct parts using the various supported keyword arguments. With a raw, already-encoded uri string, use parse(HTTP.URI, str) to parse the HTTP.URI directly. The HTTP.URI constructors will automatically escape any provided query arguments, typically provided as "key"=>"value"::Pair or Dict("key"=>"value"). Note that multiple values for a single query key can provided like Dict("key"=>["value1", "value2"]).
The URI struct stores the compelte URI in the uri::String field and the component parts in the following SubString fields:
scheme, e.g."http"or"https"userinfo, e.g."username:password"hoste.g."julialang.org"porte.g."80"or""pathe.g"/"querye.g."Foo=1&Bar=2"fragment
The HTTP.resource(::URI) function returns a target-resource string for the URI RFC7230 5.3. e.g. "$path?$query#$fragment".
The HTTP.queryparams(::URI) function returns a Dict containing the query.
HTTP.URIs.escapeuri — Function.percent-encode a string, dict, or pair for a uri
HTTP.URIs.unescapeuri — Function.unescape a percent-encoded uri/url
HTTP.URIs.splitpath — Function.Splits the path into components See: http://tools.ietf.org/html/rfc3986#section-3.3
Base.isvalid — Method.checks if a HTTP.URI is valid
Cookies
HTTP.Cookies.Cookie — Type.Cookie()
Cookie(; kwargs...)
Cookie(name, value; kwargs...)A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an HTTP response or the Cookie header of an HTTP request. Supported fields (which can be set using keyword arguments) include:
name: name of the cookievalue: value of the cookiepath: applicable path for the cookiedomain: applicable domain for the cookieexpires: aDates.DateTimerepresenting when the cookie should expiremaxage:maxage == 0means no max age,maxage < 0means delete cookie now,max age > 0means the # of seconds until expirationsecure::Bool: secure cookie attributehttponly::Bool: httponly cookie attributehostonly::Bool: hostonly cookie attribute
See http:#tools.ietf.org/html/rfc6265 for details.
Utilities
HTTP.sniff — Function.HTTP.sniff(content::Union{Vector{UInt8}, String, IO}) => String (mimetype)
HTTP.sniff will look at the first 512 bytes of content to try and determine a valid mimetype. If a mimetype can't be determined appropriately, "application/octet-stream" is returned.
Supports JSON detection through the HTTP.isjson(content) function.
HTTP.Strings.escapehtml — Function.escapeHTML(i::String)
Returns a string with special HTML characters escaped: &, <, >, ", '
HTTP.jl Internal Architecture
HTTP.Layer — Type.Request Execution Stack
The Request Execution Stack is separated into composable layers.
Each layer is defined by a nested type Layer{Next} where the Next parameter defines the next layer in the stack. The request method for each layer takes a Layer{Next} type as its first argument and dispatches the request to the next layer using request(Next, ...).
The example below defines three layers and three stacks each with a different combination of layers.
abstract type Layer end
abstract type Layer1{Next <: Layer} <: Layer end
abstract type Layer2{Next <: Layer} <: Layer end
abstract type Layer3 <: Layer end
request(::Type{Layer1{Next}}, data) where Next = "L1", request(Next, data)
request(::Type{Layer2{Next}}, data) where Next = "L2", request(Next, data)
request(::Type{Layer3}, data) = "L3", data
const stack1 = Layer1{Layer2{Layer3}}
const stack2 = Layer2{Layer1{Layer3}}
const stack3 = Layer1{Layer3}julia> request(stack1, "foo")
("L1", ("L2", ("L3", "foo")))
julia> request(stack2, "bar")
("L2", ("L1", ("L3", "bar")))
julia> request(stack3, "boo")
("L1", ("L3", "boo"))This stack definition pattern gives the user flexibility in how layers are combined but still allows Julia to do whole-stack comiple time optimistations.
e.g. the request(stack1, "foo") call above is optimised down to a single function:
julia> code_typed(request, (Type{stack1}, String))[1].first
CodeInfo(:(begin
return (Core.tuple)("L1", (Core.tuple)("L2", (Core.tuple)("L3", data)))
end))HTTP.stack — Function.The stack() function returns the default HTTP Layer-stack type. This type is passed as the first parameter to the HTTP.request function.
stack() accepts optional keyword arguments to enable/disable specific layers in the stack: request(method, args...; kw...) request(stack(;kw...), args...; kw...)
The minimal request execution stack is:
stack = MessageLayer{ConnectionPoolLayer{StreamLayer}}The figure below illustrates the full request exection stack and its relationship with HTTP.Response, HTTP.Parsers, HTTP.Stream and the HTTP.ConnectionPool.
┌────────────────────────────────────────────────────────────────────────────┐
│ ┌───────────────────┐ │
│ HTTP.jl Request Execution Stack │ HTTP.ParsingError ├ ─ ─ ─ ─ ┐ │
│ └───────────────────┘ │
│ ┌───────────────────┐ │ │
│ │ HTTP.IOError ├ ─ ─ ─ │
│ └───────────────────┘ │ │ │
│ ┌───────────────────┐ │
│ │ HTTP.StatusError │─ ─ │ │ │
│ └───────────────────┘ │ │
│ ┌───────────────────┐ │ │ │
│ request(method, url, headers, body) -> │ HTTP.Response │ │ │
│ ────────────────────────── └─────────▲─────────┘ │ │ │
│ ║ ║ │ │
│ ┌────────────────────────────────────────────────────────────┐ │ │ │
│ │ request(RedirectLayer, method, ::URI, ::Headers, body) │ │ │
│ ├────────────────────────────────────────────────────────────┤ │ │ │
│ │ request(BasicAuthLayer, method, ::URI, ::Headers, body) │ │ │
│ ├────────────────────────────────────────────────────────────┤ │ │ │
│ │ request(CookieLayer, method, ::URI, ::Headers, body) │ │ │
│ ├────────────────────────────────────────────────────────────┤ │ │ │
│ │ request(CanonicalizeLayer, method, ::URI, ::Headers, body) │ │ │
│ ├────────────────────────────────────────────────────────────┤ │ │ │
│ │ request(MessageLayer, method, ::URI, ::Headers, body) │ │ │
│ ├────────────────────────────────────────────────────────────┤ │ │ │
│ │ request(AWS4AuthLayer, ::URI, ::Request, body) │ │ │
│ ├────────────────────────────────────────────────────────────┤ │ │ │
│ │ request(RetryLayer, ::URI, ::Request, body) │ │ │
│ ├────────────────────────────────────────────────────────────┤ │ │ │
│ │ request(ExceptionLayer, ::URI, ::Request, body) ├ ─ ┘ │
│ ├────────────────────────────────────────────────────────────┤ │ │ │
┌┼───┤ request(ConnectionPoolLayer, ::URI, ::Request, body) ├ ─ ─ ─ │
││ ├────────────────────────────────────────────────────────────┤ │ │
││ │ request(DebugLayer, ::IO, ::Request, body) │ │
││ ├────────────────────────────────────────────────────────────┤ │ │
││ │ request(TimeoutLayer, ::IO, ::Request, body) │ │
││ ├────────────────────────────────────────────────────────────┤ │ │
││ │ request(StreamLayer, ::IO, ::Request, body) │ │
││ └──────────────┬───────────────────┬─────────────────────────┘ │ │
│└──────────────────┼────────║──────────┼───────────────║─────────────────────┘
│ │ ║ │ ║ │
│┌──────────────────▼───────────────┐ │ ┌──────────────────────────────────┐
││ HTTP.Request │ │ │ HTTP.Response │ │
││ │ │ │ │
││ method::String ◀───┼──▶ status::Int │ │
││ target::String │ │ │ headers::Vector{Pair} │
││ headers::Vector{Pair} │ │ │ body::Vector{UInt8} │ │
││ body::Vector{UInt8} │ │ │ │
│└──────────────────▲───────────────┘ │ └───────────────▲────────────────┼─┘
│┌──────────────────┴────────║──────────▼───────────────║──┴──────────────────┐
││ HTTP.Stream <:IO ║ ╔══════╗ ║ │ │
││ ┌───────────────────────────┐ ║ ┌──▼─────────────────────────┐ │
││ │ startwrite(::Stream) │ ║ │ startread(::Stream) │ │ │
││ │ write(::Stream, body) │ ║ │ read(::Stream) -> body │ │
││ │ ... │ ║ │ ... │ │ │
││ │ closewrite(::Stream) │ ║ │ closeread(::Stream) │ │
││ └───────────────────────────┘ ║ └────────────────────────────┘ │ │
│└───────────────────────────║────────┬──║──────║───────║──┬──────────────────┘
│┌──────────────────────────────────┐ │ ║ ┌────▼───────║──▼────────────────┴─┐
││ HTTP.Messages │ │ ║ │ HTTP.Parsers │
││ │ │ ║ │ │
││ writestartline(::IO, ::Request) │ │ ║ │ parse_status_line(bytes, ::Req') │
││ writeheaders(::IO, ::Request) │ │ ║ │ parse_header_field(bytes, ::Req')│
│└──────────────────────────────────┘ │ ║ └──────────────────────────────────┘
│ ║ │ ║
│┌───────────────────────────║────────┼──║────────────────────────────────────┐
└▶ HTTP.ConnectionPool ║ │ ║ │
│ ┌──────────────▼────────┐ ┌───────────────────────┐ │
│ getconnection() -> │ HTTP.Transaction <:IO │ │ HTTP.Transaction <:IO │ │
│ └───────────────────────┘ └───────────────────────┘ │
│ ║ ╲│╱ ║ ╲│╱ │
│ ║ │ ║ │ │
│ ┌───────────▼───────────┐ ┌───────────▼───────────┐ │
│ pool: [│ HTTP.Connection │,│ HTTP.Connection │...]│
│ └───────────┬───────────┘ └───────────┬───────────┘ │
│ ║ │ ║ │ │
│ ┌───────────▼───────────┐ ┌───────────▼───────────┐ │
│ │ Base.TCPSocket <:IO │ │MbedTLS.SSLContext <:IO│ │
│ └───────────────────────┘ └───────────┬───────────┘ │
│ ║ ║ │ │
│ ║ ║ ┌───────────▼───────────┐ │
│ ║ ║ │ Base.TCPSocket <:IO │ │
│ ║ ║ └───────────────────────┘ │
└───────────────────────────║───────────║────────────────────────────────────┘
║ ║
┌───────────────────────────║───────────║──────────────┐ ┏━━━━━━━━━━━━━━━━━━┓
│ HTTP Server ▼ │ ┃ data flow: ════▶ ┃
│ Request Response │ ┃ reference: ────▶ ┃
└──────────────────────────────────────────────────────┘ ┗━━━━━━━━━━━━━━━━━━┛See docs/src/layers.monopic.
Request Execution Layers
request(RedirectLayer, method, ::URI, headers, body) -> HTTP.ResponseRedirects the request in the case of 3xx response status.
request(BasicAuthLayer, method, ::URI, headers, body) -> HTTP.ResponseAdd Authorization: Basic header using credentials from url userinfo.
HTTP.CookieRequest.CookieLayer — Type.request(CookieLayer, method, ::URI, headers, body) -> HTTP.ResponseAdd locally stored Cookies to the request headers. Store new Cookies found in the response headers.
request(CanonicalizeLayer, method, ::URI, headers, body) -> HTTP.ResponseRewrite request and response headers in Canonical-Camel-Dash-Format.
HTTP.MessageRequest.MessageLayer — Type.request(MessageLayer, method, ::URI, headers, body) -> HTTP.ResponseConstruct a Request object and set mandatory headers.
request(AWS4AuthLayer, ::URI, ::Request, body) -> HTTP.ResponseAdd a AWS Signature Version 4 Authorization header to a Request.
Credentials are read from environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN.
HTTP.RetryRequest.RetryLayer — Type.request(RetryLayer, ::URI, ::Request, body) -> HTTP.ResponseRetry the request if it throws a recoverable exception.
Base.retry and Base.ExponentialBackOff implement a randomised exponentially increasing delay is introduced between attempts to avoid exacerbating network congestion.
Methods of isrecoverable(e) define which exception types lead to a retry. e.g. HTTP.IOError, Sockets.DNSError, Base.EOFError and HTTP.StatusError (if status is `5xx).
request(ExceptionLayer, ::URI, ::Request, body) -> HTTP.ResponseThrow a StatusError if the request returns an error response status.
request(ConnectionPoolLayer, ::URI, ::Request, body) -> HTTP.ResponseRetrieve an IO connection from the ConnectionPool.
Close the connection if the request throws an exception. Otherwise leave it open so that it can be reused.
IO related exceptions from Base are wrapped in HTTP.IOError. See isioerror.
HTTP.TimeoutRequest.TimeoutLayer — Type.request(TimeoutLayer, ::IO, ::Request, body) -> HTTP.ResponseClose IO if no data has been received for timeout seconds.
HTTP.StreamRequest.StreamLayer — Type.request(StreamLayer, ::IO, ::Request, body) -> HTTP.ResponseCreate a Stream to send a Request and body to an IO stream and read the response.
Send the Request body in a background task and begins reading the response immediately so that the transmission can be aborted if the Response status indicates that the server does not wish to receive the message body. RFC7230 6.5.
Parser
Source: Parsers.jl
HTTP.Parsers — Module.The parser separates a raw HTTP Message into its component parts.
If the input data is invalid the Parser throws a HTTP.ParseError.
The parse_* functions processes a single element of a HTTP Message at a time and return a SubString containing the unused portion of the input.
The Parser does not interpret the Message Headers. It is beyond the scope of the Parser to deal with repeated header fields, multi-line values, cookies or case normalization.
The Parser has no knowledge of the high-level Request and Response structs defined in Messages.jl. However, the Request and Response structs must have field names compatible with those expected by the parse_status_line! and parse_request_line! functions.
Messages
Source: Messages.jl
HTTP.Messages — Module.The Messages module defines structs that represent HTTP.Request and HTTP.Response Messages.
The Response struct has a request field that points to the corresponding Request; and the Request struct has a response field. The Request struct also has a parent field that points to a Response in the case of HTTP Redirect.
The Messages module defines IO read and write methods for Messages but it does not deal with URIs, creating connections, or executing requests.
The read methods throw EOFError exceptions if input data is incomplete. and call parser functions that may throw HTTP.ParsingError exceptions. The read and write methods may also result in low level IO exceptions.
Sending Messages
Messages are formatted and written to an IO stream by Base.write(::IO,::HTTP.Messages.Message) and or HTTP.Messages.writeheaders.
Receiving Messages
Messages are parsed from IO stream data by HTTP.Messages.readheaders. This function calls HTTP.Parsers.parse_header_field and passes each header-field to HTTP.Messages.appendheader.
readheaders relies on HTTP.IOExtras.unread! to push excess data back to the input stream.
Headers
Headers are represented by Vector{Pair{String,String}}. As compared to Dict{String,String} this allows repeated header fields and preservation of order.
Header values can be accessed by name using HTTP.Messages.header and HTTP.Messages.setheader (case-insensitive).
The HTTP.Messages.appendheader function handles combining multi-line values, repeated header fields and special handling of multiple Set-Cookie headers.
Bodies
The HTTP.Message structs represent the Message Body as Vector{UInt8}.
Streaming of request and response bodies is handled by the HTTP.StreamLayer and the HTTP.Stream <: IO stream.
Streams
Source: Streams.jl
HTTP.Streams.Stream — Type.Stream(::IO, ::Request)Creates a HTTP.Stream that wraps an existing IO stream.
startwrite(::Stream)sends theRequestheaders to theIOstream.write(::Stream, body)sends thebody(or a chunk of the body).closewrite(::Stream)sends the final0chunk (if needed) and callsclosewriteon theIOstream. When theIOstream is aHTTP.ConnectionPool.Transaction, callingclosewritereleases theHTTP.ConnectionPool.Connectionback into the pool for use by the next pipelined request.startread(::Stream)callsstartreadon theIOstream then reads and parses theResponseheaders. When theIOstream is aHTTP.ConnectionPool.Transaction, callingstartreadwaits for other pipelined responses to be read from theHTTP.ConnectionPool.Connection.eof(::Stream)andreadavailable(::Stream)parse the body from theIOstream.closeread(::Stream)reads the trailers and callsclosereadon theIOstream. When theIOstream is aHTTP.ConnectionPool.Transaction, callingclosereadreleases the readlock and allows the next pipelined response to be read by anotherStreamthat is waiting instartread. If a complete response has not been recieved,closereadthrowsEOFError.
Connections
Source: ConnectionPool.jl
HTTP.ConnectionPool — Module.This module provides the getconnection function with support for:
Opening TCP and SSL connections.
Reusing connections for multiple Request/Response Messages,
Pipelining Request/Response Messages. i.e. allowing a new Request to be sent before previous Responses have been read.
This module defines a Connection struct to manage pipelining and connection reuse and a Transaction<: IO struct to manage a single pipelined request. Methods are provided for eof, readavailable, unsafe_write and close. This allows the Transaction object to act as a proxy for the TCPSocket or SSLContext that it wraps.
The pool is a collection of open Connections. The request function calls getconnection to retrieve a connection from the pool. When the request function has written a Request Message it calls closewrite to signal that the Connection can be reused for writing (to send the next Request). When the request function has read the Response Message it calls closeread to signal that the Connection can be reused for reading.
Internal Interfaces
Parser Interface
HTTP.Parsers.find_end_of_header
HTTP.Parsers.find_end_of_line
HTTP.Parsers.find_end_of_trailer
HTTP.Parsers.parse_status_line!
HTTP.Parsers.parse_request_line!
HTTP.Parsers.parse_header_field
HTTP.Parsers.parse_chunk_sizeMessages Interface
HTTP.Messages.Request — Type.Request <: MessageRepresents a HTTP Request Message.
method::StringRFC7230 3.1.1target::StringRFC7230 5.3version::VersionNumberRFC7230 2.6headers::Vector{Pair{String,String}}RFC7230 3.2body::Vector{UInt8}RFC7230 3.3response, theResponseto thisRequesttxcount, number of times thisRequesthas been sent (see RetryRequest.jl).parent, theResponse(if any) that led to this request (e.g. in the case of a redirect). RFC7230 6.4
HTTP.Messages.Response — Type.Response <: MessageRepresents a HTTP Response Message.
version::VersionNumberRFC7230 2.6status::Int16RFC7230 3.1.2 RFC7231 6headers::Vector{Pair{String,String}}RFC7230 3.2body::Vector{UInt8}RFC7230 3.3request, theRequestthat yielded thisResponse.
HTTP.Messages.iserror — Function.iserror(::Response)Does this Response have an error status?
HTTP.Messages.isredirect — Function.isredirect(::Response)Does this Response have a redirect status?
HTTP.Messages.ischunked — Function.ischunked(::Message)Does the Message have a "Transfer-Encoding: chunked" header?
HTTP.Messages.issafe — Function.issafe(::Request)https://tools.ietf.org/html/rfc7231#section-4.2.1
HTTP.Messages.isidempotent — Function.isidempotent(::Request)https://tools.ietf.org/html/rfc7231#section-4.2.2
HTTP.Messages.header — Function.header(::Message, key [, default=""]) -> StringGet header value for key (case-insensitive).
HTTP.Messages.hasheader — Function.hasheader(::Message, key) -> BoolDoes header value for key exist (case-insensitive)?
hasheader(::Message, key, value) -> BoolDoes header for key match value (both case-insensitive)?
HTTP.Messages.setheader — Function.setheader(::Message, key => value)Set header value for key (case-insensitive).
HTTP.Messages.defaultheader — Function.defaultheader(::Message, key => value)Set header value for key if it is not already set.
HTTP.Messages.appendheader — Function.appendheader(::Message, key => value)Append a header value to message.headers.
If key is "" the value is appended to the value of the previous header.
If key is the same as the previous header, the value is appended to the value of the previous header with a comma delimiter
Set-Cookie headers are not comma-combined because cookies often contain internal commas.
HTTP.Messages.readheaders — Function.readheaders(::IO, ::Message)Read headers (and startline) from an IO stream into a Message struct. Throw EOFError if input is incomplete.
HTTP.MessageRequest.setuseragent! — Function.Set the default User-Agent string to be used in each HTTP request; when set, can be manually overridden by passing in an explicit User-Agent header
HTTP.Messages.readchunksize — Function.Read chunk-size from an IO stream. After the final zero size chunk, read trailers into a Message struct.
HTTP.Messages.headerscomplete — Method.headerscomplete(::Message)Have the headers been read into this Message?
HTTP.Messages.writestartline — Function.writestartline(::IO, ::Message)e.g. "GET /path HTTP/1.1\r\n" or "HTTP/1.1 200 OK\r\n"
HTTP.Messages.writeheaders — Function.writeheaders(::IO, ::Message)Write Message start line and a line for each "name: value" pair and a trailing blank line.
Base.write — Method.write(::IO, ::Message)Write start line, headers and body of HTTP Message.
IOExtras Interface
HTTP.IOExtras
HTTP.IOExtras.unread!
HTTP.IOExtras.startwrite(::IO)
HTTP.IOExtras.isioerrorStreams Interface
HTTP.Streams.closebody — Function.closebody(::Stream)Write the final 0 chunk if needed.
HTTP.Streams.isaborted — Function.isaborted(::Stream{Response})Has the server signaled that it does not wish to receive the message body?
"If [the response] indicates the server does not wish to receive the message body and is closing the connection, the client SHOULD immediately cease transmitting the body and close the connection." RFC7230, 6.5
Connection Pooling Interface
HTTP.ConnectionPool.Connection — Type.Connection{T <: IO}A TCPSocket or SSLContext connection to a HTTP host and port.
Fields:
host::Stringport::String, exactly as specified in the URI (i.e. may be empty).pipeline_limit, number of requests to send before waiting for responses.idle_timeout, No. of sconds to maintain connection after last transaction.peerport, remote TCP port number (used for debug messages).localport, local TCP port number (used for debug messages).io::T, theTCPSocketor `SSLContext.excess::ByteView, left over bytes read from the connection after the end of a response message. These bytes are probably the start of the next response message.sequence, number of most recentTransaction.writecount, number of Messages that have been written.writedone, signal thatwritecountwas incremented.readcount, number of Messages that have been read.readdone, signal thatreadcountwas incremented.timestamp, time data was last recieved.
HTTP.ConnectionPool.Transaction — Type.A single pipelined HTTP Request/Response transaction`.
Fields:
c, the sharedConnectionused for thisTransaction.sequence::Int, identifies thisTransactionamong the others that sharec.
HTTP.ConnectionPool.pool — Constant.The pool is a collection of open Connections. The request function calls getconnection to retrieve a connection from the pool. When the request function has written a Request Message it calls closewrite to signal that the Connection can be reused for writing (to send the next Request). When the request function has read the Response Message it calls closeread to signal that the Connection can be reused for reading.
HTTP.ConnectionPool.getconnection — Function.getconnection(type, host, port) -> ConnectionFind a reusable Connection in the pool, or create a new Connection if required.
HTTP.IOExtras.unread! — Method.unread!(::Transaction, bytes)Push bytes back into a connection's excess buffer (to be returned by the next read).
HTTP.IOExtras.startwrite — Method.startwrite(::Transaction)Wait for prior pending writes to complete.
HTTP.IOExtras.closewrite — Method.closewrite(::Transaction)Signal that an entire Request Message has been written to the Transaction.
HTTP.IOExtras.startread — Method.startread(::Transaction)Wait for prior pending reads to complete.
HTTP.IOExtras.closeread — Method.closeread(::Transaction)Signal that an entire Response Message has been read from the Transaction.
Increment readcount and wake up tasks waiting in startread.