Package
HTTP server for Pony, built on lori.
A listener actor implements lori.TCPListenerActor and creates
stallion.HTTPServerActor instances in _on_accept. Each connection actor owns
a stallion.HTTPServer that handles HTTP parsing and response management,
delivering HTTP events via stallion.HTTPServerLifecycleEventReceiver callbacks.
use stallion = "stallion"
use lori = "lori"
actor Main
new create(env: Env) =>
let auth = lori.TCPListenAuth(env.root)
MyListener(auth, "localhost", "8080")
actor MyListener is lori.TCPListenerActor
var _tcp_listener: lori.TCPListener = lori.TCPListener.none()
let _server_auth: lori.TCPServerAuth
let _config: stallion.ServerConfig
new create(auth: lori.TCPListenAuth, host: String, port: String) =>
_server_auth = lori.TCPServerAuth(auth)
_config = stallion.ServerConfig(host, port)
_tcp_listener = lori.TCPListener(auth, host, port, this)
fun ref _listener(): lori.TCPListener => _tcp_listener
fun ref _on_accept(fd: U32): lori.TCPConnectionActor =>
MyServer(_server_auth, fd, _config)
actor MyServer is stallion.HTTPServerActor
var _http: stallion.HTTPServer = stallion.HTTPServer.none()
new create(auth: lori.TCPServerAuth, fd: U32,
config: stallion.ServerConfig)
=>
_http = stallion.HTTPServer(auth, fd, this, config)
fun ref _http_connection(): stallion.HTTPServer => _http
fun ref on_request_complete(request': stallion.Request val,
responder: stallion.Responder)
=>
let body: String val = "Hello!"
let response = stallion.ResponseBuilder(stallion.StatusOK)
.add_header("Content-Length", body.size().string())
.finish_headers()
.add_chunk(body)
.build()
responder.respond(response)
For streaming responses, use chunked transfer encoding.
start_chunked_response() returns a stallion.StartChunkedResponseResult
indicating success or the reason for failure. Each send_chunk() returns a
stallion.ChunkSendToken — override on_chunk_sent() to drive flow-controlled
delivery:
fun ref on_request_complete(request': stallion.Request val,
responder: stallion.Responder)
=>
match responder.start_chunked_response(stallion.StatusOK)
| stallion.StreamingStarted =>
let token = responder.send_chunk("chunk 1")
// When on_chunk_sent(token) fires, send the next chunk...
responder.send_chunk("chunk 2")
responder.finish_response()
| stallion.ChunkedNotSupported =>
// HTTP/1.0 — fall back to a complete response
responder.respond(fallback_response)
| stallion.AlreadyResponded => None
end
For HTTPS, use stallion.HTTPServer.ssl instead of stallion.HTTPServer. Store
an SSLContext val in the listener and pass it through in _on_accept:
use stallion = "stallion"
use "files"
use "ssl/net"
use lori = "lori"
actor Main
new create(env: Env) =>
let sslctx = recover val
SSLContext
.> set_cert(
FilePath(FileAuth(env.root), "cert.pem"),
FilePath(FileAuth(env.root), "key.pem"))?
.> set_client_verify(false)
.> set_server_verify(false)
end
let auth = lori.TCPListenAuth(env.root)
MyListener(auth, "localhost", "8443", sslctx)
actor MyListener is lori.TCPListenerActor
var _tcp_listener: lori.TCPListener = lori.TCPListener.none()
let _server_auth: lori.TCPServerAuth
let _config: stallion.ServerConfig
let _ssl_ctx: SSLContext val
new create(auth: lori.TCPListenAuth, host: String, port: String,
ssl_ctx: SSLContext val)
=>
_ssl_ctx = ssl_ctx
_server_auth = lori.TCPServerAuth(auth)
_config = stallion.ServerConfig(host, port)
_tcp_listener = lori.TCPListener(auth, host, port, this)
fun ref _listener(): lori.TCPListener => _tcp_listener
fun ref _on_accept(fd: U32): lori.TCPConnectionActor =>
MyServer(_server_auth, fd, _config, _ssl_ctx)
The actor explicitly chooses stallion.HTTPServer (plain HTTP) or
stallion.HTTPServer.ssl (HTTPS) in its constructor. The MyServer actor in
the HTTPS example would use
stallion.HTTPServer.ssl(auth, ssl_ctx, fd, this, config) instead of
stallion.HTTPServer(auth, fd, this, config).
Public Types¶
- primitive AlreadyResponded
- primitive BodyTooLarge
- primitive CONNECT
- class ChunkSendToken
- primitive ChunkedNotSupported
- primitive DELETE
- primitive DefaultIdleTimeout
- primitive GET
- primitive HEAD
- primitive HTTP10
- primitive HTTP11
- class HTTPServer
- trait HTTPServerActor
- trait HTTPServerLifecycleEventReceiver
- class Headers
- primitive InvalidChunk
- primitive InvalidContentLength
- primitive InvalidURI
- primitive InvalidVersion
- primitive MalformedHeaders
- interface Method
- primitive Methods
- primitive OPTIONS
- primitive PATCH
- primitive POST
- primitive PUT
- type ParseError
- class Request
- class Responder
- interface ResponseBodyBuilder
- primitive ResponseBuilder
- interface ResponseHeadersBuilder
- class ServerConfig
- type StartChunkedResponseResult
- interface Status
- primitive StatusAccepted
- primitive StatusBadGateway
- primitive StatusBadRequest
- primitive StatusConflict
- primitive StatusContinue
- primitive StatusCreated
- primitive StatusForbidden
- primitive StatusFound
- primitive StatusGatewayTimeout
- primitive StatusGone
- primitive StatusHTTPVersionNotSupported
- primitive StatusInternalServerError
- primitive StatusLengthRequired
- primitive StatusMethodNotAllowed
- primitive StatusMovedPermanently
- primitive StatusNoContent
- primitive StatusNotAcceptable
- primitive StatusNotFound
- primitive StatusNotImplemented
- primitive StatusNotModified
- primitive StatusOK
- primitive StatusPartialContent
- primitive StatusPayloadTooLarge
- primitive StatusPermanentRedirect
- primitive StatusRequestHeaderFieldsTooLarge
- primitive StatusRequestTimeout
- primitive StatusSeeOther
- primitive StatusServiceUnavailable
- primitive StatusSwitchingProtocols
- primitive StatusTemporaryRedirect
- primitive StatusTooManyRequests
- primitive StatusURITooLong
- primitive StatusUnauthorized
- primitive StatusUnprocessableEntity
- primitive StatusUnsupportedMediaType
- primitive StreamingStarted
- primitive TRACE
- primitive TooLarge
- primitive UnknownMethod
- type Version