Server API

    Server Lifecycle and Request Handlers

    HTTP.Server — Type
    Server(; network="tcp", address="127.0.0.1:0", handler, stream=false, ...)

    An HTTP server, returned by serve! and listen!. port returns its port. close(server) stops accepting connections and waits for the requests in progress to finish, forceclose closes every connection at once, and wait(server) returns when the server stops accepting connections.

    Server tasks, including handlers, run on Julia's :interactive thread pool. Start Julia with at least one interactive thread, such as --threads=4,1, so that tasks on the default pool that never yield cannot stall the server. Without an interactive thread, these tasks run on the default pool.

    On a plain TCP listener, a connection that starts with the HTTP/2 connection preface is served as cleartext HTTP/2; allow_h2c = false turns that off. A TLS listener offers HTTP/2 when its TLS.Config lists "h2" in alpn_protocols.

    The constructor takes the keywords of serve! with timeouts in nanoseconds only; stream = true marks handler as a stream handler. Start the server with listen!(server).

    source
    HTTP.Stream — Type
    Stream

    One HTTP exchange, read and written as an IO. A server passes one to each stream handler, and the client's open returns one.

    On a server stream, startread returns the request, reading the stream reads the request body, and setstatus, setheader, and writes build the response. On a client stream, writes send the request body, and after startread reading the stream reads the response body.

    source
    HTTP.listen! — Function
    listen!(server) -> Server

    Start server, made with the Server constructor, in the background and return it.

    source
    listen!(handler, host="127.0.0.1", port=8080; kwargs...) -> Server
    listen!(handler, port; kwargs...) -> Server
    listen!(handler, listener; kwargs...) -> Server

    Start an HTTP server in the background and return its Server. handler(stream::Stream) reads each request from the Stream and writes the response to it. listen! takes the keywords of serve! except max_body_bytes, since a stream handler reads the body itself.

    source
    HTTP.listen — Function
    listen(handler, args...; kwargs...) -> Server

    Like listen!, but block until the server is closed.

    source
    HTTP.serve! — Function
    serve!(handler, host="127.0.0.1", port=8080; kwargs...) -> Server
    serve!(handler, port; kwargs...) -> Server
    serve!(handler, listener; kwargs...) -> Server

    Start an HTTP server in the background and return its Server. handler(req::Request) returns the Response for each request; a handler that throws sends 500 Internal Server Error. Port 0 picks a free port. listener is a listener from Reseau.TCP.listen or Reseau.TLS.listen; pass a TLS listener to serve HTTPS. Server tasks run on Julia's :interactive thread pool; see Server.

    Keywords

    • read_header_timeout, read_timeout, write_timeout, idle_timeout: timeouts in seconds, all off by default. Each also has a nanosecond form ending in _ns, such as read_timeout_ns. read_header_timeout limits reading a request's head, read_timeout then limits reading its body, and idle_timeout limits the wait for the next request on a kept-alive connection. The header and idle timeouts fall back to read_timeout when they are 0. A request whose head or body times out gets 408 Request Timeout.
    • max_body_bytes = 64 MiB: the largest request body serve! reads into memory; a larger one gets 413 Content Too Large. 0 means no limit.
    • max_header_bytes = 1 MiB: the largest request head.
    • http2_settings: the HTTP2Settings for HTTP/2 connections.
    • max_concurrent_streams = 100: the most HTTP/2 streams a connection may have open; 0 means no limit.
    • allow_h2c = true: serve cleartext HTTP/2 to clients that send the HTTP/2 connection preface.
    • listenany = false: true ignores port and listens on a free port.
    • reuseaddr = true, backlog = 128: options for the listener that serve! creates; they do not apply to a listener argument.

    Extended help

    readtimeout is a deprecated name for read_timeout.

    source
    HTTP.serve — Function
    serve(handler, args...; kwargs...) -> Server

    Like serve!, but block until the server is closed.

    source
    HTTP.streamhandler — Function
    streamhandler(request_handler) -> stream handler

    Return a stream handler, for listen!, that reads each request into memory, calls request_handler(req), and writes the response it returns. A response body that is not in memory, such as a file from fileserver, is streamed.

    source
    HTTP.servefile — Function
    servefile(request, path; index_file="index.html", redirect_canonical=true,
              etag=nothing, cache_control=nothing) -> Response

    Build the response to request for the file or directory at path, with the conditional and range handling of servecontent. A directory is served by its index_file. With redirect_canonical, a request for a directory without a trailing slash, a file with one, or the index file itself is redirected to the canonical path. Methods other than GET and HEAD get 405, a missing file 404, and an unsafe request path, such as one with .., 400.

    etag may be :weak_stat, for an ETag made from the file's size and modification time, a function (path, stat) -> String, or a string; by default no ETag is sent. cache_control sets the Cache-Control header.

    source
    HTTP.fileserver — Function
    fileserver(root; index_file="index.html", redirect_canonical=true, etag=nothing,
               cache_control=nothing, spa_fallback=nothing) -> handler

    Return a request handler that serves the files under the directory root with servefile, which describes the keywords. With spa_fallback, a missing path whose last segment does not look like a file name, such as /users/42, gets the file spa_fallback from root, as a single-page app needs; a missing path such as /app.js still gets 404. Throws ArgumentError when root is not an existing directory.

    source
    HTTP.servecontent — Function
    servecontent(request, source; name="", size=nothing, modtime=nothing,
                 content_type=nothing, etag=nothing, headers=Headers(),
                 allow_ranges=true) -> Response

    Build the response to request for source, an AbstractVector{UInt8} or a seekable IO; pass codeunits(str) for a string. Conditional requests (If-None-Match, If-Modified-Since, If-Match, If-Unmodified-Since) get 304 or 412 when they apply. A GET or HEAD request for one byte range gets 206 Partial Content, and an unsatisfiable range gets 416. Any other Range, such as several ranges or another unit, is ignored and the whole content is sent.

    • name: a file name whose extension sets the Content-Type when content_type is not given. Without either, the type is detected from the content.
    • size: the length of source, needed when it cannot be found by seeking.
    • modtime: a DateTime sent as Last-Modified.
    • etag: the ETag value.
    • headers: more response headers.
    • allow_ranges: answer Range requests.
    source
    HTTP.forceclose — Function
    forceclose(server)

    Stop server at once: stop accepting connections and close every open connection, including those with requests in progress.

    source
    HTTP.port — Function
    port(server) -> Int

    Return the port server listens on, or the configured port before it starts listening.

    source
    HTTP.startread — Function
    startread(stream)

    Start reading from stream and return the message head.

    On a client stream from open, this finishes sending the request and returns the Response with its status and headers. On a server stream, it returns the Request. Either way, read the body from stream itself, with read(stream) or readbytes!(stream, buf).

    source
    HTTP.startwrite — Function
    startwrite(stream) -> Response

    Start the response of a server-side Stream and return the response metadata. write(stream, data) starts it too.

    Chunked and HTTP/2 responses send their head here. A fixed-length (Content-Length) HTTP/1 response holds its head and body so that a small response goes out in one write. Without an explicit startwrite, the whole body is held until closewrite, so the server can still send an error response if the handler throws or writes the wrong number of bytes. After startwrite, a body that grows past 4 KiB is sent as it is written, and a later failure closes the connection instead.

    source
    HTTP.setstatus — Function
    setstatus(stream, status) -> nothing

    Set the status of the response on a server stream. Call it before the first write; after that it throws ArgumentError.

    source
    HTTP.addtrailer — Function
    addtrailer(stream, key => value) -> nothing
    addtrailer(stream, headers) -> nothing

    Add trailers to the response on a server stream. They are sent after the body, so add them before closewrite(stream). Only chunked HTTP/1 and HTTP/2 responses carry trailers; an HTTP/1 response with a Content-Length drops them.

    source
    HTTP.closeread — Function
    closeread(stream) -> Response

    Stop reading from stream and return its Response: the response received on a client stream, or the response being written on a server stream. Body bytes that were not read are discarded, and the connection is then closed instead of reused.

    source
    HTTP.peeraddr — Function
    peeraddr(stream::Stream) -> Union{Nothing, Reseau.TCP.SocketAddr}

    Return the client's address for a server stream, or nothing when it is not known. string(addr) gives "ip:port"; addr.ip is a tuple of the address bytes and addr.port is the port. Works over HTTP/1 and HTTP/2, with or without TLS. Throws ArgumentError for a client stream.

    source

    Routing and Middleware

    The router and middleware live in HTTP.Handlers. Except for handlertimeout and logging_middleware, the names below are also available from HTTP directly, as in HTTP.Router and HTTP.register!.

    HTTP.Handlers.Handler — Type
    Handler

    The name of the handler interface. Nothing subtypes or dispatches on it.

    A handler is a function f(req::HTTP.Request) -> HTTP.Response, run with serve!. A stream handler is a function f(stream::HTTP.Stream), run with listen!. Middleware used with stream handlers must take and return stream handlers.

    source
    HTTP.Handlers.Middleware — Type
    Middleware

    The name of the middleware interface. Nothing subtypes or dispatches on it. Middleware is a function that takes a Handler and returns a new one.

    source
    HTTP.Handlers.Router — Type
    HTTP.Router([_404], [_405], [middleware])

    A handler that calls the handler register!ed for the request's method and path. _404 handles a path with no route, and _405 a path whose routes do not accept the method; by default they return empty 404 and 405 responses. middleware, if given, wraps each handler as it is registered. A router works with request handlers (serve!) and with stream handlers (listen!).

    A route path is made of segments:

    • exact segments, such as /users
    • variables, such as /users/{id}
    • variables with a regular expression, such as /files/{name:\w+}
    • *, which matches any one segment
    • ** at the end, which matches the rest of the path

    A handler reads the matched route with getroute and its variables with getparams and getparam.

    source
    HTTP.Handlers.Node — Type
    Node

    Internal trie node used by Router to store exact, wildcard, and parameterized path segments.

    source
    HTTP.Handlers.register! — Function
    register!(router, method, path, handler) -> Nothing
    register!(router, path, handler) -> Nothing
    register!(handler, router, method, path) -> Nothing
    register!(handler, router, path) -> Nothing

    Add a route to router: requests with method and a path matching path go to handler. Without method, the route accepts every method. See Router for the path syntax.

    The handler-first forms allow do blocks:

    HTTP.register!(router, "GET", "/users/{id}") do req
        return HTTP.Response(200; body = HTTP.getparam(req, "id"))
    end
    source
    HTTP.Handlers.getroute — Function
    HTTP.getroute(req) -> Union{Nothing, String}

    Return the registered path, such as "/users/{id}", of the route that matched req, or nothing.

    source
    HTTP.Handlers.getparams — Function
    HTTP.getparams(req) -> Union{Nothing, Dict{String, String}}

    Return the path variables of the route that matched req, or nothing when no route matched or it has no variables.

    source
    HTTP.Handlers.getparam — Function
    HTTP.getparam(req, name, default=nothing)

    Return the path variable name of the route that matched req, or default.

    source
    HTTP.Handlers.handlertimeout — Function
    handlertimeout(timeout_s; status=503, body="handler timed out", content_type="text/plain; charset=utf-8")
        -> middleware

    Return middleware that answers with status, body, and content_type when a request handler takes longer than timeout_s seconds. The handler runs with a child RequestContext whose deadline is the earlier of the timeout and the request's own deadline. At the timeout that context is canceled, but the handler keeps running until it returns or checks the context. Only request handlers are supported.

    source
    HTTP.Handlers.logging_middleware — Function
    logging_middleware(handler; logger=nothing, level=Logging.Info) -> handler

    Wrap handler so that each request it handles logs one record, an access log.

    The message reads like GET /users/1 200 0.412ms. The record has the request method and target, the response status, the handler's time in elapsed_ms, and the response body length in bytes when it is known without reading the body (nothing otherwise). Records are in the :access log group and logged at level, to logger when given and to the current logger otherwise. When the handler throws, the record is logged at Logging.Error with the exception and the status the server sends, and the exception is rethrown.

    It wraps request handlers and stream handlers. Stream handler records also have the client's peer address from peeraddr. For a stream handler, the middleware finishes the response (closewrite) before logging, so a response that fails then, such as a body shorter than its Content-Length, is logged as that failure.

    server = HTTP.serve!(HTTP.Handlers.logging_middleware(router), "127.0.0.1", 8080)
    source

    Server-Sent Events

    HTTP.SSEEvent — Type
    SSEEvent(data; event=nothing, id=nothing, retry=nothing)

    One server-sent event: what a server writes to an SSEStream, and what the client passes to an sse_callback.

    Fields:

    • data: the event data; several data: lines are joined with "\n"
    • event: the event type, or nothing
    • id: the last event ID received, or nothing
    • retry: the last reconnection time received, in milliseconds, or nothing
    • fields: the event's fields by name
    source
    HTTP.SSEStream — Type
    SSEStream(; max_len=16*1024*1024)

    The body of a server-sent event response from sse_stream. write(stream, event::SSEEvent) sends an event and close(stream) ends the response. max_len limits the size of one event, in bytes.

    source
    HTTP.sse_stream — Function
    sse_stream(status=200; max_len=16*1024*1024, kwargs...) -> Response
    sse_stream(f, status; max_len=16*1024*1024, kwargs...) -> Response
    sse_stream(response[, f]) -> SSEStream

    Build a server-sent event response for a serve! handler to return. It has an SSEStream body and the headers Content-Type: text/event-stream and Cache-Control: no-cache. The other keywords are those of Response.

    With a function f, usually a do block as in sse_stream(200) do stream, f(stream) runs on its own task and writes SSEEvents to the stream; the response ends when f returns. Without f, write events to response.body and close it to end the response.

    The response forms take a Response whose body is already an SSEStream, set its headers, start f if given, and return the stream.

    source