silk.http.server.
The server side of one HTTP/1.0 or HTTP/1.1 connection, with streaming bodies and fixed limits.
When to use#
Use this module to serve HTTP over a byte duplex: a socket from silk.net.socket_native, or a
MemoryByteDuplex in tests. silk.http.server_native accepts sockets and calls
withConnection for you.
Call
withConnectionwith the transport,Limits, and aConnectionHandler.In the handler, call
withRequestfor each request. It returnsNonewhen the peer closes between requests.In the request callback, read the body with
readSome, then answer withrespond,reject,withUpgrade, orwithTunnel.In the
respondcallback, write the body withResponseWriter.writeAll, then callResponseWriter.finish.
Details#
The connection serves one request at a time. The request, the body decoder, the response writer,
and an upgraded channel are lent to callbacks, and cannot escape them. Connection.phase
tells what the connection can do next.
The server adds the Connection field. It closes the connection after a response if:
The
ReusePolicyor the peer asks for it.The request body was not read to its end.
The response body ends at close.
The request count reached
maxRequestsPerConnection.The request is HTTP/1.0, and it is not a keep-alive request with
Http10KeepAlive.
For Expect: 100-continue, the first readSome or discardRemaining sends 100 Continue
first, unless maxInformationalResponses is 0: then it reads the body without one. Another
expectation makes Request.expectationRejected true.
An HTTP/1.0 request can be answered with an HTTP/1.0 or an HTTP/1.1 response head, as RFC 9110 allows; the response is not chunked, and the connection closes after it unless it is kept alive.
A request that the server cannot read gets a bare response with no body before the error is
returned and the connection closes: 400 for a malformed head or body framing, 413 for a body over
the limits, 414 for a target over maxTargetBytes, 431 for header fields over the limits, 501
for a transfer coding other than chunked, and 505 for a version other than HTTP/1.0 or HTTP/1.1.
Nothing is sent when the input ends early.
Errors#
ServerError keeps the cause from the lower layer: the head parser, the body framing, the
buffer, or the header values. Most errors set the phase to Failed.
Gotchas#
When the scope ends, the connection closes at once. It does not flush or drain. Call
finishConnectionfor a graceful close.If a
respondcallback returns withoutResponseWriter.finish, or fails, the connection is closed after the request.A request callback that returns without a response closes the connection.
Examples#
Answer one request#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.io.buffered_input { BufferError }
import silk.io.byte_duplex { ByteDuplex }
import silk.collections.bytes { Bytes }
import silk.core.effect { Effect }
import silk.http.message { Header, ResponseHead, Status, ValueError, Version }
import silk.http.body { Limits as BodyLimits, TrailerPolicy }
import silk.http.head { Limits as HeadLimits }
import silk.http.headers { Headers, Limits as ValueLimits }
import silk.http.server {
BodyMode,
Connection,
ConnectionHandler,
Limits,
Request,
ResponseWriter,
ReusePolicy,
ServerError,
respond,
withConnection,
withRequest,
}
import silk.collections.list { List }
import silk.io.memory_byte_duplex {
MemoryByteDuplex,
MemoryReadEvent,
MemoryWriteAction,
MemoryWriteEvent
}
import silk.system.monotonic_clock { MonotonicClock }
import silk.core.option { Option }
import silk.core.result { Result }
import silk.system.system_clock { Instant, SystemClock }
import silk.num.u64
import silk.num.usize
struct FixedClock {}
impl MonotonicClock for FixedClock {
effect fn now(self: &mut Self) -> Instant {
return SystemClock.make(0, 0)
}
effect fn getResolution(self: &mut Self) -> u64 {
return u64.toU64(1)
}
effect fn waitUntil(self: &mut Self, when: Instant) -> () {
drop when
return ()
}
effect fn waitFor(self: &mut Self, duration: u64) -> () {
drop duration
return ()
}
}
fn valueLimits() -> ValueLimits {
return ValueLimits {
maxMethodBytes: 32,
maxTargetBytes: 128,
maxNameBytes: 64,
maxValueBytes: 256,
maxFields: 12,
maxFieldBytes: 512,
maxOwnedBytes: 2048,
}
}
fn limits() -> Limits {
return Limits {
head: HeadLimits {
maxHeadBytes: 1024,
maxStartLineBytes: 256,
maxFieldLineBytes: 256,
maxOwnedBytes: 2048,
values: valueLimits(),
},
body: BodyLimits {
maxWireBytes: 1024,
maxPayloadBytes: 512,
maxChunkBytes: 64,
maxChunks: 8,
maxChunkLineBytes: 64,
maxExtensionBytes: 128,
maxTrailerBytes: 256,
maxTrailerFields: 4,
maxOwnedBytes: 2048,
trailerValues: valueLimits(),
},
values: valueLimits(),
readCapacity: 256,
writeCapacity: 256,
maxRequestsPerConnection: 1,
maxInformationalResponses: 2,
maxDiscardWireBytes: u64.toU64(256),
shutdownDrainBytes: 16,
}
}
// Writes the body and ends the response with no trailers.
effect<'call> fn writeHello<
'call,
'writerView: 'call,
'requestView: 'writerView,
'connectionView: 'requestView,
'transportView: 'connectionView,
>(
writer: &'call mut ResponseWriter<
'writerView,
'requestView,
'connectionView,
'transportView,
MemoryByteDuplex
>,
) -> i32
! ServerError
? &mut MonotonicClock {
let progress = run ResponseWriter.writeAll(&mut writer.*, b"Hello", Option<Instant>.none())
if progress.consumed != 5 {
return 1
}
let entries: [Header<'static>; 0] = []
let trailers = match move Headers.make(&entries, valueLimits()) {
Result.Success { value } => value
Result.Failure { error } => {
fail ServerError.Value { error: move error }
}
}
run ResponseWriter.finish(&mut writer.*, &trailers, Option<Instant>.none())
return 0
}
// Answers one request with 200 and a five-byte body.
effect<'call> fn handleRequest<
'call,
'requestView: 'call,
'connectionView: 'requestView,
'transportView: 'connectionView,
>(
request: &'call mut Request<'requestView, 'connectionView, 'transportView, MemoryByteDuplex>,
) -> i32
! ServerError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock {
let length = match move Header.make("Content-Length", b"5", valueLimits()) {
Result.Success { value } => value
Result.Failure { error: _ } => {
return 1
}
}
let entries: [Header<'static>; 1] = [length]
let headers = match move Headers.make(&entries, valueLimits()) {
Result.Success { value } => value
Result.Failure { error: _ } => {
return 1
}
}
let status = match move Status.fromCode(200) {
Result.Success { value } => value
Result.Failure { error: _ } => {
return 1
}
}
let response = match move ResponseHead.make(
Version.Http11,
status,
Option<&'static [u8]>.some(b"OK"),
headers,
valueLimits(),
) {
Result.Success { value } => move value
Result.Failure { error: _ } => {
return 1
}
}
return run respond(
move request,
&response,
BodyMode.ContentLength { length: u64.toU64(5) },
ReusePolicy.CloseAfterResponse,
TrailerPolicy.defaultPolicy(),
Option<Instant>.none(),
writeHello,
)
}
struct HelloHandler {}
impl ConnectionHandler<
MemoryByteDuplex,
i32,
ServerError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock
> for HelloHandler {
effect<'call> fn handle<'call, 'connection: 'call, 'transport: 'connection>(
handler: Self,
connection: &'call mut Connection<'connection, 'transport, MemoryByteDuplex>,
) -> i32
! ServerError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock where
&'transport mut MemoryByteDuplex provides &ByteDuplex from &mut ByteDuplex
| &mut MonotonicClock {
drop handler
// `None` means that the peer closed before a request.
return match run withRequest(&mut connection.*, Option<Instant>.none(), handleRequest) {
Option.Some { value } => value
Option.None => 1
}
}
}
fn equal(left: &[u8], right: &[u8]) -> bool {
if left.length != right.length {
return false
}
let mut index = usize.ZERO
while index < left.length {
if left[index] != right[index] {
return false
}
index = index + usize.ONE
}
return true
}
effect fn program() -> i32
! ServerError | BufferError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock {
// A peer that sends one GET request, then ends.
let input = run Bytes.copy(b"GET / HTTP/1.1\r\nHost: example.test\r\n\r\n")
let mut reads = List<MemoryReadEvent>.make()
run List.append(
&mut reads,
MemoryReadEvent.Data { readyAt: SystemClock.make(0, 0), bytes: move input }
)
run List.append(&mut reads, MemoryReadEvent.End { readyAt: SystemClock.make(0, 0) })
let mut writes = List<MemoryWriteEvent>.make()
run List.append(
&mut writes,
MemoryWriteEvent {
readyAt: SystemClock.make(0, 0),
action: MemoryWriteAction.Accept { count: 256 }
},
)
let mut transport = run MemoryByteDuplex.make(
move reads,
move writes,
256,
64,
Option<i32>.none()
)
let code = run withConnection(&mut transport, limits(), HelloHandler {})
if code != 0 {
return code
}
let expected = b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\nConnection: close\r\n\r\nHello"
if !equal(transport.outbound(), expected) {
return 1
}
return 0
}
effect fn failed(error: ServerError | BufferError | OutOfMemoryError) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
let mut allocator = Allocator.systemAllocatorProvider()
let mut clock = FixedClock {}
return run Effect.catchAll(program(), failed) |> Effect.provideMut<MonotonicClock>(&mut clock)
|> Effect.provideMut<Allocator>(&mut allocator)
}Import as Connection with import silk.http.server { Connection }.
Public declarations: 22.
ConnectionPhase#
pub enum ConnectionPhaseThe state of a server connection. Each operation is allowed only in some phases.
Ready#
ReadywithRequest can read the next request.
RequestActive#
RequestActiveA request is active. Read its body and select a response.
Responding#
RespondingA ResponseWriter is writing the response.
Closing#
ClosingThe connection closes after this response. No more requests are read.
Upgraded#
UpgradedThe connection was given to another protocol, after an upgrade or a tunnel. HTTP operations fail.
Closed#
ClosedThe connection is done. No more I/O is allowed.
Failed#
FailedA protocol or transport error occurred. No more I/O is allowed.
Implementation Debug for ConnectionPhase#
impl Debug for ConnectionPhaseOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Ready.
BodyMode#
pub union BodyModeHow the response body is framed.
NoBody#
NoBodyNo body. Use it for HEAD, 204, and 304 responses too.
ContentLength#
ContentLengthA body of exactly length bytes. The head must have the same Content-Length.
Field length#
pub length: u64The number of body bytes. ResponseWriter.finish fails if fewer were written.
Chunked#
ChunkedHTTP/1.1 chunked framing. Trailers are allowed.
CloseDelimited#
CloseDelimitedThe body ends when the connection closes. The connection is not reused.
Implementation Copy for BodyMode#
impl Copy for BodyModeReusePolicy#
pub enum ReusePolicyWhether to keep the connection open after the response. A policy never keeps a connection whose request was not read to the end.
Automatic#
AutomaticKeeps an HTTP/1.1 connection open if both messages are complete and the peer did not ask to close.
CloseAfterResponse#
CloseAfterResponseCloses the connection after this response.
Http10KeepAlive#
Http10KeepAliveLike Automatic, and also keeps an HTTP/1.0 connection open if the peer sent Connection:
keep-alive.
Limits#
pub struct LimitsThe limits of a server connection. withConnection checks them with validateLimits.
Field head#
pub head: HeadLimitsThe limits for parsing request heads and checking response heads.
Field body#
pub body: BodyLimitsThe limits for body framing, size, trailers, and decoder memory.
Field values#
pub values: HeaderLimitsThe limits for response values, including the Connection field that the server adds.
Field readCapacity#
pub readCapacity: usizeThe size of the input buffer. It is 1 through MAX_CAPACITY of silk.io.buffered_input.
Field writeCapacity#
pub writeCapacity: usizeThe size of the output buffer. It is 1 through MAX_CAPACITY of silk.io.buffered_input.
Field maxRequestsPerConnection#
pub maxRequestsPerConnection: usizeThe maximum number of requests on one connection. With zero, no request is read.
Field maxInformationalResponses#
pub maxInformationalResponses: usizeThe maximum number of 1xx responses for one request, including an automatic 100 Continue.
Field maxDiscardWireBytes#
pub maxDiscardWireBytes: u64The maximum number of bytes that one discardRemaining call reads and drops.
Field shutdownDrainBytes#
pub shutdownDrainBytes: usizeThe maximum number of input bytes that finishConnection reads and drops.
Implementation Copy for Limits#
impl Copy for LimitsServerLimitKind#
pub enum ServerLimitKindA limit of the server, separate from the parser and framing limits.
InformationalResponses#
InformationalResponsesThe number of 1xx responses for one request.
Implementation Debug for ServerLimitKind#
impl Debug for ServerLimitKindOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as InformationalResponses.
ServerError#
pub union ServerErrorThe error of a server operation, with its lower-level cause: the head parser, the body framing,
the buffer, or the header values. Most errors set the phase to Failed.
Head#
HeadA request head or a response head is not valid.
Field error#
pub error: ParseErrorThe parser error.
Body#
BodyA request body or a response body broke its framing.
Field error#
pub error: BodyErrorThe framing error, with the progress before it.
Buffer#
BufferA buffer or transport operation failed.
Field error#
pub error: BufferErrorThe buffer error, with the transport progress.
Output#
OutputOutput failed while a response body was written. Some bytes were sent.
Field error#
pub error: BufferErrorThe buffer error.
Field progress#
pub progress: WriteProgressThe bytes that were accepted before the error.
Value#
ValueA response value or header is not valid.
Field error#
pub error: ValueErrorThe value error.
LimitExceeded#
LimitExceededAn operation went over a server limit.
Field limit#
pub limit: ServerLimitKindThe limit.
Field allowed#
pub allowed: u64The value of the limit.
Field attempted#
pub attempted: u64The count that the operation tried to reach.
SizeOverflow#
SizeOverflowA count or size does not fit in its type.
UnsupportedExpectation#
UnsupportedExpectationThe request has an Expect value other than 100-continue, so its body cannot be read.
InvalidBodyMode#
InvalidBodyModeThe body mode or the response head does not fit the request or the status.
InvalidState#
InvalidStateThe operation is not allowed in the current phase.
Field phase#
pub phase: ConnectionPhaseThe current phase.
UpgradeRejected#
UpgradeRejectedThe request or the response does not allow this upgrade. See withUpgrade.
TunnelRejected#
TunnelRejectedThe request or the response does not allow a tunnel. See withTunnel.
TruncatedHead#
TruncatedHeadThe input ended in the middle of a request head.
Implementation Debug for ServerError#
impl Debug for ServerErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as Head { ... }.
WriteProgress#
pub struct WriteProgressThe progress of one ResponseWriter call.
Field consumed#
pub consumed: usizeThe number of body bytes from input that this call accepted.
Field buffered#
pub buffered: usizeThe number of framed bytes that this call put in the output buffer.
Field totalPayload#
pub totalPayload: u64The total body bytes of the response so far.
Field totalWire#
pub totalWire: u64The total framed body bytes of the response so far, with chunk framing.
Implementation Copy for WriteProgress#
impl Copy for WriteProgressImplementation Debug for WriteProgress#
impl Debug for WriteProgressOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the fields, as WriteProgress { consumed: ..., buffered: ..., ... }.
Connection#
pub struct Connection<'connection, 'transport, P>A server connection. withConnection lends it to a ConnectionHandler.
Details#
The connection serves one request at a time. In the handler, call withRequest for each
request, read the body with readSome, then answer with respond, reject,
withUpgrade, or withTunnel. The request, the body decoder, the response writer, and an
upgraded channel are lent to callbacks, and cannot escape them. Connection.phase tells what
the connection can do next.
The server adds the Connection field. It closes the connection after a response if the
ReusePolicy or the peer asks for it, the request body was not read to its end, the response
body ends at close, the request count reached maxRequestsPerConnection, or the request is
HTTP/1.0 and not a keep-alive request with Http10KeepAlive.
Gotchas#
When the scope ends, the connection closes at once. It does not flush or drain. Call
finishConnection for a graceful close. A request callback that returns without a response
closes the connection.
Implementation Connection<'connection, 'transport, P>#
impl<'connection, 'transport, P> Connection<'connection, 'transport, P>Method phase#
pub fn phase(self: &Self) -> ConnectionPhaseReturns the current phase.
Method requests#
pub fn requests(self: &Self) -> usizeReturns the number of requests that were read on this connection.
Method unread#
pub fn unread(self: &Self) -> usizeReturns the number of bytes in the input buffer that were not read yet.
Request#
pub struct Request<'request, 'connection, 'transport, P>The active request. withRequest lends it to a callback.
Implementation Request<'request, 'connection, 'transport, P>#
impl<'request, 'connection, 'transport, P> Request<'request, 'connection, 'transport, P>Method head#
pub effect fn head<'head>(self: &'head Self) -> RequestHead<'head> ! ServerErrorReturns the parsed head of the request.
Errors#
InvalidState if the request is no longer active.
Method bodyComplete#
pub effect fn bodyComplete(self: &Self) -> bool ! ServerErrorReturns whether the request body was read to its end.
Errors#
InvalidState if the request is no longer active.
Method expectationRejected#
pub effect fn expectationRejected(self: &Self) -> bool ! ServerErrorReturns whether the request has an Expect value other than 100-continue.
If it is true, the body cannot be read. Answer with reject, for example with 417.
Errors#
InvalidState if the request is no longer active.
ResponseWriter#
pub struct ResponseWriter<'writer, 'request, 'connection, 'transport, P>Writes the body of a final response. respond lends it to a callback.
Gotchas#
Call finish after the body. If the callback returns without it, or fails, the connection is
closed after the request.
ConnectionHandler#
pub interface ConnectionHandler<P, A, E, ?R>The code that serves one connection. withConnection lends the connection to it. In it, call
withRequest for each request. When it returns or fails, the transport is closed at once.
Operation handle#
effect<'call> fn handle<'call, 'connection: 'call, 'transport: 'connection>(
handler: Self,
connection: &'call mut Connection<'connection, 'transport, P>,
) -> A ! E ? R
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockServes connection. The connection cannot escape this call.
validateLimits#
pub fn validateLimits(limits: &Limits) -> Result<(), ServerError>Checks the buffer sizes of limits. It does not allocate or do I/O.
Errors#
Buffer with InvalidCapacity if readCapacity or writeCapacity is zero or too large.
withConnection#
pub effect<'env> fn withConnection<
'env,
A,
E,
?CallbackRequirements,
P,
H: ConnectionHandler<P, A, E ? CallbackRequirements> + 'env,
>(
transport: &'env mut P,
limits: Limits,
handler: H,
) -> A
! E | ServerError | BufferError | OutOfMemoryError
? CallbackRequirements | &mut Allocator
where &'env mut P provides &ByteDuplex from &mut ByteDuplex,
&'env mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock,
CallbackRequirements in Without<CallbackRequirements, ByteDuplex>Serves one connection over transport with handler, and closes it after.
Details#
It allocates the parsers and the buffers, then calls the handler. When the handler returns or fails, the transport is closed at once.
Errors#
ServerErroriflimitsis not valid.OutOfMemoryErrorif the parsers or buffers cannot be allocated.The error of the handler.
Gotchas#
When the handler returns, the connection closes at once. It does not flush or drain. Call
finishConnection in the handler for a graceful close.
withRequest#
pub effect fn withRequest<
'request,
'connection: 'request,
'transport: 'connection,
'callback,
A,
E,
?CallbackRequirements,
P,
>(
connection: &'request mut Connection<'connection, 'transport, P>,
deadline: Option<Instant>,
callback: for<'call, 'requestView: 'call, 'connectionView: 'requestView, 'transportView: 'connectionView> once fn<'callback>(
&'call mut Request<'requestView, 'connectionView, 'transportView, P>,
) -> once Effect<'call; A ! E ? CallbackRequirements>,
) -> Option<A>
! E | ServerError | OutOfMemoryError
? CallbackRequirements | &mut Allocator | &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockReads the next request head, and lends the request to callback.
Details#
It returns None, and calls nothing, when the peer closes before a new request, or when
maxRequestsPerConnection is reached. If the callback returns without a complete response, the
connection is set to close.
Errors#
InvalidStateif the phase is notReady.Headif the head is not valid, andTruncatedHeadif the input ends in the head.Bodyif the body framing of the request is not valid.
Before a Head or Body error, the server sends a bare 4xx or 5xx response. See the module.
The error of the callback.
readSome#
pub effect fn readSome<'request, 'connection, 'transport, P>(
request: &mut Request<'request, 'connection, 'transport, P>,
output: &mut [u8],
deadline: Option<Instant>,
) -> usize
! ServerError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockReads the next bytes of the request body into the start of output.
Details#
It returns at least one byte, or zero at the end of the body. If the request has Expect:
100-continue, the first call sends 100 Continue.
Errors#
UnsupportedExpectationifRequest.expectationRejectedis true.Bodyif the body breaks its framing or a limit, after a bare 400 or 413 response.InvalidStateif the request is no longer active.
discardRemaining#
pub effect fn discardRemaining<'request, 'connection, 'transport, P>(
request: &mut Request<'request, 'connection, 'transport, P>,
maxWireBytes: u64,
deadline: Option<Instant>,
) -> ()
! ServerError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockReads and drops the rest of the request body, so that the connection can be reused.
Details#
It reads at most the smaller of maxWireBytes and limits.maxDiscardWireBytes. If the body
needs Expect: 100-continue, it sends 100 Continue first.
Errors#
BodywithDiscardLimitif the body is longer than the limit. The phase becomesFailed.UnsupportedExpectationifRequest.expectationRejectedis true.
finishConnection#
pub effect fn finishConnection<'connection, 'transport, P>(
connection: &mut Connection<'connection, 'transport, P>,
maxDrainBytes: usize,
deadline: Instant,
) -> ()
! ServerError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockCloses the connection gracefully.
Details#
It flushes the output and shuts down writes. Then it reads and drops at most the smaller of
maxDrainBytes and limits.shutdownDrainBytes, so that the peer gets the response before the
close. The phase becomes Closed.
Errors#
InvalidStateif the phase is notReady,Closing, orUpgraded.Bufferif the flush, the shutdown, or the drain fails.
sendInformational#
pub effect fn sendInformational<'request, 'connection, 'transport, 'value, P>(
request: &mut Request<'request, 'connection, 'transport, P>,
head: &ValueResponseHead<'value>,
deadline: Option<Instant>,
) -> ()
! ServerError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends a 1xx response, such as 103 Early Hints, and flushes it.
Errors#
InvalidStateif the status is not 1xx, is 101, has another version than the request, or is a second 100.InvalidBodyModeif the head hasContent-Length,Transfer-Encoding,Trailer, orConnection.LimitExceededifmaxInformationalResponsesis reached.
respond#
pub effect fn respond<
'writer,
'request: 'writer,
'connection: 'request,
'transport: 'connection,
'value: 'writer,
'names: 'request,
'callback,
A,
E,
?CallbackRequirements,
P,
>(
request: &'writer mut Request<'request, 'connection, 'transport, P>,
head: &ValueResponseHead<'value>,
mode: BodyMode,
reuse: ReusePolicy,
trailerPolicy: TrailerPolicy<'names>,
deadline: Option<Instant>,
callback: for<'call, 'writerView: 'call, 'requestView: 'writerView, 'connectionView: 'requestView, 'transportView: 'connectionView> once fn<'callback>(
&'call mut ResponseWriter<'writerView, 'requestView, 'connectionView, 'transportView, P>,
) -> once Effect<'call; A ! E ? CallbackRequirements>,
) -> A
! E | ServerError | OutOfMemoryError
? CallbackRequirements | &mut Allocator | &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends the head of the final response, and lends a ResponseWriter to callback for the body.
Details#
The server adds Connection: close or keep-alive as needed. The callback writes the body and
calls ResponseWriter.finish. If it does not, or fails, the connection closes after the
request.
Errors#
InvalidBodyModeif the status is less than 200, the version is neither the version of the request nor HTTP/1.1,modeisChunkedfor an HTTP/1.0 request, ormodedoes not fit the head and the status.InvalidStateif the request is not active.The error of the callback.
reject#
pub effect fn reject<
'loan,
'request: 'loan,
'connection: 'request,
'transport: 'connection,
'value,
P,
>(
request: &'loan mut Request<'request, 'connection, 'transport, P>,
head: &ValueResponseHead<'value>,
deadline: Option<Instant>,
) -> ()
! ServerError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends a final response with no body, and closes the connection after it.
It does not read the rest of the request body. Use it for errors such as 400, 413, or 417.
Errors#
InvalidBodyMode if the status is less than 200, or the version is neither the version of the
request nor HTTP/1.1.
withUpgrade#
pub effect fn withUpgrade<
'loan,
'request: 'loan,
'connection: 'request,
'transport: 'connection,
'value: 'loan,
'callback,
A,
E,
?CallbackRequirements,
P,
>(
request: &'loan mut Request<'request, 'connection, 'transport, P>,
selectedProtocol: string,
response: &ValueResponseHead<'value>,
deadline: Option<Instant>,
callback: for<'call, 'transportView: 'call> once fn<'callback>(
&'call mut BufferedDuplex<'transportView, P>,
) -> once Effect<'call; A ! E ? CallbackRequirements>,
) -> A
! E | ServerError | OutOfMemoryError
? CallbackRequirements | &mut Allocator | &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends a 101 response, and lends the buffered channel to callback for the new protocol.
Details#
The channel keeps any bytes that the peer sent after the request head. After this call, the
phase is Upgraded, and HTTP operations fail.
Errors#
UpgradeRejected if one of these is false:
The request has no body,
Connection: upgrade, andselectedProtocolinUpgrade.The response is 101, has the same version, has
selectedProtocolinUpgrade, and has no body fields.
withTunnel#
pub effect fn withTunnel<
'loan,
'request: 'loan,
'connection: 'request,
'transport: 'connection,
'value: 'loan,
'callback,
A,
E,
?CallbackRequirements,
P,
>(
request: &'loan mut Request<'request, 'connection, 'transport, P>,
response: &ValueResponseHead<'value>,
deadline: Option<Instant>,
callback: for<'call, 'transportView: 'call> once fn<'callback>(
&'call mut BufferedDuplex<'transportView, P>,
) -> once Effect<'call; A ! E ? CallbackRequirements>,
) -> A
! E | ServerError | OutOfMemoryError
? CallbackRequirements | &mut Allocator | &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends a 2xx response to CONNECT, and lends the buffered channel to callback for the tunnel.
Details#
The channel keeps any bytes that the peer sent after the request head. After this call, the
phase is Upgraded.
Errors#
TunnelRejected if the method is not CONNECT, the request has a body, the status is not 2xx,
the version is not the same, or the response has body fields.
Implementation ResponseWriter<'writer, 'request, 'connection, 'transport, P>#
impl<'writer, 'request, 'connection, 'transport, P>
ResponseWriter<'writer, 'request, 'connection, 'transport, P>Method writeSome#
pub effect fn writeSome(
self: &mut Self,
input: &[u8],
deadline: Option<Instant>,
) -> WriteProgress
! ServerError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockWrites a prefix of input to the body, and returns the progress.
It accepts at least one byte unless input is empty.
Errors#
Bodyif the bytes go over the declaredContentLength.Outputif the transport fails. The progress tells what was sent.InvalidStateif the response is finished.
Method writeAll#
pub effect fn writeAll(
self: &mut Self,
input: &[u8],
deadline: Option<Instant>,
) -> WriteProgress
! ServerError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockWrites all of input to the body, and returns the progress.
Errors#
As ResponseWriter.writeSome. Output includes the bytes of earlier steps of this call.
Method finish#
pub effect fn finish<'value>(
self: &mut Self,
trailers: &Headers<'value>,
deadline: Option<Instant>,
) -> ()
! ServerError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockEnds the body, writes trailers, and flushes the response.
Call it one time. Trailers are sent only with Chunked. For other modes, give empty headers.
Errors#
Bodyif aContentLengthbody is short, or the trailers are not allowed.OutputorBufferif the transport fails.InvalidStateif the response is already finished.
Category: HTTP.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.