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