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