263 lines
6.1 KiB
Plaintext
263 lines
6.1 KiB
Plaintext
public type PoolLimits {
|
|
idle_ms: Int
|
|
chunk_bytes: Int
|
|
read_ms: Int
|
|
}
|
|
|
|
public type StreamRequest {
|
|
method: Text
|
|
target: Text
|
|
headers: List<Header>
|
|
body: AsyncStream<dever.io.ReadEvent>
|
|
}
|
|
|
|
public type StreamResponse {
|
|
status: Int
|
|
headers: List<Header>
|
|
body: AsyncStream<dever.io.ReadEvent>
|
|
}
|
|
|
|
public type ClientResult {
|
|
Ready(client: dever.system.HttpClient)
|
|
error Failed(message: Text)
|
|
}
|
|
|
|
public type StreamResponseResult {
|
|
Read(response: StreamResponse)
|
|
error Failed(message: Text)
|
|
}
|
|
|
|
public default_pool_limits() (result: PoolLimits) {
|
|
result = PoolLimits {
|
|
idle_ms = 10000
|
|
chunk_bytes = 65536
|
|
read_ms = 60000
|
|
}
|
|
}
|
|
|
|
public client(
|
|
origin: Text,
|
|
tls: dever.system.ClientTls,
|
|
limits: Limits,
|
|
pool: PoolLimits
|
|
) (client: dever.system.HttpClient) {
|
|
client = ready_client(dever.system.http_client(origin, tls, limits, pool))
|
|
}
|
|
|
|
ready_client(result: ClientResult.Ready(client)) (value: dever.system.HttpClient) {
|
|
value = client
|
|
}
|
|
|
|
ready_client(result: ClientResult.Failed(message)) (value: dever.system.HttpClient) {
|
|
fail(ClientResult.Failed(message))
|
|
}
|
|
|
|
public request(client: dever.system.HttpClient, request: Request) (
|
|
response: Response
|
|
) {
|
|
response = read_response(dever.system.http_request(client, request))
|
|
}
|
|
|
|
public open(client: dever.system.HttpClient, request: Request) (
|
|
response: StreamResponse
|
|
) {
|
|
response = read_stream_response(dever.system.http_open(client, request))
|
|
}
|
|
|
|
public open_stream(client: dever.system.HttpClient, request: StreamRequest) (
|
|
response: StreamResponse
|
|
) {
|
|
response = read_stream_response(dever.system.http_open_stream(client, request))
|
|
}
|
|
|
|
read_stream_response(result: StreamResponseResult.Read(response)) (
|
|
value: StreamResponse
|
|
) {
|
|
value = response
|
|
}
|
|
|
|
read_stream_response(result: StreamResponseResult.Failed(message)) (
|
|
value: StreamResponse
|
|
) {
|
|
fail(StreamResponseResult.Failed(message))
|
|
}
|
|
|
|
public close_client(client: dever.system.HttpClient) () {
|
|
closed(dever.system.http_close_client(client))
|
|
}
|
|
|
|
public serve_tls(
|
|
route: handler(request: Request) (response: Response),
|
|
listener: dever.system.Listener,
|
|
limits: Limits,
|
|
tls: dever.system.ServerTls
|
|
) () {
|
|
dever.system.http_serve_tls(route, listener, limits, tls)
|
|
}
|
|
|
|
public serve_live_tls(
|
|
route: handler(request: Request, reply: dever.system.HttpReply) (),
|
|
listener: dever.system.Listener,
|
|
limits: Limits,
|
|
live: LiveLimits,
|
|
tls: dever.system.ServerTls
|
|
) () {
|
|
dever.system.http_serve_live_tls(route, listener, limits, live, tls)
|
|
}
|
|
|
|
public type Header {
|
|
name: Text
|
|
value: Bytes
|
|
}
|
|
|
|
public type Request {
|
|
method: Text
|
|
target: Text
|
|
headers: List<Header>
|
|
body: Bytes
|
|
}
|
|
|
|
public type Response {
|
|
status: Int
|
|
headers: List<Header>
|
|
body: Bytes
|
|
}
|
|
|
|
public type Limits {
|
|
header_bytes: Int
|
|
body_bytes: Int
|
|
timeout_ms: Int
|
|
connections: Int
|
|
http2: Http2Limits?
|
|
}
|
|
|
|
# streams 为每连接并发流数;窗口限制协议层未消费的接收正文。
|
|
public type Http2Limits {
|
|
streams: Int
|
|
stream_window_bytes: Int
|
|
connection_window_bytes: Int
|
|
}
|
|
|
|
public default_http2_limits() (result: Http2Limits) {
|
|
result = Http2Limits {
|
|
streams = 16
|
|
stream_window_bytes = 65535
|
|
connection_window_bytes = 262144
|
|
}
|
|
}
|
|
|
|
public type LiveLimits {
|
|
chunk_bytes: Int
|
|
idle_ms: Int
|
|
heartbeat_ms: Int
|
|
}
|
|
|
|
public default_live_limits() (result: LiveLimits) {
|
|
result = LiveLimits {
|
|
chunk_bytes = 65536
|
|
idle_ms = 60000
|
|
heartbeat_ms = 15000
|
|
}
|
|
}
|
|
|
|
public type ResponseResult {
|
|
Read(response: Response)
|
|
error Failed(message: Text)
|
|
}
|
|
|
|
public default_limits() (result: Limits) {
|
|
result = Limits {
|
|
header_bytes = 8192
|
|
body_bytes = 1048576
|
|
timeout_ms = 5000
|
|
connections = 32
|
|
http2 = null
|
|
}
|
|
}
|
|
|
|
public header(name: Text, value: Text) (result: Header) {
|
|
result = Header {
|
|
name = text.lower(name)
|
|
value = dever.bytes.from_text(value)
|
|
}
|
|
}
|
|
|
|
# 返回第一个匹配项的原始值;重复头保留在 headers 列表中。
|
|
public header_value(headers: List<Header>, name: Text) (value: Bytes?) {
|
|
value = found_header(find(named_header, headers, text.lower(name)))
|
|
}
|
|
|
|
named_header(header: Header, name: Text) (matches: Bool) {
|
|
matches = text.lower(header.name) == name
|
|
}
|
|
|
|
found_header(header: null) (value: Bytes?) {
|
|
value = null
|
|
}
|
|
|
|
found_header(header: Header) (value: Bytes?) {
|
|
value = header.value
|
|
}
|
|
|
|
# serve 是长驻任务,调用者用 run/stop 管理生命周期;故障沿任务作用域传播。
|
|
public serve(
|
|
route: handler(request: Request) (response: Response),
|
|
listener: dever.system.Listener,
|
|
limits: Limits
|
|
) () {
|
|
dever.system.http_serve(route, listener, limits)
|
|
}
|
|
|
|
# 单次请求,无连接池或重试;address 为数字 IP,Host 由请求头指定。
|
|
public send(address: Text, port: Int, request: Request, limits: Limits) (
|
|
response: Response
|
|
) {
|
|
response = read_response(dever.system.http_send(address, port, request, limits))
|
|
}
|
|
|
|
read_response(result: ResponseResult.Read(response)) (value: Response) {
|
|
value = response
|
|
}
|
|
|
|
read_response(result: ResponseResult.Failed(message)) (value: Response) {
|
|
fail(ResponseResult.Failed(message))
|
|
}
|
|
|
|
# handler 可发送完整正文、逐块写入、SSE,或升级 WebSocket;返回即结束会话。
|
|
public serve_live(
|
|
route: handler(request: Request, reply: dever.system.HttpReply) (),
|
|
listener: dever.system.Listener,
|
|
limits: Limits,
|
|
live: LiveLimits
|
|
) () {
|
|
dever.system.http_serve_live(route, listener, limits, live)
|
|
}
|
|
|
|
public respond(reply: dever.system.HttpReply, response: Response) () {
|
|
wrote(dever.system.http_respond(reply, response))
|
|
}
|
|
|
|
public start(reply: dever.system.HttpReply, status: Int, headers: List<Header>) () {
|
|
wrote(dever.system.http_start(reply, status, headers))
|
|
}
|
|
|
|
public write(reply: dever.system.HttpReply, bytes: Bytes) () {
|
|
wrote(dever.system.http_write(reply, bytes))
|
|
}
|
|
|
|
public finish(reply: dever.system.HttpReply) () {
|
|
closed(dever.system.http_finish(reply))
|
|
}
|
|
|
|
wrote(result: dever.io.WriteResult.Done) () {}
|
|
|
|
wrote(result: dever.io.WriteResult.Failed(message)) () {
|
|
fail(dever.io.WriteResult.Failed(message))
|
|
}
|
|
|
|
closed(result: dever.io.CloseResult.Closed) () {}
|
|
|
|
closed(result: dever.io.CloseResult.Failed(message)) () {
|
|
fail(dever.io.CloseResult.Failed(message))
|
|
}
|