http_net/head.rs
1//! Incremental scanning of message heads, their interpretation, and the
2//! borrowed views handed to callers.
3//!
4//! The scanner finds one CRLF-terminated line at a time and remembers where
5//! it stopped searching, so input that arrives one byte at a time is still
6//! examined once: head parsing is linear in the head's length no matter how
7//! it is split. Each line is fully validated when it completes; field
8//! positions are stored as offsets from the message start so the head can be
9//! read back without copying.
10
11use alloc::vec::Vec;
12use core::{fmt, slice};
13
14use crate::{
15 error::HttpError,
16 limits::Limits,
17 method::Method,
18 redact::{FieldName, FieldValue},
19 syntax::{
20 ListSplit, check_field_value, find_byte, is_host_value, is_ows, is_reason, is_target_chars,
21 is_tchar, is_token, list_elements, parse_decimal, trim_ows,
22 },
23};
24
25/// A byte range of a message head: `start..end`, as offsets into
26/// [`RawHead::bytes`](crate::RawHead::bytes) (or into the input of a
27/// stateless parser).
28///
29/// Offsets are `u32` because every budget in [`Limits`] is capped at
30/// 16 MiB, so a head can never be longer. Spans stay valid when the head
31/// bytes are moved or copied, which is what makes a head cheap to copy into
32/// a passport ([`RequestHead::copy_into`]).
33///
34/// # Examples
35///
36/// ```
37/// use http_net::Span;
38///
39/// let head = b"GET / HTTP/1.1\r\n";
40/// let method = Span { start: 0, end: 3 };
41/// assert_eq!(method.get(head), b"GET");
42/// assert_eq!(method.len(), 3);
43/// // Out of range: an empty slice, never a panic.
44/// assert_eq!(Span { start: 10, end: 99 }.get(head), b"");
45/// ```
46#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
47pub struct Span {
48 /// The first byte.
49 pub start: u32,
50 /// One past the last byte.
51 pub end: u32,
52}
53
54impl Span {
55 #[inline]
56 pub(crate) fn new(start: usize, end: usize) -> Self {
57 // Offsets are bounded by the buffer capacity, which `Limits` keeps
58 // far below `u32::MAX`.
59 Self {
60 start: start as u32,
61 end: end as u32,
62 }
63 }
64
65 /// The bytes of `head` the span covers; empty when the span lies
66 /// outside `head` or is reversed.
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// let span = http_net::Span { start: 4, end: 5 };
72 /// assert_eq!(span.get(b"GET / HTTP/1.1"), b"/");
73 /// ```
74 #[inline]
75 #[must_use]
76 pub fn get<'b>(&self, head: &'b [u8]) -> &'b [u8] {
77 head.get(self.start as usize..self.end as usize)
78 .unwrap_or(&[])
79 }
80
81 /// The span's length in bytes (0 for a reversed span).
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// assert_eq!(http_net::Span { start: 2, end: 7 }.len(), 5);
87 /// ```
88 #[inline]
89 #[must_use]
90 pub const fn len(&self) -> u32 {
91 self.end.saturating_sub(self.start)
92 }
93
94 /// Whether the span covers no bytes.
95 ///
96 /// # Examples
97 ///
98 /// ```
99 /// assert!(http_net::Span::default().is_empty());
100 /// ```
101 #[inline]
102 #[must_use]
103 pub const fn is_empty(&self) -> bool {
104 self.len() == 0
105 }
106
107 /// Whether the span lies inside a head of `len` bytes, in order.
108 pub(crate) const fn fits(&self, len: usize) -> bool {
109 self.start <= self.end && (self.end as usize) <= len
110 }
111}
112
113/// One field line of a head: the name's span and the value's span (the
114/// value without surrounding whitespace), as offsets into the head bytes.
115///
116/// # Examples
117///
118/// ```
119/// use http_net::{ServerConn, ServerEvent};
120///
121/// let mut conn = ServerConn::new();
122/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a \r\n\r\n");
123/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
124/// let raw = req.raw();
125/// let host = raw.fields()[0];
126/// assert_eq!(host.name.get(raw.bytes()), b"Host");
127/// assert_eq!(host.value.get(raw.bytes()), b"a");
128/// ```
129#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
130pub struct FieldSpan {
131 /// The field name, as received.
132 pub name: Span,
133 /// The field value, without leading or trailing whitespace.
134 pub value: Span,
135}
136
137/// The connections' own name for a field record.
138pub(crate) type Field = FieldSpan;
139
140/// Where scanned field records go: the connection's reusable vector, a
141/// caller's slice (the stateless parsers, which allocate nothing), or
142/// nowhere (trailers that are validated and discarded).
143pub(crate) trait FieldSink {
144 fn put(&mut self, field: Field) -> Result<(), HttpError>;
145}
146
147impl FieldSink for Vec<Field> {
148 #[inline]
149 fn put(&mut self, field: Field) -> Result<(), HttpError> {
150 self.push(field);
151 Ok(())
152 }
153}
154
155/// Validates fields without keeping them.
156pub(crate) struct Discard;
157
158impl FieldSink for Discard {
159 #[inline]
160 fn put(&mut self, _field: Field) -> Result<(), HttpError> {
161 Ok(())
162 }
163}
164
165/// Fills a caller's slice; a field that does not fit is `TooManyHeaders`.
166pub(crate) struct SliceSink<'s> {
167 slots: &'s mut [Field],
168 len: usize,
169}
170
171impl<'s> SliceSink<'s> {
172 pub(crate) fn new(slots: &'s mut [Field]) -> Self {
173 Self { slots, len: 0 }
174 }
175
176 /// The slice back, and how many records were written to its front.
177 pub(crate) fn into_parts(self) -> (&'s mut [Field], usize) {
178 (self.slots, self.len)
179 }
180}
181
182impl FieldSink for SliceSink<'_> {
183 #[inline]
184 fn put(&mut self, field: Field) -> Result<(), HttpError> {
185 let slot = self
186 .slots
187 .get_mut(self.len)
188 .ok_or(HttpError::TooManyHeaders)?;
189 *slot = field;
190 self.len += 1;
191 Ok(())
192 }
193}
194
195#[derive(Clone, Copy, Debug, PartialEq, Eq)]
196pub(crate) enum HeadKind {
197 Request,
198 Response,
199 Trailer,
200}
201
202pub(crate) enum Scan {
203 Partial,
204 /// The head is complete; the value is its length including the blank line.
205 Done(usize),
206}
207
208/// Finds the next CRLF-terminated line starting at `line_start`, resuming
209/// the search at `*scan`. Returns the end of the line content (the index of
210/// its CR). `budget` bounds the line length including CRLF.
211pub(crate) fn find_line(
212 msg: &[u8],
213 line_start: usize,
214 scan: &mut usize,
215 budget: usize,
216 too_long: HttpError,
217) -> Result<Option<usize>, HttpError> {
218 let from = (*scan).max(line_start);
219 let hay = msg.get(from..).unwrap_or(&[]);
220 match find_byte(b'\n', hay) {
221 Some(i) => {
222 let lf = from + i;
223 if lf + 1 - line_start > budget {
224 return Err(too_long);
225 }
226 if lf == line_start || msg.get(lf - 1) != Some(&b'\r') {
227 return Err(HttpError::BareLf);
228 }
229 *scan = lf + 1;
230 Ok(Some(lf - 1))
231 }
232 None => {
233 *scan = msg.len();
234 if msg.len().saturating_sub(line_start) >= budget {
235 Err(too_long)
236 } else {
237 Ok(None)
238 }
239 }
240 }
241}
242
243/// Resumable scanner over a head (start line plus field lines) or a trailer
244/// section (field lines only), keeping its fields in a reusable vector.
245pub(crate) struct HeadScanner {
246 lines: LineScan,
247 pub(crate) fields: Vec<Field>,
248}
249
250impl HeadScanner {
251 pub(crate) const fn new() -> Self {
252 Self {
253 lines: LineScan::new(),
254 fields: Vec::new(),
255 }
256 }
257
258 /// Prepares for the next message; keeps the field vector's allocation.
259 pub(crate) fn reset(&mut self) {
260 self.lines = LineScan::new();
261 self.fields.clear();
262 }
263
264 /// Fields scanned in the current section, stored or not.
265 pub(crate) fn field_count(&self) -> usize {
266 self.lines.count
267 }
268
269 pub(crate) fn start_line(&self) -> Span {
270 self.lines.start_line()
271 }
272
273 /// Scans `msg` (the bytes from the message start to the end of input).
274 /// With `store` the fields are kept in [`fields`](Self::fields);
275 /// otherwise they are validated and counted only.
276 #[inline]
277 pub(crate) fn advance(
278 &mut self,
279 msg: &[u8],
280 limits: &Limits,
281 kind: HeadKind,
282 store: bool,
283 ) -> Result<Scan, HttpError> {
284 if store {
285 self.lines.advance(msg, limits, kind, &mut self.fields)
286 } else {
287 self.lines.advance(msg, limits, kind, &mut Discard)
288 }
289 }
290}
291
292/// The line-by-line state of a head scan: where the search stopped and
293/// what has been counted. Shared by the connections and the stateless
294/// parsers; the fields go to a [`FieldSink`].
295pub(crate) struct LineScan {
296 scan: usize,
297 line_start: usize,
298 start_line: Option<Span>,
299 skipped: usize,
300 field_bytes: usize,
301 count: usize,
302}
303
304impl LineScan {
305 pub(crate) const fn new() -> Self {
306 Self {
307 scan: 0,
308 line_start: 0,
309 start_line: None,
310 skipped: 0,
311 field_bytes: 0,
312 count: 0,
313 }
314 }
315
316 pub(crate) fn start_line(&self) -> Span {
317 self.start_line.unwrap_or_default()
318 }
319
320 /// Scans `msg` (the bytes from the message start to the end of input),
321 /// handing each validated field to `sink`.
322 pub(crate) fn advance<S: FieldSink>(
323 &mut self,
324 msg: &[u8],
325 limits: &Limits,
326 kind: HeadKind,
327 sink: &mut S,
328 ) -> Result<Scan, HttpError> {
329 let (section_bytes, section_fields) = if kind == HeadKind::Trailer {
330 (limits.max_trailer_bytes(), limits.max_trailer_fields())
331 } else {
332 (limits.max_header_bytes(), limits.max_headers())
333 };
334 loop {
335 let in_start = kind != HeadKind::Trailer && self.start_line.is_none();
336 let (budget, too_long) = if in_start {
337 (
338 limits.max_start_line().saturating_sub(self.skipped),
339 HttpError::StartLineTooLong,
340 )
341 } else {
342 // One line may not exceed the field-line budget, nor what is
343 // left of the section; whichever is smaller decides the error.
344 let section = section_bytes.saturating_sub(self.field_bytes);
345 if limits.max_field_line() < section {
346 (limits.max_field_line(), HttpError::FieldLineTooLong)
347 } else {
348 (section, HttpError::HeadersTooLarge)
349 }
350 };
351 let Some(end) = find_line(msg, self.line_start, &mut self.scan, budget, too_long)?
352 else {
353 return Ok(Scan::Partial);
354 };
355 let start = self.line_start;
356 let line = msg.get(start..end).unwrap_or(&[]);
357 let line_len = self.scan - start;
358 self.line_start = self.scan;
359
360 if in_start {
361 if line.is_empty() {
362 if kind == HeadKind::Request {
363 // RFC 9112 section 2.2: ignore empty lines before the
364 // request line. They count against its budget.
365 self.skipped += line_len;
366 continue;
367 }
368 return Err(HttpError::InvalidStartLine);
369 }
370 if find_byte(b'\r', line).is_some() {
371 return Err(HttpError::BareCr);
372 }
373 self.start_line = Some(Span::new(start, end));
374 continue;
375 }
376 if line.is_empty() {
377 return Ok(Scan::Done(self.scan));
378 }
379 self.field_bytes += line_len;
380 // Every field line must leave room for the blank line that ends
381 // the section, so the section as a whole fits the budget.
382 if self.field_bytes + 2 > section_bytes {
383 return Err(HttpError::HeadersTooLarge);
384 }
385 if self.count >= section_fields {
386 return Err(HttpError::TooManyHeaders);
387 }
388 let field = parse_field(line, start)?;
389 self.count += 1;
390 sink.put(field)?;
391 }
392 }
393}
394
395/// Validates one field line (`line` starts at offset `base` in the head).
396// Forced inline: the scanner is compiled once per field sink, and without
397// it this per-field call stays out of line (about 8% on the head
398// benchmark, 12% on client response parsing).
399#[inline(always)]
400fn parse_field(line: &[u8], base: usize) -> Result<Field, HttpError> {
401 if line.first().is_some_and(|&b| is_ows(b)) {
402 return Err(HttpError::ObsFold);
403 }
404 let Some(colon) = find_byte(b':', line) else {
405 return Err(if find_byte(b'\r', line).is_some() {
406 HttpError::BareCr
407 } else {
408 HttpError::InvalidHeaderName
409 });
410 };
411 let name = &line[..colon];
412 if name.last().is_some_and(|&b| is_ows(b)) {
413 return Err(HttpError::WhitespaceBeforeColon);
414 }
415 if !name.iter().all(|&b| is_tchar(b)) || name.is_empty() {
416 return Err(if find_byte(b'\r', name).is_some() {
417 HttpError::BareCr
418 } else {
419 HttpError::InvalidHeaderName
420 });
421 }
422 let raw = &line[colon + 1..];
423 let lead = raw.iter().take_while(|&&b| is_ows(b)).count();
424 let value = trim_ows(raw);
425 check_field_value(value)?;
426 let value_start = base + colon + 1 + lead;
427 Ok(Field {
428 name: Span::new(base, base + colon),
429 value: Span::new(value_start, value_start + value.len()),
430 })
431}
432
433/// The HTTP version of a message.
434///
435/// # Examples
436///
437/// ```
438/// use http_net::Version;
439///
440/// assert_eq!(Version::Http11.as_str(), "HTTP/1.1");
441/// ```
442#[non_exhaustive]
443#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
444pub enum Version {
445 /// HTTP/1.0: no chunked encoding, keep-alive only when asked for.
446 Http10,
447 /// HTTP/1.1 (also used for HTTP/1.2 through 1.9, which RFC 9110 section
448 /// 2.5 says to process as the highest implemented minor version).
449 Http11,
450}
451
452impl Version {
453 /// The version's wire text.
454 ///
455 /// # Examples
456 ///
457 /// ```
458 /// assert_eq!(http_net::Version::Http10.as_str(), "HTTP/1.0");
459 /// ```
460 #[must_use]
461 pub const fn as_str(&self) -> &'static str {
462 match self {
463 Self::Http10 => "HTTP/1.0",
464 Self::Http11 => "HTTP/1.1",
465 }
466 }
467}
468
469/// How a message's body is delimited.
470///
471/// # Examples
472///
473/// ```
474/// use http_net::{BodyFraming, ServerConn, ServerEvent};
475///
476/// let mut conn = ServerConn::new();
477/// let _ = conn.feed(b"POST /x HTTP/1.1\r\nHost: a\r\nContent-Length: 3\r\n\r\nabc");
478/// match conn.poll().unwrap() {
479/// ServerEvent::Request(req) => assert_eq!(req.framing(), BodyFraming::Length(3)),
480/// other => panic!("{other:?}"),
481/// }
482/// ```
483#[non_exhaustive]
484#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
485pub enum BodyFraming {
486 /// No body.
487 None,
488 /// Exactly this many bytes (`Content-Length`).
489 Length(u64),
490 /// `Transfer-Encoding: chunked`.
491 Chunked,
492 /// The body runs until the peer closes the connection (responses only).
493 UntilClose,
494}
495
496/// The form of a request target (RFC 9112 section 3.2).
497///
498/// # Examples
499///
500/// ```
501/// use http_net::{ServerConn, ServerEvent, TargetForm};
502///
503/// let mut conn = ServerConn::new();
504/// let _ = conn.feed(b"OPTIONS * HTTP/1.1\r\nHost: a\r\n\r\n");
505/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
506/// assert_eq!(req.target_form(), TargetForm::Asterisk);
507/// ```
508#[non_exhaustive]
509#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
510pub enum TargetForm {
511 /// `/path?query`: the usual form for requests to an origin server.
512 Origin,
513 /// `scheme://authority/path?query`: requests to a proxy (and, per RFC
514 /// 9112 section 3.2.2, acceptable to origin servers too).
515 Absolute,
516 /// `host:port`: only with `CONNECT`.
517 Authority,
518 /// `*`: only with `OPTIONS`, for the server as a whole.
519 Asterisk,
520}
521
522/// The `h2c` upgrade token, which is never treated as an upgrade offer
523/// (RFC 9113 section 3.1 deprecates it; forwarded blindly by a proxy, it is
524/// the h2c smuggling attack).
525pub(crate) fn is_h2c(protocol: &[u8]) -> bool {
526 let name = protocol
527 .iter()
528 .position(|&b| b == b'/')
529 .map_or(protocol, |i| &protocol[..i]);
530 name.eq_ignore_ascii_case(b"h2c")
531}
532
533/// Whether a `101` naming `chosen` answers an `Upgrade` offer `element`:
534/// ASCII case-insensitive, and a name without a version matches an offer of
535/// that name with any version (`websocket` answers `websocket/13`).
536pub(crate) fn protocol_matches(chosen: &[u8], element: &[u8]) -> bool {
537 if is_h2c(element) || is_h2c(chosen) {
538 return false;
539 }
540 if chosen.eq_ignore_ascii_case(element) {
541 return true;
542 }
543 !chosen.contains(&b'/')
544 && element
545 .iter()
546 .position(|&b| b == b'/')
547 .is_some_and(|i| element[..i].eq_ignore_ascii_case(chosen))
548}
549
550pub(crate) fn parse_version(v: &[u8]) -> Result<Version, HttpError> {
551 match v {
552 [b'H', b'T', b'T', b'P', b'/', major, b'.', minor]
553 if major.is_ascii_digit() && minor.is_ascii_digit() =>
554 {
555 match (major, minor) {
556 (b'1', b'0') => Ok(Version::Http10),
557 (b'1', _) => Ok(Version::Http11),
558 _ => Err(HttpError::UnsupportedVersion),
559 }
560 }
561 _ => Err(HttpError::InvalidVersion),
562 }
563}
564
565/// What the framing-relevant fields of a message say.
566#[derive(Default)]
567struct FieldFacts {
568 content_length: Option<u64>,
569 te_seen: bool,
570 te_codings: usize,
571 te_chunked: usize,
572 te_last_chunked: bool,
573 te_other: bool,
574 close: bool,
575 keep_alive: bool,
576 upgrade_token: bool,
577 upgrade_field: bool,
578 /// An `Upgrade` element other than `h2c`.
579 upgrade_offer: bool,
580 expect_continue: bool,
581 /// An `Expect` element other than `100-continue`.
582 expect_other: bool,
583 hosts: usize,
584 host: Option<Span>,
585}
586
587fn scan_fields(head: &[u8], fields: &[Field]) -> Result<FieldFacts, HttpError> {
588 let mut facts = FieldFacts::default();
589 for field in fields {
590 let name = field.name.get(head);
591 let value = field.value.get(head);
592 if name.eq_ignore_ascii_case(b"content-length") {
593 if facts.content_length.is_some() {
594 return Err(HttpError::DuplicateContentLength);
595 }
596 facts.content_length =
597 Some(parse_decimal(value).ok_or(HttpError::InvalidContentLength)?);
598 } else if name.eq_ignore_ascii_case(b"transfer-encoding") {
599 facts.te_seen = true;
600 for element in list_elements(value) {
601 let (coding, params) = match find_byte(b';', element) {
602 Some(i) => (trim_ows(&element[..i]), true),
603 None => (element, false),
604 };
605 if !is_token(coding) {
606 return Err(HttpError::InvalidTransferEncoding);
607 }
608 facts.te_codings += 1;
609 if coding.eq_ignore_ascii_case(b"chunked") {
610 if params {
611 return Err(HttpError::InvalidTransferEncoding);
612 }
613 facts.te_chunked += 1;
614 facts.te_last_chunked = true;
615 } else {
616 facts.te_other = true;
617 facts.te_last_chunked = false;
618 }
619 }
620 } else if name.eq_ignore_ascii_case(b"connection") {
621 for token in list_elements(value) {
622 if token.eq_ignore_ascii_case(b"close") {
623 facts.close = true;
624 } else if token.eq_ignore_ascii_case(b"keep-alive") {
625 facts.keep_alive = true;
626 } else if token.eq_ignore_ascii_case(b"upgrade") {
627 facts.upgrade_token = true;
628 }
629 }
630 } else if name.eq_ignore_ascii_case(b"upgrade") {
631 facts.upgrade_field |= !value.is_empty();
632 facts.upgrade_offer |= list_elements(value).any(|e| !is_h2c(e));
633 } else if name.eq_ignore_ascii_case(b"host") {
634 facts.hosts += 1;
635 facts.host = Some(field.value);
636 } else if name.eq_ignore_ascii_case(b"expect") {
637 // RFC 9110 section 10.1.1: the expectation is case-insensitive.
638 for e in list_elements(value) {
639 if e.eq_ignore_ascii_case(b"100-continue") {
640 facts.expect_continue = true;
641 } else {
642 facts.expect_other = true;
643 }
644 }
645 }
646 }
647 Ok(facts)
648}
649
650/// Applies RFC 9112 section 6 to the transfer-coding facts.
651fn transfer_framing(
652 facts: &FieldFacts,
653 version: Version,
654) -> Result<Option<BodyFraming>, HttpError> {
655 if !facts.te_seen {
656 return Ok(None);
657 }
658 if version == Version::Http10 {
659 return Err(HttpError::TransferEncodingInHttp10);
660 }
661 if facts.content_length.is_some() {
662 return Err(HttpError::ConflictingFraming);
663 }
664 if facts.te_codings == 0 || facts.te_chunked > 1 || !facts.te_last_chunked {
665 return Err(HttpError::InvalidTransferEncoding);
666 }
667 if facts.te_other {
668 return Err(HttpError::UnsupportedTransferEncoding);
669 }
670 Ok(Some(BodyFraming::Chunked))
671}
672
673/// Everything learned from a request head. Spans are offsets into the head
674/// bytes, so the facts stay valid when the bytes are copied.
675#[derive(Clone, Copy, Debug, PartialEq, Eq)]
676pub(crate) struct RequestInfo {
677 pub(crate) method: Method,
678 pub(crate) start_line: Span,
679 pub(crate) method_span: Span,
680 pub(crate) target: Span,
681 target_form: TargetForm,
682 pub(crate) version: Version,
683 pub(crate) framing: BodyFraming,
684 content_length: Option<u64>,
685 pub(crate) keep_alive: bool,
686 pub(crate) upgrade: bool,
687 pub(crate) expect_continue: bool,
688 unknown_expectation: bool,
689 pub(crate) host: Option<Span>,
690 /// The authority of an absolute-form target, which replaces `Host`.
691 pub(crate) authority: Option<Span>,
692 /// The path-and-query part of the target: the whole target except for
693 /// the absolute form, where it is what follows the authority.
694 pub(crate) origin: Span,
695}
696
697impl RequestInfo {
698 pub(crate) const EMPTY: Self = Self {
699 method: Method::Get,
700 start_line: Span { start: 0, end: 0 },
701 method_span: Span { start: 0, end: 0 },
702 target: Span { start: 0, end: 0 },
703 target_form: TargetForm::Origin,
704 version: Version::Http11,
705 framing: BodyFraming::None,
706 content_length: None,
707 keep_alive: false,
708 upgrade: false,
709 expect_continue: false,
710 unknown_expectation: false,
711 host: None,
712 authority: None,
713 origin: Span { start: 0, end: 0 },
714 };
715}
716
717/// Validates a request target against the forms its method allows.
718pub(crate) fn check_target(method: Method, target: &[u8]) -> Result<(), HttpError> {
719 let ok = match target.first() {
720 None => false,
721 Some(b'/') => method != Method::Connect && is_target_chars(target),
722 Some(b'*') if target.len() == 1 => method == Method::Options,
723 Some(_) if method == Method::Connect => {
724 // authority-form: host ":" port, with a non-empty host and port.
725 is_authority(target)
726 && target
727 .iter()
728 .rposition(|&b| b == b':')
729 .is_some_and(|c| c + 1 < target.len() && !target[c..].contains(&b']'))
730 }
731 Some(_) => split_absolute_form(target).is_some(),
732 };
733 if ok {
734 Ok(())
735 } else {
736 Err(HttpError::InvalidTarget)
737 }
738}
739
740/// `host [":" port]` with a non-empty host: RFC 9110 section 4.2.1 makes an
741/// empty host in an `http` URI invalid.
742fn is_authority(s: &[u8]) -> bool {
743 !s.is_empty() && s[0] != b':' && is_host_value(s)
744}
745
746/// Splits an absolute-form target, `scheme "://" authority path-abempty
747/// [ "?" query ]`, returning the authority's range within it.
748///
749/// Only the hierarchical form with an authority is accepted: it is the form
750/// RFC 9112 section 3.2.2 describes (requests to proxies, and future
751/// requests to origin servers), and it is the only one that names the host
752/// the request is for. Userinfo is refused (RFC 9110 section 4.2.4 says to
753/// treat it as an error), as is an empty host.
754fn split_absolute_form(target: &[u8]) -> Option<(usize, usize)> {
755 let colon = find_byte(b':', target)?;
756 let scheme = &target[..colon];
757 let scheme_ok = scheme.first().is_some_and(u8::is_ascii_alphabetic)
758 && scheme
759 .iter()
760 .all(|&b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.'));
761 if !scheme_ok || !target[colon..].starts_with(b"://") {
762 return None;
763 }
764 let auth_start = colon + 3;
765 let after = &target[auth_start..];
766 let auth_len = after
767 .iter()
768 .position(|&b| b == b'/' || b == b'?')
769 .unwrap_or(after.len());
770 let authority = &after[..auth_len];
771 let rest = &after[auth_len..];
772 (is_authority(authority) && is_target_chars(rest))
773 .then_some((auth_start, auth_start + auth_len))
774}
775
776pub(crate) fn interpret_request(
777 head: &[u8],
778 start: Span,
779 fields: &[Field],
780 limits: &Limits,
781) -> Result<RequestInfo, HttpError> {
782 let line = start.get(head);
783 let base = start.start as usize;
784 let sp1 = find_byte(b' ', line).ok_or(HttpError::InvalidStartLine)?;
785 let sp2 = line
786 .iter()
787 .rposition(|&b| b == b' ')
788 .ok_or(HttpError::InvalidStartLine)?;
789 if sp2 == sp1 {
790 return Err(HttpError::InvalidStartLine);
791 }
792 let method_bytes = &line[..sp1];
793 if !is_token(method_bytes) {
794 return Err(HttpError::InvalidMethod);
795 }
796 let version = parse_version(&line[sp2 + 1..])?;
797 let method = Method::from_bytes(method_bytes);
798 let target = &line[sp1 + 1..sp2];
799 check_target(method, target)?;
800 let target_start = base + sp1 + 1;
801 let target_span = Span::new(target_start, base + sp2);
802 let (target_form, authority, origin) = match target.first() {
803 Some(b'/') => (TargetForm::Origin, None, target_span),
804 Some(b'*') => (TargetForm::Asterisk, None, target_span),
805 _ if method == Method::Connect => (TargetForm::Authority, None, target_span),
806 _ => match split_absolute_form(target) {
807 Some((a, b)) => (
808 TargetForm::Absolute,
809 Some(Span::new(target_start + a, target_start + b)),
810 Span::new(target_start + b, base + sp2),
811 ),
812 None => return Err(HttpError::InvalidTarget),
813 },
814 };
815
816 let facts = scan_fields(head, fields)?;
817 let framing = match transfer_framing(&facts, version)? {
818 Some(f) => f,
819 None => match facts.content_length {
820 Some(n) if n > limits.max_body() => return Err(HttpError::BodyTooLarge),
821 Some(0) | None => BodyFraming::None,
822 Some(n) => BodyFraming::Length(n),
823 },
824 };
825 if facts.hosts > 1 {
826 return Err(HttpError::InvalidHost);
827 }
828 if let Some(host) = facts.host {
829 if !is_host_value(host.get(head)) {
830 return Err(HttpError::InvalidHost);
831 }
832 } else if version == Version::Http11 {
833 return Err(HttpError::MissingHost);
834 }
835 let keep_alive = match version {
836 Version::Http11 => !facts.close,
837 Version::Http10 => facts.keep_alive && !facts.close,
838 };
839 Ok(RequestInfo {
840 method,
841 start_line: start,
842 method_span: Span::new(base, base + sp1),
843 target: target_span,
844 target_form,
845 version,
846 framing,
847 content_length: facts.content_length,
848 keep_alive,
849 // RFC 9110 section 7.8: Upgrade in an HTTP/1.0 request is ignored.
850 // An offer of only `h2c` is no offer: the request is served as
851 // HTTP/1.1 (RFC 9113 section 3.1).
852 upgrade: version == Version::Http11 && facts.upgrade_token && facts.upgrade_offer,
853 // Reported for any version, so the caller can answer 417 (RFC 9110
854 // section 10.1.1 MAY); it never changes framing.
855 unknown_expectation: facts.expect_other,
856 // RFC 9110 section 10.1.1: ignored in HTTP/1.0, and meaningless
857 // without a body to wait for.
858 expect_continue: version == Version::Http11
859 && facts.expect_continue
860 && framing != BodyFraming::None,
861 host: facts.host,
862 authority,
863 origin,
864 })
865}
866
867/// Everything learned from a response head.
868#[derive(Clone, Copy, Debug, PartialEq, Eq)]
869pub(crate) struct ResponseInfo {
870 pub(crate) status: u16,
871 pub(crate) start_line: Span,
872 reason: Span,
873 pub(crate) version: Version,
874 pub(crate) framing: BodyFraming,
875 content_length: Option<u64>,
876 pub(crate) keep_alive: bool,
877 pub(crate) upgrade_field: bool,
878}
879
880impl ResponseInfo {
881 pub(crate) const EMPTY: Self = Self {
882 status: 0,
883 start_line: Span { start: 0, end: 0 },
884 reason: Span { start: 0, end: 0 },
885 version: Version::Http11,
886 framing: BodyFraming::None,
887 content_length: None,
888 keep_alive: false,
889 upgrade_field: false,
890 };
891}
892
893/// What the request asked for, which decides how its response is framed
894/// (RFC 9112 section 6.3): a response to `HEAD` has no body whatever its
895/// fields say, and a 2xx to `CONNECT` turns the connection into a tunnel.
896/// The input to [`parse_response_head`](crate::parse_response_head).
897///
898/// # Examples
899///
900/// ```
901/// use http_net::Asked;
902///
903/// let after_head = Asked { head: true, ..Asked::default() };
904/// assert!(after_head.head && !after_head.connect);
905/// ```
906#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
907pub struct Asked {
908 /// The request was `HEAD`.
909 pub head: bool,
910 /// The request was `CONNECT`.
911 pub connect: bool,
912}
913
914pub(crate) fn interpret_response(
915 head: &[u8],
916 start: Span,
917 fields: &[Field],
918 limits: &Limits,
919 asked: Asked,
920) -> Result<ResponseInfo, HttpError> {
921 let line = start.get(head);
922 let base = start.start as usize;
923 // status-line = HTTP-version SP status-code SP [ reason-phrase ]
924 // The SP after the code is required of senders, but some servers omit
925 // it when the reason is empty (`HTTP/1.1 200`); accepting that cannot
926 // change framing, so the client does (RFC 9112 section 4).
927 if line.len() < 12 || line[8] != b' ' || (line.len() > 12 && line[12] != b' ') {
928 return Err(HttpError::InvalidStartLine);
929 }
930 let version = parse_version(&line[..8])?;
931 let code = &line[9..12];
932 if !code.iter().all(u8::is_ascii_digit) {
933 return Err(HttpError::InvalidStatus);
934 }
935 let status = code
936 .iter()
937 .fold(0u16, |acc, &d| acc * 10 + u16::from(d - b'0'));
938 if !(100..=599).contains(&status) {
939 return Err(HttpError::InvalidStatus);
940 }
941 let reason_start = line.len().min(13);
942 let reason = &line[reason_start..];
943 if !is_reason(reason) {
944 return Err(HttpError::InvalidStartLine);
945 }
946
947 let facts = scan_fields(head, fields)?;
948 let bodiless = asked.head
949 || (100..200).contains(&status)
950 || status == 204
951 || status == 304
952 || (asked.connect && (200..300).contains(&status));
953 let framing = if bodiless {
954 BodyFraming::None
955 } else {
956 match transfer_framing(&facts, version)? {
957 Some(f) => f,
958 None => match facts.content_length {
959 Some(n) if n > limits.max_body() => return Err(HttpError::BodyTooLarge),
960 Some(0) => BodyFraming::None,
961 Some(n) => BodyFraming::Length(n),
962 None => BodyFraming::UntilClose,
963 },
964 }
965 };
966 let keep_alive = framing != BodyFraming::UntilClose
967 && match version {
968 Version::Http11 => !facts.close,
969 Version::Http10 => facts.keep_alive && !facts.close,
970 };
971 Ok(ResponseInfo {
972 status,
973 start_line: start,
974 reason: Span::new(base + reason_start, base + line.len()),
975 version,
976 framing,
977 content_length: facts.content_length,
978 keep_alive,
979 upgrade_field: facts.upgrade_field,
980 })
981}
982
983/// Iterator over a head's fields as `(name, value)` pairs, in arrival order.
984///
985/// Names are returned as received (field names are case-insensitive; compare
986/// with `eq_ignore_ascii_case`). Values have surrounding whitespace removed
987/// and may contain any byte RFC 9110 allows, including `obs-text` above
988/// 0x7F, so they are bytes rather than `str`.
989///
990/// # Examples
991///
992/// ```
993/// use http_net::{ServerConn, ServerEvent};
994///
995/// let mut conn = ServerConn::new();
996/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nX-One: 1\r\n\r\n");
997/// if let ServerEvent::Request(req) = conn.poll().unwrap() {
998/// let names: Vec<&str> = req.headers().map(|(n, _)| n).collect();
999/// assert_eq!(names, ["Host", "X-One"]);
1000/// }
1001/// ```
1002#[derive(Clone)]
1003pub struct Headers<'a> {
1004 head: &'a [u8],
1005 fields: slice::Iter<'a, Field>,
1006}
1007
1008impl<'a> Headers<'a> {
1009 pub(crate) fn new(head: &'a [u8], fields: &'a [Field]) -> Self {
1010 Self {
1011 head,
1012 fields: fields.iter(),
1013 }
1014 }
1015}
1016
1017impl<'a> Iterator for Headers<'a> {
1018 type Item = (&'a str, &'a [u8]);
1019
1020 #[inline]
1021 fn next(&mut self) -> Option<Self::Item> {
1022 let field = self.fields.next()?;
1023 Some((
1024 core::str::from_utf8(field.name.get(self.head)).unwrap_or(""),
1025 field.value.get(self.head),
1026 ))
1027 }
1028
1029 #[inline]
1030 fn size_hint(&self) -> (usize, Option<usize>) {
1031 self.fields.size_hint()
1032 }
1033}
1034
1035impl ExactSizeIterator for Headers<'_> {}
1036
1037/// Shows the fields as `(name, value)` pairs; the values of credential
1038/// fields (`authorization`, `proxy-authorization`, `cookie`, `set-cookie`)
1039/// are replaced by `<redacted N bytes>`.
1040impl fmt::Debug for Headers<'_> {
1041 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1042 let head = self.head;
1043 f.debug_list()
1044 .entries(self.fields.clone().map(|field| {
1045 let name = field.name.get(head);
1046 (
1047 FieldName(name),
1048 FieldValue {
1049 name,
1050 value: field.value.get(head),
1051 },
1052 )
1053 }))
1054 .finish()
1055 }
1056}
1057
1058/// Iterator over the values of every field with one name, in arrival
1059/// order: what [`RequestHead::header_all`] and
1060/// [`ResponseHead::header_all`] return. Each `Set-Cookie`, for example, is
1061/// its own field and its own item; nothing is comma-joined.
1062///
1063/// # Examples
1064///
1065/// ```
1066/// use http_net::{ServerConn, ServerEvent};
1067///
1068/// let mut conn = ServerConn::new();
1069/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nVia: 1.1 p1\r\nVia: 1.1 p2\r\n\r\n");
1070/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1071/// let vias: Vec<&[u8]> = req.header_all("via").collect();
1072/// assert_eq!(vias, [&b"1.1 p1"[..], &b"1.1 p2"[..]]);
1073/// ```
1074///
1075/// The values borrow the head (`'a`), not the name (`'n`), so they outlive
1076/// a temporary name used for the lookup.
1077#[derive(Clone)]
1078pub struct HeaderValues<'a, 'n> {
1079 head: &'a [u8],
1080 fields: slice::Iter<'a, Field>,
1081 name: &'n [u8],
1082}
1083
1084impl<'a> Iterator for HeaderValues<'a, '_> {
1085 type Item = &'a [u8];
1086
1087 #[inline]
1088 fn next(&mut self) -> Option<Self::Item> {
1089 let (head, name) = (self.head, self.name);
1090 self.fields
1091 .find(|f| f.name.get(head).eq_ignore_ascii_case(name))
1092 .map(|f| f.value.get(head))
1093 }
1094
1095 #[inline]
1096 fn size_hint(&self) -> (usize, Option<usize>) {
1097 (0, self.fields.size_hint().1)
1098 }
1099}
1100
1101impl fmt::Debug for HeaderValues<'_, '_> {
1102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1103 let name = self.name;
1104 f.debug_list()
1105 .entries(self.clone().map(|value| FieldValue { name, value }))
1106 .finish()
1107 }
1108}
1109
1110/// Iterator over the elements of a list field (`#rule`) across every line
1111/// with one name: what [`RequestHead::header_list`],
1112/// [`ResponseHead::header_list`], and [`RequestHead::upgrade_protocols`]
1113/// return. Elements are trimmed of whitespace, empty ones are skipped, and
1114/// a comma inside a quoted string does not split an element.
1115///
1116/// # Examples
1117///
1118/// ```
1119/// use http_net::{ServerConn, ServerEvent};
1120///
1121/// let mut conn = ServerConn::new();
1122/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive, X-Trace\r\n\r\n");
1123/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1124/// let options: Vec<&[u8]> = req.header_list("connection").collect();
1125/// assert_eq!(options, [&b"keep-alive"[..], b"X-Trace"]);
1126/// ```
1127#[derive(Clone)]
1128pub struct ListElements<'a, 'n> {
1129 head: &'a [u8],
1130 fields: slice::Iter<'a, Field>,
1131 name: &'n [u8],
1132 current: ListSplit<'a>,
1133 skip_h2c: bool,
1134}
1135
1136impl<'a> Iterator for ListElements<'a, '_> {
1137 type Item = &'a [u8];
1138
1139 fn next(&mut self) -> Option<Self::Item> {
1140 loop {
1141 if let Some(e) = self.current.next() {
1142 if self.skip_h2c && is_h2c(e) {
1143 continue;
1144 }
1145 return Some(e);
1146 }
1147 let (head, name) = (self.head, self.name);
1148 let field = self
1149 .fields
1150 .find(|f| f.name.get(head).eq_ignore_ascii_case(name))?;
1151 self.current = list_elements(field.value.get(head));
1152 }
1153 }
1154}
1155
1156impl fmt::Debug for ListElements<'_, '_> {
1157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1158 let name = self.name;
1159 f.debug_list()
1160 .entries(self.clone().map(|value| FieldValue { name, value }))
1161 .finish()
1162 }
1163}
1164
1165fn list_values<'a, 'n>(head: &'a [u8], fields: &'a [Field], name: &'n str) -> ListElements<'a, 'n> {
1166 ListElements {
1167 head,
1168 fields: fields.iter(),
1169 name: name.as_bytes(),
1170 current: list_elements(&[]),
1171 skip_h2c: false,
1172 }
1173}
1174
1175fn find_header<'a>(head: &'a [u8], fields: &[Field], name: &str) -> Option<&'a [u8]> {
1176 fields
1177 .iter()
1178 .find(|f| f.name.get(head).eq_ignore_ascii_case(name.as_bytes()))
1179 .map(|f| f.value.get(head))
1180}
1181
1182fn header_values<'a, 'n>(
1183 head: &'a [u8],
1184 fields: &'a [Field],
1185 name: &'n str,
1186) -> HeaderValues<'a, 'n> {
1187 HeaderValues {
1188 head,
1189 fields: fields.iter(),
1190 name: name.as_bytes(),
1191 }
1192}
1193
1194/// A parsed request head, borrowed from the connection's buffer.
1195///
1196/// Every accessor is a slice of the bytes that arrived; nothing is copied.
1197/// The view stays valid until the next call that mutates the connection.
1198/// Read it again later with [`ServerConn::request`](crate::ServerConn::request).
1199///
1200/// # Examples
1201///
1202/// ```
1203/// use http_net::{Method, ServerConn, ServerEvent, Version};
1204///
1205/// let mut conn = ServerConn::new();
1206/// let _ = conn.feed(b"GET /search?q=rust HTTP/1.1\r\nHost: example.com\r\n\r\n");
1207/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1208/// assert_eq!(req.method(), Method::Get);
1209/// assert_eq!(req.path(), "/search");
1210/// assert_eq!(req.query(), Some("q=rust"));
1211/// assert_eq!(req.version(), Version::Http11);
1212/// assert_eq!(req.host(), Some("example.com"));
1213/// assert!(req.keep_alive());
1214/// ```
1215#[derive(Clone, Copy)]
1216pub struct RequestHead<'a> {
1217 head: &'a [u8],
1218 fields: &'a [Field],
1219 info: &'a RequestInfo,
1220}
1221
1222impl<'a> RequestHead<'a> {
1223 pub(crate) const fn new(head: &'a [u8], fields: &'a [Field], info: &'a RequestInfo) -> Self {
1224 Self { head, fields, info }
1225 }
1226
1227 /// The bytes the spans index (the head, possibly followed by more
1228 /// input), the field records, and the interpreted facts.
1229 pub(crate) const fn parts(&self) -> (&'a [u8], &'a [Field], &'a RequestInfo) {
1230 (self.head, self.fields, self.info)
1231 }
1232
1233 /// The method, classified.
1234 ///
1235 /// # Examples
1236 ///
1237 /// ```
1238 /// # use http_net::{Method, ServerConn, ServerEvent};
1239 /// # let mut conn = ServerConn::new();
1240 /// # let _ = conn.feed(b"DELETE /x HTTP/1.1\r\nHost: a\r\n\r\n");
1241 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1242 /// assert_eq!(req.method(), Method::Delete);
1243 /// ```
1244 #[must_use]
1245 pub fn method(&self) -> Method {
1246 self.info.method
1247 }
1248
1249 /// The method exactly as received.
1250 ///
1251 /// # Examples
1252 ///
1253 /// ```
1254 /// # use http_net::{Method, ServerConn, ServerEvent};
1255 /// # let mut conn = ServerConn::new();
1256 /// # let _ = conn.feed(b"PROPFIND /x HTTP/1.1\r\nHost: a\r\n\r\n");
1257 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1258 /// assert_eq!(req.method(), Method::Other);
1259 /// assert_eq!(req.method_str(), "PROPFIND");
1260 /// ```
1261 #[must_use]
1262 pub fn method_str(&self) -> &'a str {
1263 core::str::from_utf8(self.info.method_span.get(self.head)).unwrap_or("")
1264 }
1265
1266 /// The request target exactly as received (origin form `/path?query`,
1267 /// absolute form, authority form for `CONNECT`, or `*`).
1268 ///
1269 /// # Examples
1270 ///
1271 /// ```
1272 /// # use http_net::{ServerConn, ServerEvent};
1273 /// # let mut conn = ServerConn::new();
1274 /// # let _ = conn.feed(b"GET /a%20b?x=1 HTTP/1.1\r\nHost: a\r\n\r\n");
1275 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1276 /// assert_eq!(req.target(), "/a%20b?x=1");
1277 /// ```
1278 #[must_use]
1279 pub fn target(&self) -> &'a str {
1280 core::str::from_utf8(self.info.target.get(self.head)).unwrap_or("")
1281 }
1282
1283 /// Which of the four RFC 9112 section 3.2 forms the target uses.
1284 ///
1285 /// # Examples
1286 ///
1287 /// ```
1288 /// # use http_net::{ServerConn, ServerEvent, TargetForm};
1289 /// # let mut conn = ServerConn::new();
1290 /// # let _ = conn.feed(b"GET http://a.test/x HTTP/1.1\r\nHost: a.test\r\n\r\n");
1291 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1292 /// assert_eq!(req.target_form(), TargetForm::Absolute);
1293 /// ```
1294 #[must_use]
1295 pub fn target_form(&self) -> TargetForm {
1296 self.info.target_form
1297 }
1298
1299 /// The path: the target up to (not including) the first `?`, with
1300 /// percent-encoding left as received.
1301 ///
1302 /// For an absolute-form target (`http://host/p?q`) this is the path
1303 /// after the authority (`/p`), and `/` when that path is empty, so a
1304 /// router sees the same path whichever form the client used. For `*`
1305 /// and for `CONNECT`'s authority form it is the whole target.
1306 ///
1307 /// # Examples
1308 ///
1309 /// ```
1310 /// # use http_net::{ServerConn, ServerEvent};
1311 /// # let mut conn = ServerConn::new();
1312 /// # let _ = conn.feed(b"GET /files/a.txt?v=2 HTTP/1.1\r\nHost: a\r\n\r\n");
1313 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1314 /// assert_eq!(req.path(), "/files/a.txt");
1315 ///
1316 /// # let mut conn = ServerConn::new();
1317 /// # let _ = conn.feed(b"GET http://a/files/b.txt HTTP/1.1\r\nHost: a\r\n\r\n");
1318 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1319 /// assert_eq!(req.path(), "/files/b.txt");
1320 /// ```
1321 #[must_use]
1322 pub fn path(&self) -> &'a str {
1323 let origin = self.origin();
1324 let path = origin.split_once('?').map_or(origin, |(p, _)| p);
1325 if path.is_empty() && self.info.authority.is_some() {
1326 // RFC 9110 section 4.2.3: an empty path in an http URI is "/".
1327 "/"
1328 } else {
1329 path
1330 }
1331 }
1332
1333 /// The query after the first `?`, if there is one.
1334 ///
1335 /// # Examples
1336 ///
1337 /// ```
1338 /// # use http_net::{ServerConn, ServerEvent};
1339 /// # let mut conn = ServerConn::new();
1340 /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\n\r\n");
1341 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1342 /// assert_eq!(req.query(), None);
1343 /// ```
1344 #[must_use]
1345 pub fn query(&self) -> Option<&'a str> {
1346 self.origin().split_once('?').map(|(_, q)| q)
1347 }
1348
1349 /// The path-and-query part of the target.
1350 fn origin(&self) -> &'a str {
1351 core::str::from_utf8(self.info.origin.get(self.head)).unwrap_or("")
1352 }
1353
1354 /// The protocol version.
1355 ///
1356 /// # Examples
1357 ///
1358 /// ```
1359 /// # use http_net::{ServerConn, ServerEvent, Version};
1360 /// # let mut conn = ServerConn::new();
1361 /// # let _ = conn.feed(b"GET /x HTTP/1.0\r\n\r\n");
1362 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1363 /// assert_eq!(req.version(), Version::Http10);
1364 /// ```
1365 #[must_use]
1366 pub fn version(&self) -> Version {
1367 self.info.version
1368 }
1369
1370 /// All fields in arrival order.
1371 ///
1372 /// # Examples
1373 ///
1374 /// ```
1375 /// # use http_net::{ServerConn, ServerEvent};
1376 /// # let mut conn = ServerConn::new();
1377 /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nAccept: */*\r\n\r\n");
1378 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1379 /// assert_eq!(req.headers().len(), 2);
1380 /// ```
1381 #[must_use]
1382 pub fn headers(&self) -> Headers<'a> {
1383 Headers {
1384 head: self.head,
1385 fields: self.fields.iter(),
1386 }
1387 }
1388
1389 /// The value of the first field named `name` (ASCII case-insensitive).
1390 ///
1391 /// # Examples
1392 ///
1393 /// ```
1394 /// # use http_net::{ServerConn, ServerEvent};
1395 /// # let mut conn = ServerConn::new();
1396 /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nAccept: text/html \r\n\r\n");
1397 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1398 /// assert_eq!(req.header("accept"), Some(&b"text/html"[..]));
1399 /// assert_eq!(req.header("cookie"), None);
1400 /// ```
1401 #[must_use]
1402 pub fn header(&self, name: &str) -> Option<&'a [u8]> {
1403 find_header(self.head, self.fields, name)
1404 }
1405
1406 /// Like [`header`](Self::header), but only when the value is UTF-8.
1407 ///
1408 /// # Examples
1409 ///
1410 /// ```
1411 /// # use http_net::{ServerConn, ServerEvent};
1412 /// # let mut conn = ServerConn::new();
1413 /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nX: \xff\r\n\r\n");
1414 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1415 /// assert_eq!(req.header_str("host"), Some("a"));
1416 /// assert_eq!(req.header_str("x"), None);
1417 /// ```
1418 #[must_use]
1419 pub fn header_str(&self, name: &str) -> Option<&'a str> {
1420 self.header(name).and_then(|v| core::str::from_utf8(v).ok())
1421 }
1422
1423 /// The values of every field named `name` (ASCII case-insensitive), in
1424 /// arrival order: for fields that may be repeated, such as `via`,
1425 /// `forwarded`, or `cookie` from clients that send one line per cookie.
1426 ///
1427 /// # Examples
1428 ///
1429 /// ```
1430 /// # use http_net::{ServerConn, ServerEvent};
1431 /// # let mut conn = ServerConn::new();
1432 /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nCookie: a=1\r\nCookie: b=2\r\n\r\n");
1433 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1434 /// let cookies: Vec<&[u8]> = req.header_all("cookie").collect();
1435 /// assert_eq!(cookies, [&b"a=1"[..], &b"b=2"[..]]);
1436 /// assert_eq!(req.header_all("accept").count(), 0);
1437 ///
1438 /// // The values borrow the head, not the name.
1439 /// let first = {
1440 /// let name = String::from("COOKIE");
1441 /// req.header_all(&name).next()
1442 /// };
1443 /// assert_eq!(first, Some(&b"a=1"[..]));
1444 /// ```
1445 #[must_use]
1446 pub fn header_all<'n>(&self, name: &'n str) -> HeaderValues<'a, 'n> {
1447 header_values(self.head, self.fields, name)
1448 }
1449
1450 /// The declared `Content-Length`, if the request has one. Unlike
1451 /// [`framing`](Self::framing), which reports `Content-Length: 0` as
1452 /// [`BodyFraming::None`], this tells `Some(0)` from an absent field.
1453 ///
1454 /// # Examples
1455 ///
1456 /// ```
1457 /// # use http_net::{BodyFraming, ServerConn, ServerEvent};
1458 /// # let mut conn = ServerConn::new();
1459 /// # let _ = conn.feed(b"POST /x HTTP/1.1\r\nHost: a\r\nContent-Length: 0\r\n\r\n");
1460 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1461 /// assert_eq!(req.framing(), BodyFraming::None);
1462 /// assert_eq!(req.content_length(), Some(0));
1463 /// ```
1464 #[must_use]
1465 pub fn content_length(&self) -> Option<u64> {
1466 self.info.content_length
1467 }
1468
1469 /// The authority the request is for (`host [":" port]`), if known.
1470 ///
1471 /// This is the `Host` field, except for an absolute-form target
1472 /// (`GET http://example.com/ HTTP/1.1`), whose authority wins: RFC 9112
1473 /// section 3.2.2 requires a server to ignore `Host` then, so the two can
1474 /// never be read differently. The raw field stays available through
1475 /// `header("host")`. HTTP/1.1 requests always carry a valid `Host`;
1476 /// HTTP/1.0 requests may not, and an empty `Host` (a target with no
1477 /// authority) is reported as `Some("")`.
1478 ///
1479 /// # Examples
1480 ///
1481 /// ```
1482 /// # use http_net::{ServerConn, ServerEvent};
1483 /// # let mut conn = ServerConn::new();
1484 /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: 127.0.0.1:8080\r\n\r\n");
1485 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1486 /// assert_eq!(req.host(), Some("127.0.0.1:8080"));
1487 ///
1488 /// # let mut conn = ServerConn::new();
1489 /// # let _ = conn.feed(b"GET http://a.test/x HTTP/1.1\r\nHost: b.test\r\n\r\n");
1490 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1491 /// assert_eq!(req.host(), Some("a.test"));
1492 /// assert_eq!(req.header("host"), Some(&b"b.test"[..]));
1493 /// ```
1494 #[must_use]
1495 pub fn host(&self) -> Option<&'a str> {
1496 self.info
1497 .authority
1498 .or(self.info.host)
1499 .and_then(|s| core::str::from_utf8(s.get(self.head)).ok())
1500 }
1501
1502 /// Whether the client sent `Expect: 100-continue` and is waiting for a
1503 /// `100 Continue` before sending the body. Only HTTP/1.1 requests that
1504 /// have a body report it (RFC 9110 section 10.1.1).
1505 ///
1506 /// Answer it before reading the body: either
1507 /// [`ServerConn::send_continue`](crate::ServerConn::send_continue), or a
1508 /// final response straight away (which closes the connection afterwards,
1509 /// since the body was not read). The blocking `Server` sends
1510 /// `100 Continue` itself.
1511 ///
1512 /// # Examples
1513 ///
1514 /// ```
1515 /// # use http_net::{ServerConn, ServerEvent};
1516 /// # let mut conn = ServerConn::new();
1517 /// # let _ = conn.feed(b"PUT /f HTTP/1.1\r\nHost: a\r\nExpect: 100-continue\r\nContent-Length: 9\r\n\r\n");
1518 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1519 /// assert!(req.expects_continue());
1520 /// ```
1521 #[must_use]
1522 pub fn expects_continue(&self) -> bool {
1523 self.info.expect_continue
1524 }
1525
1526 /// How the request body is delimited.
1527 ///
1528 /// # Examples
1529 ///
1530 /// ```
1531 /// # use http_net::{BodyFraming, ServerConn, ServerEvent};
1532 /// # let mut conn = ServerConn::new();
1533 /// # let _ = conn.feed(b"POST /x HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n");
1534 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1535 /// assert_eq!(req.framing(), BodyFraming::Chunked);
1536 /// ```
1537 #[must_use]
1538 pub fn framing(&self) -> BodyFraming {
1539 self.info.framing
1540 }
1541
1542 /// Whether the client allows the connection to stay open after this
1543 /// exchange (HTTP/1.1 unless `Connection: close`; HTTP/1.0 only with
1544 /// `Connection: keep-alive`).
1545 ///
1546 /// # Examples
1547 ///
1548 /// ```
1549 /// # use http_net::{ServerConn, ServerEvent};
1550 /// # let mut conn = ServerConn::new();
1551 /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nConnection: close\r\n\r\n");
1552 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1553 /// assert!(!req.keep_alive());
1554 /// ```
1555 #[must_use]
1556 pub fn keep_alive(&self) -> bool {
1557 self.info.keep_alive
1558 }
1559
1560 /// Whether this is an HTTP/1.1 request to switch protocols: `Connection`
1561 /// lists `upgrade` and an `Upgrade` field offers at least one protocol
1562 /// other than `h2c` (read the offer with `header("upgrade")`). Answer
1563 /// with [`Response::switching_protocols`](crate::Response::switching_protocols)
1564 /// naming an offered protocol to hand the connection over.
1565 ///
1566 /// `h2c` is never an offer: RFC 9113 section 3.1 deprecates the
1567 /// HTTP/2 upgrade, and a proxy that forwards it blindly is open to h2c
1568 /// smuggling. A request offering only `h2c` is served as HTTP/1.1.
1569 ///
1570 /// # Examples
1571 ///
1572 /// ```
1573 /// # use http_net::{ServerConn, ServerEvent};
1574 /// # let mut conn = ServerConn::new();
1575 /// # let _ = conn.feed(b"GET /ws HTTP/1.1\r\nHost: a\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n");
1576 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1577 /// assert!(req.is_upgrade());
1578 /// assert_eq!(req.header("upgrade"), Some(&b"websocket"[..]));
1579 ///
1580 /// # let mut conn = ServerConn::new();
1581 /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: Upgrade, HTTP2-Settings\r\nUpgrade: h2c\r\nHTTP2-Settings: AAMAAABkAAQAoAAA\r\n\r\n");
1582 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1583 /// assert!(!req.is_upgrade());
1584 /// ```
1585 #[must_use]
1586 pub fn is_upgrade(&self) -> bool {
1587 self.info.upgrade
1588 }
1589
1590 /// Whether the request carries an expectation other than
1591 /// `100-continue` (any `Expect` list element, any HTTP version), which
1592 /// a server may answer with `417 Expectation Failed` (RFC 9110 section
1593 /// 10.1.1). The core never answers it by itself; the blocking server
1594 /// does. The expectation never changes how the body is framed.
1595 ///
1596 /// # Examples
1597 ///
1598 /// ```
1599 /// # use http_net::{ServerConn, ServerEvent};
1600 /// # let mut conn = ServerConn::new();
1601 /// # let _ = conn.feed(b"PUT /f HTTP/1.1\r\nHost: a\r\nExpect: 100-continue, x-fast\r\nContent-Length: 1\r\n\r\n");
1602 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1603 /// assert!(req.expects_continue());
1604 /// assert!(req.has_unknown_expectation());
1605 /// ```
1606 #[must_use]
1607 pub fn has_unknown_expectation(&self) -> bool {
1608 self.info.unknown_expectation
1609 }
1610
1611 /// The protocols the request's `Upgrade` field offers, in order, as
1612 /// product tokens (`websocket`, `foo/2`), across every `Upgrade` line;
1613 /// `h2c` is left out (it is never an offer). Empty unless
1614 /// [`is_upgrade`](Self::is_upgrade).
1615 ///
1616 /// # Examples
1617 ///
1618 /// ```
1619 /// # use http_net::{ServerConn, ServerEvent};
1620 /// # let mut conn = ServerConn::new();
1621 /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: upgrade\r\nUpgrade: h2c, websocket/13, irc\r\n\r\n");
1622 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1623 /// let offered: Vec<&[u8]> = req.upgrade_protocols().collect();
1624 /// assert_eq!(offered, [&b"websocket/13"[..], b"irc"]);
1625 /// ```
1626 #[must_use]
1627 pub fn upgrade_protocols(&self) -> ListElements<'a, 'static> {
1628 let mut list = list_values(self.head, self.fields, "upgrade");
1629 list.skip_h2c = true;
1630 if !self.info.upgrade {
1631 list.fields = [].iter();
1632 }
1633 list
1634 }
1635
1636 /// The options the request's `Connection` field lists, across every
1637 /// `Connection` line, in order (`close`, `keep-alive`, `upgrade`, and the
1638 /// names of fields that are hop-by-hop for this message). Compare them
1639 /// ASCII case-insensitively. A proxy passes them to
1640 /// [`is_hop_by_hop`](crate::is_hop_by_hop).
1641 ///
1642 /// # Examples
1643 ///
1644 /// ```
1645 /// # use http_net::{ServerConn, ServerEvent};
1646 /// # let mut conn = ServerConn::new();
1647 /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive, X-Trace\r\n\r\n");
1648 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1649 /// let options: Vec<&[u8]> = req.connection_options().collect();
1650 /// assert_eq!(options, [&b"keep-alive"[..], b"X-Trace"]);
1651 /// ```
1652 #[must_use]
1653 pub fn connection_options(&self) -> ListElements<'a, 'static> {
1654 list_values(self.head, self.fields, "connection")
1655 }
1656
1657 /// The elements of a comma-separated list field (`#rule`, RFC 9110
1658 /// section 5.6.1) across every line with this name, in order, trimmed
1659 /// of whitespace, empty elements skipped. A comma inside a quoted
1660 /// string does not split an element.
1661 ///
1662 /// # Examples
1663 ///
1664 /// ```
1665 /// # use http_net::{ServerConn, ServerEvent};
1666 /// # let mut conn = ServerConn::new();
1667 /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nAccept: text/html, ,\r\nAccept: x/y;q=\"0.5,1\"\r\n\r\n");
1668 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1669 /// let accept: Vec<&[u8]> = req.header_list("accept").collect();
1670 /// assert_eq!(accept, [&b"text/html"[..], b"x/y;q=\"0.5,1\""]);
1671 /// ```
1672 #[must_use]
1673 pub fn header_list<'n>(&self, name: &'n str) -> ListElements<'a, 'n> {
1674 list_values(self.head, self.fields, name)
1675 }
1676
1677 /// Whether the request's `Upgrade` field offers `protocol` (see
1678 /// [`Response::switching_protocols`](crate::Response::switching_protocols)).
1679 pub(crate) fn offers(&self, protocol: &[u8]) -> bool {
1680 self.info.upgrade
1681 && self
1682 .header_all("upgrade")
1683 .any(|v| list_elements(v).any(|e| protocol_matches(protocol, e)))
1684 }
1685}
1686
1687/// Shows method, target, version, fields, and framing; the values of
1688/// credential fields are replaced by `<redacted N bytes>`.
1689impl fmt::Debug for RequestHead<'_> {
1690 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1691 f.debug_struct("RequestHead")
1692 .field("method", &self.method_str())
1693 .field("target", &self.target())
1694 .field("version", &self.version())
1695 .field("headers", &self.headers())
1696 .field("framing", &self.framing())
1697 .finish()
1698 }
1699}
1700
1701/// A parsed response head, borrowed from the client connection's buffer.
1702///
1703/// # Examples
1704///
1705/// ```
1706/// use http_net::{ClientConn, ClientEvent, Request};
1707///
1708/// let mut conn = ClientConn::new();
1709/// let mut out = Vec::new();
1710/// conn.send_request(&Request::get("/").header("host", "a"), &mut out).unwrap();
1711/// let _ = conn.feed(b"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
1712/// let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1713/// assert_eq!(resp.status(), 404);
1714/// assert_eq!(resp.reason(), "Not Found");
1715/// ```
1716#[derive(Clone, Copy)]
1717pub struct ResponseHead<'a> {
1718 head: &'a [u8],
1719 fields: &'a [Field],
1720 info: &'a ResponseInfo,
1721}
1722
1723impl<'a> ResponseHead<'a> {
1724 pub(crate) const fn new(head: &'a [u8], fields: &'a [Field], info: &'a ResponseInfo) -> Self {
1725 Self { head, fields, info }
1726 }
1727
1728 /// As [`RequestHead::parts`], for a response.
1729 pub(crate) const fn parts(&self) -> (&'a [u8], &'a [Field], &'a ResponseInfo) {
1730 (self.head, self.fields, self.info)
1731 }
1732
1733 /// The status code (`100..=599`).
1734 ///
1735 /// # Examples
1736 ///
1737 /// ```
1738 /// # use http_net::{ClientConn, ClientEvent, Request};
1739 /// # let mut conn = ClientConn::new();
1740 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1741 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1742 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1743 /// assert_eq!(resp.status(), 200);
1744 /// ```
1745 #[must_use]
1746 pub fn status(&self) -> u16 {
1747 self.info.status
1748 }
1749
1750 /// The reason phrase, if it is UTF-8 (it carries no meaning; RFC 9112
1751 /// tells clients to ignore it). Empty for a status line without one,
1752 /// including `HTTP/1.1 200` with no space after the code.
1753 ///
1754 /// # Examples
1755 ///
1756 /// ```
1757 /// # use http_net::{ClientConn, ClientEvent, Request};
1758 /// # let mut conn = ClientConn::new();
1759 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1760 /// # let _ = conn.feed(b"HTTP/1.1 200 \r\nContent-Length: 0\r\n\r\n");
1761 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1762 /// assert_eq!(resp.reason(), "");
1763 /// ```
1764 #[must_use]
1765 pub fn reason(&self) -> &'a str {
1766 core::str::from_utf8(self.info.reason.get(self.head)).unwrap_or("")
1767 }
1768
1769 /// The protocol version.
1770 ///
1771 /// # Examples
1772 ///
1773 /// ```
1774 /// # use http_net::{ClientConn, ClientEvent, Request, Version};
1775 /// # let mut conn = ClientConn::new();
1776 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1777 /// # let _ = conn.feed(b"HTTP/1.0 200 OK\r\n\r\n");
1778 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1779 /// assert_eq!(resp.version(), Version::Http10);
1780 /// ```
1781 #[must_use]
1782 pub fn version(&self) -> Version {
1783 self.info.version
1784 }
1785
1786 /// All fields in arrival order.
1787 ///
1788 /// # Examples
1789 ///
1790 /// ```
1791 /// # use http_net::{ClientConn, ClientEvent, Request};
1792 /// # let mut conn = ClientConn::new();
1793 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1794 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\nX: y\r\n\r\n");
1795 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1796 /// assert_eq!(resp.headers().count(), 2);
1797 /// ```
1798 #[must_use]
1799 pub fn headers(&self) -> Headers<'a> {
1800 Headers {
1801 head: self.head,
1802 fields: self.fields.iter(),
1803 }
1804 }
1805
1806 /// The value of the first field named `name` (ASCII case-insensitive).
1807 ///
1808 /// # Examples
1809 ///
1810 /// ```
1811 /// # use http_net::{ClientConn, ClientEvent, Request};
1812 /// # let mut conn = ClientConn::new();
1813 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1814 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 0\r\n\r\n");
1815 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1816 /// assert_eq!(resp.header("content-type"), Some(&b"text/plain"[..]));
1817 /// ```
1818 #[must_use]
1819 pub fn header(&self, name: &str) -> Option<&'a [u8]> {
1820 find_header(self.head, self.fields, name)
1821 }
1822
1823 /// Like [`header`](Self::header), but only when the value is UTF-8.
1824 ///
1825 /// # Examples
1826 ///
1827 /// ```
1828 /// # use http_net::{ClientConn, ClientEvent, Request};
1829 /// # let mut conn = ClientConn::new();
1830 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1831 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nServer: x\r\nContent-Length: 0\r\n\r\n");
1832 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1833 /// assert_eq!(resp.header_str("server"), Some("x"));
1834 /// ```
1835 #[must_use]
1836 pub fn header_str(&self, name: &str) -> Option<&'a str> {
1837 self.header(name).and_then(|v| core::str::from_utf8(v).ok())
1838 }
1839
1840 /// The values of every field named `name`, in arrival order. Each
1841 /// `Set-Cookie` is its own field (they are never comma-joined), so
1842 /// this is how a client reads all of them.
1843 ///
1844 /// # Examples
1845 ///
1846 /// ```
1847 /// # use http_net::{ClientConn, ClientEvent, Request};
1848 /// # let mut conn = ClientConn::new();
1849 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1850 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nSet-Cookie: a=1\r\nSet-Cookie: b=2; Path=/\r\nContent-Length: 0\r\n\r\n");
1851 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1852 /// let cookies: Vec<&[u8]> = resp.header_all("set-cookie").collect();
1853 /// assert_eq!(cookies, [&b"a=1"[..], &b"b=2; Path=/"[..]]);
1854 /// ```
1855 #[must_use]
1856 pub fn header_all<'n>(&self, name: &'n str) -> HeaderValues<'a, 'n> {
1857 header_values(self.head, self.fields, name)
1858 }
1859
1860 /// The declared `Content-Length`, if the response has one, whatever the
1861 /// framing rules made of it (a `HEAD` response's length is reported
1862 /// here while [`framing`](Self::framing) is `None`).
1863 ///
1864 /// # Examples
1865 ///
1866 /// ```
1867 /// # use http_net::{BodyFraming, ClientConn, ClientEvent, Request};
1868 /// # let mut conn = ClientConn::new();
1869 /// # conn.send_request(&Request::head("/").header("host", "a"), &mut Vec::new()).unwrap();
1870 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 1234\r\n\r\n");
1871 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1872 /// assert_eq!(resp.framing(), BodyFraming::None);
1873 /// assert_eq!(resp.content_length(), Some(1234));
1874 /// ```
1875 #[must_use]
1876 pub fn content_length(&self) -> Option<u64> {
1877 self.info.content_length
1878 }
1879
1880 /// The elements of a list field across every line with this name (see
1881 /// [`RequestHead::header_list`]).
1882 ///
1883 /// # Examples
1884 ///
1885 /// ```
1886 /// # use http_net::{ClientConn, ClientEvent, Request};
1887 /// # let mut conn = ClientConn::new();
1888 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1889 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nVary: accept\r\nVary: origin, cookie\r\nContent-Length: 0\r\n\r\n");
1890 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1891 /// assert_eq!(resp.header_list("vary").count(), 3);
1892 /// ```
1893 #[must_use]
1894 pub fn header_list<'n>(&self, name: &'n str) -> ListElements<'a, 'n> {
1895 list_values(self.head, self.fields, name)
1896 }
1897
1898 /// Whether this is an interim (1xx) response head, as reported by
1899 /// [`ClientEvent::Informational`](crate::ClientEvent::Informational).
1900 ///
1901 /// # Examples
1902 ///
1903 /// ```
1904 /// # use http_net::{ClientConn, ClientEvent, Request};
1905 /// # let mut conn = ClientConn::new();
1906 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1907 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1908 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1909 /// assert!(!resp.is_informational());
1910 /// ```
1911 #[must_use]
1912 pub fn is_informational(&self) -> bool {
1913 (100..200).contains(&self.info.status)
1914 }
1915
1916 /// How the response body is delimited (accounts for `HEAD` requests and
1917 /// bodiless status codes).
1918 ///
1919 /// # Examples
1920 ///
1921 /// ```
1922 /// # use http_net::{BodyFraming, ClientConn, ClientEvent, Request};
1923 /// # let mut conn = ClientConn::new();
1924 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1925 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\n\r\n");
1926 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1927 /// assert_eq!(resp.framing(), BodyFraming::UntilClose);
1928 /// ```
1929 #[must_use]
1930 pub fn framing(&self) -> BodyFraming {
1931 self.info.framing
1932 }
1933
1934 /// Whether the connection can carry another request after this response.
1935 ///
1936 /// # Examples
1937 ///
1938 /// ```
1939 /// # use http_net::{ClientConn, ClientEvent, Request};
1940 /// # let mut conn = ClientConn::new();
1941 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1942 /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1943 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1944 /// assert!(resp.keep_alive());
1945 /// ```
1946 #[must_use]
1947 pub fn keep_alive(&self) -> bool {
1948 self.info.keep_alive
1949 }
1950}
1951
1952/// Shows status, reason, version, fields, and framing; the values of
1953/// credential fields (`set-cookie` above all) are replaced by
1954/// `<redacted N bytes>`.
1955impl fmt::Debug for ResponseHead<'_> {
1956 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1957 f.debug_struct("ResponseHead")
1958 .field("status", &self.status())
1959 .field("reason", &self.reason())
1960 .field("version", &self.version())
1961 .field("headers", &self.headers())
1962 .field("framing", &self.framing())
1963 .finish()
1964 }
1965}
1966
1967#[cfg(test)]
1968mod tests {
1969 use super::*;
1970
1971 fn scan(msg: &[u8], kind: HeadKind) -> Result<(HeadScanner, usize), HttpError> {
1972 let mut s = HeadScanner::new();
1973 match s.advance(msg, &Limits::new(), kind, true)? {
1974 Scan::Done(n) => Ok((s, n)),
1975 Scan::Partial => Err(HttpError::UnexpectedEof),
1976 }
1977 }
1978
1979 #[test]
1980 fn test_scanner_resumes_without_rescanning() {
1981 let msg = b"GET / HTTP/1.1\r\nHost: a\r\n\r\n";
1982 let mut s = HeadScanner::new();
1983 for end in 1..msg.len() {
1984 assert!(matches!(
1985 s.advance(&msg[..end], &Limits::new(), HeadKind::Request, true),
1986 Ok(Scan::Partial)
1987 ));
1988 }
1989 assert!(matches!(
1990 s.advance(msg, &Limits::new(), HeadKind::Request, true),
1991 Ok(Scan::Done(n)) if n == msg.len()
1992 ));
1993 assert_eq!(s.fields.len(), 1);
1994 }
1995
1996 #[test]
1997 fn test_scanner_rejects_line_shapes() {
1998 let cases: &[(&[u8], HttpError)] = &[
1999 (b"GET / HTTP/1.1\nHost: a\r\n\r\n", HttpError::BareLf),
2000 (b"GET / HTTP/1.1\r\n Host: a\r\n\r\n", HttpError::ObsFold),
2001 (
2002 b"GET / HTTP/1.1\r\nHost : a\r\n\r\n",
2003 HttpError::WhitespaceBeforeColon,
2004 ),
2005 (
2006 b"GET / HTTP/1.1\r\nHost\r\n\r\n",
2007 HttpError::InvalidHeaderName,
2008 ),
2009 (
2010 b"GET / HTTP/1.1\r\n: a\r\n\r\n",
2011 HttpError::InvalidHeaderName,
2012 ),
2013 (b"GET / HTTP/1.1\r\nHo\rst: a\r\n\r\n", HttpError::BareCr),
2014 (b"GET / HTTP/1.1\r\nHost: a\rb\r\n\r\n", HttpError::BareCr),
2015 (b"GET /\r HTTP/1.1\r\n\r\n", HttpError::BareCr),
2016 (
2017 b"GET / HTTP/1.1\r\nHost: a\x00\r\n\r\n",
2018 HttpError::InvalidHeaderValue,
2019 ),
2020 ];
2021 for (msg, err) in cases {
2022 assert_eq!(scan(msg, HeadKind::Request).err(), Some(*err), "{msg:?}");
2023 }
2024 }
2025
2026 #[test]
2027 fn test_scanner_skips_leading_empty_lines_for_requests_only() {
2028 assert!(scan(b"\r\n\r\nGET / HTTP/1.1\r\n\r\n", HeadKind::Request).is_ok());
2029 assert_eq!(
2030 scan(b"\r\nHTTP/1.1 200 OK\r\n\r\n", HeadKind::Response).err(),
2031 Some(HttpError::InvalidStartLine)
2032 );
2033 }
2034
2035 #[test]
2036 fn test_scanner_enforces_limits_at_boundaries() {
2037 let limits = Limits::new().with_max_start_line(16);
2038 // "GET / HTTP/1.1\r\n" is exactly 16 bytes.
2039 let mut s = HeadScanner::new();
2040 assert!(
2041 s.advance(b"GET / HTTP/1.1\r\n\r\n", &limits, HeadKind::Request, true)
2042 .is_ok()
2043 );
2044 let mut s = HeadScanner::new();
2045 assert_eq!(
2046 s.advance(b"GET /a HTTP/1.1\r\n\r\n", &limits, HeadKind::Request, true)
2047 .err(),
2048 Some(HttpError::StartLineTooLong)
2049 );
2050 // Partial input already at the budget fails without waiting for LF.
2051 let mut s = HeadScanner::new();
2052 assert_eq!(
2053 s.advance(b"GET /aaaaaaaaaaaa", &limits, HeadKind::Request, true)
2054 .err(),
2055 Some(HttpError::StartLineTooLong)
2056 );
2057
2058 let limits = Limits::new().with_max_headers(1);
2059 let mut s = HeadScanner::new();
2060 assert_eq!(
2061 s.advance(
2062 b"GET / HTTP/1.1\r\nA: 1\r\nB: 2\r\n\r\n",
2063 &limits,
2064 HeadKind::Request,
2065 true
2066 )
2067 .err(),
2068 Some(HttpError::TooManyHeaders)
2069 );
2070
2071 // "A: 1\r\n" is 6 bytes; with 8 the final CRLF still fits.
2072 let limits = Limits::new().with_max_header_bytes(8);
2073 let mut s = HeadScanner::new();
2074 assert!(
2075 s.advance(
2076 b"GET / HTTP/1.1\r\nA: 1\r\n\r\n",
2077 &limits,
2078 HeadKind::Request,
2079 true
2080 )
2081 .is_ok()
2082 );
2083 let mut s = HeadScanner::new();
2084 assert_eq!(
2085 s.advance(
2086 b"GET / HTTP/1.1\r\nA: 12\r\nB: 1\r\n\r\n",
2087 &limits,
2088 HeadKind::Request,
2089 true
2090 )
2091 .err(),
2092 Some(HttpError::HeadersTooLarge)
2093 );
2094 }
2095
2096 fn response(line: &[u8]) -> Result<ResponseInfo, HttpError> {
2097 let mut msg = line.to_vec();
2098 msg.extend_from_slice(b"\r\nContent-Length: 0\r\n\r\n");
2099 let (s, _) = scan(&msg, HeadKind::Response)?;
2100 interpret_response(
2101 &msg,
2102 s.start_line(),
2103 &s.fields,
2104 &Limits::new(),
2105 Asked {
2106 head: false,
2107 connect: false,
2108 },
2109 )
2110 }
2111
2112 #[test]
2113 fn test_status_line_without_space_after_code_is_accepted() {
2114 let info = response(b"HTTP/1.1 200").unwrap();
2115 assert_eq!(info.status, 200);
2116 assert_eq!(info.reason, Span::new(12, 12));
2117 assert_eq!(response(b"HTTP/1.1 200 ").unwrap().status, 200);
2118 assert_eq!(response(b"HTTP/1.1 204 No Content").unwrap().status, 204);
2119 assert_eq!(
2120 response(b"HTTP/1.1 20").err(),
2121 Some(HttpError::InvalidStartLine)
2122 );
2123 assert_eq!(
2124 response(b"HTTP/1.1 2000").err(),
2125 Some(HttpError::InvalidStartLine)
2126 );
2127 assert_eq!(
2128 response(b"HTTP/1.1200 OK").err(),
2129 Some(HttpError::InvalidStartLine)
2130 );
2131 assert_eq!(
2132 response(b"HTTP/1.1 600").err(),
2133 Some(HttpError::InvalidStatus)
2134 );
2135 }
2136
2137 #[test]
2138 fn test_protocol_matching_rules() {
2139 assert!(protocol_matches(b"websocket", b"websocket"));
2140 assert!(protocol_matches(b"WebSocket", b"websocket"));
2141 assert!(protocol_matches(b"websocket", b"websocket/13"));
2142 assert!(protocol_matches(b"foo/2", b"FOO/2"));
2143 assert!(!protocol_matches(b"foo/2", b"foo/3"));
2144 assert!(!protocol_matches(b"foo/2", b"foo"));
2145 assert!(!protocol_matches(b"ws", b"websocket"));
2146 assert!(!protocol_matches(b"h2c", b"h2c"));
2147 assert!(!protocol_matches(b"H2C", b"h2c"));
2148 assert!(is_h2c(b"h2c/1") && is_h2c(b"H2c") && !is_h2c(b"h2"));
2149 }
2150
2151 #[test]
2152 fn test_authority_targets_refuse_empty_host_and_bad_escapes() {
2153 assert!(check_target(Method::Connect, b"a%41:443").is_ok());
2154 assert!(check_target(Method::Connect, b"a%4:443").is_err());
2155 assert!(check_target(Method::Get, b"http://a%zz/").is_err());
2156 assert!(check_target(Method::Get, b"http://a%41b/").is_ok());
2157 assert!(check_target(Method::Get, b"ftp://h/").is_ok());
2158 }
2159
2160 #[test]
2161 fn test_versions() {
2162 assert_eq!(parse_version(b"HTTP/1.1"), Ok(Version::Http11));
2163 assert_eq!(parse_version(b"HTTP/1.0"), Ok(Version::Http10));
2164 assert_eq!(parse_version(b"HTTP/1.9"), Ok(Version::Http11));
2165 assert_eq!(
2166 parse_version(b"HTTP/2.0"),
2167 Err(HttpError::UnsupportedVersion)
2168 );
2169 assert_eq!(
2170 parse_version(b"HTTP/0.9"),
2171 Err(HttpError::UnsupportedVersion)
2172 );
2173 assert_eq!(parse_version(b"http/1.1"), Err(HttpError::InvalidVersion));
2174 assert_eq!(parse_version(b"HTTP/1.10"), Err(HttpError::InvalidVersion));
2175 assert_eq!(parse_version(b"HTTP/1"), Err(HttpError::InvalidVersion));
2176 }
2177
2178 #[test]
2179 fn test_target_forms_follow_method() {
2180 assert!(check_target(Method::Get, b"/").is_ok());
2181 assert!(check_target(Method::Options, b"*").is_ok());
2182 assert!(check_target(Method::Get, b"*").is_err());
2183 assert!(check_target(Method::Connect, b"example.com:443").is_ok());
2184 assert!(check_target(Method::Connect, b"[::1]:443").is_ok());
2185 assert!(check_target(Method::Connect, b"example.com").is_err());
2186 assert!(check_target(Method::Connect, b"/").is_err());
2187 assert!(check_target(Method::Get, b"http://example.com/a?b").is_ok());
2188 assert!(check_target(Method::Get, b"http://[::1]:80/").is_ok());
2189 assert!(check_target(Method::Get, b"http://x").is_ok());
2190 assert!(check_target(Method::Get, b"http://x?q").is_ok());
2191 assert!(check_target(Method::Get, b"http://u@x/").is_err());
2192 assert!(check_target(Method::Get, b"http:x").is_err());
2193 assert!(check_target(Method::Get, b"http://:80/").is_err());
2194 assert!(check_target(Method::Get, b"http://x/[a]").is_err());
2195 assert!(check_target(Method::Connect, b":443").is_err());
2196 assert!(check_target(Method::Get, b"1http://x").is_err());
2197 assert!(check_target(Method::Get, b"example.com").is_err());
2198 assert!(check_target(Method::Get, b"").is_err());
2199 }
2200}