Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

http.server

import http.server

http lifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelled http.server.* needs import http.server.

HttpServer: the server end of the module.

It accepts connections, speaks HTTP/1.1 or HTTP/2 as negotiated, runs the middleware chain around the matched handler, and serves static files when configured to. It can run single-threaded or hand connections to a pool of workers.

Classes

HttpServer

class http.HttpServer

An HTTP/1.1 server.

import http

var server = http.server(3000)

server.get('/', @(request, response) {
  response.html('<h1>Hello</h1>')
})

server.get('/users/:id', @(request, response) {
  response.json({ id: request.param('id') })
})

server.listen()

The pieces a server put in front of an application usually provides are here rather than assumed: TLS with use_tls(), static files with serve_files(), response compression, byte ranges, conditional requests, keep-alive with bounded reuse, and limits on every part of a request that a peer controls the size of.

  • printable — has a @to_string(), so echo and print() show something useful

Fields

FieldTypeDescription
hoststringThe address to bind to.
portnumberThe port to bind to.
read_timeoutnumberHow long to wait for a request to arrive, in milliseconds.
write_timeoutnumberHow long a write may block before the client is treated as gone.
keep_alive_timeoutnumberHow long an idle keep-alive connection is held open, in milliseconds.
max_keep_alive_requestsnumberThe most requests one connection may serve before it is closed.
max_line_sizenumberThe longest request line, in bytes.
max_header_sizenumberThe largest header section, in bytes.
max_header_countnumberThe most header fields one request may carry.
header_timeoutnumberHow long the whole request head may take to arrive, in seconds, once its first byte has.
max_body_sizenumberThe largest request body accepted, in bytes.
server_namestringThe value sent in the Server header.
compressionboolWhether to compress responses whose media type benefits from it and whose client asked for it.
compression_min_sizenumberThe smallest response worth compressing, in bytes.
compression_quality?numberHow hard to compress, on the scale of whichever coding content negotiation lands on - brotli 0-11,…
trust_proxyboolWhether HttpRequest.client_ip() should consult forwarding headers.
trusted_proxieslistThe proxy addresses to skip when walking a forwarding chain.
socket?TcpStreamThe listening socket, once listen() has bound it.
http2boolWhether to speak HTTP/2 when a client asks for it - through ALPN on a TLS connection, or through the…

Constructor

http.HttpServer(port: ?number, host: ?string)

Parameters

  • port (?number) — defaults to 8000
  • host (?string) — defaults to '127.0.0.1'

HttpServer.handle()

http.HttpServer.handle(method: string, pattern: string, handler, name: ?string)

Registers handler for method requests matching pattern.

See Router for what a pattern may contain: literal segments, :name parameters, and a trailing catch-all.

Parameters

  • method (string)
  • pattern (string)
  • handler (function(2)) — called with the request and response
  • name (?string) — a route name, for url_for()

Returns — HttpServer: this same instance, for chaining

HttpServer.get()

http.HttpServer.get(pattern: string, handler, name: ?string)

Registers a GET handler. A HEAD request for the same path is answered by it too, with the body dropped.

Parameters

  • pattern (string)
  • handler (function(2))
  • name (?string)

Returns — HttpServer: this same instance, for chaining

HttpServer.post()

http.HttpServer.post(pattern: string, handler, name: ?string)

Registers a POST handler.

Parameters

  • pattern (string)
  • handler (function(2))
  • name (?string)

Returns — HttpServer: this same instance, for chaining

HttpServer.put()

http.HttpServer.put(pattern: string, handler, name: ?string)

Registers a PUT handler.

Parameters

  • pattern (string)
  • handler (function(2))
  • name (?string)

Returns — HttpServer: this same instance, for chaining

HttpServer.patch()

http.HttpServer.patch(pattern: string, handler, name: ?string)

Registers a PATCH handler.

Parameters

  • pattern (string)
  • handler (function(2))
  • name (?string)

Returns — HttpServer: this same instance, for chaining

HttpServer.delete()

http.HttpServer.delete(pattern: string, handler, name: ?string)

Registers a DELETE handler.

Parameters

  • pattern (string)
  • handler (function(2))
  • name (?string)

Returns — HttpServer: this same instance, for chaining

HttpServer.options()

http.HttpServer.options(pattern: string, handler, name: ?string)

Registers an OPTIONS handler, replacing the automatic one for this path.

Parameters

  • pattern (string)
  • handler (function(2))
  • name (?string)

Returns — HttpServer: this same instance, for chaining

HttpServer.head()

http.HttpServer.head(pattern: string, handler, name: ?string)

Registers a HEAD handler, replacing the automatic GET fallback for this path.

Parameters

  • pattern (string)
  • handler (function(2))
  • name (?string)

Returns — HttpServer: this same instance, for chaining

HttpServer.any()

http.HttpServer.any(pattern: string, handler)

Registers one handler for every method a route can carry.

Parameters

  • pattern (string)
  • handler (function(2))

Returns — HttpServer: this same instance, for chaining

HttpServer.use()

http.HttpServer.use(middleware)

Adds a middleware, called for every request before the route handler.

A middleware takes (request, response, next) and must call next() to let the rest of the chain run; not calling it is how a middleware short-circuits, which is exactly what an authentication or rate-limiting layer wants to do.

server.use(@(request, response, next) {
  var started = time()
  next()
  echo '${request.method} ${request.path} ${response.status} ' +
    '${(time() - started) * 1000}ms'
})

Middleware run in the order they were added, outermost first.

Parameters

  • middleware (function(3))

Returns — HttpServer: this same instance, for chaining

HttpServer.not_found()

http.HttpServer.not_found(handler)

Sets the handler called when no route matches. The default sends a plain 404, or a JSON one when the client asked for JSON.

Parameters

  • handler (function(2))

Returns — HttpServer: this same instance, for chaining

HttpServer.error_handler()

http.HttpServer.error_handler(handler)

Sets the handler called when a route handler raises.

It takes (request, response, error) and is responsible for producing the response. Without one, the server sends a bare 500 and reports the error through on_error() listeners - it never puts an exception message in a response body, since that is how internal paths and query fragments end up on a user’s screen.

Parameters

  • handler (function(3))

Returns — HttpServer: this same instance, for chaining

HttpServer.serve_files()

http.HttpServer.serve_files(prefix: string, directory: string, options: ?dict)

Serves the files under directory at URLs beginning with prefix.

server.serve_files('/static', './public', { cache_age: 86400 })

Parameters

  • prefix (string)
  • directory (string)
  • options (?dict) — passed through to StaticFiles - index_files, cache_age, etag, precompressed, allow_dotfiles, fallback

Returns — HttpServer: this same instance, for chaining

HttpServer.routes()

http.HttpServer.routes() -> Router

The router, for anything the convenience methods above do not cover - listing routes, or building a URL from a route name.

Returns Router

HttpServer.on_connect()

http.HttpServer.on_connect(listener)

Adds a listener called with the Connection each time a client connects.

Parameters

  • listener (function(1))

Returns — HttpServer: this same instance, for chaining

HttpServer.on_disconnect()

http.HttpServer.on_disconnect(listener)

Adds a listener called with the Connection when a client disconnects.

Parameters

  • listener (function(1))

Returns — HttpServer: this same instance, for chaining

HttpServer.on_receive()

http.HttpServer.on_receive(listener)

Adds a listener called with (request, response) after a request has been parsed and before it is routed.

Parameters

  • listener (function(2))

Returns — HttpServer: this same instance, for chaining

HttpServer.on_reply()

http.HttpServer.on_reply(listener)

Adds a listener called with (request, response) after a response has been sent. This is where an access log belongs.

Parameters

  • listener (function(2))

Returns — HttpServer: this same instance, for chaining

HttpServer.on_error()

http.HttpServer.on_error(listener)

Adds a listener called with (error, connection) whenever serving a connection fails.

Without at least one such listener, connection-level errors are swallowed: one client sending a malformed request must not take the server down with it.

Parameters

  • listener (function(2))

Returns — HttpServer: this same instance, for chaining

HttpServer.use_tls()

http.HttpServer.use_tls(cert_chain: string, private_key: string, options: ?dict)

Turns on TLS, using the given PEM-encoded certificate chain and private key.

cert_chain must be the server certificate followed by any intermediates - leaving the intermediates out is the single most common TLS misconfiguration, and it fails only for the clients that do not happen to have them cached.

Parameters

  • cert_chain (string) — PEM, leaf first
  • private_key (string) — PEM
  • options (?dict) — alpn (a list of protocol names), client_ca (PEM roots for mutual TLS), require_client_cert, min_version and max_version

Returns — HttpServer: this same instance, for chaining

Note: The certificate and key are parsed when the first handshake runs, not here, so a malformed or mismatched pair surfaces as a failed connection rather than as a failed call to this method.

HttpServer.load_certs()

http.HttpServer.load_certs(cert_path: string, key_path: ?string, options: ?dict)

Loads the certificate and key from files rather than strings.

Parameters

  • cert_path (string)
  • key_path (?string) — defaults to cert_path, for a combined PEM file
  • options (?dict) — as use_tls()

Returns — HttpServer: this same instance, for chaining

HttpServer.set_tls_config()

http.HttpServer.set_tls_config(config)

Uses a net.tls.TlsConfig built elsewhere, for anything use_tls() does not expose.

Parameters

  • config (TlsConfig)

Returns — HttpServer: this same instance, for chaining

HttpServer.is_secure()

http.HttpServer.is_secure() -> bool

Whether this server is configured to serve over TLS.

Returns bool

HttpServer.listen()

http.HttpServer.listen()

Binds the socket and serves connections until close() is called.

Connections are served one at a time on the calling thread. For a server that uses more than one core, see http.serve(), which runs this same request pipeline across a pool of isolates.

Raises HttpError if the socket cannot be bound

HttpServer.bind()

http.HttpServer.bind()

Binds and starts listening without accepting anything, so a caller can drive the accept loop itself.

The listener is left in non-blocking mode, since accept() and listen() here go through a net.Acceptor. A caller driving its own loop over socket directly gets nil from accept() whenever nothing is waiting.

Raises HttpError if the socket cannot be bound

HttpServer.accept()

http.HttpServer.accept() -> ?TcpStream

Accepts one connection, blocking until one arrives. Only valid after bind().

Returns nil if the server is stopped while this is waiting, since there is then nothing left to wait for.

Returns ?TcpStream

HttpServer.address()

http.HttpServer.address() -> ?SocketAddr

The address the server is listening on. After binding to port 0, this is how to discover the port that was actually chosen.

Returns ?SocketAddr

HttpServer.is_listening()

http.HttpServer.is_listening() -> bool

Whether the server is currently listening.

Returns bool

HttpServer.close()

http.HttpServer.close()

Stops the server and closes the listening socket. The accept loop reads the stopped flag on its next round and ends, within one net.Acceptor interval of this call.

HttpServer.serve_connection()

http.HttpServer.serve_connection(client)

Serves every request on one already-accepted client socket, then closes it.

This is the whole per-connection pipeline - TLS handshake, keep-alive loop, parsing, dispatch, response - and is public so that a caller running its own accept loop (or handing sockets to worker isolates) can reuse it exactly as listen() does.

Parameters

  • client (TcpStream)

HttpServer.accept_connection()

http.HttpServer.accept_connection(client)

Turns an accepted socket into a Connection, running the TLS handshake when one is configured and notifying on_connect() listeners.

Split out of serve_connection() so that a caller driving its own event loop can take a connection on without also committing to serving it to completion on the spot: see serve_next().

Parameters

  • client (TcpStream)

Returns — ?Connection: nil when the handshake failed, in which case the socket has already been closed and the failure reported to on_error() listeners

HttpServer.serve_next()

http.HttpServer.serve_next(connection, served: ?number)

Reads and answers exactly one request, and reports whether the connection may be used again.

This is the unit an event loop works in. _serve_requests() calls it in a loop for one connection at a time, which is what listen() does; a polled worker calls it once per connection that has actually become readable, which is what lets one thread hold many connections at once.

Parameters

  • connection (Connection)
  • served (?number) — how many requests this connection has already answered, so the keep-alive budget and the shorter idle read timeout apply from the second request onwards

Returns — bool: whether to keep the connection open

HttpServer.serve_http2()

http.HttpServer.serve_http2(connection)

Runs an HTTP/2 session on connection until the peer goes away.

Unlike HTTP/1.1, this owns the connection for its whole life: an HTTP/2 connection is already multiplexed internally, so the streams on it are interleaved even though the connection itself is not interleaved with any other.

Parameters

  • connection (Connection)

HttpServer.is_http2_connection()

http.HttpServer.is_http2_connection(connection) -> bool

Whether a connection that has just been taken on is going to speak HTTP/2. Reading this costs a peek at the first bytes on a cleartext connection, so it is asked once and the answer kept.

Parameters

  • connection (Connection)

Returns bool

HttpServer.report_error()

http.HttpServer.report_error(error, connection)

Hands error to this server’s on_error() listeners.

Public so that a caller running its own connection loop reports failures through the same listeners the built-in loops use, instead of inventing a second place errors can appear.

Parameters

  • error (Error)
  • connection (?Connection)

HttpServer.finish_connection()

http.HttpServer.finish_connection(connection)

Notifies on_disconnect() listeners and closes the connection.

Parameters

  • connection (Connection)

HttpServer.handle_request()

http.HttpServer.handle_request(request, response) -> HttpResponse

Runs one already-parsed request through the middleware chain, the router and the error handling, and returns the response.

This is the whole application-facing half of the server, with no reference to how the request arrived. That is what lets the same routes and middleware serve an HTTP/1.1 connection and an HTTP/2 stream without either protocol knowing about the other.

Parameters

  • request (HttpRequest)
  • response (?HttpResponse) — an existing response to fill in

Returns HttpResponse

HttpServer.to_string()

http.HttpServer.to_string()

2026, Richard Ore and Zuri contributors