Skip to main content

ClientConn

Struct ClientConn 

Source
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

Source

pub fn new() -> Self

A connection with the default Limits.

§Examples
let mut conn = http_net::ClientConn::new();
assert!(matches!(conn.poll(), Ok(http_net::ClientEvent::Idle)));
Source

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);
Source

pub fn limits(&self) -> &Limits

The limits this connection enforces.

§Examples
assert_eq!(http_net::ClientConn::new().limits().max_headers(), 100);
Source

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);
Source

pub fn read_buf(&mut self) -> &mut [u8] ⓘ

Spare space at the end of the input buffer; follow with commit.

§Examples
let mut conn = http_net::ClientConn::new();
assert!(!conn.read_buf().is_empty());
Source

pub fn commit(&mut self, n: usize)

Records that n bytes were written into read_buf.

§Examples
let mut conn = http_net::ClientConn::new();
conn.read_buf()[..4].copy_from_slice(b"HTTP");
conn.commit(4);
Source

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));
Source

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

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"));
Source

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"));
Source

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"));
Source

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);
Source

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);
Source

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());
Source

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");
Source

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));
Source

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);
Source

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)?;
Source

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());
Source

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);

Trait Implementations§

Source§

impl Debug for ClientConn

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ClientConn

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.