http_net/raw.rs
1//! Tier 3: the bytes and offsets behind a parsed head, copying a head out
2//! (the zero-copy passport path), owned heads, and the stateless parsers.
3//!
4//! A head is its bytes plus `u32` spans into them, so it can be moved or
5//! copied without re-parsing: [`RequestHead::copy_into`] copies the bytes
6//! and spans into a caller's reused vectors and hands back the interpreted
7//! [`HeadFacts`], and [`OwnedRequestHead::from_parts`] rebuilds a view from
8//! them after checking that their structure is intact. The stateless
9//! parsers run the connections' own scanner and interpretation over a
10//! caller's slice, with the field records written into a caller's array:
11//! they allocate nothing.
12
13use alloc::vec::Vec;
14use core::fmt;
15
16use crate::{
17 error::HttpError,
18 head::{
19 Asked, Field, FieldSpan, HeadKind, LineScan, RequestHead, RequestInfo, ResponseHead,
20 ResponseInfo, Scan, SliceSink, Span, check_target, interpret_request, interpret_response,
21 parse_version,
22 },
23 limits::Limits,
24 method::Method,
25 scan::{check_field_value, find_byte, is_ows, is_token},
26};
27
28/// The bytes of a head and the spans of its parts, all relative to
29/// [`bytes`](Self::bytes): what [`RequestHead::raw`] and
30/// [`ResponseHead::raw`] return.
31///
32/// The bytes run from the first byte the connection kept for the message
33/// (any empty lines a client sent before the request line, which RFC 9112
34/// section 2.2 lets a server skip, are included) to the end of the blank
35/// line that ends the head. Spans for parts a head does not have are empty:
36/// `status` on a request, `method` and `target` on a response.
37///
38/// `Debug` shows lengths and spans only, never the bytes, so a raw head in
39/// a log cannot leak a credential.
40///
41/// # Examples
42///
43/// ```
44/// use http_net::{ServerConn, ServerEvent};
45///
46/// let mut conn = ServerConn::new();
47/// let _ = conn.feed(b"GET /a HTTP/1.1\r\nHost: x\r\n\r\nbody bytes are not part of it");
48/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
49/// let raw = req.raw();
50/// assert_eq!(raw.bytes(), b"GET /a HTTP/1.1\r\nHost: x\r\n\r\n");
51/// assert_eq!(raw.method().get(raw.bytes()), b"GET");
52/// assert_eq!(raw.target().get(raw.bytes()), b"/a");
53/// assert_eq!(raw.version().get(raw.bytes()), b"HTTP/1.1");
54/// assert!(raw.status().is_empty());
55/// assert_eq!(raw.fields().len(), 1);
56/// ```
57#[derive(Clone, Copy)]
58pub struct RawHead<'a> {
59 bytes: &'a [u8],
60 start_line: Span,
61 method: Span,
62 target: Span,
63 version: Span,
64 status: Span,
65 fields: &'a [FieldSpan],
66}
67
68impl<'a> RawHead<'a> {
69 /// The head bytes, from its first byte to the end of the blank line.
70 ///
71 /// # Examples
72 ///
73 /// See [`RawHead`].
74 #[must_use]
75 pub fn bytes(&self) -> &'a [u8] {
76 self.bytes
77 }
78
79 /// The request line or status line, without its CRLF.
80 ///
81 /// # Examples
82 ///
83 /// ```
84 /// # use http_net::{ServerConn, ServerEvent};
85 /// # let mut conn = ServerConn::new();
86 /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: x\r\n\r\n");
87 /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
88 /// let raw = req.raw();
89 /// assert_eq!(raw.start_line().get(raw.bytes()), b"GET / HTTP/1.1");
90 /// ```
91 #[must_use]
92 pub fn start_line(&self) -> Span {
93 self.start_line
94 }
95
96 /// The method (requests; empty for a response).
97 ///
98 /// # Examples
99 ///
100 /// See [`RawHead`].
101 #[must_use]
102 pub fn method(&self) -> Span {
103 self.method
104 }
105
106 /// The request target (requests; empty for a response).
107 ///
108 /// # Examples
109 ///
110 /// See [`RawHead`].
111 #[must_use]
112 pub fn target(&self) -> Span {
113 self.target
114 }
115
116 /// The protocol version as received (`HTTP/1.0`, `HTTP/1.1`, or another
117 /// `HTTP/1.x`, which `version()` reports as `Http11`).
118 ///
119 /// # Examples
120 ///
121 /// See [`RawHead`].
122 #[must_use]
123 pub fn version(&self) -> Span {
124 self.version
125 }
126
127 /// The three status digits (responses; empty for a request).
128 ///
129 /// # Examples
130 ///
131 /// ```
132 /// # use http_net::{ClientConn, ClientEvent, Request};
133 /// # let mut conn = ClientConn::new();
134 /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
135 /// # let _ = conn.feed(b"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
136 /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
137 /// let raw = resp.raw();
138 /// assert_eq!(raw.status().get(raw.bytes()), b"404");
139 /// assert!(raw.method().is_empty());
140 /// ```
141 #[must_use]
142 pub fn status(&self) -> Span {
143 self.status
144 }
145
146 /// Every field line's name and value spans, in arrival order.
147 ///
148 /// # Examples
149 ///
150 /// See [`FieldSpan`].
151 #[must_use]
152 pub fn fields(&self) -> &'a [FieldSpan] {
153 self.fields
154 }
155}
156
157impl fmt::Debug for RawHead<'_> {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 f.debug_struct("RawHead")
160 .field("len", &self.bytes.len())
161 .field("start_line", &self.start_line)
162 .field("fields", &self.fields.len())
163 .finish_non_exhaustive()
164 }
165}
166
167/// The interpreted facts of a request head (method, version, framing,
168/// keep-alive, upgrade and expectation flags, target form, and the spans of
169/// the host and of the target's parts), so a view can be rebuilt from
170/// copied bytes without parsing them again. Returned by
171/// [`RequestHead::copy_into`], taken by [`OwnedRequestHead::from_parts`].
172///
173/// # Examples
174///
175/// ```
176/// use http_net::{OwnedRequestHead, ServerConn, ServerEvent};
177///
178/// let mut conn = ServerConn::new();
179/// let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\n\r\n");
180/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
181/// let (mut bytes, mut fields) = (Vec::new(), Vec::new());
182/// let facts = req.copy_into(&mut bytes, &mut fields);
183/// let owned = OwnedRequestHead::from_parts(bytes, fields, facts)?;
184/// assert_eq!(owned.view().path(), "/x");
185/// # Ok::<(), http_net::HttpError>(())
186/// ```
187#[derive(Clone, Copy, Debug, PartialEq, Eq)]
188pub struct HeadFacts {
189 info: RequestInfo,
190}
191
192/// The length of a validated head inside `bytes`: the line that holds the
193/// last field value (or the start line) ends at the next LF, and the blank
194/// line's CRLF follows it.
195fn head_len(bytes: &[u8], start_line: Span, fields: &[Field]) -> usize {
196 let after = fields.last().map_or(start_line.end, |f| f.value.end) as usize;
197 match bytes.get(after..).and_then(|rest| find_byte(b'\n', rest)) {
198 Some(lf) => (after + lf + 1 + 2).min(bytes.len()),
199 None => bytes.len(),
200 }
201}
202
203impl<'a> RequestHead<'a> {
204 /// The head's bytes and the spans of its parts, for code that works on
205 /// offsets (passports, proxies, other engines).
206 ///
207 /// # Examples
208 ///
209 /// See [`RawHead`].
210 #[must_use]
211 pub fn raw(&self) -> RawHead<'a> {
212 let (head, fields, info) = self.parts();
213 let sl = info.start_line;
214 let bytes = head.get(..head_len(head, sl, fields)).unwrap_or(head);
215 RawHead {
216 bytes,
217 start_line: sl,
218 method: info.method_span,
219 target: info.target,
220 version: Span {
221 start: info.target.end.saturating_add(1),
222 end: sl.end,
223 },
224 status: Span::default(),
225 fields,
226 }
227 }
228
229 /// Copies the head bytes (one copy) and field spans into `bytes` and
230 /// `fields`, which are cleared first, and returns the interpreted facts:
231 /// with them, [`OwnedRequestHead::from_parts`] (or a passport) rebuilds a
232 /// view without parsing again. Once the vectors have grown to the
233 /// largest head seen, the copy allocates nothing.
234 ///
235 /// # Examples
236 ///
237 /// ```
238 /// use http_net::{OwnedRequestHead, ServerConn, ServerEvent};
239 ///
240 /// // A passport's buffers, reused for every request.
241 /// let (mut bytes, mut fields) = (Vec::with_capacity(4096), Vec::with_capacity(64));
242 /// let mut conn = ServerConn::new();
243 /// let _ = conn.feed(b"POST /api HTTP/1.1\r\nHost: a\r\nContent-Length: 2\r\n\r\nhi");
244 /// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
245 /// let facts = req.copy_into(&mut bytes, &mut fields);
246 /// assert_eq!(bytes, b"POST /api HTTP/1.1\r\nHost: a\r\nContent-Length: 2\r\n\r\n");
247 /// let owned = OwnedRequestHead::from_parts(bytes, fields, facts)?;
248 /// assert_eq!(owned.view().content_length(), Some(2));
249 /// # Ok::<(), http_net::HttpError>(())
250 /// ```
251 #[must_use = "the facts are needed to rebuild a view from the copied bytes"]
252 pub fn copy_into(&self, bytes: &mut Vec<u8>, fields: &mut Vec<FieldSpan>) -> HeadFacts {
253 let raw = self.raw();
254 bytes.clear();
255 bytes.extend_from_slice(raw.bytes);
256 fields.clear();
257 fields.extend_from_slice(raw.fields);
258 HeadFacts {
259 info: *self.parts().2,
260 }
261 }
262
263 /// An owned copy of the head, for keeping it across body events or
264 /// sending it to another thread.
265 ///
266 /// # Examples
267 ///
268 /// ```
269 /// use http_net::{ServerConn, ServerEvent};
270 ///
271 /// let mut conn = ServerConn::new();
272 /// let _ = conn.feed(b"GET /keep HTTP/1.1\r\nHost: a\r\n\r\n");
273 /// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
274 /// let owned = req.to_owned();
275 /// drop(conn);
276 /// assert_eq!(owned.view().path(), "/keep");
277 /// ```
278 #[must_use]
279 #[allow(clippy::wrong_self_convention)]
280 pub fn to_owned(&self) -> OwnedRequestHead {
281 let raw = self.raw();
282 OwnedRequestHead {
283 bytes: raw.bytes.to_vec(),
284 fields: raw.fields.to_vec(),
285 facts: HeadFacts {
286 info: *self.parts().2,
287 },
288 }
289 }
290}
291
292impl<'a> ResponseHead<'a> {
293 /// The head's bytes and the spans of its parts (see [`RawHead`]).
294 ///
295 /// # Examples
296 ///
297 /// See [`RawHead::status`].
298 #[must_use]
299 pub fn raw(&self) -> RawHead<'a> {
300 let (head, fields, info) = self.parts();
301 let sl = info.start_line;
302 let bytes = head.get(..head_len(head, sl, fields)).unwrap_or(head);
303 RawHead {
304 bytes,
305 start_line: sl,
306 method: Span::default(),
307 target: Span::default(),
308 version: Span {
309 start: sl.start,
310 end: sl.start.saturating_add(8).min(sl.end),
311 },
312 status: Span {
313 start: sl.start.saturating_add(9).min(sl.end),
314 end: sl.start.saturating_add(12).min(sl.end),
315 },
316 fields,
317 }
318 }
319}
320
321/// A request head that owns its bytes and spans: from
322/// [`RequestHead::to_owned`], or rebuilt from a passport's parts with
323/// [`from_parts`](Self::from_parts). `Debug` shows the head the way
324/// [`RequestHead`] does, credential values redacted.
325///
326/// # Examples
327///
328/// See [`RequestHead::to_owned`] and [`HeadFacts`].
329#[derive(Clone, PartialEq, Eq)]
330pub struct OwnedRequestHead {
331 bytes: Vec<u8>,
332 fields: Vec<FieldSpan>,
333 facts: HeadFacts,
334}
335
336impl OwnedRequestHead {
337 /// A view of the owned head, with every accessor of a borrowed one.
338 ///
339 /// # Examples
340 ///
341 /// See [`RequestHead::to_owned`].
342 #[must_use]
343 pub fn view(&self) -> RequestHead<'_> {
344 RequestHead::new(&self.bytes, &self.fields, &self.facts.info)
345 }
346
347 /// Rebuilds an owned head from copied parts ([`RequestHead::copy_into`]),
348 /// checking first that they still describe one head: every span lies
349 /// inside `bytes`, the start line and every field line have the
350 /// structure the parser accepted (method, target, and version where the
351 /// facts say, each field name a token followed by a colon, each value
352 /// without control bytes or surrounding whitespace, the lines in order
353 /// and back to back, the blank line last), and the host and target
354 /// spans in the facts point where they should. A passport whose
355 /// structure was changed is refused, never read. The check is
356 /// structural, not an integrity check: a change that keeps every rule (a
357 /// different target, `Host`, or field value of valid bytes) is accepted,
358 /// so a passport that crosses a trust boundary needs its own MAC.
359 ///
360 /// The framing facts themselves (body length, keep-alive) are taken as
361 /// given: they come from the same trusted copy, and recomputing them
362 /// would be the parse this is meant to avoid.
363 ///
364 /// # Errors
365 ///
366 /// [`HttpError::InvalidState`], naming the first rule that failed.
367 ///
368 /// # Examples
369 ///
370 /// ```
371 /// use http_net::{HttpError, OwnedRequestHead, ServerConn, ServerEvent};
372 ///
373 /// let mut conn = ServerConn::new();
374 /// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
375 /// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
376 /// let (mut bytes, mut fields) = (Vec::new(), Vec::new());
377 /// let facts = req.copy_into(&mut bytes, &mut fields);
378 /// bytes[16] = b' '; // the first field name now starts with a space
379 /// assert!(matches!(
380 /// OwnedRequestHead::from_parts(bytes, fields, facts),
381 /// Err(HttpError::InvalidState(_))
382 /// ));
383 /// # Ok::<(), http_net::HttpError>(())
384 /// ```
385 pub fn from_parts(
386 bytes: Vec<u8>,
387 fields: Vec<FieldSpan>,
388 facts: HeadFacts,
389 ) -> Result<Self, HttpError> {
390 validate(&bytes, &fields, &facts.info).map_err(HttpError::InvalidState)?;
391 Ok(Self {
392 bytes,
393 fields,
394 facts,
395 })
396 }
397
398 /// Gives the parts back, so a passport pool can reuse the vectors for
399 /// the next head without allocating.
400 ///
401 /// # Examples
402 ///
403 /// ```
404 /// use http_net::{ServerConn, ServerEvent};
405 ///
406 /// let mut conn = ServerConn::new();
407 /// let _ = conn.feed(b"GET /a HTTP/1.1\r\nHost: a\r\n\r\n");
408 /// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
409 /// let (mut bytes, mut fields, _facts) = req.to_owned().into_parts();
410 /// let capacity = bytes.capacity();
411 /// bytes.clear();
412 /// fields.clear();
413 /// assert_eq!(bytes.capacity(), capacity);
414 /// ```
415 #[must_use]
416 pub fn into_parts(self) -> (Vec<u8>, Vec<FieldSpan>, HeadFacts) {
417 (self.bytes, self.fields, self.facts)
418 }
419
420 /// Drops the head, zeroing its bytes first, including any spare
421 /// capacity (a vector reused through [`RequestHead::copy_into`] can
422 /// still hold an earlier, longer head there). A plain drop frees the
423 /// bytes as they are, so an `Authorization` or `Cookie` value lingers
424 /// in freed memory; call this where
425 /// [`ServerConn::set_wipe`](crate::ServerConn::set_wipe) is on. A clone
426 /// is a separate copy and needs its own `wipe`.
427 ///
428 /// # Examples
429 ///
430 /// ```
431 /// use http_net::{ServerConn, ServerEvent};
432 ///
433 /// let mut conn = ServerConn::new();
434 /// conn.set_wipe(true);
435 /// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nAuthorization: Bearer s3cret\r\n\r\n");
436 /// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
437 /// let head = req.to_owned();
438 /// assert_eq!(head.view().path(), "/");
439 /// head.wipe();
440 /// ```
441 pub fn wipe(self) {
442 let mut bytes = self.bytes;
443 let capacity = bytes.capacity();
444 bytes.resize(capacity, 0);
445 crate::buffer::zero(&mut bytes);
446 }
447}
448
449impl fmt::Debug for OwnedRequestHead {
450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451 fmt::Debug::fmt(&self.view(), f)
452 }
453}
454
455/// The checks behind [`OwnedRequestHead::from_parts`].
456fn validate(bytes: &[u8], fields: &[Field], info: &RequestInfo) -> Result<(), &'static str> {
457 let len = bytes.len();
458 let sl = info.start_line;
459 if !sl.fits(len) || sl.is_empty() {
460 return Err("the start line span is outside the head");
461 }
462 // Only empty lines (RFC 9112 section 2.2) may come before the start line.
463 let before = Span {
464 start: 0,
465 end: sl.start,
466 }
467 .get(bytes);
468 if before.len() % 2 != 0 || !before.chunks(2).all(|c| c == b"\r\n") {
469 return Err("bytes before the start line are not empty lines");
470 }
471 if bytes.get(sl.end as usize..sl.end as usize + 2) != Some(b"\r\n") {
472 return Err("the start line does not end in CRLF");
473 }
474 // method SP target SP version
475 let m = info.method_span;
476 let t = info.target;
477 if m.start != sl.start || m.is_empty() || !m.fits(len) {
478 return Err("the method span does not start the start line");
479 }
480 if !is_token(m.get(bytes)) || Method::from_bytes(m.get(bytes)) != info.method {
481 return Err("the method bytes do not match the facts");
482 }
483 if t.start != m.end + 1
484 || t.is_empty()
485 || t.end >= sl.end
486 || bytes.get(m.end as usize) != Some(&b' ')
487 {
488 return Err("the target span is not after the method");
489 }
490 if bytes.get(t.end as usize) != Some(&b' ') {
491 return Err("the target is not followed by a space");
492 }
493 if check_target(info.method, t.get(bytes)).is_err() {
494 return Err("the target bytes are not a valid target for the method");
495 }
496 let version = Span {
497 start: t.end + 1,
498 end: sl.end,
499 };
500 if parse_version(version.get(bytes)) != Ok(info.version) {
501 return Err("the version bytes do not match the facts");
502 }
503 let inside_target = |s: Span| s.start >= t.start && s.end <= t.end && s.start <= s.end;
504 if !inside_target(info.origin) {
505 return Err("the origin span is outside the target");
506 }
507 if info.authority.is_some_and(|a| !inside_target(a)) {
508 return Err("the authority span is outside the target");
509 }
510 // Field lines, back to back after the start line.
511 let mut pos = sl.end as usize + 2;
512 for field in fields {
513 let (name, value) = (field.name, field.value);
514 if name.start as usize != pos || name.is_empty() || !name.fits(len) {
515 return Err("a field line does not start where the previous line ended");
516 }
517 if !is_token(name.get(bytes)) || bytes.get(name.end as usize) != Some(&b':') {
518 return Err("a field name is not a token followed by a colon");
519 }
520 if !value.fits(len) || value.start < name.end + 1 {
521 return Err("a field value span is outside its line");
522 }
523 let lead = Span {
524 start: name.end + 1,
525 end: value.start,
526 };
527 if !lead.get(bytes).iter().all(|&b| is_ows(b)) {
528 return Err("bytes between a colon and its value are not whitespace");
529 }
530 let v = value.get(bytes);
531 if v.first().is_some_and(|&b| is_ows(b)) || v.last().is_some_and(|&b| is_ows(b)) {
532 return Err("a field value has surrounding whitespace");
533 }
534 if check_field_value(v).is_err() {
535 return Err("a field value holds a byte a field may not");
536 }
537 let mut end = value.end as usize;
538 while bytes.get(end).is_some_and(|&b| is_ows(b)) {
539 end += 1;
540 }
541 if bytes.get(end..end + 2) != Some(b"\r\n") {
542 return Err("a field line does not end in CRLF after its value");
543 }
544 pos = end + 2;
545 }
546 if pos + 2 != len || bytes.get(pos..) != Some(b"\r\n") {
547 return Err("the head does not end with the blank line");
548 }
549 if let Some(host) = info.host {
550 let is_host_value = fields
551 .iter()
552 .any(|f| f.value == host && f.name.get(bytes).eq_ignore_ascii_case(b"host"));
553 if !is_host_value {
554 return Err("the host span is not the value of a Host field");
555 }
556 }
557 Ok(())
558}
559
560/// The result of a stateless parse: a complete head and how many input
561/// bytes it took, or `Partial` when the input ends before the head does.
562///
563/// # Examples
564///
565/// ```
566/// use http_net::{FieldSpan, Limits, Parsed, parse_request_head};
567///
568/// let mut fields = [FieldSpan::default(); 16];
569/// let parsed = parse_request_head(b"GET / HTTP/1.1\r\nHo", &Limits::new(), &mut fields)?;
570/// assert!(matches!(parsed, Parsed::Partial));
571/// # Ok::<(), http_net::HttpError>(())
572/// ```
573#[non_exhaustive]
574#[derive(Debug)]
575pub enum Parsed<T> {
576 /// A whole head: `len` bytes of the input, any leading empty lines
577 /// included; the body (if any) starts there.
578 Complete {
579 /// The parsed head.
580 head: T,
581 /// The bytes of input the head took.
582 len: usize,
583 },
584 /// The input ends before the head does: call again with more input.
585 Partial,
586}
587
588/// A request head from [`parse_request_head`], borrowing the input and the
589/// caller's field array.
590///
591/// # Examples
592///
593/// See [`parse_request_head`].
594#[derive(Clone, Copy)]
595pub struct ParsedRequest<'a> {
596 bytes: &'a [u8],
597 fields: &'a [FieldSpan],
598 info: RequestInfo,
599}
600
601impl ParsedRequest<'_> {
602 /// The usual view of the head.
603 ///
604 /// # Examples
605 ///
606 /// See [`parse_request_head`].
607 #[must_use]
608 pub fn view(&self) -> RequestHead<'_> {
609 RequestHead::new(self.bytes, self.fields, &self.info)
610 }
611
612 /// The interpreted facts, as [`RequestHead::copy_into`] returns them.
613 ///
614 /// # Examples
615 ///
616 /// ```
617 /// use http_net::{FieldSpan, Limits, Parsed, parse_request_head};
618 ///
619 /// let mut fields = [FieldSpan::default(); 4];
620 /// let Parsed::Complete { head, .. } = parse_request_head(b"GET / HTTP/1.0\r\n\r\n", &Limits::new(), &mut fields)? else { panic!() };
621 /// let _facts = head.facts();
622 /// # Ok::<(), http_net::HttpError>(())
623 /// ```
624 #[must_use]
625 pub fn facts(&self) -> HeadFacts {
626 HeadFacts { info: self.info }
627 }
628}
629
630impl fmt::Debug for ParsedRequest<'_> {
631 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632 fmt::Debug::fmt(&self.view(), f)
633 }
634}
635
636/// A response head from [`parse_response_head`].
637///
638/// # Examples
639///
640/// See [`parse_response_head`].
641#[derive(Clone, Copy)]
642pub struct ParsedResponse<'a> {
643 bytes: &'a [u8],
644 fields: &'a [FieldSpan],
645 info: ResponseInfo,
646}
647
648impl ParsedResponse<'_> {
649 /// The usual view of the head.
650 ///
651 /// # Examples
652 ///
653 /// See [`parse_response_head`].
654 #[must_use]
655 pub fn view(&self) -> ResponseHead<'_> {
656 ResponseHead::new(self.bytes, self.fields, &self.info)
657 }
658}
659
660impl fmt::Debug for ParsedResponse<'_> {
661 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
662 fmt::Debug::fmt(&self.view(), f)
663 }
664}
665
666/// Parses one request head from the start of `input`, with the rules and
667/// budgets of [`ServerConn`](crate::ServerConn) (the same scanner and
668/// interpretation code), writing the field records into `fields`.
669/// Allocates nothing. Unlike `ServerConn`, it does not check for the HTTP/2
670/// connection preface first; call [`is_h2_preface`](crate::is_h2_preface)
671/// for that.
672///
673/// It is stateless: given more input after `Partial`, it parses again from
674/// the start. A caller that receives a head in many small pieces and needs
675/// linear total work should use `ServerConn`, which resumes where it
676/// stopped. A head with more fields than `fields` holds is
677/// [`HttpError::TooManyHeaders`] (as is one over
678/// [`Limits::max_headers`]).
679///
680/// # Errors
681///
682/// Every request parse error `ServerConn::poll` can return for a head,
683/// except `UnexpectedEof` (running out of input is `Partial` here) and
684/// `Http2Preface` (the preface is reported as
685/// [`HttpError::UnsupportedVersion`]; call
686/// [`is_h2_preface`](crate::is_h2_preface) first to tell them apart).
687///
688/// # Examples
689///
690/// ```
691/// use http_net::{FieldSpan, Limits, Parsed, parse_request_head};
692///
693/// let input = b"POST /notes HTTP/1.1\r\nHost: a\r\nContent-Length: 5\r\n\r\nhello";
694/// let mut fields = [FieldSpan::default(); 32];
695/// let Parsed::Complete { head, len } = parse_request_head(input, &Limits::new(), &mut fields)? else {
696/// panic!("incomplete");
697/// };
698/// let req = head.view();
699/// assert_eq!(req.path(), "/notes");
700/// assert_eq!(req.content_length(), Some(5));
701/// assert_eq!(&input[len..], b"hello");
702/// # Ok::<(), http_net::HttpError>(())
703/// ```
704pub fn parse_request_head<'a>(
705 input: &'a [u8],
706 limits: &Limits,
707 fields: &'a mut [FieldSpan],
708) -> Result<Parsed<ParsedRequest<'a>>, HttpError> {
709 let mut lines = LineScan::new();
710 let mut sink = SliceSink::new(fields);
711 let len = match lines.advance(input, limits, HeadKind::Request, &mut sink)? {
712 Scan::Partial => return Ok(Parsed::Partial),
713 Scan::Done(len) => len,
714 };
715 let (slots, count) = sink.into_parts();
716 let slots: &'a [FieldSpan] = slots;
717 let fields = slots.get(..count).unwrap_or(&[]);
718 let bytes = input.get(..len).unwrap_or(input);
719 let info = interpret_request(bytes, lines.start_line(), fields, limits)?;
720 Ok(Parsed::Complete {
721 head: ParsedRequest {
722 bytes,
723 fields,
724 info,
725 },
726 len,
727 })
728}
729
730/// Parses one response head from the start of `input` with the rules of
731/// [`ClientConn`](crate::ClientConn), framed by the method of the request
732/// it answers (a response to `HEAD` has no body; a 2xx to `CONNECT` is a
733/// tunnel; any other method frames by the fields). Interim (1xx) heads are returned like any other; check
734/// [`ResponseHead::is_informational`] and parse the next head after `len`.
735/// No [`ClientLeniency`](crate::ClientLeniency) applies, so obsolete line
736/// folding is always [`HttpError::ObsFold`]. Allocates nothing.
737///
738/// # Errors
739///
740/// Every response parse error `ClientConn::poll` can return for a head
741/// (`UnexpectedEof` aside), and [`HttpError::TooManyHeaders`] when the head
742/// has more fields than `fields` holds.
743///
744/// # Examples
745///
746/// ```
747/// use http_net::{BodyFraming, FieldSpan, Limits, Method, Parsed, parse_response_head};
748///
749/// let input = b"HTTP/1.1 200 OK\r\nContent-Length: 100\r\n\r\n";
750/// let mut fields = [FieldSpan::default(); 8];
751/// let Parsed::Complete { head, .. } = parse_response_head(input, &Limits::new(), Method::Head, &mut fields)? else {
752/// panic!("incomplete");
753/// };
754/// // A response to HEAD has no body, whatever its fields say.
755/// assert_eq!(head.view().framing(), BodyFraming::None);
756/// assert_eq!(head.view().content_length(), Some(100));
757/// # Ok::<(), http_net::HttpError>(())
758/// ```
759pub fn parse_response_head<'a>(
760 input: &'a [u8],
761 limits: &Limits,
762 request_method: Method,
763 fields: &'a mut [FieldSpan],
764) -> Result<Parsed<ParsedResponse<'a>>, HttpError> {
765 let mut lines = LineScan::new();
766 let mut sink = SliceSink::new(fields);
767 let len = match lines.advance(input, limits, HeadKind::Response, &mut sink)? {
768 Scan::Partial => return Ok(Parsed::Partial),
769 Scan::Done(len) => len,
770 };
771 let (slots, count) = sink.into_parts();
772 let slots: &'a [FieldSpan] = slots;
773 let fields = slots.get(..count).unwrap_or(&[]);
774 let bytes = input.get(..len).unwrap_or(input);
775 let asked = Asked::from_method(request_method);
776 let info = interpret_response(bytes, lines.start_line(), fields, limits, asked)?;
777 Ok(Parsed::Complete {
778 head: ParsedResponse {
779 bytes,
780 fields,
781 info,
782 },
783 len,
784 })
785}
786
787#[cfg(test)]
788mod tests {
789 use alloc::vec;
790
791 use super::*;
792 use crate::{ServerConn, ServerEvent};
793
794 fn owned_parts(input: &[u8]) -> (Vec<u8>, Vec<FieldSpan>, HeadFacts) {
795 let mut conn = ServerConn::new();
796 let _ = conn.feed(input);
797 let Ok(ServerEvent::Request(req)) = conn.poll() else {
798 panic!("no request in {input:?}");
799 };
800 let (mut bytes, mut fields) = (Vec::new(), Vec::new());
801 let facts = req.copy_into(&mut bytes, &mut fields);
802 (bytes, fields, facts)
803 }
804
805 #[test]
806 fn test_span_get_and_len_never_panic() {
807 let head = b"abc";
808 assert_eq!(Span { start: 0, end: 3 }.get(head), b"abc");
809 assert_eq!(Span { start: 2, end: 9 }.get(head), b"");
810 assert_eq!(Span { start: 3, end: 1 }.get(head), b"");
811 assert_eq!(Span { start: 3, end: 1 }.len(), 0);
812 assert_eq!(
813 Span {
814 start: u32::MAX,
815 end: u32::MAX
816 }
817 .get(head),
818 b""
819 );
820 assert!(Span { start: 1, end: 1 }.is_empty());
821 }
822
823 #[test]
824 fn test_raw_head_spans_point_at_the_parts() {
825 let (bytes, fields, _) =
826 owned_parts(b"\r\nPUT /f?q HTTP/1.0\r\nX: v \r\nHost: h\r\n\r\nbody");
827 assert_eq!(bytes, b"\r\nPUT /f?q HTTP/1.0\r\nX: v \r\nHost: h\r\n\r\n");
828 assert_eq!(fields.len(), 2);
829 assert_eq!(fields[0].value.get(&bytes), b"v");
830 let mut conn = ServerConn::new();
831 let _ = conn.feed(&bytes);
832 let Ok(ServerEvent::Request(req)) = conn.poll() else {
833 panic!()
834 };
835 let raw = req.raw();
836 assert_eq!(raw.bytes(), &bytes[..]);
837 assert_eq!(raw.start_line().get(raw.bytes()), b"PUT /f?q HTTP/1.0");
838 assert_eq!(raw.version().get(raw.bytes()), b"HTTP/1.0");
839 assert!(!alloc::format!("{raw:?}").contains("PUT"));
840 }
841
842 #[test]
843 fn test_owned_head_view_equals_original() {
844 let input = b"GET http://a.test/p?q=1 HTTP/1.1\r\nHost: b\r\nCookie: s=1\r\nVia: 1.1 x\r\nVia: 1.1 y\r\n\r\n";
845 let mut conn = ServerConn::new();
846 let _ = conn.feed(input);
847 let Ok(ServerEvent::Request(req)) = conn.poll() else {
848 panic!()
849 };
850 let owned = req.to_owned();
851 let view = owned.view();
852 assert_eq!(view.method_str(), req.method_str());
853 assert_eq!(view.target(), req.target());
854 assert_eq!(view.target_form(), req.target_form());
855 assert_eq!(view.path(), req.path());
856 assert_eq!(view.query(), req.query());
857 assert_eq!(view.host(), req.host());
858 assert_eq!(view.version(), req.version());
859 assert_eq!(view.framing(), req.framing());
860 assert_eq!(view.keep_alive(), req.keep_alive());
861 assert!(view.headers().eq(req.headers()));
862 assert!(view.header_all("via").eq(req.header_all("via")));
863 assert_eq!(alloc::format!("{owned:?}"), alloc::format!("{req:?}"));
864 let (b, f, facts) = owned_parts(input);
865 let rebuilt = OwnedRequestHead::from_parts(b, f, facts).unwrap();
866 assert_eq!(rebuilt, owned);
867 }
868
869 #[test]
870 fn test_from_parts_accepts_every_valid_copy() {
871 for input in [
872 &b"GET / HTTP/1.1\r\nHost: a\r\n\r\n"[..],
873 b"\r\n\r\nGET / HTTP/1.0\r\n\r\n",
874 b"OPTIONS * HTTP/1.1\r\nHost: a\r\nX:\r\nY: \t \r\n\r\n",
875 b"CONNECT a:443 HTTP/1.1\r\nHost: a:443\r\n\r\n",
876 b"POST /x HTTP/1.1\r\nHost: \r\nTransfer-Encoding: chunked\r\n\r\n",
877 ] {
878 let (b, f, facts) = owned_parts(input);
879 assert!(
880 OwnedRequestHead::from_parts(b, f, facts).is_ok(),
881 "{input:?}"
882 );
883 }
884 }
885
886 /// Every way a passport buffer can be changed after the copy is refused.
887 #[test]
888 fn test_from_parts_refuses_every_tampered_part() {
889 let input = b"GET /a HTTP/1.1\r\nHost: h\r\nX-Two: v\r\n\r\n";
890 let (bytes, fields, facts) = owned_parts(input);
891 let refused = |b: Vec<u8>, f: Vec<FieldSpan>, facts: HeadFacts| {
892 matches!(
893 OwnedRequestHead::from_parts(b, f, facts),
894 Err(HttpError::InvalidState(_))
895 )
896 };
897 // Bytes changed under the spans.
898 let tamper_byte = |i: usize, b: u8| {
899 let mut v = bytes.clone();
900 v[i] = b;
901 v
902 };
903 assert!(refused(tamper_byte(0, b'P'), fields.clone(), facts)); // method
904 assert!(refused(tamper_byte(3, b'_'), fields.clone(), facts)); // SP after method
905 assert!(refused(tamper_byte(5, b'#'), fields.clone(), facts)); // target byte
906 assert!(refused(tamper_byte(13, b'2'), fields.clone(), facts)); // version
907 assert!(refused(tamper_byte(15, b'X'), fields.clone(), facts)); // start-line CRLF
908 assert!(refused(tamper_byte(17, b' '), fields.clone(), facts)); // name
909 assert!(refused(tamper_byte(21, b'='), fields.clone(), facts)); // colon
910 assert!(refused(tamper_byte(23, 0), fields.clone(), facts)); // value control byte
911 assert!(refused(tamper_byte(24, b'x'), fields.clone(), facts)); // field CRLF
912 let mut shorter = bytes.clone();
913 let _ = shorter.pop();
914 assert!(refused(shorter, fields.clone(), facts)); // blank line cut
915 let mut longer = bytes.clone();
916 longer.push(b'x');
917 assert!(refused(longer, fields.clone(), facts)); // bytes past the head
918 let mut leading = b"x\r\n".to_vec();
919 leading.extend_from_slice(&bytes);
920 assert!(refused(leading, fields.clone(), facts)); // junk before the start line
921 // Spans moved.
922 let tamper_field = |i: usize, change: &dyn Fn(&mut FieldSpan)| {
923 let mut f = fields.clone();
924 change(&mut f[i]);
925 f
926 };
927 assert!(refused(
928 bytes.clone(),
929 tamper_field(0, &|f| f.name.end += 1),
930 facts
931 ));
932 assert!(refused(
933 bytes.clone(),
934 tamper_field(0, &|f| f.name.start += 1),
935 facts
936 ));
937 assert!(refused(
938 bytes.clone(),
939 tamper_field(0, &|f| f.value.end += 50),
940 facts
941 ));
942 assert!(refused(
943 bytes.clone(),
944 tamper_field(0, &|f| f.value.start = 0),
945 facts
946 ));
947 assert!(refused(
948 bytes.clone(),
949 tamper_field(1, &|f| f.value.end -= 1),
950 facts
951 ));
952 assert!(refused(
953 bytes.clone(),
954 tamper_field(1, &|f| *f = FieldSpan::default()),
955 facts
956 ));
957 let mut swapped = fields.clone();
958 swapped.swap(0, 1);
959 assert!(refused(bytes.clone(), swapped, facts)); // out of order
960 let mut dropped = fields.clone();
961 let _ = dropped.pop();
962 assert!(refused(bytes.clone(), dropped, facts)); // a line no span covers
963 let mut doubled = fields.clone();
964 doubled.push(fields[1]);
965 assert!(refused(bytes.clone(), doubled, facts)); // overlapping
966 // Facts moved.
967 let tamper_facts = |change: &dyn Fn(&mut RequestInfo)| {
968 let mut info = facts.info;
969 change(&mut info);
970 HeadFacts { info }
971 };
972 assert!(refused(
973 bytes.clone(),
974 fields.clone(),
975 tamper_facts(&|i| i.start_line.end += 1)
976 ));
977 assert!(refused(
978 bytes.clone(),
979 fields.clone(),
980 tamper_facts(&|i| i.target.end += 1)
981 ));
982 assert!(refused(
983 bytes.clone(),
984 fields.clone(),
985 tamper_facts(&|i| i.method = Method::Post)
986 ));
987 assert!(refused(
988 bytes.clone(),
989 fields.clone(),
990 tamper_facts(&|i| i.host = Some(fields[1].value))
991 ));
992 assert!(refused(
993 bytes.clone(),
994 fields.clone(),
995 tamper_facts(&|i| i.origin = Span { start: 0, end: 3 })
996 ));
997 assert!(refused(
998 bytes.clone(),
999 fields.clone(),
1000 tamper_facts(&|i| i.authority = Some(Span { start: 0, end: 3 }))
1001 ));
1002 // The untouched parts are still accepted.
1003 assert!(OwnedRequestHead::from_parts(bytes, fields, facts).is_ok());
1004 }
1005
1006 #[test]
1007 fn test_stateless_request_parse_complete_partial_and_errors() {
1008 let mut fields = [FieldSpan::default(); 4];
1009 let input = b"GET / HTTP/1.1\r\nHost: a\r\n\r\nGET";
1010 let Ok(Parsed::Complete { head, len }) =
1011 parse_request_head(input, &Limits::new(), &mut fields)
1012 else {
1013 panic!()
1014 };
1015 assert_eq!(len, input.len() - 3);
1016 assert_eq!(head.view().host(), Some("a"));
1017 for cut in 0..len {
1018 let mut fields = [FieldSpan::default(); 4];
1019 assert!(matches!(
1020 parse_request_head(&input[..cut], &Limits::new(), &mut fields),
1021 Ok(Parsed::Partial)
1022 ));
1023 }
1024 let mut fields = [FieldSpan::default(); 4];
1025 assert_eq!(
1026 parse_request_head(b"GET / HTTP/1.1\r\n\r\n", &Limits::new(), &mut fields).err(),
1027 Some(HttpError::MissingHost)
1028 );
1029 assert_eq!(
1030 parse_request_head(
1031 b"GET / HTTP/1.1\nHost: a\r\n\r\n",
1032 &Limits::new(),
1033 &mut fields
1034 )
1035 .err(),
1036 Some(HttpError::BareLf)
1037 );
1038 // More fields than the caller's array holds.
1039 let mut one = [FieldSpan::default(); 1];
1040 assert_eq!(
1041 parse_request_head(
1042 b"GET / HTTP/1.1\r\nHost: a\r\nX: 1\r\n\r\n",
1043 &Limits::new(),
1044 &mut one
1045 )
1046 .err(),
1047 Some(HttpError::TooManyHeaders)
1048 );
1049 let mut none: [FieldSpan; 0] = [];
1050 assert!(matches!(
1051 parse_request_head(b"GET / HTTP/1.0\r\n\r\n", &Limits::new(), &mut none),
1052 Ok(Parsed::Complete { .. })
1053 ));
1054 }
1055
1056 #[test]
1057 fn test_stateless_response_parse_follows_what_was_asked() {
1058 let mut fields = [FieldSpan::default(); 4];
1059 let input = b"HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nabc";
1060 let Ok(Parsed::Complete { head, len }) =
1061 parse_response_head(input, &Limits::new(), Method::Get, &mut fields)
1062 else {
1063 panic!()
1064 };
1065 assert_eq!(head.view().framing(), crate::BodyFraming::Length(3));
1066 assert_eq!(&input[len..], b"abc");
1067 assert_eq!(
1068 head.view().raw().status().get(head.view().raw().bytes()),
1069 b"200"
1070 );
1071 let mut fields = [FieldSpan::default(); 4];
1072 let Ok(Parsed::Complete { head, .. }) =
1073 parse_response_head(input, &Limits::new(), Method::Connect, &mut fields)
1074 else {
1075 panic!()
1076 };
1077 assert_eq!(head.view().framing(), crate::BodyFraming::None);
1078 let mut fields = [FieldSpan::default(); 4];
1079 assert_eq!(
1080 parse_response_head(
1081 b"\r\nHTTP/1.1 200 OK\r\n\r\n",
1082 &Limits::new(),
1083 Method::Get,
1084 &mut fields
1085 )
1086 .err(),
1087 Some(HttpError::InvalidStartLine)
1088 );
1089 let mut fields = [FieldSpan::default(); 4];
1090 assert!(matches!(
1091 parse_response_head(b"HTTP/1.1 103 Early Hints\r\nLink: </a>\r\n\r\n", &Limits::new(), Method::Get, &mut fields),
1092 Ok(Parsed::Complete { head, .. }) if head.view().is_informational()
1093 ));
1094 let v = vec![b'x'; 3];
1095 let mut fields = [FieldSpan::default(); 4];
1096 assert!(matches!(
1097 parse_response_head(&v, &Limits::new(), Method::Get, &mut fields),
1098 Ok(Parsed::Partial)
1099 ));
1100 }
1101}