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