diff --git a/dev/changelog/index.html b/dev/changelog/index.html index bb2d9198..4b8ba17e 100644 --- a/dev/changelog/index.html +++ b/dev/changelog/index.html @@ -3,4 +3,4 @@ HTTP.request(...; response_stream = io) close(io)(#543, #752, #775).
  • The internal client request layer stack have been reworked to be value based instead of type based. This is breaking if you implement custom layers but not for regular client usage. Refer to the documentation for how to update. (#789)
  • The server side Handlers/Router framework have been reworked. Refer to the documentation for how to update. (#818)
  • The default value (optional third argument) to HTTP.header can now be of any type (not just AbstractString). (#820)
  • HTTP.jl now attempts to reencode malformed, non-ascii, headers from Latin-1 to UTF-8. (#830)
  • Headers with the empty string as their value are now omitted from requests (this matches the behavior of e.g. curl). (#831)
  • Requests to localhost are no longer proxied. (#833)
  • The cookie-code have been reworked. In particular it is now safe to use concurrently. (#836)
  • The websockets code have been reworked. (#843)
  • HTTP.jl exception types are now more consistent. (#846)
  • Removed

    v0.9.17 - 2021-11-17

    Fixed

    v0.9.16 - 2021-09-29

    See changes for 0.9.15: this release is equivalent to 0.9.15 with #752 reverted. #752 might be included in a future breaking release instead, see #774.

    v0.9.15 - 2021-09-27

    Note: This release have been pulled back since #752 turned out to be breaking.

    Changed

    Fixed

    v0.9.14 - 2021-08-31

    Changed

    Fixed

    v0.9.13 - 2021-08-01

    Changed

    v0.9.12 - 2021-07-01

    Fixed

    v0.9.11 - 2021-06-30

    Changed

    Fixed

    v0.9.10 - 2021-05-30

    Fixed

    v0.9.9 - 2021-05-23

    Added

    Fixed

    v0.9.8 - 2021-05-02

    Fixed

    Changed

    v0.9.7 - 2021-04-28

    Added

    v0.9.6 - 2021-04-27

    Added

    Changed

    Fixed

    v0.9.5 - 2021-02-23

    Fixed

    v0.9.4 - 2021-02-23

    Changed

    Fixed

    v0.9.3 - 2021-02-10

    Added

    Changed

    v0.9.2 - 2020-12-22

    Changed

    Fixed

    v0.9.1 - 2020-12-04

    Changed

    v0.9.0 - 2020-11-12

    Added

    Changed

    Fixed

    +close(io)(#543, #752).
  • The Content-Type header for requests with HTTP.Form bodies is now automatically set also for PUT requests (just like POST requests) (#770, #740).
  • Fixed

    v0.9.14 - 2021-08-31

    Changed

    Fixed

    v0.9.13 - 2021-08-01

    Changed

    v0.9.12 - 2021-07-01

    Fixed

    v0.9.11 - 2021-06-30

    Changed

    Fixed

    v0.9.10 - 2021-05-30

    Fixed

    v0.9.9 - 2021-05-23

    Added

    Fixed

    v0.9.8 - 2021-05-02

    Fixed

    Changed

    v0.9.7 - 2021-04-28

    Added

    v0.9.6 - 2021-04-27

    Added

    Changed

    Fixed

    v0.9.5 - 2021-02-23

    Fixed

    v0.9.4 - 2021-02-23

    Changed

    Fixed

    v0.9.3 - 2021-02-10

    Added

    Changed

    v0.9.2 - 2020-12-22

    Changed

    Fixed

    v0.9.1 - 2020-12-04

    Changed

    v0.9.0 - 2020-11-12

    Added

    Changed

    Fixed

    diff --git a/dev/client/index.html b/dev/client/index.html index ba4a17c7..0f4c7371 100644 --- a/dev/client/index.html +++ b/dev/client/index.html @@ -43,4 +43,4 @@ HTTP.pushlayer!(Auth.auth_layer) # Now can use normal HTTP.jl methods and auth_layer will be included -HTTP.get(url; authcreds=creds)

    For more ideas or examples on how client-side layers work, it can be useful to see how HTTP.request is built on layers internally, in the /src/clientlayers source code directory.

    +HTTP.get(url; authcreds=creds)

    For more ideas or examples on how client-side layers work, it can be useful to see how HTTP.request is built on layers internally, in the /src/clientlayers source code directory.

    diff --git a/dev/examples/index.html b/dev/examples/index.html index 2cc464f8..d4eb2182 100644 --- a/dev/examples/index.html +++ b/dev/examples/index.html @@ -454,4 +454,4 @@ close(server) - + diff --git a/dev/index.html b/dev/index.html index 3562b3cf..12424782 100644 --- a/dev/index.html +++ b/dev/index.html @@ -58,4 +58,4 @@ # simple echo server send(ws, msg) end -end

    Further Documentation

    Check out the client, server, and websocket-specific documentation pages for more in-depth discussions and examples for the many configurations available.

    Migrating Legacy Code to 1.0

    The 1.0 release is finally here! It's been a lot of work over the course of about 9 months combing through every part of the codebase to try and modernize APIs, fix long-standing issues, and bring the level of functionality up to par with other language http implementations. Along the way, some breaking changes were made, but with the aim that the package will now be committed to current published APIs for a long time to come. With the amount of increased functionality and fixes, we hope it provides enough incentive to make the update; as always, if you run into issues upgrading or feel something didn't get polished or fixed quite right, don't hesitate to open an issue so we can help.

    The sections below outline a mix of breaking changes that were made, in addition to some of the new features in 1.0 with the aim to help those updating legacy codebases.

    Struct Changes

    In addition, in the face of redirects or retried requests, note the response_stream will not be written to until the final response is received.

    Keyword Argument Changes

    Other Largish Changes

    "Handlers" framework overhaul

    The server-side Handlers framework has been changed to a more modern and flexible framework, including the Handler and Middleware interfaces. It's similar in ways to the old interfaces, but in our opinion, simpler and more straightforward with the clear distinction/pattern between what a Handler does vs. a Middlware.

    In that vein, HTTP.Handlers.handle has been removed. HTTP.serve expects a single request or stream Handler function, which should be of the form f(::Request)::Response for the request case, or f(::Stream)::Nothing for streams.

    There are also plans to either include some common useful middleware functions in HTTP.jl directly, or a sister package specifically for collecting useful middlewares people can reuse.

    WebSockets overhaul

    The WebSockets code was some of the oldest and least maintained code in HTTP.jl. It was debated removing it entirely, but there aren't really other modern implementations that are well-maintained. So the WebSockets code was overhauled, modernized, and is now tested against the industry standard autobahn test suite (yay for 3rd party verification!). The API changed as well; while WebSockets.open and WebSockets.listen have stayed the same, the WebSocket object itself now doesn't subtype IO and has a restricted interface like:

    HTTP.Router reimplementation

    While clever, the old HTTP.Router implementation relied on having routes registered "statically", which can be really inconvenient for any cases where the routes are generated programmatically or need to be set/updated dynamically.

    The new HTTP.Router implementation uses a text-matching based trie data structure on incoming request path segments to find the right matching handler to process the request. It also supports parsing and storing path variables, like /api/{id} or double wildcards for matching trailing path segments, like /api/**.

    HTTP.Router now also supports complete unrestricted route registration via HTTP.register!.

    Internal client-side layers overhaul

    While grandiose in vision, the old type-based "layers" framework relied heavily on type parameter abuse for generating a large "stack" of layers to handle different parts of each HTTP.request. The new framework actually matches very closely with the server-side Handler and Middleware interfaces, and can be found in more detail under the Client-side Middleware (Layers) section of the docs. The new implementation, while hopefully bringing greater consistency between client-side and server-side frameworks, is much simpler and forced a large cleanup of state-handling in the HTTP.request process for the better.

    In addition to the changing of all the client-side layer definitions, HTTP.stack now behaves slightly different in returning the new "layer" chain for HTTP.request, while also accepting custom request/stream layers is provided. A new HTTP.@client macro is provided for convenience in the case that users want to write a custom client-side middleware/layer and wrap its usage in an HTTP.jl-like client.

    There also existed a few internal methods previously for manipulating the global stack of client-side layers (insert, insert_default!, etc.). These have been removed and replaced with a more formal (and documented) API via HTTP.pushlayer! and HTTP.poplayer!. These can be used to globally manipulate the client-side stack of layers for any HTTP.request that is made.

    +end

    Further Documentation

    Check out the client, server, and websocket-specific documentation pages for more in-depth discussions and examples for the many configurations available.

    Migrating Legacy Code to 1.0

    The 1.0 release is finally here! It's been a lot of work over the course of about 9 months combing through every part of the codebase to try and modernize APIs, fix long-standing issues, and bring the level of functionality up to par with other language http implementations. Along the way, some breaking changes were made, but with the aim that the package will now be committed to current published APIs for a long time to come. With the amount of increased functionality and fixes, we hope it provides enough incentive to make the update; as always, if you run into issues upgrading or feel something didn't get polished or fixed quite right, don't hesitate to open an issue so we can help.

    The sections below outline a mix of breaking changes that were made, in addition to some of the new features in 1.0 with the aim to help those updating legacy codebases.

    Struct Changes

    In addition, in the face of redirects or retried requests, note the response_stream will not be written to until the final response is received.

    Keyword Argument Changes

    Other Largish Changes

    "Handlers" framework overhaul

    The server-side Handlers framework has been changed to a more modern and flexible framework, including the Handler and Middleware interfaces. It's similar in ways to the old interfaces, but in our opinion, simpler and more straightforward with the clear distinction/pattern between what a Handler does vs. a Middlware.

    In that vein, HTTP.Handlers.handle has been removed. HTTP.serve expects a single request or stream Handler function, which should be of the form f(::Request)::Response for the request case, or f(::Stream)::Nothing for streams.

    There are also plans to either include some common useful middleware functions in HTTP.jl directly, or a sister package specifically for collecting useful middlewares people can reuse.

    WebSockets overhaul

    The WebSockets code was some of the oldest and least maintained code in HTTP.jl. It was debated removing it entirely, but there aren't really other modern implementations that are well-maintained. So the WebSockets code was overhauled, modernized, and is now tested against the industry standard autobahn test suite (yay for 3rd party verification!). The API changed as well; while WebSockets.open and WebSockets.listen have stayed the same, the WebSocket object itself now doesn't subtype IO and has a restricted interface like:

    HTTP.Router reimplementation

    While clever, the old HTTP.Router implementation relied on having routes registered "statically", which can be really inconvenient for any cases where the routes are generated programmatically or need to be set/updated dynamically.

    The new HTTP.Router implementation uses a text-matching based trie data structure on incoming request path segments to find the right matching handler to process the request. It also supports parsing and storing path variables, like /api/{id} or double wildcards for matching trailing path segments, like /api/**.

    HTTP.Router now also supports complete unrestricted route registration via HTTP.register!.

    Internal client-side layers overhaul

    While grandiose in vision, the old type-based "layers" framework relied heavily on type parameter abuse for generating a large "stack" of layers to handle different parts of each HTTP.request. The new framework actually matches very closely with the server-side Handler and Middleware interfaces, and can be found in more detail under the Client-side Middleware (Layers) section of the docs. The new implementation, while hopefully bringing greater consistency between client-side and server-side frameworks, is much simpler and forced a large cleanup of state-handling in the HTTP.request process for the better.

    In addition to the changing of all the client-side layer definitions, HTTP.stack now behaves slightly different in returning the new "layer" chain for HTTP.request, while also accepting custom request/stream layers is provided. A new HTTP.@client macro is provided for convenience in the case that users want to write a custom client-side middleware/layer and wrap its usage in an HTTP.jl-like client.

    There also existed a few internal methods previously for manipulating the global stack of client-side layers (insert, insert_default!, etc.). These have been removed and replaced with a more formal (and documented) API via HTTP.pushlayer! and HTTP.poplayer!. These can be used to globally manipulate the client-side stack of layers for any HTTP.request that is made.

    diff --git a/dev/reference/index.html b/dev/reference/index.html index e52211cd..45d2f497 100644 --- a/dev/reference/index.html +++ b/dev/reference/index.html @@ -49,14 +49,14 @@ bytes = readavailable(io) play_audio(bytes) end -endsource
    HTTP.getFunction
    HTTP.get(url [, headers]; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("GET", ...). See HTTP.request.

    source
    HTTP.putFunction
    HTTP.put(url, headers, body; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("PUT", ...). See HTTP.request.

    source
    HTTP.postFunction
    HTTP.post(url, headers, body; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("POST", ...). See HTTP.request.

    source
    HTTP.headFunction
    HTTP.head(url; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("HEAD", ...). See HTTP.request.

    source
    HTTP.patchFunction
    HTTP.patch(url, headers, body; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("PATCH", ...). See HTTP.request.

    source
    HTTP.deleteFunction
    HTTP.delete(url [, headers]; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("DELETE", ...). See HTTP.request.

    source
    HTTP.openFunction
    WebSockets.open(handler, url; verbose=false, kw...)

    Initiate a websocket connection to url (which should have schema like ws:// or wss://), and call handler(ws) with the websocket connection. Passing verbose=true or verbose=2 will enable debug logging for the life of the websocket connection. handler should be a function of the form f(ws) -> nothing, where ws is a WebSocket. Supported keyword arguments are the same as supported by HTTP.request. Typical websocket usage is:

    WebSockets.open(url) do ws
    +end
    source
    HTTP.getFunction
    HTTP.get(url [, headers]; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("GET", ...). See HTTP.request.

    source
    HTTP.putFunction
    HTTP.put(url, headers, body; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("PUT", ...). See HTTP.request.

    source
    HTTP.postFunction
    HTTP.post(url, headers, body; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("POST", ...). See HTTP.request.

    source
    HTTP.headFunction
    HTTP.head(url; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("HEAD", ...). See HTTP.request.

    source
    HTTP.patchFunction
    HTTP.patch(url, headers, body; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("PATCH", ...). See HTTP.request.

    source
    HTTP.deleteFunction
    HTTP.delete(url [, headers]; <keyword arguments>) -> HTTP.Response

    Shorthand for HTTP.request("DELETE", ...). See HTTP.request.

    source
    HTTP.openFunction
    WebSockets.open(handler, url; verbose=false, kw...)

    Initiate a websocket connection to url (which should have schema like ws:// or wss://), and call handler(ws) with the websocket connection. Passing verbose=true or verbose=2 will enable debug logging for the life of the websocket connection. handler should be a function of the form f(ws) -> nothing, where ws is a WebSocket. Supported keyword arguments are the same as supported by HTTP.request. Typical websocket usage is:

    WebSockets.open(url) do ws
         # iterate incoming websocket messages
         for msg in ws
             # send message back to server or do other logic here
             send(ws, msg)
         end
         # iteration ends when the websocket connection is closed by server or error
    -end
    source
    HTTP.open(method, url, [,headers]) do io
    +end
    source
    HTTP.open(method, url, [,headers]) do io
         write(io, body)
         [startread(io) -> HTTP.Response]
         while !eof(io)
    @@ -66,16 +66,16 @@
         open(`vlc -q --play-and-exit --intf dummy -`, "w") do vlc
             write(vlc, http)
         end
    -end
    source
    HTTP.downloadFunction
    download(url, [local_path], [headers]; update_period=1, kw...)

    Similar to Base.download this downloads a file, returning the filename. If the local_path:

    • is not provided, then it is saved in a temporary directory
    • if part to a directory is provided then it is saved into that directory
    • otherwise the local path is uses as the filename to save to.

    When saving into a directory, the filename is determined (where possible), from the rules of the HTTP.

    • update_period controls how often (in seconds) to report the progress.
      • set to Inf to disable reporting
    • headers specifies headers to be used for the HTTP GET request
    • any additional keyword args (kw...) are passed on to the HTTP request.
    source

    Request/Response Objects

    HTTP.Messages.RequestType
    HTTP.Request(
    +end
    source
    HTTP.downloadFunction
    download(url, [local_path], [headers]; update_period=1, kw...)

    Similar to Base.download this downloads a file, returning the filename. If the local_path:

    • is not provided, then it is saved in a temporary directory
    • if part to a directory is provided then it is saved into that directory
    • otherwise the local path is uses as the filename to save to.

    When saving into a directory, the filename is determined (where possible), from the rules of the HTTP.

    • update_period controls how often (in seconds) to report the progress.
      • set to Inf to disable reporting
    • headers specifies headers to be used for the HTTP GET request
    • any additional keyword args (kw...) are passed on to the HTTP request.
    source

    Request/Response Objects

    HTTP.Messages.RequestType
    HTTP.Request(
         method, target, headers=[], body=nobody;
         version=v"1.1", url::URI=URI(), responsebody=nothing, parent=nothing, context=HTTP.Context()
    -)

    Represents a HTTP Request Message with fields:

    • method::String RFC7230 3.1.1

    • target::String RFC7230 5.3

    • version::HTTPVersion RFC7230 2.6

    • headers::HTTP.Headers RFC7230 3.2

    • body::Union{Vector{UInt8}, IO} RFC7230 3.3

    • response, the Response to this Request

    • url::URI, the full URI of the request

    • parent, the Response (if any) that led to this request (e.g. in the case of a redirect). RFC7230 6.4

    • context, a Dict{Symbol, Any} store used by middleware to share state

    source
    HTTP.Messages.ResponseType
    HTTP.Response(status, headers::HTTP.Headers, body; request=nothing)
    +)

    Represents a HTTP Request Message with fields:

    • method::String RFC7230 3.1.1

    • target::String RFC7230 5.3

    • version::HTTPVersion RFC7230 2.6

    • headers::HTTP.Headers RFC7230 3.2

    • body::Union{Vector{UInt8}, IO} RFC7230 3.3

    • response, the Response to this Request

    • url::URI, the full URI of the request

    • parent, the Response (if any) that led to this request (e.g. in the case of a redirect). RFC7230 6.4

    • context, a Dict{Symbol, Any} store used by middleware to share state

    source
    HTTP.Messages.ResponseType
    HTTP.Response(status, headers::HTTP.Headers, body; request=nothing)
     HTTP.Response(status, body)
    -HTTP.Response(body)

    Represents an HTTP response message with fields:

    source
    HTTP.Streams.StreamType
    Stream(::Request, ::IO)

    Creates a HTTP.Stream that wraps an existing IO stream.

    • startwrite(::Stream) sends the Request headers to the IO stream.

    • write(::Stream, body) sends the body (or a chunk of the body).

    • closewrite(::Stream) sends the final 0 chunk (if needed) and calls closewrite on the IO stream.

    • startread(::Stream) calls startread on the IO stream then reads and parses the Response headers.

    • eof(::Stream) and readavailable(::Stream) parse the body from the IO stream.

    • closeread(::Stream) reads the trailers and calls closeread on the IO stream. When the IO stream is a HTTP.Connections.Connection, calling closeread releases the connection back to the connection pool for reuse. If a complete response has not been received, closeread throws EOFError.

    source
    HTTP.WebSockets.WebSocketType
    WebSocket(io::HTTP.Connection, req, resp; client=true)

    Representation of a websocket connection. Use WebSockets.open to open a websocket connection, passing a handler function f(ws) to send and receive messages. Use WebSockets.listen to listen for incoming websocket connections, passing a handler function f(ws) to send and receive messages.

    Call send(ws, msg) to send a message; if msg is an AbstractString, a TEXT websocket message will be sent; if msg is an AbstractVector{UInt8}, a BINARY websocket message will be sent. Otherwise, msg should be an iterable of either AbstractString or AbstractVector{UInt8}, and a fragmented message will be sent, one frame for each iterated element.

    Control frames can be sent by calling ping(ws[, data]), pong(ws[, data]), or close(ws[, body::WebSockets.CloseFrameBody]). Calling close will initiate the close sequence and close the underlying connection.

    To receive messages, call receive(ws), which will block until a non-control, full message is received. PING messages will automatically be responded to when received. CLOSE messages will also be acknowledged and then a WebSocketError will be thrown with the WebSockets.CloseFrameBody payload, which may include a non-error CLOSE frame status code. WebSockets.isok(err) can be called to check if the CLOSE was normal or unexpected. Fragmented messages will be received until the final frame is received and the full concatenated payload can be returned. receive(ws) returns a Vector{UInt8} for BINARY messages, and a String for TEXT messages.

    For convenience, WebSockets support the iteration protocol, where each iteration will receive a non-control message, with iteration terminating when the connection is closed. E.g.:

    WebSockets.open(url) do ws
    +HTTP.Response(body)

    Represents an HTTP response message with fields:

    source
    HTTP.Streams.StreamType
    Stream(::Request, ::IO)

    Creates a HTTP.Stream that wraps an existing IO stream.

    • startwrite(::Stream) sends the Request headers to the IO stream.

    • write(::Stream, body) sends the body (or a chunk of the body).

    • closewrite(::Stream) sends the final 0 chunk (if needed) and calls closewrite on the IO stream.

    • startread(::Stream) calls startread on the IO stream then reads and parses the Response headers.

    • eof(::Stream) and readavailable(::Stream) parse the body from the IO stream.

    • closeread(::Stream) reads the trailers and calls closeread on the IO stream. When the IO stream is a HTTP.Connections.Connection, calling closeread releases the connection back to the connection pool for reuse. If a complete response has not been received, closeread throws EOFError.

    source
    HTTP.WebSockets.WebSocketType
    WebSocket(io::HTTP.Connection, req, resp; client=true)

    Representation of a websocket connection. Use WebSockets.open to open a websocket connection, passing a handler function f(ws) to send and receive messages. Use WebSockets.listen to listen for incoming websocket connections, passing a handler function f(ws) to send and receive messages.

    Call send(ws, msg) to send a message; if msg is an AbstractString, a TEXT websocket message will be sent; if msg is an AbstractVector{UInt8}, a BINARY websocket message will be sent. Otherwise, msg should be an iterable of either AbstractString or AbstractVector{UInt8}, and a fragmented message will be sent, one frame for each iterated element.

    Control frames can be sent by calling ping(ws[, data]), pong(ws[, data]), or close(ws[, body::WebSockets.CloseFrameBody]). Calling close will initiate the close sequence and close the underlying connection.

    To receive messages, call receive(ws), which will block until a non-control, full message is received. PING messages will automatically be responded to when received. CLOSE messages will also be acknowledged and then a WebSocketError will be thrown with the WebSockets.CloseFrameBody payload, which may include a non-error CLOSE frame status code. WebSockets.isok(err) can be called to check if the CLOSE was normal or unexpected. Fragmented messages will be received until the final frame is received and the full concatenated payload can be returned. receive(ws) returns a Vector{UInt8} for BINARY messages, and a String for TEXT messages.

    For convenience, WebSockets support the iteration protocol, where each iteration will receive a non-control message, with iteration terminating when the connection is closed. E.g.:

    WebSockets.open(url) do ws
         for msg in ws
             # do cool stuff with msg
         end
    -end
    source
    HTTP.Messages.headerFunction
    HTTP.header(::Message, key [, default=""]) -> String

    Get header value for key (case-insensitive).

    source
    HTTP.Messages.headersFunction
    HTTP.headers(m::Message, key) -> Vector{String}

    Get all headers with key k or empty if none

    source
    HTTP.Messages.hasheaderFunction
    HTTP.hasheader(::Message, key) -> Bool

    Does header value for key exist (case-insensitive)?

    source
    HTTP.hasheader(::Message, key, value) -> Bool

    Does header for key match value (both case-insensitive)?

    source
    HTTP.Messages.headercontainsFunction
    HTTP.headercontains(::Message, key, value) -> Bool

    Does the header for key (interpreted as comma-separated list) contain value (both case-insensitive)?

    source
    HTTP.Messages.setheaderFunction
    HTTP.setheader(::Message, key => value)

    Set header value for key (case-insensitive).

    source
    HTTP.Messages.appendheaderFunction
    HTTP.appendheader(::Message, key => value)

    Append a header value to message.headers.

    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.

    source
    HTTP.Messages.removeheaderFunction
    HTTP.removeheader(::Message, key)

    Remove header for key (case-insensitive).

    source
    HTTP.Messages.decodeFunction
    HTTP.decode(r::Union{Request, Response}) -> Vector{UInt8}

    For a gzip encoded request/response body, decompress it and return the decompressed body.

    source

    Request body types

    HTTP.Forms.FormType
    HTTP.Form(data; boundary=string(rand(UInt128), base=16))

    Construct a request body for multipart/form-data encoding from data.

    data must iterate key-value pairs (e.g. AbstractDict or Vector{Pair}) where the key/value of the iterator is the key/value of each mutipart boundary chunk. Files and other large data arguments can be provided as values as IO arguments: either an IOStream such as returned via open(file), or an IOBuffer for in-memory data.

    For complete control over a multipart chunk's details, an HTTP.Multipart type is provided to support setting the filename, Content-Type, and Content-Transfer-Encoding.

    Examples

    data = Dict(
    +end
    source
    HTTP.Messages.headerFunction
    HTTP.header(::Message, key [, default=""]) -> String

    Get header value for key (case-insensitive).

    source
    HTTP.Messages.headersFunction
    HTTP.headers(m::Message, key) -> Vector{String}

    Get all headers with key k or empty if none

    source
    HTTP.Messages.hasheaderFunction
    HTTP.hasheader(::Message, key) -> Bool

    Does header value for key exist (case-insensitive)?

    source
    HTTP.hasheader(::Message, key, value) -> Bool

    Does header for key match value (both case-insensitive)?

    source
    HTTP.Messages.headercontainsFunction
    HTTP.headercontains(::Message, key, value) -> Bool

    Does the header for key (interpreted as comma-separated list) contain value (both case-insensitive)?

    source
    HTTP.Messages.setheaderFunction
    HTTP.setheader(::Message, key => value)

    Set header value for key (case-insensitive).

    source
    HTTP.Messages.appendheaderFunction
    HTTP.appendheader(::Message, key => value)

    Append a header value to message.headers.

    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.

    source
    HTTP.Messages.removeheaderFunction
    HTTP.removeheader(::Message, key)

    Remove header for key (case-insensitive).

    source
    HTTP.Messages.decodeFunction
    HTTP.decode(r::Union{Request, Response}) -> Vector{UInt8}

    For a gzip encoded request/response body, decompress it and return the decompressed body.

    source

    Request body types

    HTTP.Forms.FormType
    HTTP.Form(data; boundary=string(rand(UInt128), base=16))

    Construct a request body for multipart/form-data encoding from data.

    data must iterate key-value pairs (e.g. AbstractDict or Vector{Pair}) where the key/value of the iterator is the key/value of each mutipart boundary chunk. Files and other large data arguments can be provided as values as IO arguments: either an IOStream such as returned via open(file), or an IOBuffer for in-memory data.

    For complete control over a multipart chunk's details, an HTTP.Multipart type is provided to support setting the filename, Content-Type, and Content-Transfer-Encoding.

    Examples

    data = Dict(
         "text" => "text data",
         # filename (cat.png) and content-type (image/png) inferred from the IOStream
         "file1" => open("cat.png"),
    @@ -84,11 +84,11 @@
     )
     body = HTTP.Form(data)
     headers = []
    -HTTP.post(url, headers, body)
    source
    HTTP.Forms.MultipartType
    HTTP.Multipart(filename::String, data::IO, content_type=HTTP.sniff(data), content_transfer_encoding="")

    A type to represent a single multipart upload chunk for a file. This type would be used as the value in a key-value pair when constructing a HTTP.Form for a request body (see example below). The data argument must be an IO type such as IOStream, or IOBuffer. The content_type and content_transfer_encoding arguments allow manual setting of these multipart headers. Content-Type will default to the result of the HTTP.sniff(data) mimetype detection algorithm, whereas Content-Transfer-Encoding will be left out if not specified.

    Examples

    body = HTTP.Form(Dict(
    +HTTP.post(url, headers, body)
    source
    HTTP.Forms.MultipartType
    HTTP.Multipart(filename::String, data::IO, content_type=HTTP.sniff(data), content_transfer_encoding="")

    A type to represent a single multipart upload chunk for a file. This type would be used as the value in a key-value pair when constructing a HTTP.Form for a request body (see example below). The data argument must be an IO type such as IOStream, or IOBuffer. The content_type and content_transfer_encoding arguments allow manual setting of these multipart headers. Content-Type will default to the result of the HTTP.sniff(data) mimetype detection algorithm, whereas Content-Transfer-Encoding will be left out if not specified.

    Examples

    body = HTTP.Form(Dict(
         "key" => HTTP.Multipart("File.txt", open("MyFile.txt"), "text/plain"),
     ))
     headers = []
    -HTTP.post(url, headers, body)

    Extended help

    Filename SHOULD be included when the Multipart represents the contents of a file RFC7578 4.2

    Content-Disposition set to "form-data" MUST be included with each Multipart. An additional "name" parameter MUST be included An optional "filename" parameter SHOULD be included if the contents of a file are sent This will be formatted such as: Content-Disposition: form-data; name="user"; filename="myfile.txt" RFC7578 4.2

    Content-Type for each Multipart is optional, but SHOULD be included if the contents of a file are sent. RFC7578 4.4

    Content-Transfer-Encoding for each Multipart is deprecated RFC7578 4.7

    Other Content- header fields MUST be ignored RFC7578 4.8

    source

    Request exceptions

    Request functions may throw the following exceptions:

    HTTP.Exceptions.ConnectErrorType
    HTTP.ConnectError

    Raised when an error occurs while trying to establish a request connection to the remote server. To see the underlying error, see the error field.

    source
    HTTP.Exceptions.TimeoutErrorType
    HTTP.TimeoutError

    Raised when a request times out according to readtimeout keyword argument provided.

    source
    HTTP.Exceptions.StatusErrorType
    HTTP.StatusError

    Raised when an HTTP.Response has a 4xx, 5xx or unrecognised status code.

    Fields:

    • status::Int16, the response status code.
    • method::String, the request method.
    • target::String, the request target.
    • response, the HTTP.Response
    source
    HTTP.Exceptions.RequestErrorType
    HTTP.RequestError

    Raised when an error occurs while physically sending a request to the remote server or reading the response back. To see the underlying error, see the error field.

    source

    URIs

    HTTP.jl uses the URIs.jl package for handling URIs. Some functionality from URIs.jl, relevant to HTTP.jl, are listed below:

    URIs.URIType
    URI(; scheme="", host="", port="", etc...)
    +HTTP.post(url, headers, body)

    Extended help

    Filename SHOULD be included when the Multipart represents the contents of a file RFC7578 4.2

    Content-Disposition set to "form-data" MUST be included with each Multipart. An additional "name" parameter MUST be included An optional "filename" parameter SHOULD be included if the contents of a file are sent This will be formatted such as: Content-Disposition: form-data; name="user"; filename="myfile.txt" RFC7578 4.2

    Content-Type for each Multipart is optional, but SHOULD be included if the contents of a file are sent. RFC7578 4.4

    Content-Transfer-Encoding for each Multipart is deprecated RFC7578 4.7

    Other Content- header fields MUST be ignored RFC7578 4.8

    source

    Request exceptions

    Request functions may throw the following exceptions:

    HTTP.Exceptions.ConnectErrorType
    HTTP.ConnectError

    Raised when an error occurs while trying to establish a request connection to the remote server. To see the underlying error, see the error field.

    source
    HTTP.Exceptions.TimeoutErrorType
    HTTP.TimeoutError

    Raised when a request times out according to readtimeout keyword argument provided.

    source
    HTTP.Exceptions.StatusErrorType
    HTTP.StatusError

    Raised when an HTTP.Response has a 4xx, 5xx or unrecognised status code.

    Fields:

    • status::Int16, the response status code.
    • method::String, the request method.
    • target::String, the request target.
    • response, the HTTP.Response
    source
    HTTP.Exceptions.RequestErrorType
    HTTP.RequestError

    Raised when an error occurs while physically sending a request to the remote server or reading the response back. To see the underlying error, see the error field.

    source

    URIs

    HTTP.jl uses the URIs.jl package for handling URIs. Some functionality from URIs.jl, relevant to HTTP.jl, are listed below:

    URIs.URIType
    URI(; scheme="", host="", port="", etc...)
     URI(str) = parse(URI, str::String)

    A type representing a URI (e.g. a URL). Can be constructed from distinct parts using the various supported keyword arguments, or from a string. The URI constructors will automatically escape any provided query arguments, typically provided as "key"=>"value"::Pair or Dict("key"=>"value"). For all other components, you need to manually percent encode them before passing them to the URI constructor. Note that multiple values for a single query key can provided like Dict("key"=>["value1", "value2"]), in which case the constructor will percent encode only the values you pass in as the query part.

    When constructing a URI from a String, you need to ensure that the string is correctly percent encoded already.

    The URI struct stores the complete 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"
    • host e.g. "julialang.org"
    • port e.g. "80" or ""
    • path e.g "/"
    • query e.g. "Foo=1&Bar=2"
    • fragment

    The queryparams(::URI) function returns a Dict containing the query.

    Note that you manually need to percent decode the content of the individual component fields before you further use their content, as they are returned in percent-encoded form.

    URIs.escapeuriFunction
    escapeuri(x)

    Apply URI percent-encoding to escape special characters in x.

    URIs.unescapeuriFunction
    unescapeuri(str)

    Percent-decode a string according to the URI escaping rules.

    URIs.splitpathFunction
    URIs.splitpath(path|uri; rstrip_empty_segment=true)

    Splits the path into component segments based on /, according to http://tools.ietf.org/html/rfc3986#section-3.3. Any fragment and query parts of the string are ignored if present.

    A final empty path segment (trailing '/') is removed, if present. This is technically incompatible with the segment grammar of RFC3986, but it seems to be a common recommendation to make paths with and without a trailing slash equivalent. To preserve any final empty path segment, set rstrip_empty_segment=false.

    Examples

    julia> URIs.splitpath(URI("http://example.com/foo/bar?a=b&c=d"))
     2-element Array{String,1}:
      "foo"
    @@ -99,20 +99,20 @@
      "foo"
      "bar"
    Base.isvalidMethod

    checks if a URI is valid

    Cookies

    HTTP.Cookies.CookieType
    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::String: name of the cookie
    • value::String: value of the cookie
    • path::String: applicable path for the cookie
    • domain::String: applicable domain for the cookie
    • expires::Dates.DateTime: when the cookie should expire
    • maxage::Int: maxage == 0 means no max age, maxage < 0 means delete cookie now, maxage > 0 means the # of seconds until expiration
    • secure::Bool: secure cookie attribute
    • httponly::Bool: httponly cookie attribute
    • hostonly::Bool: hostonly cookie attribute
    • samesite::Bool: SameSite cookie attribute

    See IETF RFC 6265 for details.

    The string representation of a cookie is generated by calling stringify(cookie; isrequest=true), where isrequest=true will only include the name=value pair for requests, and if false, will generate the "Set-Cookie" representation for a response header.

    A Vector{Cookie} can be retrieved from a Request/Response object by calling Cookies.cookies(r).

    A Cookie can be added to a Request/Response object by calling Cookies.addcookie!(r, cookie).

    source
    HTTP.Cookies.stringifyFunction
    stringify(cookie::Cookie, isrequest=true)

    Generate the string representation of a cookie. By default, isrequest=true, and only the name=value pair will be included in the cookie string. For isrequest=false, the other cookie attributes will be included, ;-separated, for use in a "Set-Cookie" header.

    source
    HTTP.Cookies.addcookie!Function
    Cookies.addcookie!(r::Union{HTTP.Request, HTTP.Response}, c::Cookie)

    Convenience function for adding a single cookie to a request or response object. For requests, the cookie will be stringified and concatenated to any existing "Cookie" header. For responses, an additional "Set-Cookie" header will be appended.

    source
    HTTP.Cookies.cookiesFunction
    HTTP.cookies(r::Union{Request, Response}) -> Vector{Cookie}

    Return a list of cookies, if any, parsed from the request "Cookie" or response "Set-Cookie" headers.

    source

    WebSockets

    Sockets.sendMethod
    send(ws::WebSocket, msg)

    Send a message on a websocket connection. If msg is an AbstractString, a TEXT websocket message will be sent; if msg is an AbstractVector{UInt8}, a BINARY websocket message will be sent. Otherwise, msg should be an iterable of either AbstractString or AbstractVector{UInt8}, and a fragmented message will be sent, one frame for each iterated element.

    Control frames can be sent by calling ping(ws[, data]), pong(ws[, data]), or close(ws[, body::WebSockets.CloseFrameBody]). Calling close will initiate the close sequence and close the underlying connection.

    source
    HTTP.WebSockets.receiveFunction
    receive(ws::WebSocket) -> Union{String, Vector{UInt8}}

    Receive a message from a websocket connection. Returns a String if the message was TEXT, or a Vector{UInt8} if the message was BINARY. If control frames (ping or pong) are received, they are handled automatically and a non-control message is waited for. If a CLOSE message is received, it is responded to and a WebSocketError is thrown with the WebSockets.CloseFrameBody as the error value. This error can be checked with WebSockets.isok(err) to see if the closing was "normal" or if an actual error occurred. For fragmented messages, the incoming frames will continue to be read until the final fragment is received. The bodies of each fragment are concatenated into the final message returned by receive. Note that WebSocket objects can be iterated, where each iteration yields a message until the connection is closed.

    source
    Missing docstring.

    Missing docstring for HTTP.WebSockets.close(::HTTP.WebSockets.WebSocket, body). Check Documenter's build log for details.

    HTTP.WebSockets.pingFunction
    ping(ws, data=[])

    Send a PING control frame on a websocket connection. data is an optional body to send with the message. PONG messages are automatically responded to when a PING message is received by a websocket connection.

    source
    HTTP.WebSockets.pongFunction
    pong(ws, data=[])

    Send a PONG control frame on a websocket connection. data is an optional body to send with the message. Note that PING messages are automatically responded to internally by the websocket connection with a corresponding PONG message, but in certain cases, a unidirectional PONG message can be used as a one-way heartbeat.

    source
    Base.iterateMethod
    iterate(ws)

    Continuously call receive(ws) on a WebSocket connection, with each iteration yielding a message until the connection is closed. E.g.

    for msg in ws
    +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::String: name of the cookie
    • value::String: value of the cookie
    • path::String: applicable path for the cookie
    • domain::String: applicable domain for the cookie
    • expires::Dates.DateTime: when the cookie should expire
    • maxage::Int: maxage == 0 means no max age, maxage < 0 means delete cookie now, maxage > 0 means the # of seconds until expiration
    • secure::Bool: secure cookie attribute
    • httponly::Bool: httponly cookie attribute
    • hostonly::Bool: hostonly cookie attribute
    • samesite::Bool: SameSite cookie attribute

    See IETF RFC 6265 for details.

    The string representation of a cookie is generated by calling stringify(cookie; isrequest=true), where isrequest=true will only include the name=value pair for requests, and if false, will generate the "Set-Cookie" representation for a response header.

    A Vector{Cookie} can be retrieved from a Request/Response object by calling Cookies.cookies(r).

    A Cookie can be added to a Request/Response object by calling Cookies.addcookie!(r, cookie).

    source
    HTTP.Cookies.stringifyFunction
    stringify(cookie::Cookie, isrequest=true)

    Generate the string representation of a cookie. By default, isrequest=true, and only the name=value pair will be included in the cookie string. For isrequest=false, the other cookie attributes will be included, ;-separated, for use in a "Set-Cookie" header.

    source
    HTTP.Cookies.addcookie!Function
    Cookies.addcookie!(r::Union{HTTP.Request, HTTP.Response}, c::Cookie)

    Convenience function for adding a single cookie to a request or response object. For requests, the cookie will be stringified and concatenated to any existing "Cookie" header. For responses, an additional "Set-Cookie" header will be appended.

    source
    HTTP.Cookies.cookiesFunction
    HTTP.cookies(r::Union{Request, Response}) -> Vector{Cookie}

    Return a list of cookies, if any, parsed from the request "Cookie" or response "Set-Cookie" headers.

    source

    WebSockets

    Sockets.sendMethod
    send(ws::WebSocket, msg)

    Send a message on a websocket connection. If msg is an AbstractString, a TEXT websocket message will be sent; if msg is an AbstractVector{UInt8}, a BINARY websocket message will be sent. Otherwise, msg should be an iterable of either AbstractString or AbstractVector{UInt8}, and a fragmented message will be sent, one frame for each iterated element.

    Control frames can be sent by calling ping(ws[, data]), pong(ws[, data]), or close(ws[, body::WebSockets.CloseFrameBody]). Calling close will initiate the close sequence and close the underlying connection.

    source
    HTTP.WebSockets.receiveFunction
    receive(ws::WebSocket) -> Union{String, Vector{UInt8}}

    Receive a message from a websocket connection. Returns a String if the message was TEXT, or a Vector{UInt8} if the message was BINARY. If control frames (ping or pong) are received, they are handled automatically and a non-control message is waited for. If a CLOSE message is received, it is responded to and a WebSocketError is thrown with the WebSockets.CloseFrameBody as the error value. This error can be checked with WebSockets.isok(err) to see if the closing was "normal" or if an actual error occurred. For fragmented messages, the incoming frames will continue to be read until the final fragment is received. The bodies of each fragment are concatenated into the final message returned by receive. Note that WebSocket objects can be iterated, where each iteration yields a message until the connection is closed.

    source
    Missing docstring.

    Missing docstring for HTTP.WebSockets.close(::HTTP.WebSockets.WebSocket, body). Check Documenter's build log for details.

    HTTP.WebSockets.pingFunction
    ping(ws, data=[])

    Send a PING control frame on a websocket connection. data is an optional body to send with the message. PONG messages are automatically responded to when a PING message is received by a websocket connection.

    source
    HTTP.WebSockets.pongFunction
    pong(ws, data=[])

    Send a PONG control frame on a websocket connection. data is an optional body to send with the message. Note that PING messages are automatically responded to internally by the websocket connection with a corresponding PONG message, but in certain cases, a unidirectional PONG message can be used as a one-way heartbeat.

    source
    Base.iterateMethod
    iterate(ws)

    Continuously call receive(ws) on a WebSocket connection, with each iteration yielding a message until the connection is closed. E.g.

    for msg in ws
         # do something with msg
    -end
    source
    HTTP.WebSockets.isclosedFunction
    WebSockets.isclosed(ws) -> Bool

    Check whether a WebSocket has sent and received CLOSE frames.

    source
    HTTP.WebSockets.isokFunction
    WebSockets.isok(x::WebSocketError) -> Bool

    Returns true if the WebSocketError has a non-error status code. When calling receive(websocket), if a CLOSE frame is received, the CLOSE frame body is parsed and thrown inside the WebSocketError, but if the CLOSE frame has a non-error status code, it's safe to ignore the error and return from the WebSockets.open or WebSockets.listen calls without throwing.

    source

    Utilities

    HTTP.Sniff.sniffFunction
    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.

    Examples

    julia> HTTP.sniff("Hello world!!")
    +end
    source
    HTTP.WebSockets.isclosedFunction
    WebSockets.isclosed(ws) -> Bool

    Check whether a WebSocket has sent and received CLOSE frames.

    source
    HTTP.WebSockets.isokFunction
    WebSockets.isok(x::WebSocketError) -> Bool

    Returns true if the WebSocketError has a non-error status code. When calling receive(websocket), if a CLOSE frame is received, the CLOSE frame body is parsed and thrown inside the WebSocketError, but if the CLOSE frame has a non-error status code, it's safe to ignore the error and return from the WebSockets.open or WebSockets.listen calls without throwing.

    source

    Utilities

    HTTP.Sniff.sniffFunction
    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.

    Examples

    julia> HTTP.sniff("Hello world!!")
     "text/plain; charset=utf-8"
     
     julia> HTTP.sniff("<html><body>Hello world!!</body></html>")
     "text/html; charset=utf-8"
     
     julia> HTTP.sniff("{"a": -1.0}")
    -"application/json; charset=utf-8"
    source
    HTTP.Strings.escapehtmlFunction
    escapehtml(i::String)

    Returns a string with special HTML characters escaped: &, <, >, ", '

    source
    HTTP.Strings.tocameldashFunction
    tocameldash(s::String)

    Ensure the first character and characters that follow a '-' are uppercase.

    source
    HTTP.Strings.iso8859_1_to_utf8Function
    iso8859_1_to_utf8(bytes::AbstractVector{UInt8})

    Convert from ISO8859_1 to UTF8.

    source
    HTTP.Strings.ascii_lc_isequalFunction

    Case insensitive ASCII character comparison.

    source
    HTTP.ascii_lc_isequal(a::String, b::String)

    Case insensitive ASCII string comparison.

    source
    HTTP.StatusCodes.statustextFunction
    statustext(::Int) -> String

    String representation of a HTTP status code.

    Examples

    julia> statustext(200)
    +"application/json; charset=utf-8"
    source
    HTTP.Strings.escapehtmlFunction
    escapehtml(i::String)

    Returns a string with special HTML characters escaped: &, <, >, ", '

    source
    HTTP.Strings.tocameldashFunction
    tocameldash(s::String)

    Ensure the first character and characters that follow a '-' are uppercase.

    source
    HTTP.Strings.iso8859_1_to_utf8Function
    iso8859_1_to_utf8(bytes::AbstractVector{UInt8})

    Convert from ISO8859_1 to UTF8.

    source
    HTTP.Strings.ascii_lc_isequalFunction

    Case insensitive ASCII character comparison.

    source
    HTTP.ascii_lc_isequal(a::String, b::String)

    Case insensitive ASCII string comparison.

    source
    HTTP.StatusCodes.statustextFunction
    statustext(::Int) -> String

    String representation of a HTTP status code.

    Examples

    julia> statustext(200)
     "OK"
     
     julia> statustext(404)
    -"Not Found"
    source

    Server / Handlers

    Core Server

    HTTP.Servers.listenFunction
    HTTP.listen(handler, host=Sockets.localhost, port=8081; kw...)
    +"Not Found"
    source

    Server / Handlers

    Core Server

    HTTP.Servers.listenFunction
    HTTP.listen(handler, host=Sockets.localhost, port=8081; kw...)
     HTTP.listen(handler, port::Integer=8081; kw...)
     HTTP.listen(handler, server::Base.IOServer; kw...)
     HTTP.listen!(args...; kw...) -> HTTP.Server

    Listen for HTTP connections and execute the handler function for each request. Listening details can be passed as host/port pair, a single port (host will default to localhost), or an already listening server object, as returned from Sockets.listen. To open up a server to external requests, the host argument is typically "0.0.0.0".

    The HTTP.listen! form is non-blocking and returns an HTTP.Server object which can be wait(server)ed on manually, or close(server)ed to gracefully shut down the server. Calling HTTP.forceclose(server) will immediately force close the server and all active connections. HTTP.listen will block on the server listening loop until interrupted or and an irrecoverable error occurs.

    The handler function should be of the form f(::HTTP.Stream)::Nothing, and should at the minimum set a status via setstatus() and call startwrite() either explicitly or implicitly by writing out a response via write(). Failure to do this will result in an HTTP 500 error being transmitted to the client.

    Optional keyword arguments:

    • sslconfig=nothing, Provide an MbedTLS.SSLConfig object to handle ssl connections. Pass sslconfig=MbedTLS.SSLConfig(false) to disable ssl verification (useful for testing). Construct a custom SSLConfig object with MbedTLS.SSLConfig(certfile, keyfile).
    • tcpisvalid = tcp->true, function f(::TCPSocket)::Bool to check if accepted connections are valid before processing requests. e.g. to do source IP filtering.
    • readtimeout::Int=0, close the connection if no data is received for this many seconds. Use readtimeout = 0 to disable.
    • reuseaddr::Bool=false, allow multiple servers to listen on the same port. Not supported on some OS platforms. Can check HTTP.Servers.supportsreuseaddr().
    • server::Base.IOServer=nothing, provide an IOServer object to listen on; allows manually closing or configuring the server socket.
    • verbose::Bool=false, log connection information to stdout.
    • access_log::Function, function for formatting access log messages. The function should accept two arguments, io::IO to which the messages should be written, and http::HTTP.Stream which can be used to query information from. See also @logfmt_str.
    • on_shutdown::Union{Function, Vector{<:Function}, Nothing}=nothing, one or more functions to be run if the server is closed (for example by an InterruptException). Note, shutdown function(s) will not run if an IOServer object is supplied to the server keyword argument and closed by close(server).

    e.g.

    # start a blocking server
    @@ -157,7 +157,7 @@
     
     chat_client() = HTTP.open("POST", "http://127.0.0.1:8087") do io
         chat(io)
    -end
    source
    HTTP.Handlers.serveFunction
    HTTP.serve(handler, host=Sockets.localhost, port=8081; kw...)
    +end
    source
    HTTP.Handlers.serveFunction
    HTTP.serve(handler, host=Sockets.localhost, port=8081; kw...)
     HTTP.serve(handler, port::Integer=8081; kw...)
     HTTP.serve(handler, server::Base.IOServer; kw...)
     HTTP.serve!(args...; kw...) -> HTTP.Server

    Listen for HTTP connections and execute the handler function for each request. Listening details can be passed as host/port pair, a single port (host will default to localhost), or an already listening server object, as returned from Sockets.listen. To open up a server to external requests, the host argument is typically "0.0.0.0".

    The HTTP.serve! form is non-blocking and returns an HTTP.Server object which can be wait(server)ed on manually, or close(server)ed to gracefully shut down the server. Calling HTTP.forceclose(server) will immediately force close the server and all active connections. HTTP.serve will block on the server listening loop until interrupted or and an irrecoverable error occurs.

    The handler function should be of the form f(req::HTTP.Request)::HTTP.Response. Alternatively, passing stream=true requires the handler to be of the form f(stream::HTTP.Stream) -> Nothing. See HTTP.Router for details on using it as a request handler.

    Optional keyword arguments:

    • sslconfig=nothing, Provide an MbedTLS.SSLConfig object to handle ssl connections. Pass sslconfig=MbedTLS.SSLConfig(false) to disable ssl verification (useful for testing). Construct a custom SSLConfig object with MbedTLS.SSLConfig(certfile, keyfile).
    • tcpisvalid = tcp->true, function f(::TCPSocket)::Bool to check if accepted connections are valid before processing requests. e.g. to do source IP filtering.
    • readtimeout::Int=0, close the connection if no data is received for this many seconds. Use readtimeout = 0 to disable.
    • reuseaddr::Bool=false, allow multiple servers to listen on the same port. Not supported on some OS platforms. Can check HTTP.Servers.supportsreuseaddr().
    • server::Base.IOServer=nothing, provide an IOServer object to listen on; allows manually closing or configuring the server socket.
    • verbose::Bool=false, log connection information to stdout.
    • access_log::Function, function for formatting access log messages. The function should accept two arguments, io::IO to which the messages should be written, and http::HTTP.Stream which can be used to query information from. See also @logfmt_str.
    • on_shutdown::Union{Function, Vector{<:Function}, Nothing}=nothing, one or more functions to be run if the server is closed (for example by an InterruptException). Note, shutdown function(s) will not run if an IOServer object is supplied to the server keyword argument and closed by close(server).
    # start a blocking echo server
    @@ -170,7 +170,7 @@
         return HTTP.Response(200, "response body")
     end
     # can gracefully close server manually
    -close(server)
    source
    HTTP.WebSockets.listenFunction
    WebSockets.listen(handler, host, port; verbose=false, kw...)
    +close(server)
    source
    HTTP.WebSockets.listenFunction
    WebSockets.listen(handler, host, port; verbose=false, kw...)
     WebSockets.listen!(handler, host, port; verbose=false, kw...) -> HTTP.Server

    Listen for websocket connections on host and port, and call handler(ws), which should be a function taking a single WebSocket argument. Keyword arguments kw... are the same as supported by HTTP.listen. Typical usage is like:

    WebSockets.listen(host, port) do ws
         # iterate incoming websocket messages
         for msg in ws
    @@ -178,11 +178,11 @@
             send(ws, msg)
         end
         # iteration ends when the websocket connection is closed by client or error
    -end
    source

    Middleware / Handlers

    HTTP.Handlers.HandlerType
    Handler

    Abstract type for the handler interface that exists for documentation purposes. A Handler is any function of the form f(req::HTTP.Request) -> HTTP.Response. There is no requirement to subtype Handler and users should not rely on or dispatch on Handler. A Handler function f can be passed to HTTP.serve wherein a server will pass each incoming request to f to be handled and a response to be returned. Handler functions are also the inputs to Middleware functions which are functions of the form f(::Handler) -> Handler, i.e. they take a Handler function as input, and return a "modified" or enhanced Handler function.

    For advanced cases, a Handler function can also be of the form f(stream::HTTP.Stream) -> Nothing. In this case, the server would be run like HTTP.serve(f, ...; stream=true). For this use-case, the handler function reads the request and writes the response to the stream directly. Note that any middleware used with a stream handler also needs to be of the form f(stream_handler) -> stream_handler, i.e. it needs to accept a stream Handler function and return a stream Handler function.

    source
    HTTP.Handlers.MiddlewareType
    Middleware

    Abstract type for the middleware interface that exists for documentation purposes. A Middleware is any function of the form f(::Handler) -> Handler (ref: Handler). There is no requirement to subtype Middleware and users should not rely on or dispatch on the Middleware type. While HTTP.serve(f, ...) requires a handler function f to be passed, middleware can be "stacked" to create a chain of functions that are called in sequence, like HTTP.serve(base_handler |> cookie_middleware |> auth_middlware, ...), where the base_handler Handler function is passed to cookie_middleware, which takes the handler and returns a "modified" handler (that parses and stores cookies). This "modified" handler is then an input to the auth_middlware, which further enhances/modifies the handler.

    source
    HTTP.Handlers.streamhandlerFunction
    streamhandler(request_handler) -> stream handler

    Middleware that takes a request handler and returns a stream handler. Used by default in HTTP.serve to take the user-provided request handler and process the Stream from HTTP.listen and pass the parsed Request to the handler.

    Is included by default in HTTP.serve as the base "middleware" when stream=false is passed.

    source
    HTTP.Handlers.RouterType
    HTTP.Router(_404, _405, middleware=nothing)

    Define a router object that maps incoming requests by path to registered routes and associated handlers. Paths can be registered using HTTP.register!. The router object itself is a "request handler" that can be called like:

    r = HTTP.Router()
    -resp = r(request)

    Which will inspect the request, find the matching, registered handler from the url, and pass the request on to be handled further.

    See HTTP.register! for additional information on registering handlers based on routes.

    If a request doesn't have a matching, registered handler, the _404 handler is called which, by default, returns a HTTP.Response(404). If a route matches the path, but not the method/verb (e.g. there's a registerd route for "GET /api", but the request is "POST /api"), then the _405 handler is called, which by default returns HTTP.Response(405) (method not allowed).

    A middleware (Middleware) can optionally be provided as well, which will be called after the router has matched the request to a route, but before the route's handler is called. This provides a "hook" for matched routes that can be helpful for metric tracking, logging, etc. Note that the middleware is only called if the route is matched; for the 404 and 405 cases, users should wrap those handlers in the middleware manually.

    source
    HTTP.Handlers.register!Function
    HTTP.register!(r::Router, method, path, handler)
    -HTTP.register!(r::Router, path, handler)

    Register a handler function that should be called when an incoming request matches path and the optionally provided method (if not provided, any method is allowed). Can be used to dynamically register routes. When a registered route is matched, the original route string is stored in the request.context[:route] variable. The following path types are allowed for matching:

    • /api/widgets: exact match of static strings
    • /api/*/owner: single * to wildcard match anything for a single segment
    • /api/widget/{id}: Define a path variable id that matches any valued provided for this segment; path variables are available in the request context like HTTP.getparams(req)["id"]
    • /api/widget/{id:[0-9]+}: Define a path variable id that does a regex match for integers for this segment
    • /api/**: double wildcard matches any number of trailing segments in the request path; the double wildcard must be the last segment in the path
    source
    HTTP.Handlers.getparamFunction
    HTTP.getparam(req, name, default=nothing) -> String

    Retrieve a matched path parameter with name name from request context. If a path was registered with a router via HTTP.register! like "/api/widget/{id}", then the path parameter can be retrieved like `id = HTTP.getparam(req, "id").

    source
    HTTP.Handlers.getparamsFunction
    HTTP.getparams(req) -> Dict{String, String}

    Retrieve any matched path parameters from the request context. If a path was registered with a router via HTTP.register! like "/api/widget/{id}", then the path parameters are available in the request context and can be retrieved like id = HTTP.getparams(req)["id"].

    source
    HTTP.Handlers.cookie_middlewareFunction
    HTTP.Handlers.cookie_middleware(handler) -> handler

    Middleware that parses and stores any cookies in the incoming request in the request context. Cookies can then be retrieved by calling HTTP.getcookies(req) in subsequent middlewares/handlers.

    source
    HTTP.Handlers.getcookiesFunction
    HTTP.getcookies(req) -> Vector{Cookie}

    Retrieve any parsed cookies from a request context. Cookies are expected to be stored in the req.context[:cookies] of the request context as implemented in the HTTP.Handlers.cookie_middleware middleware.

    source
    HTTP.@logfmt_strMacro
    logfmt"..."

    Parse an NGINX-style log format string and return a function mapping (io::IO, http::HTTP.Stream) -> body suitable for passing to HTTP.listen using the access_log keyword argument.

    The following variables are currently supported:

    • $http_name: arbitrary request header (with - replaced with _, e.g. http_user_agent)
    • $sent_http_name: arbitrary response header (with - replaced with _)
    • $request: the request line, e.g. GET /index.html HTTP/1.1
    • $request_method: the request method
    • $request_uri: the request URI
    • $remote_addr: client address
    • $remote_port: client port
    • $remote_user: user name supplied with the Basic authentication
    • $server_protocol: server protocol
    • $time_iso8601: local time in ISO8601 format
    • $time_local: local time in Common Log Format
    • $status: response status code
    • $body_bytes_sent: number of bytes in response body

    Examples

    logfmt"[$time_iso8601] \"$request\" $status" # [2021-05-01T12:34:40+0100] "GET /index.html HTTP/1.1" 200
    +end
    source

    Middleware / Handlers

    HTTP.Handlers.HandlerType
    Handler

    Abstract type for the handler interface that exists for documentation purposes. A Handler is any function of the form f(req::HTTP.Request) -> HTTP.Response. There is no requirement to subtype Handler and users should not rely on or dispatch on Handler. A Handler function f can be passed to HTTP.serve wherein a server will pass each incoming request to f to be handled and a response to be returned. Handler functions are also the inputs to Middleware functions which are functions of the form f(::Handler) -> Handler, i.e. they take a Handler function as input, and return a "modified" or enhanced Handler function.

    For advanced cases, a Handler function can also be of the form f(stream::HTTP.Stream) -> Nothing. In this case, the server would be run like HTTP.serve(f, ...; stream=true). For this use-case, the handler function reads the request and writes the response to the stream directly. Note that any middleware used with a stream handler also needs to be of the form f(stream_handler) -> stream_handler, i.e. it needs to accept a stream Handler function and return a stream Handler function.

    source
    HTTP.Handlers.MiddlewareType
    Middleware

    Abstract type for the middleware interface that exists for documentation purposes. A Middleware is any function of the form f(::Handler) -> Handler (ref: Handler). There is no requirement to subtype Middleware and users should not rely on or dispatch on the Middleware type. While HTTP.serve(f, ...) requires a handler function f to be passed, middleware can be "stacked" to create a chain of functions that are called in sequence, like HTTP.serve(base_handler |> cookie_middleware |> auth_middlware, ...), where the base_handler Handler function is passed to cookie_middleware, which takes the handler and returns a "modified" handler (that parses and stores cookies). This "modified" handler is then an input to the auth_middlware, which further enhances/modifies the handler.

    source
    HTTP.Handlers.streamhandlerFunction
    streamhandler(request_handler) -> stream handler

    Middleware that takes a request handler and returns a stream handler. Used by default in HTTP.serve to take the user-provided request handler and process the Stream from HTTP.listen and pass the parsed Request to the handler.

    Is included by default in HTTP.serve as the base "middleware" when stream=false is passed.

    source
    HTTP.Handlers.RouterType
    HTTP.Router(_404, _405, middleware=nothing)

    Define a router object that maps incoming requests by path to registered routes and associated handlers. Paths can be registered using HTTP.register!. The router object itself is a "request handler" that can be called like:

    r = HTTP.Router()
    +resp = r(request)

    Which will inspect the request, find the matching, registered handler from the url, and pass the request on to be handled further.

    See HTTP.register! for additional information on registering handlers based on routes.

    If a request doesn't have a matching, registered handler, the _404 handler is called which, by default, returns a HTTP.Response(404). If a route matches the path, but not the method/verb (e.g. there's a registerd route for "GET /api", but the request is "POST /api"), then the _405 handler is called, which by default returns HTTP.Response(405) (method not allowed).

    A middleware (Middleware) can optionally be provided as well, which will be called after the router has matched the request to a route, but before the route's handler is called. This provides a "hook" for matched routes that can be helpful for metric tracking, logging, etc. Note that the middleware is only called if the route is matched; for the 404 and 405 cases, users should wrap those handlers in the middleware manually.

    source
    HTTP.Handlers.register!Function
    HTTP.register!(r::Router, method, path, handler)
    +HTTP.register!(r::Router, path, handler)

    Register a handler function that should be called when an incoming request matches path and the optionally provided method (if not provided, any method is allowed). Can be used to dynamically register routes. When a registered route is matched, the original route string is stored in the request.context[:route] variable. The following path types are allowed for matching:

    • /api/widgets: exact match of static strings
    • /api/*/owner: single * to wildcard match anything for a single segment
    • /api/widget/{id}: Define a path variable id that matches any valued provided for this segment; path variables are available in the request context like HTTP.getparams(req)["id"]
    • /api/widget/{id:[0-9]+}: Define a path variable id that does a regex match for integers for this segment
    • /api/**: double wildcard matches any number of trailing segments in the request path; the double wildcard must be the last segment in the path
    source
    HTTP.Handlers.getparamFunction
    HTTP.getparam(req, name, default=nothing) -> String

    Retrieve a matched path parameter with name name from request context. If a path was registered with a router via HTTP.register! like "/api/widget/{id}", then the path parameter can be retrieved like `id = HTTP.getparam(req, "id").

    source
    HTTP.Handlers.getparamsFunction
    HTTP.getparams(req) -> Dict{String, String}

    Retrieve any matched path parameters from the request context. If a path was registered with a router via HTTP.register! like "/api/widget/{id}", then the path parameters are available in the request context and can be retrieved like id = HTTP.getparams(req)["id"].

    source
    HTTP.Handlers.cookie_middlewareFunction
    HTTP.Handlers.cookie_middleware(handler) -> handler

    Middleware that parses and stores any cookies in the incoming request in the request context. Cookies can then be retrieved by calling HTTP.getcookies(req) in subsequent middlewares/handlers.

    source
    HTTP.Handlers.getcookiesFunction
    HTTP.getcookies(req) -> Vector{Cookie}

    Retrieve any parsed cookies from a request context. Cookies are expected to be stored in the req.context[:cookies] of the request context as implemented in the HTTP.Handlers.cookie_middleware middleware.

    source
    HTTP.@logfmt_strMacro
    logfmt"..."

    Parse an NGINX-style log format string and return a function mapping (io::IO, http::HTTP.Stream) -> body suitable for passing to HTTP.listen using the access_log keyword argument.

    The following variables are currently supported:

    • $http_name: arbitrary request header (with - replaced with _, e.g. http_user_agent)
    • $sent_http_name: arbitrary response header (with - replaced with _)
    • $request: the request line, e.g. GET /index.html HTTP/1.1
    • $request_method: the request method
    • $request_uri: the request URI
    • $remote_addr: client address
    • $remote_port: client port
    • $remote_user: user name supplied with the Basic authentication
    • $server_protocol: server protocol
    • $time_iso8601: local time in ISO8601 format
    • $time_local: local time in Common Log Format
    • $status: response status code
    • $body_bytes_sent: number of bytes in response body

    Examples

    logfmt"[$time_iso8601] \"$request\" $status" # [2021-05-01T12:34:40+0100] "GET /index.html HTTP/1.1" 200
     
    -logfmt"$remote_addr \"$http_user_agent\"" # 127.0.0.1 "curl/7.47.0"
    source

    Advanced Topics

    Messages Interface

    HTTP.Messages.iserrorFunction
    iserror(::Response)

    Does this Response have an error status?

    source
    HTTP.Messages.isredirectFunction
    isredirect(::Response)

    Does this Response have a redirect status?

    source
    HTTP.Messages.ischunkedFunction
    ischunked(::Message)

    Does the Message have a "Transfer-Encoding: chunked" header?

    source
    HTTP.Messages.issafeFunction
    issafe(::Request)

    https://tools.ietf.org/html/rfc7231#section-4.2.1

    source
    HTTP.Messages.isidempotentFunction
    isidempotent(::Request)

    https://tools.ietf.org/html/rfc7231#section-4.2.2

    source
    HTTP.Messages.retryableFunction
    retryable(::Request)

    Whether a Request is eligible to be retried.

    source
    HTTP.Messages.defaultheader!Function
    defaultheader!(::Message, key => value)

    Set header value in message for key if it is not already set.

    source
    HTTP.Messages.readheadersFunction
    readheaders(::IO, ::Message)

    Read headers (and startline) from an IO stream into a Message struct. Throw EOFError if input is incomplete.

    source
    HTTP.HeadersRequest.setuseragent!Function
    setuseragent!(x::Union{String, Nothing})

    Set the default User-Agent string to be used in each HTTP request. Can be manually overridden by passing an explicit User-Agent header. Setting nothing will prevent the default User-Agent header from being passed.

    source
    HTTP.Messages.readchunksizeFunction

    Read chunk-size from an IO stream. After the final zero size chunk, read trailers into a Message struct.

    source
    HTTP.Messages.headerscompleteMethod
    headerscomplete(::Message)

    Have the headers been read into this Message?

    source
    HTTP.Messages.writestartlineFunction
    writestartline(::IO, ::Message)

    e.g. "GET /path HTTP/1.1\r\n" or "HTTP/1.1 200 OK\r\n"

    source
    HTTP.Messages.writeheadersFunction
    writeheaders(::IO, ::Message)

    Write Message start line and a line for each "name: value" pair and a trailing blank line.

    source
    Base.writeMethod
    write(::IO, ::Message)

    Write start line, headers and body of HTTP Message.

    source
    HTTP.Streams.closebodyFunction
    closebody(::Stream)

    Write the final 0 chunk if needed.

    source
    HTTP.Streams.isabortedFunction
    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

    source
    HTTP.Cookies.CookieJarType
    CookieJar()

    A thread-safe object for storing cookies returned in "Set-Cookie" response headers. Keyed by appropriate host from the original request made. Can be created manually and passed like HTTP.get(url; cookiejar=mycookiejar) to avoid using the default global CookieJar. The 2 main functions for interacting with a CookieJar are Cookies.getcookies!, which returns a Vector{Cookie} for a given url (and will remove expired cookies from the jar), and Cookies.setcookies!, which will store "Set-Cookie" response headers in the cookie jar.

    source
    HTTP.Cookies.getcookies!Function
    Cookies.getcookies!(jar::CookieJar, url::URI)

    Retrieve valid Cookies from the CookieJar according to the provided url. Cookies will be returned as a Vector{Cookie}. Only cookies for http or https scheme in the url will be returned. Cookies will be checked according to the canonical host of the url and any cookie max age or expiration will be accounted for. Expired cookies will not be returned and will be removed from the cookie jar.

    source
    HTTP.Cookies.setcookies!Function
    Cookies.setcookies!(jar::CookieJar, url::URI, headers::Headers)

    Identify, "Set-Cookie" response headers from headers, parse the Cookies, and store valid entries in the cookie jar according to the canonical host in url. Cookies can be retrieved from the jar via Cookies.getcookies!.

    source

    Client-side Middleware (Layers)

    HTTP.LayerType
    Layer

    Abstract type to represent a client-side middleware that exists for documentation purposes. A layer is any function of the form f(::Handler) -> Handler, where Handler is a function of the form f(::Request) -> Response. Note that the Handler definition is from the server-side documentation, and is "hard-coded" on the client side. It may also be apparent that a Layer is the same as the Middleware interface from server-side, which is true, but we define Layer to clarify the client-side distinction and its unique usage. Custom layers can be deployed in one of two ways:

    • HTTP.@client: Create a custom "client" with shorthand verb definitions, but which include custom layers; only these new verb methods will use the custom layers.
    • HTTP.pushlayer!/HTTP.poplayer!: Allows globally adding and removing layers from the default HTTP.jl layer stack; all http requests will then use the custom layers

    Quick Examples

    module Auth
    +logfmt"$remote_addr \"$http_user_agent\"" # 127.0.0.1 "curl/7.47.0"
    source

    Advanced Topics

    Messages Interface

    HTTP.Messages.iserrorFunction
    iserror(::Response)

    Does this Response have an error status?

    source
    HTTP.Messages.isredirectFunction
    isredirect(::Response)

    Does this Response have a redirect status?

    source
    HTTP.Messages.ischunkedFunction
    ischunked(::Message)

    Does the Message have a "Transfer-Encoding: chunked" header?

    source
    HTTP.Messages.issafeFunction
    issafe(::Request)

    https://tools.ietf.org/html/rfc7231#section-4.2.1

    source
    HTTP.Messages.isidempotentFunction
    isidempotent(::Request)

    https://tools.ietf.org/html/rfc7231#section-4.2.2

    source
    HTTP.Messages.retryableFunction
    retryable(::Request)

    Whether a Request is eligible to be retried.

    source
    HTTP.Messages.defaultheader!Function
    defaultheader!(::Message, key => value)

    Set header value in message for key if it is not already set.

    source
    HTTP.Messages.readheadersFunction
    readheaders(::IO, ::Message)

    Read headers (and startline) from an IO stream into a Message struct. Throw EOFError if input is incomplete.

    source
    HTTP.HeadersRequest.setuseragent!Function
    setuseragent!(x::Union{String, Nothing})

    Set the default User-Agent string to be used in each HTTP request. Can be manually overridden by passing an explicit User-Agent header. Setting nothing will prevent the default User-Agent header from being passed.

    source
    HTTP.Messages.readchunksizeFunction

    Read chunk-size from an IO stream. After the final zero size chunk, read trailers into a Message struct.

    source
    HTTP.Messages.headerscompleteMethod
    headerscomplete(::Message)

    Have the headers been read into this Message?

    source
    HTTP.Messages.writestartlineFunction
    writestartline(::IO, ::Message)

    e.g. "GET /path HTTP/1.1\r\n" or "HTTP/1.1 200 OK\r\n"

    source
    HTTP.Messages.writeheadersFunction
    writeheaders(::IO, ::Message)

    Write Message start line and a line for each "name: value" pair and a trailing blank line.

    source
    Base.writeMethod
    write(::IO, ::Message)

    Write start line, headers and body of HTTP Message.

    source
    HTTP.Streams.closebodyFunction
    closebody(::Stream)

    Write the final 0 chunk if needed.

    source
    HTTP.Streams.isabortedFunction
    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

    source
    HTTP.Cookies.CookieJarType
    CookieJar()

    A thread-safe object for storing cookies returned in "Set-Cookie" response headers. Keyed by appropriate host from the original request made. Can be created manually and passed like HTTP.get(url; cookiejar=mycookiejar) to avoid using the default global CookieJar. The 2 main functions for interacting with a CookieJar are Cookies.getcookies!, which returns a Vector{Cookie} for a given url (and will remove expired cookies from the jar), and Cookies.setcookies!, which will store "Set-Cookie" response headers in the cookie jar.

    source
    HTTP.Cookies.getcookies!Function
    Cookies.getcookies!(jar::CookieJar, url::URI)

    Retrieve valid Cookies from the CookieJar according to the provided url. Cookies will be returned as a Vector{Cookie}. Only cookies for http or https scheme in the url will be returned. Cookies will be checked according to the canonical host of the url and any cookie max age or expiration will be accounted for. Expired cookies will not be returned and will be removed from the cookie jar.

    source
    HTTP.Cookies.setcookies!Function
    Cookies.setcookies!(jar::CookieJar, url::URI, headers::Headers)

    Identify, "Set-Cookie" response headers from headers, parse the Cookies, and store valid entries in the cookie jar according to the canonical host in url. Cookies can be retrieved from the jar via Cookies.getcookies!.

    source

    Client-side Middleware (Layers)

    HTTP.LayerType
    Layer

    Abstract type to represent a client-side middleware that exists for documentation purposes. A layer is any function of the form f(::Handler) -> Handler, where Handler is a function of the form f(::Request) -> Response. Note that the Handler definition is from the server-side documentation, and is "hard-coded" on the client side. It may also be apparent that a Layer is the same as the Middleware interface from server-side, which is true, but we define Layer to clarify the client-side distinction and its unique usage. Custom layers can be deployed in one of two ways:

    • HTTP.@client: Create a custom "client" with shorthand verb definitions, but which include custom layers; only these new verb methods will use the custom layers.
    • HTTP.pushlayer!/HTTP.poplayer!: Allows globally adding and removing layers from the default HTTP.jl layer stack; all http requests will then use the custom layers

    Quick Examples

    module Auth
     
     using HTTP
     
    @@ -214,9 +214,9 @@
     HTTP.pushlayer!(Auth.auth_layer)
     
     # Now can use normal HTTP.jl methods and auth_layer will be included
    -HTTP.get(url; authcreds=creds)
    source
    HTTP.@clientMacro
    HTTP.@client requestlayers
    +HTTP.get(url; authcreds=creds)
    source
    HTTP.@clientMacro
    HTTP.@client requestlayers
     HTTP.@client requestlayers streamlayers
    -HTTP.@client (first=requestlayers, last=requestlayers) (first=streamlayers, last=streamlayers)

    Convenience macro for creating a custom HTTP.jl client that will include custom layers when performing requests. It's common to want to define a custom Layer to enhance a specific category of requests, such as custom authentcation for a web API. Instead of affecting the global HTTP.jl request stack via HTTP.pushlayer!, a custom wrapper client can be defined with convenient shorthand methods. See Layer for an example of defining a custom layer and creating a new client that includes the layer.

    Custom layer arguments can be provided as a collection of request or stream-based layers; alternatively, a NamedTuple with keys first and last can be provided with values being a collection of layers. The NamedTuple form provides finer control over the order in which the layers will be included in the default http layer stack: first request layers are executed before all other layers, last request layers are executed right before all stream layers, and similarly for stream layers.

    An empty collection can always be passed for request or stream layers when not needed.

    One use case for custom clients is to control the value of standard HTTP.request keyword arguments. This can be achieved by passing a (first=[defaultkeywordlayer],) where defaultkeywordlayer is defined like:

    defaultkeywordlayer(handler) = (req; kw...) -> handler(req; retry=false, redirect=false, kw...)

    This client-side layer is basically a no-op as it doesn't modify the request at all, except that it hard-codes the value of the retry and redirect keyword arguments. When we pass this layer as (first=[defaultkeywordlayer],) this ensures this layer will be executed before all other layers, effectively over-writing the default and any user-provided keyword arguments for retry or redirect.

    source
    HTTP.pushlayer!Function
    HTTP.pushlayer!(layer; request=true)

    Push a layer onto the stack of layers that will be applied to all requests. The "layer" is expected to be a function that takes and returns a Handler function. See Layer for more details. If request=false, the layer is expected to take and return a "stream" handler function. The custom layer will be put on the top of the stack, so it will be the first layer executed. To add a layer at the bottom of the stack, see HTTP.pushfirstlayer!.

    source
    HTTP.pushfirstlayer!Function
    HTTP.pushfirstlayer!(layer; request=true)

    Push a layer to the start of the stack of layers that will be applied to all requests. The "layer" is expected to be a function that takes and returns a Handler function. See Layer for more details. If request=false, the layer is expected to take and return a "stream" handler function. The custom layer will be put on the bottom of the stack, so it will be the last layer executed. To add a layer at the top of the stack, see HTTP.pushlayer!.

    source
    HTTP.poplayer!Function
    HTTP.poplayer!(; request=true)

    Inverse of HTTP.pushlayer!, removes the top layer of the global HTTP.jl layer stack. Can be used to "cleanup" after a custom layer has been added. If request=false, will remove the top "stream" layer as opposed to top "request" layer.

    source
    HTTP.popfirstlayer!Function
    HTTP.popfirstlayer!(; request=true)

    Inverse of HTTP.pushfirstlayer!, removes the bottom layer of the global HTTP.jl layer stack. Can be used to "cleanup" after a custom layer has been added. If request=false, will remove the bottom "stream" layer as opposed to bottom "request" layer.

    source
    HTTP.MessageRequest.messagelayerFunction
    messagelayer(handler) -> handler

    Construct a Request object from method, url, headers, and body. Hard-coded as the first layer in the request pipeline.

    source
    HTTP.RedirectRequest.redirectlayerFunction
    redirectlayer(handler) -> handler

    Redirects the request in the case of 3xx response status.

    source
    HTTP.HeadersRequest.headerslayerFunction
    headerslayer(handler) -> handler

    Sets default expected headers.

    source
    HTTP.CookieRequest.cookielayerFunction
    cookielayer(handler) -> handler

    Check for host-appropriate cookies to include in the outgoing request from the cookiejar keyword argument (by default, a global cookiejar is used). Store "Set-Cookie" cookies from the response headers.

    source
    HTTP.TimeoutRequest.timeoutlayerFunction
    timeoutlayer(handler) -> handler

    Close the HTTP.Stream if no data has been received for readtimeout seconds.

    source
    HTTP.ExceptionRequest.exceptionlayerFunction
    exceptionlayer(handler) -> handler

    Throw a StatusError if the request returns an error response status.

    source
    HTTP.RetryRequest.retrylayerFunction
    retrylayer(handler) -> handler

    Retry 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.

    By default, requests that have a retryable body, where the request wasn't written or is idempotent will be retried. If the request is made and a response is received with a status code of 403, 408, 409, 429, or 5xx, the request will be retried.

    retries controls the # of total retries that will be attempted.

    retry_check allows passing a custom retry check in the case where the default retry check wouldn't retry, if retry_check returns true, then the request will be retried anyway.

    source
    HTTP.ConnectionRequest.connectionlayerFunction
    connectionlayer(handler) -> handler

    Retrieve an IO connection from the Connections.

    Close the connection if the request throws an exception. Otherwise leave it open so that it can be reused.

    source
    HTTP.StreamRequest.streamlayerFunction
    streamlayer(stream) -> HTTP.Response

    Create 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.

    source

    Raw Request Connection

    HTTP.openrawFunction
    HTTP.openraw(method, url, [, headers])::Tuple{Connection, Response}

    Open a raw socket that is unmanaged by HTTP.jl. Useful for doing HTTP upgrades to other protocols. Any bytes of the body read from the socket when reading headers, is returned as excess bytes in the last tuple argument.

    Example of a WebSocket upgrade:

    headers = Dict(
    +HTTP.@client (first=requestlayers, last=requestlayers) (first=streamlayers, last=streamlayers)

    Convenience macro for creating a custom HTTP.jl client that will include custom layers when performing requests. It's common to want to define a custom Layer to enhance a specific category of requests, such as custom authentcation for a web API. Instead of affecting the global HTTP.jl request stack via HTTP.pushlayer!, a custom wrapper client can be defined with convenient shorthand methods. See Layer for an example of defining a custom layer and creating a new client that includes the layer.

    Custom layer arguments can be provided as a collection of request or stream-based layers; alternatively, a NamedTuple with keys first and last can be provided with values being a collection of layers. The NamedTuple form provides finer control over the order in which the layers will be included in the default http layer stack: first request layers are executed before all other layers, last request layers are executed right before all stream layers, and similarly for stream layers.

    An empty collection can always be passed for request or stream layers when not needed.

    One use case for custom clients is to control the value of standard HTTP.request keyword arguments. This can be achieved by passing a (first=[defaultkeywordlayer],) where defaultkeywordlayer is defined like:

    defaultkeywordlayer(handler) = (req; kw...) -> handler(req; retry=false, redirect=false, kw...)

    This client-side layer is basically a no-op as it doesn't modify the request at all, except that it hard-codes the value of the retry and redirect keyword arguments. When we pass this layer as (first=[defaultkeywordlayer],) this ensures this layer will be executed before all other layers, effectively over-writing the default and any user-provided keyword arguments for retry or redirect.

    source
    HTTP.pushlayer!Function
    HTTP.pushlayer!(layer; request=true)

    Push a layer onto the stack of layers that will be applied to all requests. The "layer" is expected to be a function that takes and returns a Handler function. See Layer for more details. If request=false, the layer is expected to take and return a "stream" handler function. The custom layer will be put on the top of the stack, so it will be the first layer executed. To add a layer at the bottom of the stack, see HTTP.pushfirstlayer!.

    source
    HTTP.pushfirstlayer!Function
    HTTP.pushfirstlayer!(layer; request=true)

    Push a layer to the start of the stack of layers that will be applied to all requests. The "layer" is expected to be a function that takes and returns a Handler function. See Layer for more details. If request=false, the layer is expected to take and return a "stream" handler function. The custom layer will be put on the bottom of the stack, so it will be the last layer executed. To add a layer at the top of the stack, see HTTP.pushlayer!.

    source
    HTTP.poplayer!Function
    HTTP.poplayer!(; request=true)

    Inverse of HTTP.pushlayer!, removes the top layer of the global HTTP.jl layer stack. Can be used to "cleanup" after a custom layer has been added. If request=false, will remove the top "stream" layer as opposed to top "request" layer.

    source
    HTTP.popfirstlayer!Function
    HTTP.popfirstlayer!(; request=true)

    Inverse of HTTP.pushfirstlayer!, removes the bottom layer of the global HTTP.jl layer stack. Can be used to "cleanup" after a custom layer has been added. If request=false, will remove the bottom "stream" layer as opposed to bottom "request" layer.

    source
    HTTP.MessageRequest.messagelayerFunction
    messagelayer(handler) -> handler

    Construct a Request object from method, url, headers, and body. Hard-coded as the first layer in the request pipeline.

    source
    HTTP.RedirectRequest.redirectlayerFunction
    redirectlayer(handler) -> handler

    Redirects the request in the case of 3xx response status.

    source
    HTTP.HeadersRequest.headerslayerFunction
    headerslayer(handler) -> handler

    Sets default expected headers.

    source
    HTTP.CookieRequest.cookielayerFunction
    cookielayer(handler) -> handler

    Check for host-appropriate cookies to include in the outgoing request from the cookiejar keyword argument (by default, a global cookiejar is used). Store "Set-Cookie" cookies from the response headers.

    source
    HTTP.TimeoutRequest.timeoutlayerFunction
    timeoutlayer(handler) -> handler

    Close the HTTP.Stream if no data has been received for readtimeout seconds.

    source
    HTTP.ExceptionRequest.exceptionlayerFunction
    exceptionlayer(handler) -> handler

    Throw a StatusError if the request returns an error response status.

    source
    HTTP.RetryRequest.retrylayerFunction
    retrylayer(handler) -> handler

    Retry 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.

    By default, requests that have a retryable body, where the request wasn't written or is idempotent will be retried. If the request is made and a response is received with a status code of 403, 408, 409, 429, or 5xx, the request will be retried.

    retries controls the # of total retries that will be attempted.

    retry_check allows passing a custom retry check in the case where the default retry check wouldn't retry, if retry_check returns true, then the request will be retried anyway.

    source
    HTTP.ConnectionRequest.connectionlayerFunction
    connectionlayer(handler) -> handler

    Retrieve an IO connection from the Connections.

    Close the connection if the request throws an exception. Otherwise leave it open so that it can be reused.

    source
    HTTP.StreamRequest.streamlayerFunction
    streamlayer(stream) -> HTTP.Response

    Create 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.

    source

    Raw Request Connection

    HTTP.openrawFunction
    HTTP.openraw(method, url, [, headers])::Tuple{Connection, Response}

    Open a raw socket that is unmanaged by HTTP.jl. Useful for doing HTTP upgrades to other protocols. Any bytes of the body read from the socket when reading headers, is returned as excess bytes in the last tuple argument.

    Example of a WebSocket upgrade:

    headers = Dict(
         "Upgrade" => "websocket",
         "Connection" => "Upgrade",
         "Sec-WebSocket-Key" => "dGhlIHNhbXBsZSBub25jZQ==",
    @@ -226,4 +226,4 @@
     
     # Write a WebSocket frame
     frame = UInt8[0x81, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58]
    -write(socket, frame)
    source
    HTTP.Connections.ConnectionType
    Connection

    A Sockets.TCPSocket, MbedTLS.SSLContext or OpenSSL.SSLStream connection to a HTTP host and port.

    Fields:

    • host::String
    • port::String, exactly as specified in the URI (i.e. may be empty).
    • idle_timeout, No. of seconds to maintain connection after last request/response.
    • require_ssl_verification, whether ssl verification is required for an ssl connection
    • keepalive, whether the tcp socket should have keepalive enabled
    • peerip, remote IP adress (used for debug/log messages).
    • peerport, remote TCP port number (used for debug/log messages).
    • localport, local TCP port number (used for debug messages).
    • io::T, the Sockets.TCPSocket, MbedTLS.SSLContext or OpenSSL.SSLStream.
    • clientconnection::Bool, whether the Connection was created from client code (as opposed to server code)
    • buffer::IOBuffer, left over bytes read from the connection after the end of a response header (or chunksize). These bytes are usually part of the response body.
    • timestamp, time data was last received.
    • readable, whether the Connection object is readable
    • writable, whether the Connection object is writable
    source

    Parser Interface

    HTTP.Parsers.find_end_of_headerFunction
    find_end_of_header(bytes) -> length or 0

    Find length of header delimited by \r\n\r\n or \n\n.

    source
    HTTP.Parsers.find_end_of_chunk_sizeFunction

    Find \n after chunk size in bytes.

    source
    HTTP.Parsers.find_end_of_trailerFunction
    find_end_of_trailer(bytes) -> length or 0

    Find length of trailer delimited by \r\n\r\n (or starting with \r\n). RFC7230 4.1

    source
    HTTP.Parsers.parse_status_line!Function

    Parse HTTP response-line bytes and set the status and version fields of response. Return a SubString containing the header-field lines.

    source
    HTTP.Parsers.parse_request_line!Function

    Parse HTTP request-line bytes and set the method, target and version fields of request. Return a SubString containing the header-field lines.

    source
    HTTP.Parsers.parse_header_fieldFunction

    Parse HTTP header-field. Return Pair(field-name => field-value) and a SubString containing the remaining header-field lines.

    source
    HTTP.Parsers.parse_chunk_sizeFunction

    Parse HTTP chunk-size. Return number of bytes of chunk-data.

    chunk-size = 1*HEXDIG

    RFC7230 4.1

    source
    +write(socket, frame)source
    HTTP.Connections.ConnectionType
    Connection

    A Sockets.TCPSocket, MbedTLS.SSLContext or OpenSSL.SSLStream connection to a HTTP host and port.

    Fields:

    • host::String
    • port::String, exactly as specified in the URI (i.e. may be empty).
    • idle_timeout, No. of seconds to maintain connection after last request/response.
    • require_ssl_verification, whether ssl verification is required for an ssl connection
    • keepalive, whether the tcp socket should have keepalive enabled
    • peerip, remote IP adress (used for debug/log messages).
    • peerport, remote TCP port number (used for debug/log messages).
    • localport, local TCP port number (used for debug messages).
    • io::T, the Sockets.TCPSocket, MbedTLS.SSLContext or OpenSSL.SSLStream.
    • clientconnection::Bool, whether the Connection was created from client code (as opposed to server code)
    • buffer::IOBuffer, left over bytes read from the connection after the end of a response header (or chunksize). These bytes are usually part of the response body.
    • timestamp, time data was last received.
    • readable, whether the Connection object is readable
    • writable, whether the Connection object is writable
    source

    Parser Interface

    HTTP.Parsers.find_end_of_headerFunction
    find_end_of_header(bytes) -> length or 0

    Find length of header delimited by \r\n\r\n or \n\n.

    source
    HTTP.Parsers.find_end_of_chunk_sizeFunction

    Find \n after chunk size in bytes.

    source
    HTTP.Parsers.find_end_of_trailerFunction
    find_end_of_trailer(bytes) -> length or 0

    Find length of trailer delimited by \r\n\r\n (or starting with \r\n). RFC7230 4.1

    source
    HTTP.Parsers.parse_status_line!Function

    Parse HTTP response-line bytes and set the status and version fields of response. Return a SubString containing the header-field lines.

    source
    HTTP.Parsers.parse_request_line!Function

    Parse HTTP request-line bytes and set the method, target and version fields of request. Return a SubString containing the header-field lines.

    source
    HTTP.Parsers.parse_header_fieldFunction

    Parse HTTP header-field. Return Pair(field-name => field-value) and a SubString containing the remaining header-field lines.

    source
    HTTP.Parsers.parse_chunk_sizeFunction

    Parse HTTP chunk-size. Return number of bytes of chunk-data.

    chunk-size = 1*HEXDIG

    RFC7230 4.1

    source
    diff --git a/dev/search/index.html b/dev/search/index.html index b807c64d..b5f0820b 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · HTTP.jl

    Loading search...

      +Search · HTTP.jl

      Loading search...

        diff --git a/dev/server/index.html b/dev/server/index.html index def30d11..949ae51f 100644 --- a/dev/server/index.html +++ b/dev/server/index.html @@ -1,4 +1,4 @@ Server · HTTP.jl

        Server

        For server-side functionality, HTTP.jl provides a robust framework for core HTTP and websocket serving, flexible handler and middleware interfaces, and low-level access for unique workflows. The core server listening code is in the /src/Servers.jl file, while the handler, middleware, router, and higher level HTTP.serve function are defined in the /src/Handlers.jl file.

        HTTP.serve

        HTTP.serve/HTTP.serve! are the primary entrypoints for HTTP server functionality, while HTTP.listen/HTTP.listen! are considered the lower-level core server loop methods that only operate directly with HTTP.Streams. HTTP.serve is also built directly integrated with the Handler and Middleware interfaces and provides easy flexibility by doing so. The signature is:

        HTTP.serve(f, host, port; kw...)
         HTTP.serve!(f, host, port; kw...) -> HTTP.Server

        Where f is a Handler function, typically of the form f(::Request) -> Response, but can also operate directly on an HTTP.Stream of the form f(::Stream) -> Nothing while also passing stream=true to the keyword arguments. The host argument should be a String, or IPAddr, created like ip"0.0.0.0". port should be a valid port number as an Integer. HTTP.serve is the blocking server method, whereas HTTP.serve! is non-blocking and returns the listening HTTP.Server object that can be close(server)ed manually.

        Supported keyword arguments include:

        • sslconfig=nothing, Provide an MbedTLS.SSLConfig object to handle ssl connections. Pass sslconfig=MbedTLS.SSLConfig(false) to disable ssl verification (useful for testing). Construct a custom SSLConfig object with MbedTLS.SSLConfig(certfile, keyfile).
        • tcpisvalid = tcp->true, function f(::TCPSocket)::Bool to check if accepted connections are valid before processing requests. e.g. to do source IP filtering.
        • readtimeout::Int=0, close the connection if no data is received for this many seconds. Use readtimeout = 0 to disable.
        • reuseaddr::Bool=false, allow multiple servers to listen on the same port. Not supported on some OS platforms. Can check HTTP.Servers.supportsreuseaddr().
        • server::Base.IOServer=nothing, provide an IOServer object to listen on; allows manually closing or configuring the server socket.
        • verbose::Union{Int,Bool}=false, log connection information to stdout. Use -1 to also silence the server start and stop logs.
        • access_log::Function, function for formatting access log messages. The function should accept two arguments, io::IO to which the messages should be written, and http::HTTP.Stream which can be used to query information from. See also @logfmt_str.
        • on_shutdown::Union{Function, Vector{<:Function}, Nothing}=nothing, one or more functions to be run if the server is closed (for example by an InterruptException). Note, shutdown function(s) will not run if an IOServer object is supplied to the server keyword argument and closed by close(server).

        HTTP.Handler

        Abstract type for the handler interface that exists for documentation purposes. A Handler is any function of the form f(req::HTTP.Request) -> HTTP.Response. There is no requirement to subtype Handler and users should not rely on or dispatch on Handler. A Handler function f can be passed to HTTP.serve wherein a server will pass each incoming request to f to be handled and a response to be returned. Handler functions are also the inputs to Middleware functions which are functions of the form f(::Handler) -> Handler, i.e. they take a Handler function as input, and return a "modified" or enhanced Handler function.

        For advanced cases, a Handler function can also be of the form f(stream::HTTP.Stream) -> Nothing. In this case, the server would be run like HTTP.serve(f, ...; stream=true). For this use-case, the handler function reads the request and writes the response to the stream directly. Note that any middleware used with a stream handler also needs to be of the form f(stream_handler) -> stream_handler, i.e. it needs to accept a stream Handler function and return a stream Handler function.

        HTTP.Middleware

        Abstract type for the middleware interface that exists for documentation purposes. A Middleware is any function of the form f(::Handler) -> Handler (ref: Handler). There is no requirement to subtype Middleware and users should not rely on or dispatch on the Middleware type. While HTTP.serve(f, ...) requires a handler function f to be passed, middleware can be "stacked" to create a chain of functions that are called in sequence, like HTTP.serve(base_handler |> cookie_middleware |> auth_middlware, ...), where the base_handler Handler function is passed to cookie_middleware, which takes the handler and returns a "modified" handler (that parses and stores cookies). This "modified" handler is then an input to the auth_middlware, which further enhances/modifies the handler.

        HTTP.Router

        Object part of the Handler framework for routing requests based on path matching registered routes.

        r = HTTP.Router(_404, _405)

        Define a router object that maps incoming requests by path to registered routes and associated handlers. Paths can be registered using HTTP.register!. The router object itself is a "request handler" that can be called like:

        r = HTTP.Router()
        -resp = r(request)

        Which will inspect the request, find the matching, registered handler from the url, and pass the request on to be handled further.

        See HTTP.register! for additional information on registering handlers based on routes.

        If a request doesn't have a matching, registered handler, the _404 handler is called which, by default, returns a HTTP.Response(404). If a route matches the path, but not the method/verb (e.g. there's a registered route for "GET /api", but the request is "POST /api"), then the _405 handler is called, which by default returns HTTP.Response(405) (method not allowed).

        HTTP.listen

        Lower-level core server functionality that only operates on HTTP.Stream. Provides a level of separation from HTTP.serve and the Handler framework. Supports all the same arguments and keyword arguments as HTTP.serve, but the handler function f must take a single HTTP.Stream as argument. HTTP.listen! is the non-blocking counterpart to HTTP.listen (like HTTP.serve! is to HTTP.serve).

        Log formatting

        Nginx-style log formatting is supported via the HTTP.@logfmt_str macro and can be passed via the access_log keyword argument for HTTP.listen or HTTP.serve.

        Serving on the interactive thead pool

        Beginning in Julia 1.9, the main server loop is spawned on the interactive threadpool by default. If users do a Threads.@spawn from a handler, those threaded tasks should run elsewhere and not in the interactive threadpool, keeping the web server responsive.

        Note that just having a reserved interactive thread doesn’t guarantee CPU cycles, so users need to properly configure their running Julia session appropriately (i.e. ensuring non-interactive threads available to run tasks, etc).

        +resp = r(request)

        Which will inspect the request, find the matching, registered handler from the url, and pass the request on to be handled further.

        See HTTP.register! for additional information on registering handlers based on routes.

        If a request doesn't have a matching, registered handler, the _404 handler is called which, by default, returns a HTTP.Response(404). If a route matches the path, but not the method/verb (e.g. there's a registered route for "GET /api", but the request is "POST /api"), then the _405 handler is called, which by default returns HTTP.Response(405) (method not allowed).

        HTTP.listen

        Lower-level core server functionality that only operates on HTTP.Stream. Provides a level of separation from HTTP.serve and the Handler framework. Supports all the same arguments and keyword arguments as HTTP.serve, but the handler function f must take a single HTTP.Stream as argument. HTTP.listen! is the non-blocking counterpart to HTTP.listen (like HTTP.serve! is to HTTP.serve).

        Log formatting

        Nginx-style log formatting is supported via the HTTP.@logfmt_str macro and can be passed via the access_log keyword argument for HTTP.listen or HTTP.serve.

        Serving on the interactive thead pool

        Beginning in Julia 1.9, the main server loop is spawned on the interactive threadpool by default. If users do a Threads.@spawn from a handler, those threaded tasks should run elsewhere and not in the interactive threadpool, keeping the web server responsive.

        Note that just having a reserved interactive thread doesn’t guarantee CPU cycles, so users need to properly configure their running Julia session appropriately (i.e. ensuring non-interactive threads available to run tasks, etc).

        diff --git a/dev/websockets/index.html b/dev/websockets/index.html index 614cd4c1..4a18d3cb 100644 --- a/dev/websockets/index.html +++ b/dev/websockets/index.html @@ -30,4 +30,4 @@ # simple echo server send(ws, msg) end -end +end