pub struct ServerConn { /* private fields */ }Expand description
The server side of one HTTP/1.1 connection: a sans-IO state machine.
The connection owns a bounded input buffer. The caller moves bytes
between it and the socket: input in through feed (or
read_buf + commit to read straight
into the buffer), events out through poll, responses out
through respond into a caller-owned Vec<u8>.
Requests are handled one at a time, in order. Keep-alive is automatic:
after a response is finished the next request (possibly already buffered,
when the client pipelines) is parsed on the next poll. A connection
that must close (the client asked, HTTP/1.0 without keep-alive, the
response was sent before the request body was read, or a parse error)
reports ServerEvent::Closed once its last response is written.
Steady state allocates nothing: the input buffer and the field index are reused across requests.
§Examples
use http_net::{Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let mut out = Vec::new();
// Two pipelined requests in one read.
let _ = conn.feed(b"GET /a HTTP/1.1\r\nHost: x\r\n\r\nGET /b HTTP/1.1\r\nHost: x\r\n\r\n");
let mut paths = Vec::new();
loop {
match conn.poll().unwrap() {
ServerEvent::Request(req) => paths.push(req.path().to_string()),
ServerEvent::RequestEnd => conn.respond(&Response::text(200, "ok"), &mut out).unwrap(),
ServerEvent::NeedInput => break,
other => panic!("{other:?}"),
}
}
assert_eq!(paths, ["/a", "/b"]);Implementations§
Source§impl ServerConn
impl ServerConn
Sourcepub fn with_limits(limits: Limits) -> Self
pub fn with_limits(limits: Limits) -> Self
A connection enforcing limits.
§Examples
use http_net::{HttpError, Limits, ServerConn};
let mut conn = ServerConn::with_limits(Limits::new().with_max_body(4));
let _ = conn.feed(b"POST / HTTP/1.1\r\nHost: a\r\nContent-Length: 5\r\n\r\n");
assert_eq!(conn.poll().unwrap_err(), HttpError::BodyTooLarge);Sourcepub fn with_buffer(storage: Vec<u8>, limits: Limits) -> Self
pub fn with_buffer(storage: Vec<u8>, limits: Limits) -> Self
A connection enforcing limits that reads into storage, for
drivers that pool buffers: its capacity is used up to
Limits::buffer_capacity, its contents are ignored. Give it back
with into_buffer.
§Examples
use http_net::{Limits, ServerConn, ServerEvent};
let pooled: Vec<u8> = Vec::with_capacity(8192);
let mut conn = ServerConn::with_buffer(pooled, Limits::new());
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
assert!(matches!(conn.poll().unwrap(), ServerEvent::Request(_)));
let back = conn.into_buffer();
assert!(back.capacity() >= 8192);Sourcepub fn limits(&self) -> &Limits
pub fn limits(&self) -> &Limits
The limits this connection enforces.
§Examples
assert_eq!(http_net::ServerConn::new().limits(), &http_net::Limits::new());Sourcepub fn read_buf(&mut self) -> &mut [u8] ⓘ
pub fn read_buf(&mut self) -> &mut [u8] ⓘ
Spare space at the end of the input buffer, for reading from a
socket without an intermediate copy. Follow with
commit. It is empty only when the buffer is full of
input the parser has not been asked to process yet; poll first.
§Examples
let mut conn = http_net::ServerConn::new();
let spare = conn.read_buf();
let msg = b"GET / HTTP/1.1\r\nHost: a\r\n\r\n";
spare[..msg.len()].copy_from_slice(msg);
conn.commit(msg.len());
assert!(matches!(conn.poll(), Ok(http_net::ServerEvent::Request(_))));Sourcepub fn commit(&mut self, n: usize)
pub fn commit(&mut self, n: usize)
Records that n bytes were written into read_buf.
An n larger than the slice read_buf returned is clamped to its
length: committing bytes that were not written would hand stale
buffer contents to the parser.
§Examples
let mut conn = http_net::ServerConn::new();
conn.read_buf()[0] = b'G';
conn.commit(1);
assert!(matches!(conn.poll(), Ok(http_net::ServerEvent::NeedInput)));Sourcepub fn feed_eof(&mut self)
pub fn feed_eof(&mut self)
Records that the peer closed its sending side. A connection idle
between requests then reports ServerEvent::Closed; one in the
middle of a request reports HttpError::UnexpectedEof.
§Examples
let mut conn = http_net::ServerConn::new();
conn.feed_eof();
assert!(matches!(conn.poll(), Ok(http_net::ServerEvent::Closed)));Sourcepub fn poll(&mut self) -> Result<ServerEvent<'_>, HttpError>
pub fn poll(&mut self) -> Result<ServerEvent<'_>, HttpError>
Advances the parser and reports what happened. Call it until it
returns ServerEvent::NeedInput, ServerEvent::AwaitingResponse,
ServerEvent::Upgraded, or ServerEvent::Closed.
§Errors
Any HttpError parse error. The connection is then finished: send
one error response (see HttpError::status) with
respond, flush, and close. It is written as an
answer to a GET, or, when the failure came after a HEAD request
line, to a HEAD, without content.
§Examples
use http_net::{HttpError, ServerConn};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n folded\r\n\r\n");
assert_eq!(conn.poll().unwrap_err(), HttpError::ObsFold);Sourcepub fn request(&self) -> Option<RequestHead<'_>>
pub fn request(&self) -> Option<RequestHead<'_>>
The current request’s head, from its arrival until the next request begins (still available after an upgrade).
§Examples
use http_net::{ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"PUT /f HTTP/1.1\r\nHost: a\r\nContent-Length: 1\r\n\r\nz");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
assert_eq!(conn.request().unwrap().path(), "/f");Sourcepub fn is_upgraded(&self) -> bool
pub fn is_upgraded(&self) -> bool
Whether a 101 Switching Protocols (or a 2xx to CONNECT) was sent
and the connection now belongs to another protocol.
§Examples
assert!(!http_net::ServerConn::new().is_upgraded());Sourcepub fn remaining_input(&self) -> &[u8] ⓘ
pub fn remaining_input(&self) -> &[u8] ⓘ
Input that arrived after the last message this connection parsed:
after ServerEvent::Upgraded, the first bytes of the new protocol.
§Examples
use http_net::{Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: upgrade\r\nUpgrade: x\r\n\r\n\x81\x00");
assert!(matches!(conn.poll().unwrap(), ServerEvent::Request(_)));
assert!(matches!(conn.poll().unwrap(), ServerEvent::RequestEnd));
conn.respond(&Response::switching_protocols("x"), &mut Vec::new()).unwrap();
assert!(matches!(conn.poll().unwrap(), ServerEvent::Upgraded));
assert_eq!(conn.remaining_input(), b"\x81\x00");Sourcepub fn respond(
&mut self,
response: &Response,
out: &mut Vec<u8>,
) -> Result<(), HttpError>
pub fn respond( &mut self, response: &Response, out: &mut Vec<u8>, ) -> Result<(), HttpError>
Writes response for the current request into out.
With a full body the response is complete. With a streamed body
(Response::chunked, Response::content_length) follow with
send_body and end_body.
After a parse error, one response may still be sent; it is marked
connection: close.
§Errors
- the first error recorded by the
Responsebuilder; HttpError::InvalidStatusfor a status outside100..=599, or a 1xx other than 101;HttpError::BodyNotAllowedfor a body on 1xx, 204, 304, 101, or a 2xx toCONNECT;HttpError::UpgradeNotOfferedfor a 101 whose protocol the request’sUpgradefield did not offer;HttpError::InvalidStatewhen there is no request to answer, a response was already started, or a 101 does not answer a complete upgrade request.
§Examples
use http_net::{Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"HEAD / HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let mut out = Vec::new();
conn.respond(&Response::text(200, "hello"), &mut out).unwrap();
// HEAD: the length is announced, the body is not sent.
assert!(out.windows(17).any(|w| w == b"content-length: 5"));
assert!(out.ends_with(b"\r\n\r\n"));Sourcepub fn respond_with_date(
&mut self,
response: &Response,
date: &HttpDate,
out: &mut Vec<u8>,
) -> Result<(), HttpError>
pub fn respond_with_date( &mut self, response: &Response, date: &HttpDate, out: &mut Vec<u8>, ) -> Result<(), HttpError>
As respond, adding date: <date> unless the
response set its own date field. Keep a
DateCache per driver thread and pass
cache.update(now): the value is reformatted once per second, not
once per response.
§Errors
As respond.
§Examples
use http_net::{DateCache, Response, ServerConn, ServerEvent};
let mut dates = DateCache::new();
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let mut out = Vec::new();
conn.respond_with_date(&Response::new(204), dates.update(784_111_777), &mut out)?;
assert!(out.windows(35).any(|w| w == b"date: Sun, 06 Nov 1994 08:49:37 GMT"));Sourcepub fn respond_head_only(
&mut self,
response: &Response,
out: &mut Vec<u8>,
) -> Result<BodyPlan, HttpError>
pub fn respond_head_only( &mut self, response: &Response, out: &mut Vec<u8>, ) -> Result<BodyPlan, HttpError>
As respond, but writes only the head: for a
full-body response the caller then sends
Response::body_bytes itself, so head and body can leave in one
vectored write (write_vectored) without the body being copied into
out. The returned BodyPlan says what follows:
BodyPlan::Raw: send the body bytes, exactly as they are, right after the head; the response already counts as sent.BodyPlan::None: nothing (an empty body,HEAD, 204, 304, a tunnel).BodyPlan::Stream: a streamed response; continue withsend_bodyandend_body.
§Errors
As respond; nothing is written on error.
§Examples
use http_net::{BodyPlan, Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET /big HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll()?, ServerEvent::RequestEnd) {}
let response = Response::new(200).body(vec![b'x'; 64 * 1024]);
let mut head = Vec::new();
let plan = conn.respond_head_only(&response, &mut head)?;
assert_eq!(plan, BodyPlan::Raw);
assert!(head.ends_with(b"content-length: 65536\r\n\r\n"));
// Send `head` and `response.body_bytes()` together, e.g. with
// `std::io::Write::write_vectored`.
assert_eq!(response.body_bytes().map(<[u8]>::len), Some(64 * 1024));Sourcepub fn send_informational(
&mut self,
interim: &Response,
out: &mut Vec<u8>,
) -> Result<(), HttpError>
pub fn send_informational( &mut self, interim: &Response, out: &mut Vec<u8>, ) -> Result<(), HttpError>
Writes an interim (1xx) response other than 100 and 101, for
example 103 Early Hints with link fields, before the final
response. It may be sent more than once, for any request method,
at any point before the final response starts (RFC 9110 section
15.2), but never to an HTTP/1.0 client. Only the status and the
fields are written; an interim response has no body and does not
change the connection.
§Errors
The first error recorded by the builder; HttpError::InvalidStatus
unless the status is in 102..=199; HttpError::BodyNotAllowed
for a body; HttpError::InterimNotAllowed for an HTTP/1.0 request
or once the final response has started; HttpError::InvalidState
when there is no request (or after a parse error, an upgrade, or the
end of the connection).
§Examples
use http_net::{Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let mut out = Vec::new();
let hints = Response::new(103).header("link", "</style.css>; rel=preload; as=style");
conn.send_informational(&hints, &mut out)?;
conn.respond(&Response::text(200, "page"), &mut out)?;
assert!(out.starts_with(b"HTTP/1.1 103 Early Hints\r\nlink: </style.css>"));Sourcepub fn set_keep_alive(&mut self, keep: bool)
pub fn set_keep_alive(&mut self, keep: bool)
Stops (false) or allows (true) keep-alive. With false the
current response, or the next one if it has not started, carries
connection: close, and the connection ends after it: the gentlest
way to shed load or to cap requests per connection. If the current
response has already been written, the connection ends after it.
true cannot keep open a connection the protocol requires to close
(the client asked, or body bytes were left unread).
§Examples
use http_net::{Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
conn.set_keep_alive(false);
let mut out = Vec::new();
conn.respond(&Response::new(204), &mut out).unwrap();
assert!(out.windows(17).any(|w| w == b"connection: close"));
assert!(matches!(conn.poll().unwrap(), ServerEvent::Closed));Sourcepub fn keep_alive(&self) -> bool
pub fn keep_alive(&self) -> bool
Whether the connection can stay open after the current exchange, as
far as is known now: keep-alive is allowed (see
set_keep_alive) and neither the request,
the response, nor an error requires a close.
§Examples
use http_net::{ServerConn, ServerEvent};
let mut conn = ServerConn::new();
assert!(conn.keep_alive());
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: close\r\n\r\n");
assert!(matches!(conn.poll().unwrap(), ServerEvent::Request(_)));
assert!(!conn.keep_alive());Sourcepub fn requests_served(&self) -> u64
pub fn requests_served(&self) -> u64
The number of responses completed on this connection (full-body
responses when written, streamed ones at end_body), so a driver can
cap requests per connection.
§Examples
use http_net::{Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
assert_eq!(conn.requests_served(), 0);
conn.respond(&Response::new(204), &mut Vec::new()).unwrap();
assert_eq!(conn.requests_served(), 1);Sourcepub fn progress(&self) -> Progress
pub fn progress(&self) -> Progress
The connection’s phase, for header-read, request, and response
deadlines. Progress::Head starts at the first byte of a request,
so idle keep-alive time (Idle) is never counted against a request.
§Examples
use http_net::{Progress, Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"POST / HTTP/1.1\r\nHost: a\r\nContent-Length: 4\r\n\r\nab");
assert!(matches!(conn.poll().unwrap(), ServerEvent::Request(_)));
assert!(matches!(conn.poll().unwrap(), ServerEvent::Body(_)));
assert!(matches!(conn.poll().unwrap(), ServerEvent::NeedInput));
assert_eq!(conn.progress(), Progress::Body);
let _ = conn.feed(b"cd");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
assert_eq!(conn.progress(), Progress::AwaitingResponse);
conn.respond(&Response::new(200).chunked(), &mut Vec::new()).unwrap();
assert_eq!(conn.progress(), Progress::WritingBody);
conn.end_body(&mut Vec::new()).unwrap();
assert_eq!(conn.progress(), Progress::Idle);Sourcepub fn set_report_trailers(&mut self, report: bool)
pub fn set_report_trailers(&mut self, report: bool)
When true, a request’s trailer fields are kept (bounded by
Limits::max_trailer_fields and Limits::max_trailer_bytes) and
reported as ServerEvent::Trailers just before
ServerEvent::RequestEnd. When false (the default) they are
validated and discarded. Trailers never change how a message is
framed either way.
§Examples
use http_net::{ServerConn, ServerEvent};
let mut conn = ServerConn::new();
conn.set_report_trailers(true);
let _ = conn.feed(b"POST / HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n2\r\nhi\r\n0\r\nDigest: sha-256=x\r\n\r\n");
let mut digest = None;
loop {
match conn.poll().unwrap() {
ServerEvent::Trailers(t) => digest = t.clone().find(|(n, _)| n.eq_ignore_ascii_case("digest")).map(|(_, v)| v.to_vec()),
ServerEvent::RequestEnd => break,
_ => {}
}
}
assert_eq!(digest.as_deref(), Some(&b"sha-256=x"[..]));Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Returns the connection to its initial state for a new socket,
keeping the buffer and field-index allocations (and the limits,
set_report_trailers, and
set_wipe settings). Everything per connection
starts over: buffered input, the request in progress, keep-alive
(allowed again), and the request count. With wiping on, the whole
buffer is zeroed first.
§Examples
use http_net::{Progress, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\nGET /next");
assert!(matches!(conn.poll().unwrap(), ServerEvent::Request(_)));
conn.reset(); // the socket closed; reuse the object for the next one
assert_eq!(conn.progress(), Progress::Idle);
assert!(conn.remaining_input().is_empty());Sourcepub fn into_buffer(self) -> Vec<u8> ⓘ
pub fn into_buffer(self) -> Vec<u8> ⓘ
Sourcepub fn shrink_idle(&mut self) -> bool
pub fn shrink_idle(&mut self) -> bool
Frees the input buffer and the field indexes while the connection is idle between requests with nothing buffered, so thousands of idle keep-alive connections cost only their struct size. Returns whether memory was released; the next input allocates again.
§Examples
use http_net::{Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
assert!(matches!(conn.poll().unwrap(), ServerEvent::Request(_)));
assert!(!conn.shrink_idle()); // a request is in progress
assert!(matches!(conn.poll().unwrap(), ServerEvent::RequestEnd));
conn.respond(&Response::new(204), &mut Vec::new()).unwrap();
assert!(matches!(conn.poll().unwrap(), ServerEvent::NeedInput));
assert!(conn.shrink_idle());Sourcepub fn set_wipe(&mut self, wipe: bool)
pub fn set_wipe(&mut self, wipe: bool)
When true, the bytes of every finished request (head, body, and
framing) are zeroed before the buffer is reused, stale copies left by
compaction are zeroed, and the whole buffer is zeroed on
reset, into_buffer, and drop,
so credentials do not linger in memory between requests. Costs a
memset of each request’s bytes (about 30 to 60 ns for 2 KiB, an
estimate). Off by default.
§Examples
let mut conn = http_net::ServerConn::new();
conn.set_wipe(true);Sourcepub fn send_continue(&mut self, out: &mut Vec<u8>) -> Result<(), HttpError>
pub fn send_continue(&mut self, out: &mut Vec<u8>) -> Result<(), HttpError>
Writes HTTP/1.1 100 Continue into out: the answer to
RequestHead::expects_continue
that tells the client to send the body.
RFC 9110 section 10.1.1 requires a server that receives
Expect: 100-continue to send either this or a final response before
waiting for the body; clients otherwise stall (curl for one second,
some indefinitely). Call it after ServerEvent::Request, once the
head has been judged acceptable.
§Errors
HttpError::InterimNotAllowed for an HTTP/1.0 request (RFC 9110
section 15.2 forbids any 1xx to an HTTP/1.0 client), once a body byte
has been read or the whole body has arrived, once a response has
started, or when 100 Continue was already sent for this request;
HttpError::InvalidState when no request is waiting for its body
(none has arrived, or the connection failed, closed, or upgraded).
§Examples
use http_net::{ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"PUT /f HTTP/1.1\r\nHost: a\r\nExpect: 100-continue\r\nContent-Length: 2\r\n\r\n");
let ServerEvent::Request(req) = conn.poll()? else { unreachable!() };
assert!(req.expects_continue());
let mut out = Vec::new();
conn.send_continue(&mut out)?;
assert_eq!(out, b"HTTP/1.1 100 Continue\r\n\r\n");Sourcepub fn send_body(
&mut self,
data: &[u8],
out: &mut Vec<u8>,
) -> Result<(), HttpError>
pub fn send_body( &mut self, data: &[u8], out: &mut Vec<u8>, ) -> Result<(), HttpError>
Writes body bytes of a streamed response into out. For a HEAD
request the bytes are dropped.
§Errors
HttpError::BodyLengthMismatch past the declared
Response::content_length; HttpError::InvalidState when no
streamed response is in progress.
§Examples
use http_net::{Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET /log HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let mut out = Vec::new();
conn.respond(&Response::new(200).chunked(), &mut out).unwrap();
conn.send_body(b"line 1\n", &mut out).unwrap();
conn.end_body(&mut out).unwrap();
assert!(out.ends_with(b"7\r\nline 1\n\r\n0\r\n\r\n"));Sourcepub fn end_body(&mut self, out: &mut Vec<u8>) -> Result<(), HttpError>
pub fn end_body(&mut self, out: &mut Vec<u8>) -> Result<(), HttpError>
Ends a streamed response body (the last chunk for chunked encoding).
§Errors
HttpError::BodyLengthMismatch when fewer bytes than the declared
length were sent; HttpError::InvalidState when no streamed
response is in progress.
§Examples
use http_net::{HttpError, Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let mut out = Vec::new();
conn.respond(&Response::new(200).content_length(3), &mut out).unwrap();
conn.send_body(b"ab", &mut out).unwrap();
assert_eq!(conn.end_body(&mut out), Err(HttpError::BodyLengthMismatch));Sourcepub fn end_body_with_trailers(
&mut self,
trailers: &[(&str, &[u8])],
out: &mut Vec<u8>,
) -> Result<(), HttpError>
pub fn end_body_with_trailers( &mut self, trailers: &[(&str, &[u8])], out: &mut Vec<u8>, ) -> Result<(), HttpError>
Ends a streamed chunked body with a trailer section: the last chunk,
then trailers as fields. Every field is validated before anything
is written.
Trailers are optional metadata a recipient may discard (RFC 9110
section 6.5), so when the body could not be chunked (an HTTP/1.0
client forced a close-delimited body) or is not sent at all (HEAD),
they are dropped with it and the call still succeeds: the handler
does not need to know which framing the client forced.
§Errors
HttpError::TrailerNotAllowed for a field RFC 9110 section 6.5.1
keeps out of trailers (framing, routing, authentication, request
modifiers, response control, content handling: content-length,
host, authorization, set-cookie, content-type, date, and
the rest of the list in docs/API.md) or for a body declared with
Response::content_length; the field errors of
Response::header; HttpError::BodyLengthMismatch and
HttpError::InvalidState as for end_body.
§Examples
use http_net::{HttpError, Response, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET /data HTTP/1.1\r\nHost: a\r\nTE: trailers\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let mut out = Vec::new();
conn.respond(&Response::new(200).chunked(), &mut out)?;
conn.send_body(b"rows", &mut out)?;
assert_eq!(
conn.end_body_with_trailers(&[("content-type", b"text/csv")], &mut out),
Err(HttpError::TrailerNotAllowed)
);
conn.end_body_with_trailers(&[("server-timing", b"db;dur=53")], &mut out)?;
assert!(out.ends_with(b"4\r\nrows\r\n0\r\nserver-timing: db;dur=53\r\n\r\n"));Source§impl ServerConn
impl ServerConn
Sourcepub fn write_head<O: Output + ?Sized>(
&mut self,
head: &ResponseHeadRef<'_>,
date: Option<&HttpDate>,
out: &mut O,
) -> Result<BodyPlan, HttpError>
pub fn write_head<O: Output + ?Sized>( &mut self, head: &ResponseHeadRef<'_>, date: Option<&HttpDate>, out: &mut O, ) -> Result<BodyPlan, HttpError>
Writes a response head described by borrowed data into any
Output and says how to send the body. Nothing is allocated; the
validation, framing fields, connection handling, and state changes
are those of respond, and the bytes are the same
as respond would write for the equivalent Response. date, when
given and the fields set no date, is written as date: <date>.
After BodyPlan::Raw write the OutgoingBody::Full bytes
yourself (for example with one vectored write of head and body); the
response then counts as complete. After BodyPlan::Stream use
send_body_into and
end_body_into (or the Vec versions).
§Errors
As respond, with the field errors of
Response::header for fields and those of
Response::switching_protocols for upgrade
(HttpError::InvalidHeaderValue when it is not a protocol token,
HttpError::UpgradeNotOffered for h2c or a protocol the request
did not offer). An upgrade on a status other than 101, or a
101 without one, is HttpError::InvalidState. Nothing is written
on error.
§Examples
use http_net::{BodyPlan, OutgoingBody, ResponseHeadRef, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET /app.js HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let body: &[u8] = b"console.log(1)";
let fields: &[(&str, &[u8])] = &[("content-type", b"text/javascript")];
let head = ResponseHeadRef::new(200, fields, OutgoingBody::Full(body.len() as u64));
let mut out = Vec::with_capacity(256);
let plan = conn.write_head(&head, None, &mut out)?;
assert_eq!(plan, BodyPlan::Raw);
assert_eq!(out, b"HTTP/1.1 200 OK\r\ncontent-length: 14\r\ncontent-type: text/javascript\r\n\r\n");
out.extend_from_slice(body); // or one vectored write of bothSourcepub fn respond_into<O: Output + ?Sized>(
&mut self,
response: &Response,
date: Option<&HttpDate>,
out: &mut O,
) -> Result<(), HttpError>
pub fn respond_into<O: Output + ?Sized>( &mut self, response: &Response, date: Option<&HttpDate>, out: &mut O, ) -> Result<(), HttpError>
respond into any Output, with an optional
date as in respond_with_date. A full
body is written after the head; a streamed one continues with
send_body_into and
end_body_into.
§Errors
As respond.
§Examples
use http_net::{Output, Response, ServerConn, ServerEvent};
/// A bounded output that refuses to grow past its capacity.
struct Slab { buf: [u8; 512], len: usize, overflow: bool }
impl Output for Slab {
fn put(&mut self, bytes: &[u8]) {
match self.buf.get_mut(self.len..self.len + bytes.len()) {
Some(dst) => {
dst.copy_from_slice(bytes);
self.len += bytes.len();
}
None => self.overflow = true, // the owner closes the connection
}
}
}
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let mut slab = Slab { buf: [0; 512], len: 0, overflow: false };
conn.respond_into(&Response::text(200, "hi"), None, &mut slab)?;
assert!(!slab.overflow);
assert!(slab.buf[..slab.len].ends_with(b"\r\n\r\nhi"));Sourcepub fn send_body_into<O: Output + ?Sized>(
&mut self,
data: &[u8],
out: &mut O,
) -> Result<(), HttpError>
pub fn send_body_into<O: Output + ?Sized>( &mut self, data: &[u8], out: &mut O, ) -> Result<(), HttpError>
§Errors
As send_body.
§Examples
use http_net::{BodyPlan, OutgoingBody, ResponseHeadRef, ServerConn, ServerEvent};
let mut conn = ServerConn::new();
let _ = conn.feed(b"GET /log HTTP/1.1\r\nHost: a\r\n\r\n");
while !matches!(conn.poll().unwrap(), ServerEvent::RequestEnd) {}
let mut out = Vec::new();
let head = ResponseHeadRef::new(200, &[], OutgoingBody::Chunked);
assert_eq!(conn.write_head(&head, None, &mut out)?, BodyPlan::Stream);
conn.send_body_into(b"line\n", &mut out)?;
conn.end_body_into(&[], &mut out)?;
assert!(out.ends_with(b"5\r\nline\n\r\n0\r\n\r\n"));