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