Liking cljdoc? Tell your friends :D

s-exp.enso

Ring adapter backed by a zero-dependency Java core: blocking I/O on virtual threads, one virtual thread per connection.

Ring adapter backed by a zero-dependency Java core: blocking I/O on virtual
threads, one virtual thread per connection.
raw docstring

flush!clj

(flush! w)

Emits any pending bytes as a chunk and forces them onto the wire.

Emits any pending bytes as a chunk and forces them onto the wire.
sourceraw docstring

portclj

(port server)

Actual listening port of server.

Actual listening port of `server`.
sourceraw docstring

run-serverclj

(run-server handler)
(run-server handler {:keys [error-handler async] :as opts})

Starts an HTTP server calling handler with Ring request maps. Returns the server, stop it with stop. Unknown options and invalid values throw ex-info naming the option.

handler is (fn [request] response), or with :async true a Ring asynchronous handler (fn [request respond raise]). It runs on a virtual thread per request (per connection on HTTP/1.1).

Response :body: nil, String, byte array, InputStream, File, a seq (each element str'd), (fn [ChunkedWriter]) streaming with write! / flush! (an enso extension), or anything satisfying ring.core.protocols/StreamableResponseBody when on the classpath. :status defaults to 200 when absent.

WebSocket (HTTP/1.1): answer an upgrade request with {:ring.websocket/listener l}, l a map of :on-open :on-message :on-ping :on-pong :on-error :on-close fns or a ring.websocket.protocols/Listener. See doc/handlers.md.

Durations are milliseconds, 0 disables a timeout; sizes are bytes.

Network:

  • :port (8080) - listen port, 0 picks an ephemeral port

  • :host ("0.0.0.0") - bind address

  • :backlog (1024) - accept queue length

  • :max-connections (10000) - open connections server-wide, TCP and QUIC together, 0 = unlimited. TCP connections over the limit are closed at accept, QUIC Initials dropped.

  • :max-connections-per-ip (0) - open connections per client address, 0 = unlimited. Leave off behind a proxy or NAT, where clients share an address.

    Timeouts:

  • :handshake-timeout (10000) - ms to complete the TLS handshake (plus the HTTP/2 preface and first SETTINGS, or the QUIC handshake), wall clock. It and :idle-timeout must not both be 0, which would leave a half-open connection with no bound.

  • :header-timeout (10000) - ms to receive a complete request head from its first byte, wall clock (slowloris protection). Answered with 408.

  • :read-timeout (30000) - longest ms without progress reading a request body; the read fails (408 unless the handler catches it). Also bounds head reads when :header-timeout is 0, and is the wall-clock time a WebSocket message may take from its first frame to its last (CLOSE 1008), less time the server held it back for :max-buffered-bytes.

  • :min-data-rate-bytes (240) - least request body bytes per second while a handler waits for them, once :min-data-rate-grace of waiting is spent (Kestrel's default), 0 = off. Below it the read fails (408, protocol error "min-data-rate"): a body trickled just inside :read-timeout can't hold a request forever. Time the handler isn't reading doesn't count.

  • :min-data-rate-grace (5000) - ms of waiting for request body bytes allowed before :min-data-rate-bytes applies.

  • :write-timeout (30000) - longest ms without write progress (a peer that stopped reading); the connection is force-closed.

  • :idle-timeout (75000) - ms a connection may sit with no request in progress: HTTP/1.1 between requests (and before the first), HTTP/2 and HTTP/3 with no open stream, a WebSocket with no frame from the client (closing handshake with 1001).

  • :handler-timeout (0) - ms a handler may run, 0 = off. On expiry the client gets 503 (nothing was sent yet) and the handler thread is interrupted.

  • :shutdown-timeout (10000) - ms stop waits for in-flight requests across all connections before force-closing them.

    Limits:

  • :max-header-bytes (65536) - request head size cap on every protocol, 431 above: the HTTP/1.1 head (and chunked trailers), the decoded HTTP/2 header list (advertised as SETTINGS_MAX_HEADER_LIST_SIZE), the decoded HTTP/3 field section (SETTINGS_MAX_FIELD_SECTION_SIZE). Over 4x this (at least 64 KiB) an HTTP/2 connection ends with GOAWAY(ENHANCE_YOUR_CALM), an HTTP/3 stream is reset.

  • :max-header-fields (100) - request header fields per head on every protocol, 431 above (Apache's LimitRequestFields and Tomcat's maxHeaderCount default).

  • :max-request-body-bytes (10485760) - request body cap on every protocol, 0 = none. A larger Content-Length gets 413 upfront; a body without one fails mid-stream. WebSocket messages have their own cap, :ws-max-message-bytes.

  • :max-keep-alive-requests (1000) - requests per HTTP/1.1 connection, 0 = unlimited. The last response carries Connection: close.

  • :max-buffered-bytes (0) - bytes the server buffers or promises (flow-control credit) for peers, server-wide: unread request bodies (HTTP/2, HTTP/3) and the HTTP/2 credit granted for them, streamed HTTP/2 response bytes, queued WebSocket sends and incoming WebSocket messages past 64 KiB. 0 = a quarter of the maximum heap. Credit is paid for before it is granted. From three quarters of it connections over their fair share are throttled, at the limit all are: HTTP/2 grants connection credit only up to the initial 65535 octets, HTTP/3 stops reading request streams until bodies are read and a WebSocket stops reading a large message until there is room (backpressure), one WebSocket at a time reading on past the limit so whole messages still complete; WebSocket asynchronous sends fail at once.

    TCP:

  • :so-nodelay (true) - TCP_NODELAY on accepted sockets.

  • :so-reuse-addr (true) - SO_REUSEADDR on the listening socket.

  • :so-linger (-1) - SO_LINGER on accepted sockets, in seconds as the socket option, -1 = off.

  • :so-rcv-buf-bytes (0) - SO_RCVBUF, set on the listening socket before bind so accepted sockets inherit it; 0 = OS default.

  • :so-snd-buf-bytes (0) - SO_SNDBUF on accepted sockets, 0 = OS default.

    TLS:

  • :ssl-context (none) - javax.net.ssl.SSLContext; when set the TCP listener speaks TLS. File bodies then go through user space (no zero-copy).

  • :ssl-context-provider (none) - fn (or java.util.function.Supplier) returning an SSLContext, called at startup and per accepted connection so rotated certificates apply to new connections; return a cached context (one built per call costs that per connection and loses session resumption). Exclusive with :ssl-context.

  • :ssl-need-client-auth (false) - require a valid client certificate.

  • :ssl-want-client-auth (false) - request a client certificate without requiring one.

  • :ssl-alpn-protocols (none) - ALPN protocol ids offered; default ["h2" "http/1.1"] with :http2, else ["http/1.1"].

  • :ssl-cipher-suites (none) - enabled cipher suites, nil = JVM default.

  • :ssl-protocols (none) - enabled TLS protocol versions, nil = JVM default.

  • :ssl-session-cache-size (0) - server TLS session cache entries, set on every context the server uses; 0 = JVM default.

    HTTP/2:

  • :http2 (false) - serve "h2" over TLS + ALPN (needs :ssl-context; cleartext HTTP/2 is :http2c).

  • :http2c (false) - serve cleartext HTTP/2 with prior knowledge (RFC 9113 §3.3) on a plain listener next to HTTP/1.1: a connection that opens with the HTTP/2 preface is HTTP/2. No Upgrade: h2c (deprecated by RFC 9113). Not with :ssl-context (use :http2).

  • :http2-max-concurrent-streams (100) - SETTINGS_MAX_CONCURRENT_STREAMS.

  • :http2-initial-window-bytes (262144) - per-stream receive window a stream starts with, [65535, 2^31-1]; it doubles, up to :http2-max-window-bytes, while the handler reads half of it within two round trips. The connection window grows to 4x this (1 MiB by default) once request body bytes arrive, and doubles by the same rule up to twice :http2-max-window-bytes, every growth as far as :max-buffered-bytes pays for it. Credit returns as handlers read.

  • :http2-max-window-bytes (8388608) - most a stream's receive window grows to, [:http2-initial-window-bytes, 2^31-1]; the connection window grows to twice this. Equal to :http2-initial-window-bytes: fixed windows.

  • :http2-max-frame-bytes (16384) - SETTINGS_MAX_FRAME_SIZE, [16384, 16777215].

  • :http2-stream-reset-limit (400) - client RST_STREAMs allowed per connection, refilling at that many per 30 s; above it ENHANCE_YOUR_CALM (CVE-2023-44487). 0 = off.

  • :http2-continuation-limit (64) - CONTINUATION frames per header block.

    HTTP/3 (QUIC via quiche):

  • :http3 (false) - serve HTTP/3 over UDP; needs :http3-cert-path and :http3-key-path.

  • :http3-port (0) - UDP port, 0 = the :port number. With :port 0 set this (or :advertise-alt-svc false): Alt-Svc must name a fixed port.

  • :http3-cert-path (none) - PEM certificate chain (quiche reads it from disk).

  • :http3-key-path (none) - PEM private key.

  • :http3-initial-max-data-bytes (524288) - initial connection flow-control window (it autotunes up to twice :http3-max-window-bytes on release shims, stays fixed on a stock libquiche); charged to :max-buffered-bytes while the connection reads a request body. Also bounds request-body bytes buffered per connection.

  • :http3-initial-max-streams-bidi (100) - concurrent request streams per connection; twice this many live handlers make new requests H3_REQUEST_REJECTED.

  • :http3-initial-max-streams-uni (8) - peer unidirectional stream credit, at least 3 (control + QPACK encoder/decoder).

  • :http3-max-udp-payload-bytes (1350) - max UDP payload, [1200, 65527]; the default is MTU-safe.

  • :http3-stateless-retry (false) - make clients prove their address before any state is allocated (RFC 9000 §8.1.2); for floods.

  • :http3-cert-reload-interval (10000) - milliseconds between checks of :http3-cert-path / :http3-key-path for changes; a changed pair is loaded for new connections, existing ones keep theirs; 0 = off.

  • :http3-retry-threshold (256) - handshaking connections from which a client Initial without a valid token gets a stateless Retry.

  • :http3-max-half-open (1024) - handshaking connections above which new Initials are dropped; 0 = unlimited.

  • :http3-stream-reset-limit (400) - peer stream resets allowed per connection, refilling at that many per 30 s (rapid reset); 0 = off.

  • :http3-event-loops (0) - event loop threads owning QUIC connections, [0, 64]; 0 = one per core on Linux, 1 elsewhere.

  • :http3-so-rcv-buf-bytes (4194304) - UDP socket receive buffer requested (best effort); 0 = OS default.

  • :http3-so-snd-buf-bytes (4194304) - UDP socket send buffer requested (best effort); 0 = OS default.

  • :http3-initial-max-stream-data-bidi-local-bytes (-1) - per-stream window, -1 = half of :http3-initial-max-data-bytes (256 KiB by default), so one unread stream can't stall the connection.

  • :http3-initial-max-stream-data-bidi-remote-bytes (-1) - same, for peer-initiated streams.

  • :http3-initial-max-stream-data-uni-bytes (-1) - same, for unidirectional streams.

  • :http3-max-window-bytes (8388608) - most a stream's receive window autotunes to, at least the per-stream initial windows; a connection's window grows to twice this as far as :max-buffered-bytes pays. Needs the patched libquiche of the release builds; ignored on a stock libquiche (fixed windows).

  • :http3-ack-delay-exponent (-1) - RFC 9000 ack_delay_exponent, [0, 20]; -1 = quiche default.

  • :http3-max-ack-delay (-1) - RFC 9000 max_ack_delay in ms as the transport parameter, [0, 16383]; -1 = quiche default.

  • :http3-active-connection-id-limit (-1) - RFC 9000 active_connection_id_limit, >= 2; -1 = quiche default.

  • :advertise-alt-svc (none) - send Alt-Svc on HTTP/1.1 and HTTP/2 responses; nil = whenever :http3 is on. True needs :http3.

  • :alt-svc-max-age (86400) - ma of the Alt-Svc header, in seconds as the header parameter.

    WebSocket:

  • :ws-max-message-bytes (1048576) - largest message once reassembled and decompressed; a larger one closes the connection with 1009. Messages are buffered whole.

  • :ws-max-queued-bytes (1048576) - payload bytes asynchronous sends may queue per connection (plus 64 per frame), 0 = unlimited. A send over it fails at once (its fail callback runs); one message larger than the limit is accepted when nothing is queued.

  • :ws-close-timeout (5000) - ms a closing handshake the server started (close, failure, idle timeout, shutdown) waits for the client's CLOSE before dropping TCP; at least 1.

  • :ws-compression (false) - negotiate permessage-deflate (RFC 7692) when the client offers it. A compressing connection holds a Deflater and an Inflater (about 300 KiB of native memory); without the server's context takeover its Deflater is borrowed from a pool per message.

  • :ws-ping-interval (0) - ms without a frame from the client after which the server sends a ping (and again at that interval), 0 = never. The client's pongs count as frames, so a live but silent client outlasts :idle-timeout; less than :idle-timeout.

  • :ws-allowed-origins (none) - origins allowed to open a WebSocket (cross-site WebSocket hijacking protection): a collection of origins such as "https://app.example.com" ("*" for any) or a fn of the Origin value. nil = same origin: the Origin scheme and host must match the connection and the Host header. A configured allowlist is a hard gate: a handshake without Origin (not from a browser) is refused. With no allowlist a handshake without Origin is allowed. A refused handshake gets 403.

    Handler and observability:

  • :async (false) - handler is a Ring asynchronous handler, (fn [request respond raise]). It runs on the request's virtual thread, which waits until respond or raise is called (from any thread), without bound unless :handler-timeout is set; raise goes to :error-handler. Only the first call counts: the handler throwing before either is a raise, after one it is logged. A StreamableResponseBody may write after returning and ends when it closes its stream.

  • :error-handler (none) - (fn [request throwable]) returning a Ring response, when the handler throws or returns nil, on every protocol. If it throws or returns nil too, a plain 500 is sent.

  • :server-header (none) - Server response header value; nil or empty omits it. A handler-supplied Server wins.

  • :server-events (none) - map of fns {:connection-opened (fn [protocol remote-addr]) :connection-closed (fn [protocol remote-addr nanos]) :request-completed (fn [protocol method status request-bytes response-bytes nanos]) :protocol-error (fn [protocol kind])}, or a com.s_exp.enso.api.ServerEvents. remote-addr is formatted as :remote-addr. A request head refused before it was parsed is reported only as a protocol error. Protocols: "http/1.1", "h2", "h2c", "h3"; "websocket" for an upgraded connection's open / close; "tcp" (connection refused at accept) and "tls" (handshake failures) for protocol errors. Delivered in order from one dedicated thread, never from a server thread; past 8192 queued events (a listener that fell behind) new ones are dropped and counted (EnsoServer.droppedEvents, a log warning, a JFR event). Exceptions are logged and ignored. No cost when absent.

    Errors are logged through java.util.logging under com.s_exp.enso.*: client-caused failures at FINE, server-side faults at WARNING (rate-limited).

Starts an HTTP server calling `handler` with Ring request maps.
  Returns the server, stop it with [[stop]]. Unknown options and invalid
  values throw ex-info naming the option.

  `handler` is `(fn [request] response)`, or with `:async` true a Ring
  asynchronous handler `(fn [request respond raise])`. It runs on a
  virtual thread per request (per connection on HTTP/1.1).

  Response `:body`: nil, String, byte array, InputStream, File, a seq
  (each element `str`'d), `(fn [ChunkedWriter])` streaming with
  [[write!]] / [[flush!]] (an enso extension), or anything satisfying
  `ring.core.protocols/StreamableResponseBody` when on the classpath.
  `:status` defaults to 200 when absent.

  WebSocket (HTTP/1.1): answer an upgrade request with
  `{:ring.websocket/listener l}`, `l` a map of `:on-open` `:on-message`
  `:on-ping` `:on-pong` `:on-error` `:on-close` fns or a
  `ring.websocket.protocols/Listener`. See doc/handlers.md.
  
  Durations are milliseconds, 0 disables a timeout; sizes are bytes.

  Network:
- `:port` (8080) - listen port, 0 picks an ephemeral port
- `:host` ("0.0.0.0") - bind address
- `:backlog` (1024) - accept queue length
- `:max-connections` (10000) - open connections server-wide, TCP and QUIC
    together, 0 = unlimited. TCP connections over the limit are closed at
    accept, QUIC Initials dropped.
- `:max-connections-per-ip` (0) - open connections per client address, 0 =
    unlimited. Leave off behind a proxy or NAT, where clients share an
    address.

  Timeouts:
- `:handshake-timeout` (10000) - ms to complete the TLS handshake (plus the
    HTTP/2 preface and first SETTINGS, or the QUIC handshake), wall clock. It
    and `:idle-timeout` must not both be 0, which would leave a half-open
    connection with no bound.
- `:header-timeout` (10000) - ms to receive a complete request head from its
    first byte, wall clock (slowloris protection). Answered with 408.
- `:read-timeout` (30000) - longest ms without progress reading a request
    body; the read fails (408 unless the handler catches it). Also bounds head
    reads when `:header-timeout` is 0, and is the wall-clock time a WebSocket
    message may take from its first frame to its last (CLOSE 1008), less time
    the server held it back for `:max-buffered-bytes`.
- `:min-data-rate-bytes` (240) - least request body bytes per second while a
    handler waits for them, once `:min-data-rate-grace` of waiting is spent
    (Kestrel's default), 0 = off. Below it the read fails (408, protocol error
    "min-data-rate"): a body trickled just inside `:read-timeout` can't hold a
    request forever. Time the handler isn't reading doesn't count.
- `:min-data-rate-grace` (5000) - ms of waiting for request body bytes allowed
    before `:min-data-rate-bytes` applies.
- `:write-timeout` (30000) - longest ms without write progress (a peer that
    stopped reading); the connection is force-closed.
- `:idle-timeout` (75000) - ms a connection may sit with no request in
    progress: HTTP/1.1 between requests (and before the first), HTTP/2 and
    HTTP/3 with no open stream, a WebSocket with no frame from the client
    (closing handshake with 1001).
- `:handler-timeout` (0) - ms a handler may run, 0 = off. On expiry the client
    gets 503 (nothing was sent yet) and the handler thread is interrupted.
- `:shutdown-timeout` (10000) - ms `stop` waits for in-flight requests across
    all connections before force-closing them.

  Limits:
- `:max-header-bytes` (65536) - request head size cap on every protocol, 431
    above: the HTTP/1.1 head (and chunked trailers), the decoded HTTP/2 header
    list (advertised as SETTINGS_MAX_HEADER_LIST_SIZE), the decoded HTTP/3
    field section (SETTINGS_MAX_FIELD_SECTION_SIZE). Over 4x this (at least 64
    KiB) an HTTP/2 connection ends with GOAWAY(ENHANCE_YOUR_CALM), an HTTP/3
    stream is reset.
- `:max-header-fields` (100) - request header fields per head on every
    protocol, 431 above (Apache's LimitRequestFields and Tomcat's
    maxHeaderCount default).
- `:max-request-body-bytes` (10485760) - request body cap on every protocol, 0
    = none. A larger Content-Length gets 413 upfront; a body without one fails
    mid-stream. WebSocket messages have their own cap,
    `:ws-max-message-bytes`.
- `:max-keep-alive-requests` (1000) - requests per HTTP/1.1 connection, 0 =
    unlimited. The last response carries Connection: close.
- `:max-buffered-bytes` (0) - bytes the server buffers or promises
    (flow-control credit) for peers, server-wide: unread request bodies
    (HTTP/2, HTTP/3) and the HTTP/2 credit granted for them, streamed HTTP/2
    response bytes, queued WebSocket sends and incoming WebSocket messages
    past 64 KiB. 0 = a quarter of the maximum heap. Credit is paid for before
    it is granted. From three quarters of it connections over their fair share
    are throttled, at the limit all are: HTTP/2 grants connection credit only
    up to the initial 65535 octets, HTTP/3 stops reading request streams until
    bodies are read and a WebSocket stops reading a large message until there
    is room (backpressure), one WebSocket at a time reading on past the limit
    so whole messages still complete; WebSocket asynchronous sends fail at
    once.

  TCP:
- `:so-nodelay` (true) - TCP_NODELAY on accepted sockets.
- `:so-reuse-addr` (true) - SO_REUSEADDR on the listening socket.
- `:so-linger` (-1) - SO_LINGER on accepted sockets, in seconds as the socket
    option, -1 = off.
- `:so-rcv-buf-bytes` (0) - SO_RCVBUF, set on the listening socket before bind
    so accepted sockets inherit it; 0 = OS default.
- `:so-snd-buf-bytes` (0) - SO_SNDBUF on accepted sockets, 0 = OS default.

  TLS:
- `:ssl-context` (none) - `javax.net.ssl.SSLContext`; when set the TCP
    listener speaks TLS. File bodies then go through user space (no
    zero-copy).
- `:ssl-context-provider` (none) - fn (or `java.util.function.Supplier`)
    returning an `SSLContext`, called at startup and per accepted connection
    so rotated certificates apply to new connections; return a cached context
    (one built per call costs that per connection and loses session
    resumption). Exclusive with `:ssl-context`.
- `:ssl-need-client-auth` (false) - require a valid client certificate.
- `:ssl-want-client-auth` (false) - request a client certificate without
    requiring one.
- `:ssl-alpn-protocols` (none) - ALPN protocol ids offered; default ["h2"
    "http/1.1"] with `:http2`, else ["http/1.1"].
- `:ssl-cipher-suites` (none) - enabled cipher suites, nil = JVM default.
- `:ssl-protocols` (none) - enabled TLS protocol versions, nil = JVM default.
- `:ssl-session-cache-size` (0) - server TLS session cache entries, set on
    every context the server uses; 0 = JVM default.

  HTTP/2:
- `:http2` (false) - serve "h2" over TLS + ALPN (needs `:ssl-context`;
    cleartext HTTP/2 is `:http2c`).
- `:http2c` (false) - serve cleartext HTTP/2 with prior knowledge (RFC 9113
    §3.3) on a plain listener next to HTTP/1.1: a connection that opens with
    the HTTP/2 preface is HTTP/2. No `Upgrade: h2c` (deprecated by RFC 9113).
    Not with `:ssl-context` (use `:http2`).
- `:http2-max-concurrent-streams` (100) - SETTINGS_MAX_CONCURRENT_STREAMS.
- `:http2-initial-window-bytes` (262144) - per-stream receive window a stream
    starts with, [65535, 2^31-1]; it doubles, up to `:http2-max-window-bytes`,
    while the handler reads half of it within two round trips. The connection
    window grows to 4x this (1 MiB by default) once request body bytes arrive,
    and doubles by the same rule up to twice `:http2-max-window-bytes`, every
    growth as far as `:max-buffered-bytes` pays for it. Credit returns as
    handlers read.
- `:http2-max-window-bytes` (8388608) - most a stream's receive window grows
    to, [`:http2-initial-window-bytes`, 2^31-1]; the connection window grows
    to twice this. Equal to `:http2-initial-window-bytes`: fixed windows.
- `:http2-max-frame-bytes` (16384) - SETTINGS_MAX_FRAME_SIZE, [16384,
    16777215].
- `:http2-stream-reset-limit` (400) - client RST_STREAMs allowed per
    connection, refilling at that many per 30 s; above it ENHANCE_YOUR_CALM
    (CVE-2023-44487). 0 = off.
- `:http2-continuation-limit` (64) - CONTINUATION frames per header block.

  HTTP/3 (QUIC via quiche):
- `:http3` (false) - serve HTTP/3 over UDP; needs `:http3-cert-path` and
    `:http3-key-path`.
- `:http3-port` (0) - UDP port, 0 = the `:port` number. With `:port` 0 set
    this (or `:advertise-alt-svc` false): Alt-Svc must name a fixed port.
- `:http3-cert-path` (none) - PEM certificate chain (quiche reads it from
    disk).
- `:http3-key-path` (none) - PEM private key.
- `:http3-initial-max-data-bytes` (524288) - initial connection flow-control
    window (it autotunes up to twice `:http3-max-window-bytes` on release
    shims, stays fixed on a stock libquiche); charged to `:max-buffered-bytes`
    while the connection reads a request body. Also bounds request-body bytes
    buffered per connection.
- `:http3-initial-max-streams-bidi` (100) - concurrent request streams per
    connection; twice this many live handlers make new requests
    H3_REQUEST_REJECTED.
- `:http3-initial-max-streams-uni` (8) - peer unidirectional stream credit, at
    least 3 (control + QPACK encoder/decoder).
- `:http3-max-udp-payload-bytes` (1350) - max UDP payload, [1200, 65527]; the
    default is MTU-safe.
- `:http3-stateless-retry` (false) - make clients prove their address before
    any state is allocated (RFC 9000 §8.1.2); for floods.
- `:http3-cert-reload-interval` (10000) - milliseconds between checks of
    :http3-cert-path / :http3-key-path for changes; a changed pair is loaded
    for new connections, existing ones keep theirs; 0 = off.
- `:http3-retry-threshold` (256) - handshaking connections from which a client
    Initial without a valid token gets a stateless Retry.
- `:http3-max-half-open` (1024) - handshaking connections above which new
    Initials are dropped; 0 = unlimited.
- `:http3-stream-reset-limit` (400) - peer stream resets allowed per
    connection, refilling at that many per 30 s (rapid reset); 0 = off.
- `:http3-event-loops` (0) - event loop threads owning QUIC connections, [0,
    64]; 0 = one per core on Linux, 1 elsewhere.
- `:http3-so-rcv-buf-bytes` (4194304) - UDP socket receive buffer requested
    (best effort); 0 = OS default.
- `:http3-so-snd-buf-bytes` (4194304) - UDP socket send buffer requested (best
    effort); 0 = OS default.
- `:http3-initial-max-stream-data-bidi-local-bytes` (-1) - per-stream window,
    -1 = half of `:http3-initial-max-data-bytes` (256 KiB by default), so one
    unread stream can't stall the connection.
- `:http3-initial-max-stream-data-bidi-remote-bytes` (-1) - same, for
    peer-initiated streams.
- `:http3-initial-max-stream-data-uni-bytes` (-1) - same, for unidirectional
    streams.
- `:http3-max-window-bytes` (8388608) - most a stream's receive window
    autotunes to, at least the per-stream initial windows; a connection's
    window grows to twice this as far as `:max-buffered-bytes` pays. Needs the
    patched libquiche of the release builds; ignored on a stock libquiche
    (fixed windows).
- `:http3-ack-delay-exponent` (-1) - RFC 9000 ack_delay_exponent, [0, 20]; -1
    = quiche default.
- `:http3-max-ack-delay` (-1) - RFC 9000 max_ack_delay in ms as the transport
    parameter, [0, 16383]; -1 = quiche default.
- `:http3-active-connection-id-limit` (-1) - RFC 9000
    active_connection_id_limit, >= 2; -1 = quiche default.
- `:advertise-alt-svc` (none) - send `Alt-Svc` on HTTP/1.1 and HTTP/2
    responses; nil = whenever `:http3` is on. True needs `:http3`.
- `:alt-svc-max-age` (86400) - `ma` of the `Alt-Svc` header, in seconds as the
    header parameter.

  WebSocket:
- `:ws-max-message-bytes` (1048576) - largest message once reassembled and
    decompressed; a larger one closes the connection with 1009. Messages are
    buffered whole.
- `:ws-max-queued-bytes` (1048576) - payload bytes asynchronous sends may
    queue per connection (plus 64 per frame), 0 = unlimited. A send over it
    fails at once (its fail callback runs); one message larger than the limit
    is accepted when nothing is queued.
- `:ws-close-timeout` (5000) - ms a closing handshake the server started
    (close, failure, idle timeout, shutdown) waits for the client's CLOSE
    before dropping TCP; at least 1.
- `:ws-compression` (false) - negotiate permessage-deflate (RFC 7692) when the
    client offers it. A compressing connection holds a Deflater and an
    Inflater (about 300 KiB of native memory); without the server's context
    takeover its Deflater is borrowed from a pool per message.
- `:ws-ping-interval` (0) - ms without a frame from the client after which the
    server sends a ping (and again at that interval), 0 = never. The client's
    pongs count as frames, so a live but silent client outlasts
    `:idle-timeout`; less than `:idle-timeout`.
- `:ws-allowed-origins` (none) - origins allowed to open a WebSocket
    (cross-site WebSocket hijacking protection): a collection of origins such
    as "https://app.example.com" ("*" for any) or a fn of the `Origin` value.
    nil = same origin: the `Origin` scheme and host must match the connection
    and the `Host` header. A configured allowlist is a hard gate: a handshake
    without `Origin` (not from a browser) is refused. With no allowlist a
    handshake without `Origin` is allowed. A refused handshake gets 403.

  Handler and observability:
- `:async` (false) - `handler` is a Ring asynchronous handler, `(fn [request
    respond raise])`. It runs on the request's virtual thread, which waits
    until `respond` or `raise` is called (from any thread), without bound
    unless `:handler-timeout` is set; `raise` goes to `:error-handler`. Only
    the first call counts: the handler throwing before either is a `raise`,
    after one it is logged. A StreamableResponseBody may write after returning
    and ends when it closes its stream.
- `:error-handler` (none) - `(fn [request throwable])` returning a Ring
    response, when the handler throws or returns nil, on every protocol. If it
    throws or returns nil too, a plain 500 is sent.
- `:server-header` (none) - `Server` response header value; nil or empty omits
    it. A handler-supplied `Server` wins.
- `:server-events` (none) - map of fns `{:connection-opened (fn [protocol
    remote-addr]) :connection-closed (fn [protocol remote-addr nanos])
    :request-completed (fn [protocol method status request-bytes
    response-bytes nanos]) :protocol-error (fn [protocol kind])}`, or a
    `com.s_exp.enso.api.ServerEvents`. `remote-addr` is formatted as
    `:remote-addr`. A request head refused before it was parsed is reported
    only as a protocol error. Protocols: "http/1.1", "h2", "h2c", "h3";
    "websocket" for an upgraded connection's open / close; "tcp" (connection
    refused at accept) and "tls" (handshake failures) for protocol errors.
    Delivered in order from one dedicated thread, never from a server thread;
    past 8192 queued events (a listener that fell behind) new ones are dropped
    and counted (`EnsoServer.droppedEvents`, a log warning, a JFR event).
    Exceptions are logged and ignored. No cost when absent.

  Errors are logged through `java.util.logging` under `com.s_exp.enso.*`:
  client-caused failures at FINE, server-side faults at WARNING (rate-limited).
sourceraw docstring

stopclj

(stop server)

Stops server. In-flight requests complete, open connections close.

Stops `server`. In-flight requests complete, open connections close.
sourceraw docstring

write!clj

(write! w data)

Buffers data (a String or byte array) into the pending chunk of a streamed (fn) body. Strings are encoded with the response's charset (the charset of its Content-Type), UTF-8 when it has none.

Buffers `data` (a String or byte array) into the pending chunk of a
streamed (fn) body. Strings are encoded with the response's charset (the
`charset` of its Content-Type), UTF-8 when it has none.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close