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