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