http_net/client.rs
1//! The client side of an HTTP/1.1 connection, without I/O.
2
3use alloc::vec::Vec;
4
5use crate::{
6 body::{Decoder, Encoder, Step, push_framing},
7 buffer::Buffer,
8 error::HttpError,
9 head::{
10 Asked, HeadKind, HeadScanner, Headers, ResponseHead, ResponseInfo, Scan,
11 interpret_response, switches_to_offered,
12 },
13 limits::{Limits, MAX_PIPELINE_DEPTH},
14 message::{OutBody, Request, check_trailers, push_last_chunk_with_trailers},
15 method::Method,
16 scan::find_byte,
17 server::Progress,
18};
19
20/// The error for sending a body the server declined (a final status in
21/// answer to `Expect: 100-continue`).
22const REFUSED: HttpError = HttpError::InvalidState(
23 "the server answered with a final status instead of 100 Continue; \
24 the body must not be sent",
25);
26
27/// What a [`ClientConn`] has for the caller after [`poll`](ClientConn::poll).
28///
29/// # Examples
30///
31/// ```
32/// use http_net::{ClientConn, ClientEvent, Request};
33///
34/// let mut conn = ClientConn::new();
35/// let mut out = Vec::new();
36/// conn.send_request(&Request::get("/").header("host", "example.com"), &mut out).unwrap();
37/// let _ = conn.feed(b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nabc\r\n0\r\n\r\n");
38/// let mut body = Vec::new();
39/// loop {
40/// match conn.poll().unwrap() {
41/// ClientEvent::Response(resp) => assert_eq!(resp.status(), 200),
42/// ClientEvent::Body(chunk) => body.extend_from_slice(chunk),
43/// ClientEvent::ResponseEnd => break,
44/// other => panic!("{other:?}"),
45/// }
46/// }
47/// assert_eq!(body, b"abc");
48/// ```
49#[non_exhaustive]
50pub enum ClientEvent<'a> {
51 /// The final response head arrived. Its body follows as
52 /// [`Body`](ClientEvent::Body) events, then
53 /// [`ResponseEnd`](ClientEvent::ResponseEnd). Interim (1xx) responses
54 /// before it are skipped unless
55 /// [`set_report_informational`](ClientConn::set_report_informational)
56 /// asked for them; either way they count against
57 /// [`Limits::max_interim`](crate::Limits::max_interim) and, together,
58 /// [`Limits::max_header_bytes`](crate::Limits::max_header_bytes).
59 Response(ResponseHead<'a>),
60 /// An interim response other than `101` (for example `103 Early Hints`,
61 /// or `102 Processing`), only with
62 /// [`set_report_informational(true)`](ClientConn::set_report_informational).
63 /// The final response follows.
64 Informational(ResponseHead<'a>),
65 /// The server answered `100 Continue` to a request built with
66 /// [`Request::expect_continue`](crate::Request::expect_continue): send
67 /// the body now.
68 Continue,
69 /// A run of body bytes, after chunked decoding.
70 Body(&'a [u8]),
71 /// The response's trailer fields, just before
72 /// [`ResponseEnd`](ClientEvent::ResponseEnd): only with
73 /// [`set_report_trailers(true)`](ClientConn::set_report_trailers) and a
74 /// non-empty trailer section.
75 Trailers(Headers<'a>),
76 /// The response is complete.
77 ResponseEnd,
78 /// More input is needed (or, for a body that runs until close,
79 /// [`feed_eof`](ClientConn::feed_eof) once the server closes).
80 NeedInput,
81 /// No request is outstanding; send the next one.
82 Idle,
83 /// The server switched protocols (101 to an upgrade request, or 2xx to
84 /// `CONNECT`); the response head was reported just before. Bytes of the
85 /// new protocol that already arrived are in
86 /// [`remaining_input`](ClientConn::remaining_input).
87 Upgraded,
88 /// The connection cannot carry another request: close the socket.
89 Closed,
90}
91
92/// Body bytes print as their length: a body can carry credentials that no
93/// field redaction sees (a token in a JSON answer).
94impl core::fmt::Debug for ClientEvent<'_> {
95 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
96 match self {
97 Self::Response(head) => f.debug_tuple("Response").field(head).finish(),
98 Self::Informational(head) => f.debug_tuple("Informational").field(head).finish(),
99 Self::Continue => f.write_str("Continue"),
100 Self::Body(bytes) => f
101 .debug_tuple("Body")
102 .field(&format_args!("{} bytes", bytes.len()))
103 .finish(),
104 Self::Trailers(fields) => f.debug_tuple("Trailers").field(fields).finish(),
105 Self::ResponseEnd => f.write_str("ResponseEnd"),
106 Self::NeedInput => f.write_str("NeedInput"),
107 Self::Idle => f.write_str("Idle"),
108 Self::Upgraded => f.write_str("Upgraded"),
109 Self::Closed => f.write_str("Closed"),
110 }
111 }
112}
113
114/// Opt-in tolerances for responses a strict client would refuse. All are
115/// off by default; requests are never parsed leniently.
116///
117/// - `obs_fold_in_responses`: replace each obsolete line fold in a response
118/// head (a field line continued on the next line, which begins with a
119/// space or tab) by overwriting the fold's CR and LF with spaces, as RFC
120/// 9112 section 5.2 tells a user agent to do. The rewrite happens in
121/// place in the connection's buffer, so offsets do not move, views stay
122/// borrowed, and nothing is allocated. Whitespace before the first field
123/// is still refused.
124///
125/// Bare LF, bare CR, `Content-Length` with `Transfer-Encoding` on a
126/// response that has a body, and whitespace before a colon are never
127/// tolerated: they are how messages get framed differently by different
128/// hops. A response with no body (`HEAD`, 1xx, 204, 304, 2xx to `CONNECT`)
129/// ends at its blank line whatever its framing fields say.
130///
131/// # Examples
132///
133/// ```
134/// use http_net::{ClientConn, ClientEvent, ClientLeniency, Request};
135///
136/// let mut conn = ClientConn::new();
137/// conn.set_leniency(ClientLeniency::new().with_obs_fold_in_responses(true));
138/// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
139/// let _ = conn.feed(b"HTTP/1.1 200 OK\r\nX-Long: part one,\r\n part two\r\nContent-Length: 0\r\n\r\n");
140/// let ClientEvent::Response(resp) = conn.poll()? else { panic!() };
141/// assert_eq!(resp.header("x-long"), Some(&b"part one, part two"[..]));
142/// # Ok::<(), http_net::HttpError>(())
143/// ```
144#[non_exhaustive]
145#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
146pub struct ClientLeniency {
147 /// Replace obs-folds in response fields with spaces instead of refusing
148 /// them with [`HttpError::ObsFold`].
149 pub obs_fold_in_responses: bool,
150}
151
152impl ClientLeniency {
153 /// Every tolerance off (the strict default).
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// assert!(!http_net::ClientLeniency::new().obs_fold_in_responses);
159 /// ```
160 #[must_use]
161 pub const fn new() -> Self {
162 Self {
163 obs_fold_in_responses: false,
164 }
165 }
166
167 /// Sets [`obs_fold_in_responses`](Self::obs_fold_in_responses).
168 ///
169 /// # Examples
170 ///
171 /// ```
172 /// let l = http_net::ClientLeniency::new().with_obs_fold_in_responses(true);
173 /// assert!(l.obs_fold_in_responses);
174 /// ```
175 #[must_use]
176 pub const fn with_obs_fold_in_responses(mut self, on: bool) -> Self {
177 self.obs_fold_in_responses = on;
178 self
179 }
180}
181
182/// The in-place obs-fold rewrite of one response head. It walks the head's
183/// line ends once, overall linear however the input is split, and tells the
184/// head scanner how much it may see: a line end whose next byte has not
185/// arrived is held back, because only that byte says whether the line is
186/// folded. The scanner therefore never completes a field line that is about
187/// to be continued.
188#[derive(Clone, Copy, Debug)]
189struct Unfold {
190 /// Where the search for the next LF resumes.
191 scan: usize,
192 /// Start of the line being examined.
193 line_start: usize,
194 /// The status line has ended (it is never folded).
195 past_status: bool,
196 /// The blank line that ends the head was seen.
197 done: bool,
198}
199
200impl Unfold {
201 const fn new() -> Self {
202 Self {
203 scan: 0,
204 line_start: 0,
205 past_status: false,
206 done: false,
207 }
208 }
209
210 /// Rewrites the folds found in `msg` (the head so far) and returns how
211 /// many of its bytes the head scanner may examine.
212 fn run(&mut self, msg: &mut [u8], eof: bool) -> usize {
213 if self.done {
214 return msg.len();
215 }
216 loop {
217 let Some(off) = msg.get(self.scan..).and_then(|rest| find_byte(b'\n', rest)) else {
218 self.scan = msg.len();
219 return msg.len();
220 };
221 let lf = self.scan + off;
222 if !self.past_status {
223 self.past_status = true;
224 self.line_start = lf + 1;
225 self.scan = lf + 1;
226 continue;
227 }
228 // line_start <= lf: it only ever moves to just past an LF.
229 let line = msg.get(self.line_start..lf).unwrap_or(&[]);
230 if line.is_empty() || line == b"\r" {
231 self.done = true;
232 return msg.len();
233 }
234 let crlf = lf > 0 && msg.get(lf - 1) == Some(&b'\r');
235 match msg.get(lf + 1) {
236 None if eof => {
237 self.scan = msg.len();
238 return msg.len();
239 }
240 None => {
241 // Revisit this LF once its next byte arrives.
242 self.scan = lf;
243 return lf;
244 }
245 Some(&b) if crlf && (b == b' ' || b == b'\t') => {
246 // RFC 9112 section 5.2: replace the fold with SP. The
247 // line goes on, so its start stays where it was.
248 msg[lf - 1] = b' ';
249 msg[lf] = b' ';
250 self.scan = lf + 1;
251 }
252 Some(_) => {
253 self.line_start = lf + 1;
254 self.scan = lf + 1;
255 }
256 }
257 }
258 }
259}
260
261#[derive(Clone, Copy, Debug, PartialEq, Eq)]
262enum State {
263 Idle,
264 Head,
265 /// An interim head was reported and is still pinned; the next poll
266 /// drops it and waits for the next head.
267 Interim,
268 Body,
269 Complete,
270 Upgraded,
271 Closed,
272}
273
274#[derive(Clone, Copy, Debug, PartialEq, Eq)]
275enum ReqWrite {
276 Streaming(Encoder),
277 Sent,
278}
279
280/// The client side of one HTTP/1.1 connection: a sans-IO state machine.
281///
282/// By default one request is outstanding at a time; with
283/// [`Limits::with_pipeline_depth`], idempotent requests may be pipelined
284/// behind it (see [`can_send`](Self::can_send)).
285/// [`send_request`](Self::send_request)
286/// serializes a [`Request`]; [`feed`](Self::feed) and [`poll`](Self::poll)
287/// parse the response. When the response allows it, the connection returns
288/// to [`ClientEvent::Idle`] and can send the next request (keep-alive).
289///
290/// The response is framed with the request in mind: a `HEAD` request's
291/// response has no body whatever its headers say, a `CONNECT` 2xx becomes a
292/// tunnel, and a response with neither `Content-Length` nor
293/// `Transfer-Encoding` runs until the server closes.
294///
295/// # Examples
296///
297/// ```
298/// use http_net::{ClientConn, ClientEvent, Request};
299///
300/// let mut conn = ClientConn::new();
301/// let mut out = Vec::new();
302/// conn.send_request(&Request::get("/a").header("host", "h"), &mut out).unwrap();
303/// assert_eq!(out, b"GET /a HTTP/1.1\r\nhost: h\r\n\r\n");
304/// let _ = conn.feed(b"HTTP/1.1 204 No Content\r\n\r\n");
305/// assert!(matches!(conn.poll().unwrap(), ClientEvent::Response(_)));
306/// assert!(matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd));
307/// assert!(matches!(conn.poll().unwrap(), ClientEvent::Idle));
308/// ```
309pub struct ClientConn {
310 buf: Buffer,
311 limits: Limits,
312 scanner: HeadScanner,
313 trailers: HeadScanner,
314 decoder: Decoder,
315 info: ResponseInfo,
316 asked: Asked,
317 upgrade_asked: bool,
318 /// The protocols the outstanding upgrade request offered, comma
319 /// separated; a `101` may switch only to these.
320 upgrade_offer: Vec<u8>,
321 state: State,
322 req: ReqWrite,
323 keep_alive: bool,
324 /// Bytes of interim (1xx) heads seen for the current request. They
325 /// count against the header budget so that a server cannot keep the
326 /// client parsing forever without answering.
327 interim_bytes: usize,
328 /// Interim heads seen for the current request, against `max_interim`.
329 interim_count: u16,
330 report_interim: bool,
331 report_trailers: bool,
332 /// The request was sent with `Expect: 100-continue` and neither a `100`,
333 /// a final response, nor body bytes have happened since.
334 waiting_continue: bool,
335 /// A final response arrived while waiting for `100`: the promised body
336 /// must not be sent, and the connection closes after the response.
337 body_refused: bool,
338 /// The request body was declared chunked (trailers allowed).
339 req_chunked: bool,
340 /// The request being answered is idempotent (it may share the
341 /// connection with pipelined requests).
342 idempotent: bool,
343 /// Requests sent after the one being answered, in order: a fixed ring,
344 /// so pipelining allocates nothing after construction.
345 queue: [Queued; MAX_PIPELINE_DEPTH as usize],
346 queue_start: usize,
347 queued: usize,
348 /// The connection failed while a response was being read, so that
349 /// request stays unanswered: `outstanding()` still counts it.
350 response_failed: bool,
351 leniency: ClientLeniency,
352 /// Where the obs-fold rewrite stopped in the current response head.
353 unfold: Unfold,
354}
355
356/// A pipelined request waiting for its response: what framing its response
357/// needs and whether it asked to close.
358#[derive(Clone, Copy, Debug)]
359struct Queued {
360 asked: Asked,
361 close: bool,
362}
363
364/// Writes the request line, fields, framing, and (for a full body) the body;
365/// returns how the rest of the body, if any, is to be written.
366fn write_request(request: &Request, out: &mut Vec<u8>) -> Result<ReqWrite, HttpError> {
367 let method = request.method_kind;
368 let expects_body = matches!(method, Method::Post | Method::Put | Method::Patch);
369 let (mut encoder, declared) = match &request.body {
370 OutBody::Full(b) if b.is_empty() && !expects_body => (Encoder::Discard, None),
371 OutBody::Full(b) => (
372 Encoder::Length {
373 remaining: b.len() as u64,
374 },
375 Some(b.len() as u64),
376 ),
377 OutBody::Length(n) => (Encoder::Length { remaining: *n }, Some(*n)),
378 OutBody::Chunked => (Encoder::Chunked, None),
379 };
380 out.extend_from_slice(request.method().as_bytes());
381 out.push(b' ');
382 out.extend_from_slice(request.target().as_bytes());
383 out.extend_from_slice(b" HTTP/1.1\r\n");
384 out.extend_from_slice(request.fields());
385 push_framing(out, encoder, declared);
386 if request.close {
387 out.extend_from_slice(b"connection: close\r\n");
388 }
389 out.extend_from_slice(b"\r\n");
390 match &request.body {
391 OutBody::Full(b) => {
392 encoder.write(b, out)?;
393 Ok(ReqWrite::Sent)
394 }
395 _ => Ok(ReqWrite::Streaming(encoder)),
396 }
397}
398
399const NO_QUEUED: Queued = Queued {
400 asked: Asked {
401 head: false,
402 connect: false,
403 },
404 close: false,
405};
406
407impl Default for ClientConn {
408 fn default() -> Self {
409 Self::new()
410 }
411}
412
413impl core::fmt::Debug for ClientConn {
414 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
415 f.debug_struct("ClientConn")
416 .field("state", &self.state)
417 .field("request", &self.req)
418 .field("buffered", &self.buf.unread().len())
419 .field("limits", &self.limits)
420 .finish()
421 }
422}
423
424impl ClientConn {
425 /// A connection with the default [`Limits`].
426 ///
427 /// # Examples
428 ///
429 /// ```
430 /// let mut conn = http_net::ClientConn::new();
431 /// assert!(matches!(conn.poll(), Ok(http_net::ClientEvent::Idle)));
432 /// ```
433 #[must_use]
434 pub fn new() -> Self {
435 Self::with_limits(Limits::new())
436 }
437
438 /// A connection enforcing `limits` on responses.
439 ///
440 /// # Examples
441 ///
442 /// ```
443 /// let conn = http_net::ClientConn::with_limits(http_net::Limits::new().with_max_body(1 << 24));
444 /// assert_eq!(conn.limits().max_body(), 1 << 24);
445 /// ```
446 #[must_use]
447 pub fn with_limits(limits: Limits) -> Self {
448 Self::from_buffer(Buffer::new(limits.buffer_capacity()), limits)
449 }
450
451 /// A connection enforcing `limits` that reads into `storage` (its
452 /// capacity is used up to [`Limits::buffer_capacity`], its contents are
453 /// ignored), for drivers that pool buffers. Give it back with
454 /// [`into_buffer`](Self::into_buffer).
455 ///
456 /// # Examples
457 ///
458 /// ```
459 /// let conn = http_net::ClientConn::with_buffer(Vec::with_capacity(4096), http_net::Limits::new());
460 /// assert!(conn.into_buffer().capacity() >= 4096);
461 /// ```
462 #[must_use]
463 pub fn with_buffer(storage: Vec<u8>, limits: Limits) -> Self {
464 Self::from_buffer(
465 Buffer::with_storage(storage, limits.buffer_capacity()),
466 limits,
467 )
468 }
469
470 fn from_buffer(buf: Buffer, limits: Limits) -> Self {
471 Self {
472 buf,
473 limits,
474 scanner: HeadScanner::new(),
475 trailers: HeadScanner::new(),
476 decoder: Decoder::new(),
477 info: ResponseInfo::EMPTY,
478 asked: Asked {
479 head: false,
480 connect: false,
481 },
482 upgrade_asked: false,
483 upgrade_offer: Vec::new(),
484 state: State::Idle,
485 req: ReqWrite::Sent,
486 keep_alive: true,
487 interim_bytes: 0,
488 interim_count: 0,
489 report_interim: false,
490 report_trailers: false,
491 waiting_continue: false,
492 body_refused: false,
493 req_chunked: false,
494 idempotent: true,
495 queue: [NO_QUEUED; MAX_PIPELINE_DEPTH as usize],
496 queue_start: 0,
497 queued: 0,
498 response_failed: false,
499 leniency: ClientLeniency::new(),
500 unfold: Unfold::new(),
501 }
502 }
503
504 /// The limits this connection enforces.
505 ///
506 /// # Examples
507 ///
508 /// ```
509 /// assert_eq!(http_net::ClientConn::new().limits().max_headers(), 100);
510 /// ```
511 #[must_use]
512 pub fn limits(&self) -> &Limits {
513 &self.limits
514 }
515
516 /// Copies as much of `bytes` into the input buffer as fits; returns how
517 /// many were taken (see [`ServerConn::feed`](crate::ServerConn::feed)).
518 ///
519 /// # Examples
520 ///
521 /// ```
522 /// let mut conn = http_net::ClientConn::new();
523 /// assert_eq!(conn.feed(b"HTTP/1.1"), 8);
524 /// ```
525 #[must_use = "bytes beyond the returned count were not taken"]
526 pub fn feed(&mut self, bytes: &[u8]) -> usize {
527 self.buf.feed(bytes)
528 }
529
530 /// Spare space at the end of the input buffer; follow with
531 /// [`commit`](Self::commit).
532 ///
533 /// # Examples
534 ///
535 /// ```
536 /// let mut conn = http_net::ClientConn::new();
537 /// assert!(!conn.read_buf().is_empty());
538 /// ```
539 pub fn read_buf(&mut self) -> &mut [u8] {
540 self.buf.spare()
541 }
542
543 /// Records that `n` bytes were written into [`read_buf`](Self::read_buf).
544 /// An `n` larger than the slice `read_buf` returned is clamped to its
545 /// length: committing bytes that were not written would hand stale
546 /// buffer contents to the parser.
547 ///
548 /// # Examples
549 ///
550 /// ```
551 /// let mut conn = http_net::ClientConn::new();
552 /// conn.read_buf()[..4].copy_from_slice(b"HTTP");
553 /// conn.commit(4);
554 /// ```
555 pub fn commit(&mut self, n: usize) {
556 self.buf.commit(n);
557 }
558
559 /// Records that the server closed its sending side: ends a body that
560 /// runs until close, or reports [`HttpError::UnexpectedEof`] mid-message.
561 ///
562 /// # Examples
563 ///
564 /// ```
565 /// use http_net::{ClientConn, ClientEvent, Request};
566 ///
567 /// let mut conn = ClientConn::new();
568 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
569 /// let _ = conn.feed(b"HTTP/1.0 200 OK\r\n\r\nall of it");
570 /// assert!(matches!(conn.poll().unwrap(), ClientEvent::Response(_)));
571 /// assert!(matches!(conn.poll().unwrap(), ClientEvent::Body(b"all of it")));
572 /// assert!(matches!(conn.poll().unwrap(), ClientEvent::NeedInput));
573 /// conn.feed_eof();
574 /// assert!(matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd));
575 /// assert!(matches!(conn.poll().unwrap(), ClientEvent::Closed));
576 /// ```
577 pub fn feed_eof(&mut self) {
578 self.buf.set_eof();
579 }
580
581 /// Writes `request` into `out` and starts waiting for its response.
582 ///
583 /// A full body is sent with `content-length` (omitted for an empty body
584 /// on methods that do not expect one); a streamed body continues with
585 /// [`send_body`](Self::send_body) and [`end_body`](Self::end_body).
586 ///
587 /// A request built with [`Request::expect_continue`] is sent head first:
588 /// [`is_waiting_for_continue`](Self::is_waiting_for_continue) is true
589 /// until the server answers `100 Continue` (reported as
590 /// [`ClientEvent::Continue`]: then send the body), a final status (then
591 /// the body must not be sent and the connection closes after the
592 /// response), or the caller sends the body anyway (RFC 9110 section
593 /// 10.1.1 allows it after a wait of its choosing).
594 ///
595 /// # Errors
596 ///
597 /// - the first error recorded by the [`Request`] builder;
598 /// - [`HttpError::MissingHost`] when the request has no `host` header;
599 /// - [`HttpError::InvalidState`] when a request is outstanding and this
600 /// one cannot be pipelined (depth 1, depth full, or not idempotent with
601 /// a full body; see [`can_send`](Self::can_send)), when the connection
602 /// is closed or upgraded, or when an `expect_continue` request has a
603 /// full body (it needs `content_length` or `chunked`);
604 /// - [`HttpError::UnexpectedData`] when response bytes nobody asked for
605 /// are buffered.
606 ///
607 /// # Examples
608 ///
609 /// ```
610 /// use http_net::{ClientConn, HttpError, Request};
611 ///
612 /// let mut conn = ClientConn::new();
613 /// let mut out = Vec::new();
614 /// assert_eq!(conn.send_request(&Request::get("/"), &mut out), Err(HttpError::MissingHost));
615 /// conn.send_request(&Request::post("/f").header("host", "a").body(&b"xyz"[..]), &mut out).unwrap();
616 /// assert_eq!(out, b"POST /f HTTP/1.1\r\nhost: a\r\ncontent-length: 3\r\n\r\nxyz");
617 /// ```
618 pub fn send_request(&mut self, request: &Request, out: &mut Vec<u8>) -> Result<(), HttpError> {
619 if let Some(e) = request.error() {
620 return Err(e);
621 }
622 if self.settled() {
623 self.state = State::Idle;
624 }
625 match self.state {
626 State::Idle => {}
627 State::Closed | State::Upgraded => {
628 return Err(HttpError::InvalidState(
629 "the connection is closed or upgraded",
630 ));
631 }
632 _ => return self.send_pipelined(request, out),
633 }
634 if !self.buf.unread().is_empty() {
635 return Err(HttpError::UnexpectedData);
636 }
637 if !request.has_host {
638 return Err(HttpError::MissingHost);
639 }
640 if request.expect_continue && matches!(request.body, OutBody::Full(_)) {
641 // The point of the expectation is to hold the body back until
642 // the server agrees; a full body would be written at once.
643 return Err(HttpError::InvalidState(
644 "expect_continue needs a streamed body (content_length or chunked), \
645 sent after ClientEvent::Continue",
646 ));
647 }
648 let method = request.method_kind;
649 self.req = write_request(request, out)?;
650 self.asked = Asked {
651 head: method == Method::Head,
652 connect: method == Method::Connect,
653 };
654 self.upgrade_asked = request.upgrade;
655 if request.upgrade {
656 self.upgrade_offer.clear();
657 for offer in request.upgrade_offers() {
658 if !self.upgrade_offer.is_empty() {
659 self.upgrade_offer.push(b',');
660 }
661 self.upgrade_offer.extend_from_slice(offer);
662 }
663 }
664 self.keep_alive = !request.close;
665 self.idempotent = method.is_idempotent();
666 self.req_chunked = matches!(request.body, OutBody::Chunked);
667 self.waiting_continue = request.expect_continue;
668 self.body_refused = false;
669 self.buf.unpin();
670 self.buf.pin_at_pos();
671 self.scanner.reset();
672 self.unfold = Unfold::new();
673 self.interim_bytes = 0;
674 self.interim_count = 0;
675 self.state = State::Head;
676 Ok(())
677 }
678
679 /// Sends `request` behind the ones already outstanding (pipelining).
680 fn send_pipelined(&mut self, request: &Request, out: &mut Vec<u8>) -> Result<(), HttpError> {
681 if !self.can_send() {
682 return Err(HttpError::InvalidState(
683 if self.limits.pipeline_depth() <= 1 {
684 "a request is already outstanding (raise Limits::with_pipeline_depth to pipeline)"
685 } else {
686 "pipelining needs room in the pipeline depth, idempotent requests, \
687 every earlier body sent, and no close, upgrade, CONNECT, or expectation"
688 },
689 ));
690 }
691 if !request.has_host {
692 return Err(HttpError::MissingHost);
693 }
694 let method = request.method_kind;
695 if !method.is_idempotent()
696 || request.upgrade
697 || request.expect_continue
698 || !matches!(request.body, OutBody::Full(_))
699 {
700 return Err(HttpError::InvalidState(
701 "only idempotent requests with a full body and no upgrade or expectation \
702 can be pipelined",
703 ));
704 }
705 let req = write_request(request, out)?;
706 debug_assert_eq!(req, ReqWrite::Sent);
707 let slot = (self.queue_start + self.queued) % self.queue.len();
708 self.queue[slot] = Queued {
709 asked: Asked {
710 head: method == Method::Head,
711 connect: false,
712 },
713 close: request.close,
714 };
715 self.queued += 1;
716 Ok(())
717 }
718
719 /// Starts on the response to the oldest queued request.
720 fn next_queued(&mut self) {
721 let next = self.queue[self.queue_start];
722 self.queue_start = (self.queue_start + 1) % self.queue.len();
723 self.queued -= 1;
724 self.asked = next.asked;
725 self.keep_alive = !next.close;
726 self.upgrade_asked = false;
727 self.idempotent = true;
728 self.req_chunked = false;
729 self.waiting_continue = false;
730 self.body_refused = false;
731 self.buf.unpin();
732 self.buf.pin_at_pos();
733 self.scanner.reset();
734 self.interim_bytes = 0;
735 self.interim_count = 0;
736 self.state = State::Head;
737 }
738
739 /// Whether any outstanding request asked to close the connection.
740 fn closing(&self) -> bool {
741 !self.keep_alive
742 || (0..self.queued).any(|i| self.queue[(self.queue_start + i) % self.queue.len()].close)
743 }
744
745 /// The number of requests sent whose response has not completed:
746 /// 0 when idle, up to [`Limits::pipeline_depth`] when pipelining. After
747 /// the connection closed it is the number of requests that never got
748 /// a response (send them again on a new connection if they are safe to
749 /// repeat).
750 ///
751 /// # Examples
752 ///
753 /// ```
754 /// use http_net::{ClientConn, Limits, Request};
755 ///
756 /// let mut conn = ClientConn::with_limits(Limits::new().with_pipeline_depth(4));
757 /// let get = |p: &str| Request::get(p).header("host", "a");
758 /// let mut out = Vec::new();
759 /// conn.send_request(&get("/1"), &mut out)?;
760 /// conn.send_request(&get("/2"), &mut out)?;
761 /// assert_eq!(conn.outstanding(), 2);
762 /// # Ok::<(), http_net::HttpError>(())
763 /// ```
764 #[must_use]
765 pub fn outstanding(&self) -> usize {
766 match self.state {
767 State::Idle => 0,
768 State::Head | State::Interim | State::Body => 1 + self.queued,
769 State::Complete | State::Upgraded => self.queued,
770 State::Closed => self.queued + usize::from(self.response_failed),
771 }
772 }
773
774 /// Whether [`send_request`](Self::send_request) would accept another
775 /// request now. With no request outstanding: the connection is open
776 /// and nothing unsolicited is buffered. With requests outstanding
777 /// (pipelining): fewer than [`Limits::pipeline_depth`] are outstanding,
778 /// all of them are idempotent with their bodies fully sent, none asked
779 /// to close, upgrade, `CONNECT`, or expect `100 Continue`, and the
780 /// response being read, once its head has arrived, keeps the connection
781 /// open (RFC 9112 section 9.6: after `close`, or a response that ends
782 /// with the connection, the client sends nothing more). The new request
783 /// must also be idempotent with a full body (RFC 9112 section 9.3.2: a
784 /// client should not pipeline non-idempotent requests).
785 ///
786 /// # Examples
787 ///
788 /// ```
789 /// use http_net::{ClientConn, Limits, Request};
790 ///
791 /// let mut conn = ClientConn::new(); // depth 1: no pipelining
792 /// assert!(conn.can_send());
793 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
794 /// assert!(!conn.can_send());
795 /// # Ok::<(), http_net::HttpError>(())
796 /// ```
797 #[must_use]
798 pub fn can_send(&self) -> bool {
799 match self.state {
800 State::Complete if self.settled() => self.buf.unread().is_empty() && !self.buf.is_eof(),
801 State::Idle => self.buf.unread().is_empty() && !self.buf.is_eof(),
802 State::Closed | State::Upgraded => false,
803 State::Head | State::Interim | State::Body | State::Complete => {
804 self.outstanding() < usize::from(self.limits.pipeline_depth())
805 && self.idempotent
806 && self.req == ReqWrite::Sent
807 && !self.closing()
808 && !self.upgrade_asked
809 && !self.asked.connect
810 && !self.waiting_continue
811 && !self.body_refused
812 && !self.buf.is_eof()
813 && (matches!(self.state, State::Head | State::Interim) || self.info.keep_alive)
814 }
815 }
816 }
817
818 /// Returns the connection to its initial state for a new socket,
819 /// keeping the buffer and field-index allocations and the limits and
820 /// reporting settings. Requests still outstanding are forgotten.
821 ///
822 /// # Examples
823 ///
824 /// ```
825 /// use http_net::{ClientConn, Progress, Request};
826 ///
827 /// let mut conn = ClientConn::new();
828 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
829 /// conn.reset();
830 /// assert_eq!(conn.progress(), Progress::Idle);
831 /// assert!(conn.can_send());
832 /// # Ok::<(), http_net::HttpError>(())
833 /// ```
834 pub fn reset(&mut self) {
835 self.buf.reset();
836 self.scanner.reset();
837 self.trailers.reset();
838 self.decoder = Decoder::new();
839 self.info = ResponseInfo::EMPTY;
840 self.asked = NO_QUEUED.asked;
841 self.upgrade_asked = false;
842 self.state = State::Idle;
843 self.req = ReqWrite::Sent;
844 self.keep_alive = true;
845 self.interim_bytes = 0;
846 self.interim_count = 0;
847 self.waiting_continue = false;
848 self.body_refused = false;
849 self.req_chunked = false;
850 self.idempotent = true;
851 self.queue_start = 0;
852 self.queued = 0;
853 self.response_failed = false;
854 }
855
856 /// Gives the input buffer's storage back, for a pool.
857 ///
858 /// # Examples
859 ///
860 /// ```
861 /// assert_eq!(http_net::ClientConn::new().into_buffer().capacity(), 0);
862 /// ```
863 #[must_use]
864 pub fn into_buffer(mut self) -> Vec<u8> {
865 self.buf.take_storage()
866 }
867
868 /// Frees the input buffer and the field indexes while no request is
869 /// outstanding and nothing is buffered. Returns whether memory was
870 /// released.
871 ///
872 /// # Examples
873 ///
874 /// ```
875 /// use http_net::{ClientConn, ClientEvent, Request};
876 ///
877 /// let mut conn = ClientConn::new();
878 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
879 /// let _ = conn.feed(b"HTTP/1.1 204 No Content\r\n\r\n");
880 /// while !matches!(conn.poll()?, ClientEvent::Idle) {}
881 /// assert!(conn.shrink_idle());
882 /// # Ok::<(), http_net::HttpError>(())
883 /// ```
884 pub fn shrink_idle(&mut self) -> bool {
885 if self.state != State::Idle {
886 return false;
887 }
888 self.buf.unpin();
889 let freed = self.buf.shrink();
890 if freed {
891 self.scanner.fields = Vec::new();
892 self.trailers.fields = Vec::new();
893 }
894 freed
895 }
896
897 /// Writes body bytes of a streamed request.
898 ///
899 /// Sending body bytes while waiting for `100 Continue` ends the wait.
900 ///
901 /// # Errors
902 ///
903 /// [`HttpError::BodyLengthMismatch`] past the declared length;
904 /// [`HttpError::InvalidState`] when no streamed request is in progress,
905 /// or when the server answered an `expect_continue` request with a final
906 /// status (the body must not be sent then).
907 ///
908 /// # Examples
909 ///
910 /// ```
911 /// use http_net::{ClientConn, Request};
912 ///
913 /// let mut conn = ClientConn::new();
914 /// let mut out = Vec::new();
915 /// conn.send_request(&Request::post("/up").header("host", "a").chunked(), &mut out).unwrap();
916 /// conn.send_body(b"part", &mut out).unwrap();
917 /// conn.end_body(&mut out).unwrap();
918 /// assert!(out.ends_with(b"4\r\npart\r\n0\r\n\r\n"));
919 /// ```
920 pub fn send_body(&mut self, data: &[u8], out: &mut Vec<u8>) -> Result<(), HttpError> {
921 if self.body_refused {
922 return Err(REFUSED);
923 }
924 match &mut self.req {
925 ReqWrite::Streaming(encoder) => {
926 encoder.write(data, out)?;
927 self.waiting_continue = false;
928 Ok(())
929 }
930 ReqWrite::Sent => Err(HttpError::InvalidState("no streamed request in progress")),
931 }
932 }
933
934 /// Ends a streamed request body.
935 ///
936 /// # Errors
937 ///
938 /// [`HttpError::BodyLengthMismatch`] when fewer bytes than declared were
939 /// sent; [`HttpError::InvalidState`] when no streamed request is in
940 /// progress, or when the server answered an `expect_continue` request
941 /// with a final status (the body must not be sent then).
942 ///
943 /// # Examples
944 ///
945 /// ```
946 /// use http_net::{ClientConn, Request};
947 ///
948 /// let mut conn = ClientConn::new();
949 /// let mut out = Vec::new();
950 /// conn.send_request(&Request::post("/").header("host", "a").content_length(2), &mut out).unwrap();
951 /// conn.send_body(b"ok", &mut out).unwrap();
952 /// conn.end_body(&mut out).unwrap();
953 /// assert!(out.ends_with(b"\r\n\r\nok"));
954 /// ```
955 pub fn end_body(&mut self, out: &mut Vec<u8>) -> Result<(), HttpError> {
956 self.end_body_with_trailers(&[], out)
957 }
958
959 /// Ends a streamed chunked request body with a trailer section (see
960 /// [`ServerConn::end_body_with_trailers`](crate::ServerConn::end_body_with_trailers)
961 /// for the fields that are refused).
962 ///
963 /// # Errors
964 ///
965 /// [`HttpError::TrailerNotAllowed`] for a forbidden field or a body
966 /// that is not chunked; the field errors of
967 /// [`Request::header`]; otherwise as [`end_body`](Self::end_body).
968 ///
969 /// # Examples
970 ///
971 /// ```
972 /// use http_net::{ClientConn, Request};
973 ///
974 /// let mut conn = ClientConn::new();
975 /// let mut out = Vec::new();
976 /// conn.send_request(&Request::put("/f").header("host", "a").chunked(), &mut out)?;
977 /// conn.send_body(b"data", &mut out)?;
978 /// conn.end_body_with_trailers(&[("content-digest", b"sha-256=:x:")], &mut out)?;
979 /// assert!(out.ends_with(b"0\r\ncontent-digest: sha-256=:x:\r\n\r\n"));
980 /// # Ok::<(), http_net::HttpError>(())
981 /// ```
982 pub fn end_body_with_trailers(
983 &mut self,
984 trailers: &[(&str, &[u8])],
985 out: &mut Vec<u8>,
986 ) -> Result<(), HttpError> {
987 if self.body_refused {
988 return Err(REFUSED);
989 }
990 let ReqWrite::Streaming(encoder) = &mut self.req else {
991 return Err(HttpError::InvalidState("no streamed request in progress"));
992 };
993 if !trailers.is_empty() && !self.req_chunked {
994 return Err(HttpError::TrailerNotAllowed);
995 }
996 if *encoder == Encoder::Chunked {
997 push_last_chunk_with_trailers(out, trailers)?;
998 } else {
999 check_trailers(trailers)?;
1000 encoder.finish(out)?;
1001 }
1002 self.req = ReqWrite::Sent;
1003 self.waiting_continue = false;
1004 Ok(())
1005 }
1006
1007 /// Advances the response parser and reports what happened.
1008 ///
1009 /// # Errors
1010 ///
1011 /// Any [`HttpError`] parse error; the connection is then closed and must
1012 /// not be reused.
1013 ///
1014 /// # Examples
1015 ///
1016 /// ```
1017 /// use http_net::{ClientConn, HttpError, Request};
1018 ///
1019 /// let mut conn = ClientConn::new();
1020 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1021 /// let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 1\r\nContent-Length: 1\r\n\r\nx");
1022 /// assert_eq!(conn.poll().unwrap_err(), HttpError::DuplicateContentLength);
1023 /// ```
1024 pub fn poll(&mut self) -> Result<ClientEvent<'_>, HttpError> {
1025 loop {
1026 match self.state {
1027 State::Idle => {
1028 if !self.buf.unread().is_empty() {
1029 return Err(self.fail(HttpError::UnexpectedData));
1030 }
1031 if self.buf.is_eof() {
1032 self.state = State::Closed;
1033 return Ok(ClientEvent::Closed);
1034 }
1035 return Ok(ClientEvent::Idle);
1036 }
1037 State::Head => return self.poll_head(),
1038 State::Interim => {
1039 self.next_head();
1040 self.state = State::Head;
1041 }
1042 State::Body => return self.poll_body(),
1043 State::Complete => {
1044 if self.reusable() && self.queued > 0 {
1045 // Pipelined: the next response is for the oldest
1046 // queued request, and may already be buffered.
1047 self.next_queued();
1048 } else if self.reusable() {
1049 self.state = State::Idle;
1050 } else {
1051 // Queued requests, if any, will get no response;
1052 // `outstanding()` says how many.
1053 self.state = State::Closed;
1054 return Ok(ClientEvent::Closed);
1055 }
1056 }
1057 State::Upgraded => return Ok(ClientEvent::Upgraded),
1058 State::Closed => return Ok(ClientEvent::Closed),
1059 }
1060 }
1061 }
1062
1063 fn poll_head(&mut self) -> Result<ClientEvent<'_>, HttpError> {
1064 loop {
1065 let start = self.buf.pin();
1066 let visible = if self.leniency.obs_fold_in_responses {
1067 let eof = self.buf.is_eof();
1068 self.unfold.run(self.buf.tail_mut(start), eof)
1069 } else {
1070 self.buf.from(start).len()
1071 };
1072 let msg = self.buf.from(start);
1073 let progress = self
1074 .scanner
1075 .advance(
1076 msg.get(..visible).unwrap_or(msg),
1077 &self.limits,
1078 HeadKind::Response,
1079 true,
1080 )
1081 .map_err(|e| self.fail(e))?;
1082 let len = match progress {
1083 Scan::Partial if self.buf.is_eof() => {
1084 return Err(self.fail(HttpError::UnexpectedEof));
1085 }
1086 Scan::Partial => return Ok(ClientEvent::NeedInput),
1087 Scan::Done(len) => len,
1088 };
1089 let info = interpret_response(
1090 self.buf.from(start),
1091 self.scanner.start_line(),
1092 &self.scanner.fields,
1093 &self.limits,
1094 self.asked,
1095 )
1096 .map_err(|e| self.fail(e))?;
1097 self.buf.consume(len);
1098 self.buf.extend_pin_to_pos();
1099 self.info = info;
1100 let status = info.status;
1101 let switched = if status == 101 {
1102 // RFC 9110 section 7.8: a 101 names the protocols it switches
1103 // to, and only to ones the request offered.
1104 let offered = self.upgrade_asked
1105 && info.upgrade_field
1106 && switches_to_offered(
1107 self.buf.from(start),
1108 &self.scanner.fields,
1109 &self.upgrade_offer,
1110 );
1111 if !offered {
1112 return Err(self.fail(HttpError::UnexpectedUpgrade));
1113 }
1114 true
1115 } else {
1116 self.asked.connect && (200..300).contains(&status)
1117 };
1118 if switched {
1119 self.waiting_continue = false;
1120 self.state = State::Upgraded;
1121 } else if (100..200).contains(&status) {
1122 // Interim response (100 Continue, 103 Early Hints): budgeted
1123 // by count and by bytes, so a server cannot keep the client
1124 // parsing forever without a final answer.
1125 self.interim_count = self.interim_count.saturating_add(1);
1126 if self.interim_count > self.limits.max_interim() {
1127 return Err(self.fail(HttpError::TooManyInterim));
1128 }
1129 self.interim_bytes = self.interim_bytes.saturating_add(len);
1130 if self.interim_bytes > self.limits.max_header_bytes() {
1131 return Err(self.fail(HttpError::HeadersTooLarge));
1132 }
1133 if status == 100 && self.waiting_continue {
1134 self.waiting_continue = false;
1135 self.next_head();
1136 return Ok(ClientEvent::Continue);
1137 }
1138 if self.report_interim {
1139 self.state = State::Interim;
1140 return Ok(ClientEvent::Informational(self.view()));
1141 }
1142 self.next_head();
1143 continue;
1144 } else {
1145 if self.waiting_continue {
1146 // RFC 9110 section 10.1.1: a final status instead of 100
1147 // means the server does not want the body. A promised
1148 // body that is never sent leaves the request unfinished,
1149 // so the connection closes after this response.
1150 self.waiting_continue = false;
1151 self.body_refused = self.req != ReqWrite::Sent;
1152 }
1153 self.decoder.start(info.framing);
1154 self.state = State::Body;
1155 }
1156 return Ok(ClientEvent::Response(self.view()));
1157 }
1158 }
1159
1160 /// Drops the current (interim) head and waits for the next one.
1161 fn next_head(&mut self) {
1162 self.buf.unpin();
1163 self.buf.pin_at_pos();
1164 self.scanner.reset();
1165 self.unfold = Unfold::new();
1166 }
1167
1168 fn reusable(&self) -> bool {
1169 self.keep_alive && self.info.keep_alive && self.req == ReqWrite::Sent && !self.body_refused
1170 }
1171
1172 /// The response ended, the connection stays open, and nothing else is
1173 /// outstanding: only the `poll` that reports `Idle` is left, so the
1174 /// connection already answers and sends as if it had run.
1175 fn settled(&self) -> bool {
1176 self.state == State::Complete && self.queued == 0 && self.reusable()
1177 }
1178
1179 fn poll_body(&mut self) -> Result<ClientEvent<'_>, HttpError> {
1180 let mut framing_bytes = 0;
1181 let step = self.decoder.step(
1182 self.buf.unread(),
1183 self.buf.is_eof(),
1184 &self.limits,
1185 &mut self.trailers,
1186 self.report_trailers,
1187 &mut framing_bytes,
1188 );
1189 self.buf.consume(framing_bytes);
1190 match step.map_err(|e| self.fail(e))? {
1191 Step::Data(n) => {
1192 let start = self.buf.pos();
1193 self.buf.consume(n);
1194 Ok(ClientEvent::Body(self.buf.range(start, start + n)))
1195 }
1196 Step::Trailers => Ok(ClientEvent::Trailers(Headers::new(
1197 self.buf.unread(),
1198 &self.trailers.fields,
1199 ))),
1200 Step::Done => {
1201 self.state = State::Complete;
1202 Ok(ClientEvent::ResponseEnd)
1203 }
1204 Step::NeedMore => Ok(ClientEvent::NeedInput),
1205 }
1206 }
1207
1208 fn fail(&mut self, e: HttpError) -> HttpError {
1209 self.response_failed = matches!(self.state, State::Head | State::Interim | State::Body);
1210 self.state = State::Closed;
1211 e
1212 }
1213
1214 fn view(&self) -> ResponseHead<'_> {
1215 ResponseHead::new(
1216 self.buf.from(self.buf.pin()),
1217 &self.scanner.fields,
1218 &self.info,
1219 )
1220 }
1221
1222 /// The current response's head, from its arrival until the connection
1223 /// moves on from it: the next `poll` after `ResponseEnd` or the next
1224 /// [`send_request`](Self::send_request) (still available after an
1225 /// upgrade).
1226 ///
1227 /// # Examples
1228 ///
1229 /// ```
1230 /// use http_net::{ClientConn, ClientEvent, Request};
1231 ///
1232 /// let mut conn = ClientConn::new();
1233 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1234 /// let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1235 /// while !matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd) {}
1236 /// assert_eq!(conn.response().unwrap().status(), 200);
1237 /// ```
1238 #[must_use]
1239 pub fn response(&self) -> Option<ResponseHead<'_>> {
1240 match self.state {
1241 State::Body | State::Complete | State::Upgraded => Some(self.view()),
1242 _ => None,
1243 }
1244 }
1245
1246 /// Whether the server switched protocols and the connection now belongs
1247 /// to another protocol.
1248 ///
1249 /// # Examples
1250 ///
1251 /// ```
1252 /// assert!(!http_net::ClientConn::new().is_upgraded());
1253 /// ```
1254 #[must_use]
1255 pub fn is_upgraded(&self) -> bool {
1256 self.state == State::Upgraded
1257 }
1258
1259 /// Input that arrived after the last message parsed: after
1260 /// [`ClientEvent::Upgraded`], the first bytes of the new protocol.
1261 ///
1262 /// # Examples
1263 ///
1264 /// ```
1265 /// use http_net::{ClientConn, ClientEvent, Request};
1266 ///
1267 /// let mut conn = ClientConn::new();
1268 /// conn.send_request(&Request::get("/").header("host", "a").upgrade("x"), &mut Vec::new()).unwrap();
1269 /// let _ = conn.feed(b"HTTP/1.1 101 Switching Protocols\r\nConnection: upgrade\r\nUpgrade: x\r\n\r\nhi");
1270 /// assert!(matches!(conn.poll().unwrap(), ClientEvent::Response(_)));
1271 /// assert!(matches!(conn.poll().unwrap(), ClientEvent::Upgraded));
1272 /// assert_eq!(conn.remaining_input(), b"hi");
1273 /// ```
1274 #[must_use]
1275 pub fn remaining_input(&self) -> &[u8] {
1276 self.buf.unread()
1277 }
1278
1279 /// When `true`, each interim response other than `101` (for example
1280 /// `103 Early Hints`) is reported as [`ClientEvent::Informational`]
1281 /// before the final response; when `false` (the default) they are
1282 /// skipped. Interim responses count against
1283 /// [`Limits::max_interim`](crate::Limits::max_interim) either way.
1284 ///
1285 /// # Examples
1286 ///
1287 /// ```
1288 /// use http_net::{ClientConn, ClientEvent, Request};
1289 ///
1290 /// let mut conn = ClientConn::new();
1291 /// conn.set_report_informational(true);
1292 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
1293 /// 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");
1294 /// let ClientEvent::Informational(hints) = conn.poll()? else { panic!() };
1295 /// assert_eq!(hints.status(), 103);
1296 /// assert_eq!(hints.header("link"), Some(&b"</a.css>; rel=preload"[..]));
1297 /// assert!(matches!(conn.poll()?, ClientEvent::Response(r) if r.status() == 204));
1298 /// # Ok::<(), http_net::HttpError>(())
1299 /// ```
1300 pub fn set_report_informational(&mut self, report: bool) {
1301 self.report_interim = report;
1302 }
1303
1304 /// When `true`, a response's trailer fields are kept (bounded by the
1305 /// trailer budgets of [`Limits`]) and reported as
1306 /// [`ClientEvent::Trailers`] just before [`ClientEvent::ResponseEnd`];
1307 /// when `false` (the default) they are validated and discarded.
1308 ///
1309 /// # Examples
1310 ///
1311 /// ```
1312 /// use http_net::{ClientConn, ClientEvent, Request};
1313 ///
1314 /// let mut conn = ClientConn::new();
1315 /// conn.set_report_trailers(true);
1316 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
1317 /// 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");
1318 /// let mut saw = false;
1319 /// loop {
1320 /// match conn.poll()? {
1321 /// ClientEvent::Trailers(t) => saw = t.len() == 1,
1322 /// ClientEvent::ResponseEnd => break,
1323 /// _ => {}
1324 /// }
1325 /// }
1326 /// assert!(saw);
1327 /// # Ok::<(), http_net::HttpError>(())
1328 /// ```
1329 pub fn set_report_trailers(&mut self, report: bool) {
1330 self.report_trailers = report;
1331 }
1332
1333 /// Sets the opt-in tolerances for responses (see [`ClientLeniency`]);
1334 /// the default is strict. Takes effect from the next response head.
1335 ///
1336 /// # Examples
1337 ///
1338 /// ```
1339 /// use http_net::{ClientConn, ClientLeniency, HttpError, Request};
1340 ///
1341 /// let folded = b"HTTP/1.1 200 OK\r\nX: a\r\n b\r\nContent-Length: 0\r\n\r\n";
1342 /// let mut strict = ClientConn::new();
1343 /// strict.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
1344 /// let _ = strict.feed(folded);
1345 /// assert_eq!(strict.poll().unwrap_err(), HttpError::ObsFold);
1346 ///
1347 /// let mut lenient = ClientConn::new();
1348 /// lenient.set_leniency(ClientLeniency::new().with_obs_fold_in_responses(true));
1349 /// lenient.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
1350 /// let _ = lenient.feed(folded);
1351 /// assert!(lenient.poll().is_ok());
1352 /// # Ok::<(), http_net::HttpError>(())
1353 /// ```
1354 pub fn set_leniency(&mut self, leniency: ClientLeniency) {
1355 self.leniency = leniency;
1356 }
1357
1358 /// Whether a request built with
1359 /// [`Request::expect_continue`](crate::Request::expect_continue) is
1360 /// still waiting: no `100 Continue`, no final response, and no body
1361 /// bytes sent yet. A client may stop waiting on its own timer and send
1362 /// the body anyway (RFC 9110 section 10.1.1).
1363 ///
1364 /// # Examples
1365 ///
1366 /// ```
1367 /// use http_net::{ClientConn, ClientEvent, Request};
1368 ///
1369 /// let mut conn = ClientConn::new();
1370 /// let mut out = Vec::new();
1371 /// let upload = Request::put("/big").header("host", "a").content_length(4).expect_continue();
1372 /// conn.send_request(&upload, &mut out)?;
1373 /// assert!(conn.is_waiting_for_continue());
1374 /// let _ = conn.feed(b"HTTP/1.1 100 Continue\r\n\r\n");
1375 /// assert!(matches!(conn.poll()?, ClientEvent::Continue));
1376 /// assert!(!conn.is_waiting_for_continue());
1377 /// conn.send_body(b"data", &mut out)?;
1378 /// conn.end_body(&mut out)?;
1379 /// # Ok::<(), http_net::HttpError>(())
1380 /// ```
1381 #[must_use]
1382 pub fn is_waiting_for_continue(&self) -> bool {
1383 self.waiting_continue
1384 }
1385
1386 /// Whether the connection can carry another request now: no request
1387 /// is outstanding (or the last response completed) and both sides allow
1388 /// keep-alive. With pipelining, [`can_send`](Self::can_send) says
1389 /// whether another request can be sent while some are outstanding.
1390 ///
1391 /// # Examples
1392 ///
1393 /// ```
1394 /// use http_net::{ClientConn, ClientEvent, Request};
1395 ///
1396 /// let mut conn = ClientConn::new();
1397 /// assert!(conn.is_reusable());
1398 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
1399 /// assert!(!conn.is_reusable());
1400 /// let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1401 /// while !matches!(conn.poll()?, ClientEvent::ResponseEnd) {}
1402 /// assert!(conn.is_reusable());
1403 /// # Ok::<(), http_net::HttpError>(())
1404 /// ```
1405 #[must_use]
1406 pub fn is_reusable(&self) -> bool {
1407 match self.state {
1408 State::Idle => self.buf.unread().is_empty() && !self.buf.is_eof(),
1409 State::Complete => self.settled() && self.buf.unread().is_empty(),
1410 _ => false,
1411 }
1412 }
1413
1414 /// The connection's phase, for response deadlines: [`Progress::Idle`]
1415 /// with no request outstanding, [`Progress::WritingBody`] while a
1416 /// request body is streamed, [`Progress::AwaitingResponse`] until the
1417 /// first byte of the response, then [`Progress::Head`] and
1418 /// [`Progress::Body`].
1419 ///
1420 /// # Examples
1421 ///
1422 /// ```
1423 /// use http_net::{ClientConn, Progress, Request};
1424 ///
1425 /// let mut conn = ClientConn::new();
1426 /// assert_eq!(conn.progress(), Progress::Idle);
1427 /// conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new())?;
1428 /// assert_eq!(conn.progress(), Progress::AwaitingResponse);
1429 /// # Ok::<(), http_net::HttpError>(())
1430 /// ```
1431 #[must_use]
1432 pub fn progress(&self) -> Progress {
1433 if matches!(self.req, ReqWrite::Streaming(_))
1434 && !self.body_refused
1435 && !matches!(self.state, State::Closed | State::Upgraded)
1436 {
1437 return Progress::WritingBody;
1438 }
1439 match self.state {
1440 State::Idle => Progress::Idle,
1441 State::Head if self.buf.from(self.buf.pin()).is_empty() => Progress::AwaitingResponse,
1442 State::Head | State::Interim => Progress::Head,
1443 State::Body => Progress::Body,
1444 State::Complete if self.settled() => Progress::Idle,
1445 State::Complete if self.reusable() => Progress::AwaitingResponse,
1446 State::Complete | State::Closed => Progress::Closed,
1447 State::Upgraded => Progress::Upgraded,
1448 }
1449 }
1450}
1451
1452#[cfg(test)]
1453mod tests {
1454 use super::*;
1455 use crate::head::BodyFraming;
1456
1457 fn get() -> Request {
1458 Request::get("/").header("host", "a")
1459 }
1460
1461 #[test]
1462 fn test_interim_responses_are_skipped() {
1463 let mut conn = ClientConn::new();
1464 conn.send_request(&get(), &mut Vec::new()).unwrap();
1465 let _ = conn.feed(b"HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 103 Early Hints\r\nLink: </a>\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok");
1466 let ClientEvent::Response(r) = conn.poll().unwrap() else {
1467 panic!("expected response");
1468 };
1469 assert_eq!(r.status(), 200);
1470 assert!(matches!(conn.poll().unwrap(), ClientEvent::Body(b"ok")));
1471 assert!(matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd));
1472 assert!(matches!(conn.poll().unwrap(), ClientEvent::Idle));
1473 }
1474
1475 #[test]
1476 fn test_unrequested_upgrade_and_unsolicited_data_are_errors() {
1477 let mut conn = ClientConn::new();
1478 conn.send_request(&get(), &mut Vec::new()).unwrap();
1479 let _ = conn
1480 .feed(b"HTTP/1.1 101 Switching Protocols\r\nUpgrade: x\r\nConnection: upgrade\r\n\r\n");
1481 assert_eq!(conn.poll().unwrap_err(), HttpError::UnexpectedUpgrade);
1482
1483 let mut conn = ClientConn::new();
1484 let _ = conn.feed(b"HTTP/1.1 200 OK\r\n\r\n");
1485 assert_eq!(conn.poll().unwrap_err(), HttpError::UnexpectedData);
1486 }
1487
1488 /// T-21: a `101` switches only to a protocol the request offered (RFC
1489 /// 9110 section 7.8); a back end answering an upgrade to something else
1490 /// must not take over the connection.
1491 #[test]
1492 fn test_switching_protocols_must_name_an_offered_protocol() {
1493 let answer = |offers: &[&str], upgrade: &str| {
1494 let mut request = Request::get("/").header("host", "a");
1495 for offer in offers {
1496 request = request.upgrade(offer);
1497 }
1498 let mut conn = ClientConn::new();
1499 conn.send_request(&request, &mut Vec::new()).unwrap();
1500 let response = alloc::format!(
1501 "HTTP/1.1 101 Switching Protocols\r\nConnection: upgrade\r\n{upgrade}\r\n"
1502 );
1503 let _ = conn.feed(response.as_bytes());
1504 match conn.poll() {
1505 Ok(ClientEvent::Response(r)) => {
1506 assert_eq!(r.status(), 101);
1507 matches!(conn.poll(), Ok(ClientEvent::Upgraded))
1508 }
1509 Err(e) => {
1510 assert_eq!(e, HttpError::UnexpectedUpgrade);
1511 false
1512 }
1513 other => panic!("unexpected {other:?}"),
1514 }
1515 };
1516 // The protocol offered, in any case, with or without a version.
1517 assert!(answer(&["websocket"], "Upgrade: websocket\r\n"));
1518 assert!(answer(&["websocket"], "Upgrade: WebSocket\r\n"));
1519 assert!(answer(&["websocket/13"], "Upgrade: websocket\r\n"));
1520 assert!(answer(&["websocket"], "Upgrade: websocket/13\r\n"));
1521 // One of several offers.
1522 assert!(answer(&["foo", "websocket"], "Upgrade: websocket\r\n"));
1523 // Anything not offered, h2c above all, or no protocol at all.
1524 assert!(!answer(&["websocket"], "Upgrade: h2c\r\n"));
1525 assert!(!answer(&["websocket"], "Upgrade: foo\r\n"));
1526 assert!(!answer(&["websocket"], "Upgrade: websocket, foo\r\n"));
1527 assert!(!answer(
1528 &["websocket"],
1529 "Upgrade: websocket\r\nUpgrade: foo\r\n"
1530 ));
1531 assert!(!answer(&["websocket/13"], "Upgrade: websocket/14\r\n"));
1532 assert!(!answer(&["websocket"], "Upgrade:\r\n"));
1533 assert!(!answer(&["websocket"], ""));
1534 }
1535
1536 #[test]
1537 fn test_head_response_has_no_body_and_connection_is_reused() {
1538 let mut conn = ClientConn::new();
1539 conn.send_request(
1540 &Request::new("HEAD", "/").header("host", "a"),
1541 &mut Vec::new(),
1542 )
1543 .unwrap();
1544 let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 100\r\n\r\n");
1545 let ClientEvent::Response(r) = conn.poll().unwrap() else {
1546 panic!("expected response");
1547 };
1548 assert_eq!(r.framing(), BodyFraming::None);
1549 assert!(matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd));
1550 assert!(matches!(conn.poll().unwrap(), ClientEvent::Idle));
1551 conn.send_request(&get(), &mut Vec::new()).unwrap();
1552 assert!(matches!(
1553 conn.send_request(&get(), &mut Vec::new()),
1554 Err(HttpError::InvalidState(_))
1555 ));
1556 }
1557
1558 #[test]
1559 fn test_close_and_streaming_request_prevent_reuse() {
1560 let mut conn = ClientConn::new();
1561 conn.send_request(&get().close(), &mut Vec::new()).unwrap();
1562 let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1563 while !matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd) {}
1564 assert!(matches!(conn.poll().unwrap(), ClientEvent::Closed));
1565 assert!(conn.send_request(&get(), &mut Vec::new()).is_err());
1566
1567 let mut conn = ClientConn::new();
1568 let mut out = Vec::new();
1569 conn.send_request(&Request::post("/").header("host", "a").chunked(), &mut out)
1570 .unwrap();
1571 let _ = conn.feed(b"HTTP/1.1 413 Content Too Large\r\nContent-Length: 0\r\n\r\n");
1572 while !matches!(conn.poll().unwrap(), ClientEvent::ResponseEnd) {}
1573 assert!(matches!(conn.poll().unwrap(), ClientEvent::Closed));
1574 assert!(matches!(conn.send_body(b"x", &mut out), Ok(())));
1575 assert!(matches!(conn.end_body(&mut out), Ok(())));
1576 assert!(matches!(
1577 conn.end_body(&mut out),
1578 Err(HttpError::InvalidState(_))
1579 ));
1580 }
1581
1582 #[test]
1583 fn test_eof_before_response_is_an_error() {
1584 let mut conn = ClientConn::new();
1585 conn.send_request(&get(), &mut Vec::new()).unwrap();
1586 conn.feed_eof();
1587 assert_eq!(conn.poll().unwrap_err(), HttpError::UnexpectedEof);
1588 }
1589}