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