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 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 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.
§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 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 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"));