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