pub struct Request { /* private fields */ }Expand description
A request for a ClientConn to send.
HTTP/1.1 requires a Host field; the connection refuses to send a
request without one. The request line always says HTTP/1.1.
§Examples
use http_net::Request;
let get = Request::get("/index.html").header("host", "example.com");
let post = Request::post("/api")
.header("host", "example.com")
.header("content-type", "application/json")
.body(br#"{"ok":true}"#.to_vec());
assert_eq!(get.method(), "GET");
assert_eq!(post.target(), "/api");Implementations§
Source§impl Request
impl Request
Sourcepub fn new(method: &str, target: &str) -> Self
pub fn new(method: &str, target: &str) -> Self
A request with method and target, validated when it is sent:
the method must be a token and the target must be in a form the
method allows (/path?query, an absolute URI, host:port for
CONNECT, or * for OPTIONS).
§Examples
let r = http_net::Request::new("PURGE", "/cache/a");
assert_eq!(r.method(), "PURGE");Sourcepub fn head(target: &str) -> Self
pub fn head(target: &str) -> Self
A HEAD request: its response carries headers and no body.
§Examples
assert_eq!(http_net::Request::head("/").method(), "HEAD");Sourcepub fn options(target: &str) -> Self
pub fn options(target: &str) -> Self
An OPTIONS request; * asks about the server as a whole.
§Examples
assert_eq!(http_net::Request::options("*").target(), "*");Sourcepub fn forward_from(head: &RequestHead<'_>) -> Self
pub fn forward_from(head: &RequestHead<'_>) -> Self
A request for an upstream server built from a received head, for a
proxy: the same method and target, every field except the hop-by-hop
ones (RFC 9110 section 7.6.1: connection, keep-alive,
proxy-connection, te, transfer-encoding, upgrade, trailer,
and any name the head’s Connection lists; see
is_hop_by_hop) in their original order,
except content-length, which the connection derives again from
the body mode of the head’s framing: a chunked body stays
chunked, a length stays that length (stream it with
ClientConn::send_body). The
connection writes its own framing and connection fields.
The target is copied as received: an absolute-form target (a request
to a proxy) stays absolute, which an origin server also accepts (RFC
9112 section 3.2.2); rewrite it with Request::new if the upstream
wants origin form. Host is forwarded as a field. Add via and
forwarding fields with header; requests are
re-serialized, never passed through as raw bytes.
Every name the client lists in Connection is dropped, as RFC 9110
section 7.6.1 requires, including end-to-end names such as
authorization or x-forwarded-for: a client can strip fields a
proxy relies on this way. Check
connection_options
first if the next hop must see one of them. Listing host drops it
too, and the request then fails closed at send (no Host).
§Errors
Recorded and returned by
ClientConn::send_request:
HttpError::InvalidState for an upgrade request (the upgrade is
hop-by-hop; a proxy tunnels it instead), and the builder errors of
Request::new and Request::header (for example a missing or
second host surfaces at send).
§Examples
use http_net::{ClientConn, Request, ServerConn, ServerEvent};
let mut downstream = ServerConn::new();
let _ = downstream.feed(b"POST /api HTTP/1.1\r\nHost: app\r\nConnection: X-Hop\r\nX-Hop: 1\r\nKeep-Alive: timeout=5\r\nAccept: */*\r\nContent-Length: 2\r\n\r\nhi");
let ServerEvent::Request(head) = downstream.poll()? else { unreachable!() };
let upstream_req = Request::forward_from(&head).header("via", "1.1 proxy");
let mut upstream = ClientConn::new();
let mut out = Vec::new();
upstream.send_request(&upstream_req, &mut out)?;
assert_eq!(out, b"POST /api HTTP/1.1\r\nHost: app\r\nAccept: */*\r\nvia: 1.1 proxy\r\ncontent-length: 2\r\n\r\n");Sourcepub fn header(self, name: &str, value: impl AsRef<[u8]>) -> Self
pub fn header(self, name: &str, value: impl AsRef<[u8]>) -> Self
Adds a header field, validated as for Response::header, except
that te is allowed on a request. A second host, or a host value
that is not host[:port], is refused with HttpError::InvalidHost.
§Examples
let r = http_net::Request::get("/").header("host", "a").header("accept", "*/*");
assert_eq!(r.header_value("accept"), Some(&b"*/*"[..]));Sourcepub fn body(self, body: impl Into<Cow<'static, [u8]>>) -> Self
pub fn body(self, body: impl Into<Cow<'static, [u8]>>) -> Self
Sets the whole body, sent with content-length.
§Examples
let r = http_net::Request::post("/").body(&b"x=1"[..]);
assert_eq!(r.body_bytes(), Some(&b"x=1"[..]));Sourcepub fn chunked(self) -> Self
pub fn chunked(self) -> Self
Streams the body with chunked encoding through
ClientConn::send_body and
ClientConn::end_body.
§Examples
assert_eq!(http_net::Request::post("/").chunked().body_bytes(), None);Sourcepub fn content_length(self, len: u64) -> Self
pub fn content_length(self, len: u64) -> Self
Streams a body of exactly len bytes.
§Examples
assert_eq!(http_net::Request::post("/").content_length(4).body_bytes(), None);Sourcepub fn close(self) -> Self
pub fn close(self) -> Self
Asks the server to close the connection after its response.
§Examples
let _ = http_net::Request::get("/").header("host", "a").close();Sourcepub fn expect_continue(self) -> Self
pub fn expect_continue(self) -> Self
Sends expect: 100-continue and holds the body back until the
server agrees (RFC 9110 section 10.1.1): for large uploads the
server may refuse from the head alone. The body must be streamed
(content_length or
chunked); send it with
ClientConn::send_body after
ClientEvent::Continue, or after a
wait of your choosing. A final status instead means the server does
not want the body: it must not be sent, and the connection closes
after the response.
§Examples
use http_net::{ClientConn, ClientEvent, HttpError, Request};
let mut conn = ClientConn::new();
let mut out = Vec::new();
let upload = Request::put("/f").header("host", "a").content_length(9).expect_continue();
conn.send_request(&upload, &mut out)?;
assert!(out.ends_with(b"expect: 100-continue\r\ncontent-length: 9\r\n\r\n"));
let _ = conn.feed(b"HTTP/1.1 413 Content Too Large\r\nContent-Length: 0\r\n\r\n");
assert!(matches!(conn.poll()?, ClientEvent::Response(r) if r.status() == 413));
assert!(matches!(conn.send_body(b"too large", &mut out), Err(HttpError::InvalidState(_))));
assert!(matches!(conn.poll()?, ClientEvent::ResponseEnd));
assert!(matches!(conn.poll()?, ClientEvent::Closed));Sourcepub fn upgrade(self, protocol: &str) -> Self
pub fn upgrade(self, protocol: &str) -> Self
Asks to switch the connection to protocol (writes
connection: upgrade and upgrade: <protocol>). A 101 answer
hands the connection over; see
ClientEvent::Upgraded.
protocol is a token or a name/version product token; anything
else is refused with HttpError::InvalidHeaderValue. h2c is
refused with HttpError::UpgradeNotOffered: RFC 9113 section 3.1
deprecates the HTTP/2 upgrade.
§Examples
use http_net::{ClientConn, HttpError, Request};
let r = Request::get("/rpc").header("host", "a").upgrade("websocket");
assert_eq!(r.header_value("upgrade"), Some(&b"websocket"[..]));
let h2c = Request::get("/").header("host", "a").upgrade("h2c");
assert_eq!(
ClientConn::new().send_request(&h2c, &mut Vec::new()),
Err(HttpError::UpgradeNotOffered)
);Sourcepub fn body_bytes(&self) -> Option<&[u8]>
pub fn body_bytes(&self) -> Option<&[u8]>
The full body, or None for a streamed one.
§Examples
assert_eq!(http_net::Request::get("/").body_bytes(), Some(&[][..]));Trait Implementations§
Source§impl Debug for Request
Shows method, target, fields, and body size; the values of credential
fields (authorization, proxy-authorization, cookie) are replaced by
<redacted N bytes>.
impl Debug for Request
Shows method, target, fields, and body size; the values of credential
fields (authorization, proxy-authorization, cookie) are replaced by
<redacted N bytes>.