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