(sigil http response)
(sigil http response) - HTTP Response Types and Serialization
Provides the <http-response> record and functions for serializing HTTP/1.1 responses to sockets.
Exports
http-responseprocedureHTTP Response Record
http-response?procedureTest if a value is a http-response struct.
http-response-statusprocedureGet the status field of a http-response struct.
http-response-headersprocedureGet the headers field of a http-response struct.
http-response-bodyprocedureGet the body field of a http-response struct.
HTTP-OKvariableStatus code constants
http-status-messageprocedureGet the human-readable message for an HTTP status code.
(http-status-message 200) ; => "OK"
(http-status-message 404) ; => "Not Found"http-response/textprocedureConvenience constructors Create a plain text response.
(http-response/text 200 "Hello, world!")http-response/htmlprocedureCreate an HTML response.
(http-response/html 200 "<h1>Hello</h1>")http-response/jsonprocedureCreate a JSON response.
body is either a dict (encoded for you with json-encode) or an already-encoded JSON string (passed through untouched).
(http-response/json 200 #{ name: "Alice" }) ; dict, encoded for you
(http-response/json 200 (json-encode #{ name: "Alice" })) ; string still workshttp-response/not-foundprocedureCreate a 404 Not Found response with a default HTML body.
http-response/redirectprocedureCreate a redirect response.
Defaults to 302 Found. Pass a status code to override.
(http-response/redirect "/login")
(http-response/redirect "/new-url" 301)http-response/errorprocedureCreate an error response with an HTML body.
(http-response/error 500 "Something went wrong")gzip-min-bytesvariableDefault minimum body size (bytes) below which compression isn't worth the header overhead.
response-compressible?procedure#t when a content type generally benefits from gzip. Already-compressed media (images, video, fonts, zip/gz) is excluded.
http-response-gzipprocedureReturn a gzip-encoded copy of response when it is worth doing, otherwise return response unchanged.
accept-encoding is the request's Accept-Encoding header value (or #f); callers typically pass (http-request-header req "Accept-Encoding"). Compression is applied only when: the client accepts gzip, the body is a string or bytevector at least min-bytes long, the content type is compressible, and the response isn't already content-encoded. The result gains Content-Encoding: gzip and Vary: Accept-Encoding; Content-Length is derived from the compressed body by the serializer.
(http-response-gzip (http-request-header req "Accept-Encoding")
(http-response/json 200 payload))body-lengthprocedureGet body length for Content-Length header For strings, we need byte length (UTF-8), not character count
streaming-body?procedureCheck if body is a streaming producer
build-status-lineprocedureBuild status line: "HTTP/1.1 200 OKrn"
build-headers-stringprocedureBuild headers string Converts keyword keys to HTTP header format
ensure-headersprocedureEnsure required headers are present
write-http-responseprocedureWrite an HTTP response to a socket.
The write function should accept (socket data) and return bytes written or #f. Returns #t on success, #f on error.
http-response->stringprocedureConvert an HTTP response to a string (for debugging).
parse-range-headerprocedureParse an HTTP Range header value into (start . end). Returns #f if the header is absent or malformed.
(parse-range-header "bytes=0-499") ; => (0 . 499)
(parse-range-header "bytes=500-") ; => (500 . #f)
(parse-range-header #f) ; => #ffile-chunk-sizevariableServe a file with automatic MIME type and optional Range support. Uses streaming I/O to send files in chunks without loading the entire file into memory.
(http-response/file "/path/to/video.mp4")
(http-response/file "/path/to/video.mp4" range-start: 0 range-end: 499)http-response/sseprocedureCreate a Server-Sent Events response.
The producer is called with two arguments:
- send: (lambda (event-type data) ...) - sends an event
- close: (lambda () ...) - closes the stream
Example:
(http-response/sse
(lambda (send close)
(send "message" (dict text: "Hello"))
(send "update" (dict count: 42))
;; Keep connection open, send more events...
))http-response/sse-broadcastprocedureCreate an SSE response that broadcasts from a channel.
Subscribes to a broadcast channel and sends events for each message. The handler transforms messages into SSE event strings; it is optional and defaults to the identity function, so a hub that already carries pre-formatted SSE strings (the common case) needs no handler.
Parameters: broadcast: The broadcast channel to subscribe to handler: Optional (lambda (msg) ...) -> string or #f. Returns SSE event string to send, or #f to skip. Defaults to identity (send each message as-is). buffer-size: Subscriber buffer size (default: 32) on-connect: Optional (lambda () ...) called on connect. Returns initial event string or #f.
Example:
;; Hub carries pre-formatted event strings — no handler needed:
(http-response/sse-broadcast hub on-connect: (lambda () (snapshot)))
;; Transform raw messages into SSE strings:
(http-response/sse-broadcast chat-broadcast
(lambda (msg) (sse-event "message" (json-encode msg))))sse-eventprocedureFormat a Server-Sent Event with event type and data.
Returns a string in SSE format: event: <type> data: <json>
The data is JSON-encoded if it's not already a string.
sse-dataprocedureFormat a simple data-only SSE event (no event type).
Returns a string in SSE format: data: <content>
sse-heartbeat-markervariableSentinel broadcast message indicating a heartbeat. Recognized by http-response/sse-broadcast, which writes the SSE comment sse-heartbeat-message in response. Treat as reserved: don't send this value as application data.
sse-heartbeat-messagevariableThe SSE comment written for each heartbeat. Lines starting with : are ignored by the browser EventSource API but trigger write-chunk, so dead connections surface as write failures.
start-sse-heartbeat!procedureSpawn a background goroutine that sends sse-heartbeat-marker on the given broadcast(s) every interval seconds.
broadcasts is either a single broadcast channel or a list of broadcast channels. interval defaults to 30 seconds.
Returns a thunk that stops the heartbeat loop when invoked.
(define stop (start-sse-heartbeat! my-broadcast))
;; later ...
(stop)Combined with http-response/sse-broadcast, this provides automatic dead-client cleanup for SSE endpoints — no changes required in user handlers.
<http-response>variable(No description)
HTTP-CREATEDvariable(No description)
HTTP-ACCEPTEDvariable(No description)
HTTP-NO-CONTENTvariable(No description)
HTTP-MOVED-PERMANENTLYvariable(No description)
HTTP-FOUNDvariable(No description)
HTTP-SEE-OTHERvariable(No description)
HTTP-NOT-MODIFIEDvariable(No description)
HTTP-TEMPORARY-REDIRECTvariable(No description)
HTTP-PERMANENT-REDIRECTvariable(No description)
HTTP-PARTIAL-CONTENTvariable(No description)
HTTP-BAD-REQUESTvariable(No description)
HTTP-UNAUTHORIZEDvariable(No description)
HTTP-FORBIDDENvariable(No description)
HTTP-NOT-FOUNDvariable(No description)
HTTP-METHOD-NOT-ALLOWEDvariable(No description)
HTTP-REQUEST-TIMEOUTvariable(No description)
HTTP-CONFLICTvariable(No description)
HTTP-GONEvariable(No description)
HTTP-LENGTH-REQUIREDvariable(No description)
HTTP-PAYLOAD-TOO-LARGEvariable(No description)
HTTP-URI-TOO-LONGvariable(No description)
HTTP-UNSUPPORTED-MEDIA-TYPEvariable(No description)
HTTP-INTERNAL-SERVER-ERRORvariable(No description)
HTTP-NOT-IMPLEMENTEDvariable(No description)
HTTP-BAD-GATEWAYvariable(No description)
HTTP-SERVICE-UNAVAILABLEvariable(No description)
HTTP-GATEWAY-TIMEOUTvariable(No description)
http-response/filevariable(No description)