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