Source code

API reference

Everything (http-server) exports, one entry each, and at the end everything (http-server testing) exports, for testing a handler. Types are written as Typed Racket writes them: Nat is an exact non-negative integer, [x] an optional argument, (U a b) either one.

(import (rnrs) (http-server))

Shared types:

Headers  = (Listof (Pair Bytevector Bytevector))
Body     = (U Bytevector #f Producer SizedBody)
Producer = (-> (U Bytevector Eof))
Answer   = (U Response BodyReader Awaiting)

The server

serve

serve : (Request -> (U Answer Switch)) [(String -> (U String #f))] -> Void

Starts the server with this handler and runs until it is sent SIGTERM or SIGINT and has drained. The optional second argument looks up settings in place of the process's environment. Raises &http-server-config-error for a malformed setting. See Handlers and Configuration.

&http-server-error, http-server-error?

An &error: the condition type of the server's own errors. http-server-error? : Any -> Boolean.

&http-server-config-error, http-server-config-error?

An &http-server-error: a setting is malformed, raised by serve before it listens. Its message names the variable. http-server-config-error? : Any -> Boolean.

Reading a request

Every string they give, header names included, has one character per byte of the request (Latin-1), and is made when called. The addresses and ports are the connection's, not the request's, each #f where the server can't say. See Handlers.

NameTypeGives
request?Any -> Booleanwhether it is a request
request-methodRequest -> Symbolthe method, such as GET
request-pathRequest -> Stringthe path, not decoded
request-queryRequest -> (U String #f)after the first ?, or #f
request-headerRequest String -> (U String #f)the first field of that name, any case
request-header-valuesRequest String -> (Listof String)every field of that name, in order
request-header-listRequest -> (Listof (Pair String String))every field, its name as sent, in order
request-hostRequest -> Stringthe host the request is for, "" if none
request-http-majorRequest -> Natthe first number of the version the request names, always 1
request-http-minorRequest -> Natits second: 2 for HTTP/1.2, which is answered as HTTP/1.1
request-has-body?Request -> Booleanwhether a body follows the head: chunked, or a Content-Length above 0
request-remote-addressRequest -> (U String #f)the address of the connection's other end, such as "192.0.2.7"
request-remote-portRequest -> (U Nat #f)that end's port
request-local-addressRequest -> (U String #f)the address the connection came in on
request-local-portRequest -> (U Nat #f)that end's port

Reading a body

See Bodies and streaming.

read-body

read-body : (Bytevector Nat Nat -> Any) (-> Response) -> BodyReader

A reader: the first procedure gets each piece of the body as bv[start, end) as it arrives; the second, called at the body's end, returns the response.

read-whole-body

read-whole-body : (Bytevector -> Response) [(U Nat #f)] -> BodyReader

A reader that collects the whole body, up to the cap (1 MiB by default), and calls the procedure with it. A bigger body gets 413.

Answering

make-response

make-response : Nat (U Bytevector #f) Headers Body -> Response

A response: status (200 to 599), reason phrase (#f for the usual one), headers, body. See Responses.

response?

Any -> Boolean.

sized-body

sized-body : Nat Producer -> SizedBody

A body of that many bytes, made by the producer as it is sent, with its Content-Length. See Bodies and streaming.

request-on-done!

request-on-done! : Request (Symbol -> Any) -> Void

Registers a procedure that the server calls once, just after the request's response is done, or once the request's code that waits has stopped. It gets written, client-closed or failed. Procedures run newest first; one registered after the response is done runs at once, in the caller. See Handlers.

Waiting

See Waiting. The waits below work only inside a thunk given to awaiting, or a reader or producer it answers with.

NameTypeDoes
awaiting(-> Answer) -> Awaitingan answer that runs the thunk where it may wait
await((Any -> Void) -> Any) -> Anygives register a resume, waits for it, returns what it was called with
sleep-msNat -> Voidwaits that many milliseconds
with-deadlineNat (-> (Values Any ...)) -> (Values Any ...)runs the thunk; its waits raise &deadline-passed after that many milliseconds
resolveString -> (Listof String)the host's addresses, as strings
next-body-piece[(U Nat #f)] -> (U Bytevector Eof)the body's next piece, or the eof object at its end; the first call's cap holds. Only in the awaiting thunk, before it answers
body-input-port[(U Nat #f)] -> BinaryInputPorta port whose reads pull the body, capped as given

Conditions, each an &error:

NameRaised whenCheck
&deadline-passeda with-deadline deadline passed during a waitdeadline-passed? : Any -> Boolean
&client-closedthe client closed or reset the connectionclient-closed? : Any -> Boolean
&resolve-errora name did not resolveresolve-error? : Any -> Boolean
&body-faileda body being pulled failed: past a cap, malformed, stalled, or with trailers past a header limitbody-failed? : Any -> Boolean

resolve-error-reason : ResolveError -> Symbol says why a lookup failed: EAI_NONAME and the resolver's other codes, or invalid-name.

body-failed-reason : BodyFailed -> Symbol says why a body failed, such as body-too-large, body-timeout or invalid-chunk-size, and body-failed-status : BodyFailed -> Nat is the status the server answers if the raise is let out.

Upgrades

See Upgrades.

switch-protocols

switch-protocols : Headers (Transport Bytevector -> Any) -> Switch

An answer that takes an HTTP/1.1 upgrade: the server writes 101 with these headers, then calls the procedure with the transport and the bytes it had already read past the request.

The transport

NameType
transport?Any -> Boolean
transport-write!Transport Bytevector [Nat Nat] [(U #f ((U #f Symbol) -> Any))] -> Any
transport-read-start!Transport (Bytevector Nat Nat -> Any) (Symbol -> Any) -> Any
transport-read-stop!Transport -> Any
transport-close!Transport -> Any
transport-abort!Transport -> Any
transport-deadline!Transport (U Nat #f) [(-> Any)] -> Any
transport-on-drain!Transport (-> Any) -> Any
transport-on-close!Transport (-> Any) -> Any

make-transport

make-transport : write read-start read-stop close deadline on-drain on-close [abort]
                 -> Transport

A transport of your own, for testing a taker without a server: each argument is the procedure the matching call above ends up in. Without abort, transport-abort! on it is refused.

Testing: (http-server testing)

A host that runs a handler for a scripted client, its waits included, with no socket and a clock the test moves. Each call that does something, a connect, a send, a close, a reset, an advance or an answer, runs all that follows from it before it returns. See Testing handlers.

(import (rnrs) (http-server) (http-server testing))

make-test-host

make-test-host : (Request -> (U Answer Switch)) [(String -> (U String #f))] -> TestHost

A host for the handler serve would get, its clock at 0 ms. The optional second argument gives the settings, as serve's does; without it every setting is its default. Raises &http-server-config-error for a malformed setting, as serve does before it listens. A CHEZ_HTTP_HOST that is not an IP address is not refused: only serve refuses it, as it listens.

The host

NameTypeDoes
test-host?Any -> Booleanwhether it is a host
test-host-connect!TestHost -> TestClienta new client, connected now
test-host-nowTestHost -> Natthe clock, in milliseconds
test-host-advance!TestHost Nat -> Voidmoves the clock on, firing each sleep, deadline and timeout as its time comes
test-host-lookupsTestHost -> (Listof String)the names resolve waits on, oldest first
test-host-answer!TestHost String (U (Listof String) Symbol) -> Voidanswers the oldest lookup of the name: its addresses, or why it fails, such as EAI_NONAME
test-host-logTestHost -> (Listof (Pair Symbol (Listof Any)))what the server logged, in order, each (what . details)
test-host-waitingTestHost -> (Listof TestClient)the clients whose handler still waits

The client

NameTypeDoes
test-client?Any -> Booleanwhether it is a client
test-client-send!TestClient Bytevector -> Voidsends the bytes, as they go on the wire
test-client-close!TestClient -> Voidcloses the client's side
test-client-reset!TestClient -> Voidresets the connection
test-client-responsesTestClient -> (Listof TestResponse)the responses it read, in order
test-client-receivedTestClient -> Bytevectorevery byte it read
test-client-connection-closed?TestClient -> Booleanwhether the server has ended the connection
test-client-waiting?TestClient -> Booleanwhether its handler still waits

A response read

NameTypeGives
test-response?Any -> Booleanwhether it is a response read
test-response-statusTestResponse -> Natthe status
test-response-reasonTestResponse -> Bytevectorthe reason phrase
test-response-headersTestResponse -> Headersevery field, in order
test-response-headerTestResponse String -> (U Bytevector #f)the first field of that name, any case, or #f
test-response-bodyTestResponse -> Bytevectorthe body, de-chunked
test-response-bytesTestResponse -> Bytevectorthe response as it was on the wire
test-response-complete?TestResponse -> Booleanwhether all of it has arrived