Skip to main content

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}