pub struct ClientConn { /* private fields */ }Expand description
The client side of one HTTP/1.1 connection: a sans-IO state machine.
One request is outstanding at a time. send_request
serializes a Request; feed and poll
parse the response. When the response allows it, the connection returns
to ClientEvent::Idle and can send the next request (keep-alive).
The response is framed with the request in mind: a HEAD request’s
response has no body whatever its headers say, a CONNECT 2xx becomes a
tunnel, and a response with neither Content-Length nor
Transfer-Encoding runs until the server closes.
§Examples
use http_net::{ClientConn, ClientEvent, Request};
let mut conn = ClientConn::new();
let mut out = Vec::new();
conn.send_request(&Request::get("/a").header("host", "h"), &mut out).unwrap();
assert_eq!(out, b"GET /a HTTP/1.1\r\nhost: h\r\n\r\n");
let _ = conn.feed(b"HTTP/1.1 204 No Content\r\n\r\n");
assert!(matches!(conn.poll().unwrap(), ClientEvent::Response(_)));
assert!(matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd));
assert!(matches!(conn.poll().unwrap(), ClientEvent::Idle));Implementations§
Source§impl ClientConn
impl ClientConn
Sourcepub fn with_limits(limits: Limits) -> Self
pub fn with_limits(limits: Limits) -> Self
A connection enforcing limits on responses.
§Examples
let conn = http_net::ClientConn::with_limits(http_net::Limits::new().with_max_body(1 << 24));
assert_eq!(conn.limits().max_body(), 1 << 24);Sourcepub fn limits(&self) -> &Limits
pub fn limits(&self) -> &Limits
The limits this connection enforces.
§Examples
assert_eq!(http_net::ClientConn::new().limits().max_headers(), 100);Sourcepub fn feed(&mut self, bytes: &[u8]) -> usize
pub fn feed(&mut self, bytes: &[u8]) -> usize
Copies as much of bytes into the input buffer as fits; returns how
many were taken (see ServerConn::feed).
§Examples
let mut conn = http_net::ClientConn::new();
assert_eq!(conn.feed(b"HTTP/1.1"), 8);Sourcepub fn feed_eof(&mut self)
pub fn feed_eof(&mut self)
Records that the server closed its sending side: ends a body that
runs until close, or reports HttpError::UnexpectedEof mid-message.
§Examples
use http_net::{ClientConn, ClientEvent, Request};
let mut conn = ClientConn::new();
conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
let _ = conn.feed(b"HTTP/1.0 200 OK\r\n\r\nall of it");
assert!(matches!(conn.poll().unwrap(), ClientEvent::Response(_)));
assert!(matches!(conn.poll().unwrap(), ClientEvent::Body(b"all of it")));
assert!(matches!(conn.poll().unwrap(), ClientEvent::NeedInput));
conn.feed_eof();
assert!(matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd));
assert!(matches!(conn.poll().unwrap(), ClientEvent::Closed));Sourcepub fn send_request(
&mut self,
request: &Request,
out: &mut Vec<u8>,
) -> Result<(), HttpError>
pub fn send_request( &mut self, request: &Request, out: &mut Vec<u8>, ) -> Result<(), HttpError>
Writes request into out and starts waiting for its response.
A full body is sent with content-length (omitted for an empty body
on methods that do not expect one); a streamed body continues with
send_body and end_body.
A request built with Request::expect_continue is sent head first:
is_waiting_for_continue is true
until the server answers 100 Continue (reported as
ClientEvent::Continue: then send the body), a final status (then
the body must not be sent and the connection closes after the
response), or the caller sends the body anyway (RFC 9110 section
10.1.1 allows it after a wait of its choosing).
§Errors
- the first error recorded by the
Requestbuilder; HttpError::MissingHostwhen the request has nohostheader;HttpError::InvalidStatewhen a request is already outstanding, the connection is closed, or anexpect_continuerequest has no streamed body (content_lengthorchunked);HttpError::UnexpectedDatawhen response bytes nobody asked for are buffered.
§Examples
use http_net::{ClientConn, HttpError, Request};
let mut conn = ClientConn::new();
let mut out = Vec::new();
assert_eq!(conn.send_request(&Request::get("/"), &mut out), Err(HttpError::MissingHost));
conn.send_request(&Request::post("/f").header("host", "a").body(&b"xyz"[..]), &mut out).unwrap();
assert_eq!(out, b"POST /f HTTP/1.1\r\nhost: a\r\ncontent-length: 3\r\n\r\nxyz");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 request.
Sending body bytes while waiting for 100 Continue ends the wait.
§Errors
HttpError::BodyLengthMismatch past the declared length;
HttpError::InvalidState when no streamed request is in progress,
or when the server answered an expect_continue request with a final
status (the body must not be sent then).
§Examples
use http_net::{ClientConn, Request};
let mut conn = ClientConn::new();
let mut out = Vec::new();
conn.send_request(&Request::post("/up").header("host", "a").chunked(), &mut out).unwrap();
conn.send_body(b"part", &mut out).unwrap();
conn.end_body(&mut out).unwrap();
assert!(out.ends_with(b"4\r\npart\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 request body.
§Errors
HttpError::BodyLengthMismatch when fewer bytes than declared were
sent; HttpError::InvalidState when no streamed request is in
progress.
§Examples
use http_net::{ClientConn, Request};
let mut conn = ClientConn::new();
let mut out = Vec::new();
conn.send_request(&Request::post("/").header("host", "a").content_length(2), &mut out).unwrap();
conn.send_body(b"ok", &mut out).unwrap();
conn.end_body(&mut out).unwrap();
assert!(out.ends_with(b"\r\n\r\nok"));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 request body with a trailer section (see
ServerConn::end_body_with_trailers
for the fields that are refused).
§Errors
HttpError::TrailerNotAllowed for a forbidden field or a body
that is not chunked; the field errors of
Request::header; otherwise as end_body.
§Examples
use http_net::{ClientConn, Request};
let mut conn = ClientConn::new();
let mut out = Vec::new();
conn.send_request(&Request::put("/f").header("host", "a").chunked(), &mut out)?;
conn.send_body(b"data", &mut out)?;
conn.end_body_with_trailers(&[("content-digest", b"sha-256=:x:")], &mut out)?;
assert!(out.ends_with(b"0\r\ncontent-digest: sha-256=:x:\r\n\r\n"));Sourcepub fn poll(&mut self) -> Result<ClientEvent<'_>, HttpError>
pub fn poll(&mut self) -> Result<ClientEvent<'_>, HttpError>
Advances the response parser and reports what happened.
§Errors
Any HttpError parse error; the connection is then closed and must
not be reused.
§Examples
use http_net::{ClientConn, HttpError, Request};
let mut conn = ClientConn::new();
conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 1\r\nContent-Length: 1\r\n\r\nx");
assert_eq!(conn.poll().unwrap_err(), HttpError::DuplicateContentLength);Sourcepub fn response(&self) -> Option<ResponseHead<'_>>
pub fn response(&self) -> Option<ResponseHead<'_>>
The current response’s head, from its arrival until the next request is sent (still available after an upgrade).
§Examples
use http_net::{ClientConn, ClientEvent, Request};
let mut conn = ClientConn::new();
conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
while !matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd) {}
assert_eq!(conn.response().unwrap().status(), 200);Sourcepub fn is_upgraded(&self) -> bool
pub fn is_upgraded(&self) -> bool
Whether the server switched protocols and the connection now belongs to another protocol.
§Examples
assert!(!http_net::ClientConn::new().is_upgraded());Sourcepub fn remaining_input(&self) -> &[u8] ⓘ
pub fn remaining_input(&self) -> &[u8] ⓘ
Input that arrived after the last message parsed: after
ClientEvent::Upgraded, the first bytes of the new protocol.
§Examples
use http_net::{ClientConn, ClientEvent, Request};
let mut conn = ClientConn::new();
conn.send_request(&Request::get("/").header("host", "a").upgrade("x"), &mut Vec::new()).unwrap();
let _ = conn.feed(b"HTTP/1.1 101 Switching Protocols\r\nConnection: upgrade\r\nUpgrade: x\r\n\r\nhi");
assert!(matches!(conn.poll().unwrap(), ClientEvent::Response(_)));
assert!(matches!(conn.poll().unwrap(), ClientEvent::Upgraded));
assert_eq!(conn.remaining_input(), b"hi");Sourcepub fn set_report_informational(&mut self, report: bool)
pub fn set_report_informational(&mut self, report: bool)
When true, each interim response other than 101 (for example
103 Early Hints) is reported as ClientEvent::Informational
before the final response; when false (the default) they are
skipped. Interim responses count against
Limits::max_interim either way.
§Examples
use http_net::{ClientConn, ClientEvent, Request};
let mut conn = ClientConn::new();
conn.set_report_informational(true);
conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
let _ = conn.feed(b"HTTP/1.1 103 Early Hints\r\nLink: </a.css>; rel=preload\r\n\r\nHTTP/1.1 204 No Content\r\n\r\n");
let ClientEvent::Informational(hints) = conn.poll()? else { panic!() };
assert_eq!(hints.status(), 103);
assert_eq!(hints.header("link"), Some(&b"</a.css>; rel=preload"[..]));
assert!(matches!(conn.poll()?, ClientEvent::Response(r) if r.status() == 204));Sourcepub fn set_report_trailers(&mut self, report: bool)
pub fn set_report_trailers(&mut self, report: bool)
When true, a response’s trailer fields are kept (bounded by the
trailer budgets of Limits) and reported as
ClientEvent::Trailers just before ClientEvent::ResponseEnd;
when false (the default) they are validated and discarded.
§Examples
use http_net::{ClientConn, ClientEvent, Request};
let mut conn = ClientConn::new();
conn.set_report_trailers(true);
conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
let _ = conn.feed(b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n2\r\nok\r\n0\r\nServer-Timing: db;dur=5\r\n\r\n");
let mut saw = false;
loop {
match conn.poll()? {
ClientEvent::Trailers(t) => saw = t.len() == 1,
ClientEvent::ResponseEnd => break,
_ => {}
}
}
assert!(saw);Sourcepub fn is_waiting_for_continue(&self) -> bool
pub fn is_waiting_for_continue(&self) -> bool
Whether a request built with
Request::expect_continue is
still waiting: no 100 Continue, no final response, and no body
bytes sent yet. A client may stop waiting on its own timer and send
the body anyway (RFC 9110 section 10.1.1).
§Examples
use http_net::{ClientConn, ClientEvent, Request};
let mut conn = ClientConn::new();
let mut out = Vec::new();
let upload = Request::put("/big").header("host", "a").content_length(4).expect_continue();
conn.send_request(&upload, &mut out)?;
assert!(conn.is_waiting_for_continue());
let _ = conn.feed(b"HTTP/1.1 100 Continue\r\n\r\n");
assert!(matches!(conn.poll()?, ClientEvent::Continue));
assert!(!conn.is_waiting_for_continue());
conn.send_body(b"data", &mut out)?;
conn.end_body(&mut out)?;Sourcepub fn is_reusable(&self) -> bool
pub fn is_reusable(&self) -> bool
Whether the connection can carry another request now: no request is outstanding (or the last response completed) and both sides allow keep-alive.
§Examples
use http_net::{ClientConn, ClientEvent, Request};
let mut conn = ClientConn::new();
assert!(conn.is_reusable());
conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
assert!(!conn.is_reusable());
let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
while !matches!(conn.poll()?, ClientEvent::ResponseEnd) {}
assert!(conn.is_reusable());Sourcepub fn progress(&self) -> Progress
pub fn progress(&self) -> Progress
The connection’s phase, for response deadlines: Progress::Idle
with no request outstanding, Progress::WritingBody while a
request body is streamed, Progress::AwaitingResponse until the
first byte of the response, then Progress::Head and
Progress::Body.
§Examples
use http_net::{ClientConn, Progress, Request};
let mut conn = ClientConn::new();
assert_eq!(conn.progress(), Progress::Idle);
conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
assert_eq!(conn.progress(), Progress::AwaitingResponse);