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