1use bytes::{Buf, BytesMut};
2use http::{HeaderName, HeaderValue, Method, StatusCode};
3use httparse::Status;
4use std::collections::VecDeque;
5
6use crate::{
7 stream::{
8 StreamBody, StreamEnd, StreamFrame, StreamHeaders, StreamRequestHeaders,
9 StreamResponseHeaders,
10 },
11 HeaderField, HttpVersion, PackedMessage, PackedRequest, PackedResponse,
12};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum H1MessageKind {
16 Request,
17 Response,
18}
19
20#[derive(Debug)]
21pub enum H1DecodeError {
22 InvalidStartLine,
23 InvalidVersion(u8),
24 InvalidHeader,
25 TooManyHeaders(usize),
26 InvalidMethod,
27 InvalidPath,
28 InvalidStatus,
29 InvalidHeaderName,
30 InvalidHeaderValue,
31 InvalidContentLength,
32 InvalidChunkedEncoding,
33}
34
35impl std::fmt::Display for H1DecodeError {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 H1DecodeError::InvalidStartLine => write!(f, "invalid start line"),
39 H1DecodeError::InvalidVersion(version) => {
40 write!(f, "unsupported http version: {}", version)
41 }
42 H1DecodeError::InvalidHeader => write!(f, "invalid header"),
43 H1DecodeError::TooManyHeaders(count) => write!(f, "too many headers: {}", count),
44 H1DecodeError::InvalidMethod => write!(f, "invalid method"),
45 H1DecodeError::InvalidPath => write!(f, "invalid path"),
46 H1DecodeError::InvalidStatus => write!(f, "invalid status"),
47 H1DecodeError::InvalidHeaderName => write!(f, "invalid header name"),
48 H1DecodeError::InvalidHeaderValue => write!(f, "invalid header value"),
49 H1DecodeError::InvalidContentLength => write!(f, "invalid content-length"),
50 H1DecodeError::InvalidChunkedEncoding => write!(f, "invalid chunked encoding"),
51 }
52 }
53}
54
55impl std::error::Error for H1DecodeError {}
56
57pub struct H1Decoder {
58 kind: H1MessageKind,
59 buf: BytesMut,
60}
61
62pub struct H1StreamDecoder {
63 kind: H1MessageKind,
64 stream_id: u64,
65 buf: BytesMut,
66 out: VecDeque<StreamFrame>,
67 state: H1StreamState,
68}
69
70enum H1StreamState {
71 ReadingHeaders,
72 ReadingBody(BodyReader),
73 Done,
74}
75
76struct BodyReader {
77 kind: BodyKind,
78}
79
80enum BodyKind {
81 None,
82 Length { remaining: usize },
83 Chunked { phase: ChunkPhase },
84}
85
86enum ChunkPhase {
87 SizeLine,
88 Data { remaining: usize },
89 DataCrlf,
90 Trailers,
91}
92
93impl H1StreamDecoder {
94 pub fn new(kind: H1MessageKind, stream_id: u64) -> Self {
95 Self {
96 kind,
97 stream_id,
98 buf: BytesMut::new(),
99 out: VecDeque::new(),
100 state: H1StreamState::ReadingHeaders,
101 }
102 }
103
104 pub fn push(&mut self, data: &[u8]) {
105 self.buf.extend_from_slice(data);
106 }
107
108 pub fn try_decode(&mut self) -> Result<Option<StreamFrame>, H1DecodeError> {
109 if let Some(frame) = self.out.pop_front() {
110 return Ok(Some(frame));
111 }
112 self.fill_out()?;
113 Ok(self.out.pop_front())
114 }
115
116 pub fn try_decode_message(
117 &mut self,
118 ) -> Result<Option<crate::packetizer::HttpPackStreamMessage>, H1DecodeError> {
119 match self.try_decode()? {
120 Some(frame) => Ok(Some(crate::packetizer::HttpPackStreamMessage::from_frame(
121 &frame,
122 ))),
123 None => Ok(None),
124 }
125 }
126
127 pub fn buffer_len(&self) -> usize {
128 self.buf.len()
129 }
130
131 fn fill_out(&mut self) -> Result<(), H1DecodeError> {
132 if !self.out.is_empty() {
133 return Ok(());
134 }
135
136 match &mut self.state {
137 H1StreamState::ReadingHeaders => {
138 let (headers, body_kind) = match self.kind {
139 H1MessageKind::Request => {
140 let (method, path, header_len, headers) =
141 match parse_request_headers(&self.buf)? {
142 Some(value) => value,
143 None => return Ok(()),
144 };
145 self.buf.advance(header_len);
146 let authority =
147 find_header_value(&headers, b"host").map(|value| value.to_vec());
148 let path = if path.is_empty() {
149 b"/".as_slice()
150 } else {
151 path.as_slice()
152 };
153 let body_kind = body_kind_from_headers(&headers)?;
154 let header = StreamHeaders::Request(StreamRequestHeaders {
155 stream_id: self.stream_id,
156 version: HttpVersion::Http11,
157 method,
158 scheme: None,
159 authority,
160 path: path.to_vec(),
161 headers,
162 });
163 (header, body_kind)
164 }
165 H1MessageKind::Response => {
166 let (status, header_len, headers) =
167 match parse_response_headers(&self.buf)? {
168 Some(value) => value,
169 None => return Ok(()),
170 };
171 self.buf.advance(header_len);
172 let body_kind = body_kind_from_headers(&headers)?;
173 let header = StreamHeaders::Response(StreamResponseHeaders {
174 stream_id: self.stream_id,
175 version: HttpVersion::Http11,
176 status,
177 headers,
178 });
179 (header, body_kind)
180 }
181 };
182
183 self.out.push_back(StreamFrame::Headers(headers));
184 match body_kind {
185 BodyKind::None => {
186 self.out.push_back(StreamFrame::End(StreamEnd {
187 stream_id: self.stream_id,
188 }));
189 self.state = H1StreamState::Done;
190 }
191 BodyKind::Length { remaining } if remaining == 0 => {
192 self.out.push_back(StreamFrame::End(StreamEnd {
193 stream_id: self.stream_id,
194 }));
195 self.state = H1StreamState::Done;
196 }
197 body_kind => {
198 self.state = H1StreamState::ReadingBody(BodyReader { kind: body_kind });
199 }
200 }
201 }
202 H1StreamState::ReadingBody(reader) => {
203 if let Some(frame) = read_body_frame(&mut self.buf, reader, self.stream_id)? {
204 self.out.push_back(frame);
205 if matches!(reader.kind, BodyKind::None) {
206 self.state = H1StreamState::Done;
207 }
208 } else if matches!(reader.kind, BodyKind::None) {
209 self.state = H1StreamState::Done;
210 }
211 }
212 H1StreamState::Done => {}
213 }
214
215 Ok(())
216 }
217}
218
219impl H1Decoder {
220 pub fn new(kind: H1MessageKind) -> Self {
221 Self {
222 kind,
223 buf: BytesMut::new(),
224 }
225 }
226
227 pub fn push(&mut self, data: &[u8]) {
228 self.buf.extend_from_slice(data);
229 }
230
231 pub fn try_decode(&mut self) -> Result<Option<PackedMessage>, H1DecodeError> {
232 match decode_message_from_prefix(&self.buf, self.kind)? {
233 Some((message, consumed)) => {
234 self.buf.advance(consumed);
235 Ok(Some(message))
236 }
237 None => Ok(None),
238 }
239 }
240
241 pub fn buffer_len(&self) -> usize {
242 self.buf.len()
243 }
244}
245
246pub fn decode_request(bytes: &[u8]) -> Result<Option<(PackedRequest, usize)>, H1DecodeError> {
247 match decode_message_from_prefix(bytes, H1MessageKind::Request)? {
248 Some((PackedMessage::Request(req), consumed)) => Ok(Some((req, consumed))),
249 Some(_) => Err(H1DecodeError::InvalidStartLine),
250 None => Ok(None),
251 }
252}
253
254pub fn decode_response(bytes: &[u8]) -> Result<Option<(PackedResponse, usize)>, H1DecodeError> {
255 match decode_message_from_prefix(bytes, H1MessageKind::Response)? {
256 Some((PackedMessage::Response(resp), consumed)) => Ok(Some((resp, consumed))),
257 Some(_) => Err(H1DecodeError::InvalidStartLine),
258 None => Ok(None),
259 }
260}
261
262fn decode_message_from_prefix(
263 bytes: &[u8],
264 kind: H1MessageKind,
265) -> Result<Option<(PackedMessage, usize)>, H1DecodeError> {
266 match kind {
267 H1MessageKind::Request => decode_request_from_prefix(bytes).map(|opt| {
268 opt.map(|(req, consumed)| (PackedMessage::Request(req), consumed))
269 }),
270 H1MessageKind::Response => decode_response_from_prefix(bytes).map(|opt| {
271 opt.map(|(resp, consumed)| (PackedMessage::Response(resp), consumed))
272 }),
273 }
274}
275
276fn decode_request_from_prefix(
277 bytes: &[u8],
278) -> Result<Option<(PackedRequest, usize)>, H1DecodeError> {
279 let (method, path, header_len, headers) = match parse_request_headers(bytes)? {
280 Some(value) => value,
281 None => return Ok(None),
282 };
283
284 let authority = find_header_value(&headers, b"host").map(|value| value.to_vec());
285 let path = if path.is_empty() {
286 b"/".as_slice()
287 } else {
288 path.as_slice()
289 };
290
291 let (body, body_len) = match decode_body(bytes, header_len, &headers)? {
292 Some(value) => value,
293 None => return Ok(None),
294 };
295
296 Ok(Some((
297 PackedRequest {
298 version: HttpVersion::Http11,
299 method: method.to_vec(),
300 scheme: None,
301 authority,
302 path: path.to_vec(),
303 headers,
304 body,
305 },
306 header_len + body_len,
307 )))
308}
309
310fn decode_response_from_prefix(
311 bytes: &[u8],
312) -> Result<Option<(PackedResponse, usize)>, H1DecodeError> {
313 let (status, header_len, headers) = match parse_response_headers(bytes)? {
314 Some(value) => value,
315 None => return Ok(None),
316 };
317
318 let (body, body_len) = match decode_body(bytes, header_len, &headers)? {
319 Some(value) => value,
320 None => return Ok(None),
321 };
322
323 Ok(Some((
324 PackedResponse {
325 version: HttpVersion::Http11,
326 status,
327 headers,
328 body,
329 },
330 header_len + body_len,
331 )))
332}
333
334fn parse_request_headers(
335 bytes: &[u8],
336) -> Result<Option<(Vec<u8>, Vec<u8>, usize, Vec<HeaderField>)>, H1DecodeError> {
337 let mut header_cap = 32usize;
338 loop {
339 let mut headers = vec![httparse::EMPTY_HEADER; header_cap];
340 let mut req = httparse::Request::new(&mut headers);
341 let status = match req.parse(bytes) {
342 Ok(status) => status,
343 Err(err) => {
344 if let httparse::Error::TooManyHeaders = err {
345 header_cap = grow_header_cap(header_cap)?;
346 continue;
347 }
348 return Err(map_parse_error(err));
349 }
350 };
351
352 let header_len = match status {
353 Status::Complete(len) => len,
354 Status::Partial => return Ok(None),
355 };
356
357 let method = req.method.ok_or(H1DecodeError::InvalidStartLine)?;
358 let path = req.path.ok_or(H1DecodeError::InvalidStartLine)?;
359 let version = req.version.ok_or(H1DecodeError::InvalidStartLine)?;
360 if version != 1 {
361 return Err(H1DecodeError::InvalidVersion(version));
362 }
363
364 Method::from_bytes(method.as_bytes()).map_err(|_| H1DecodeError::InvalidMethod)?;
365 if path.is_empty() || crate::has_crlf(path.as_bytes()) {
366 return Err(H1DecodeError::InvalidPath);
367 }
368
369 let header_fields = collect_headers(&req.headers)?;
370
371 return Ok(Some((
372 method.as_bytes().to_vec(),
373 path.as_bytes().to_vec(),
374 header_len,
375 header_fields,
376 )));
377 }
378}
379
380fn parse_response_headers(
381 bytes: &[u8],
382) -> Result<Option<(u16, usize, Vec<HeaderField>)>, H1DecodeError> {
383 let mut header_cap = 32usize;
384 loop {
385 let mut headers = vec![httparse::EMPTY_HEADER; header_cap];
386 let mut resp = httparse::Response::new(&mut headers);
387 let status = match resp.parse(bytes) {
388 Ok(status) => status,
389 Err(err) => {
390 if let httparse::Error::TooManyHeaders = err {
391 header_cap = grow_header_cap(header_cap)?;
392 continue;
393 }
394 return Err(map_parse_error(err));
395 }
396 };
397
398 let header_len = match status {
399 Status::Complete(len) => len,
400 Status::Partial => return Ok(None),
401 };
402
403 let version = resp.version.ok_or(H1DecodeError::InvalidStartLine)?;
404 if version != 1 {
405 return Err(H1DecodeError::InvalidVersion(version));
406 }
407
408 let status_code = resp.code.ok_or(H1DecodeError::InvalidStatus)?;
409 if StatusCode::from_u16(status_code).is_err() {
410 return Err(H1DecodeError::InvalidStatus);
411 }
412
413 let header_fields = collect_headers(&resp.headers)?;
414
415 return Ok(Some((status_code, header_len, header_fields)));
416 }
417}
418
419fn collect_headers(headers: &[httparse::Header<'_>]) -> Result<Vec<HeaderField>, H1DecodeError> {
420 if headers.len() > crate::MAX_HEADERS as usize {
421 return Err(H1DecodeError::TooManyHeaders(headers.len()));
422 }
423
424 let mut out = Vec::with_capacity(headers.len());
425 for header in headers {
426 let name = header.name.as_bytes().to_vec();
427 let value = header.value.to_vec();
428 HeaderName::from_bytes(&name).map_err(|_| H1DecodeError::InvalidHeaderName)?;
429 HeaderValue::from_bytes(&value).map_err(|_| H1DecodeError::InvalidHeaderValue)?;
430 out.push(HeaderField { name, value });
431 }
432
433 Ok(out)
434}
435
436fn grow_header_cap(current: usize) -> Result<usize, H1DecodeError> {
437 let next = current.saturating_mul(2);
438 if next == current || next > crate::MAX_HEADERS as usize {
439 return Err(H1DecodeError::TooManyHeaders(current));
440 }
441 Ok(next)
442}
443
444fn map_parse_error(err: httparse::Error) -> H1DecodeError {
445 match err {
446 httparse::Error::Version => H1DecodeError::InvalidVersion(0),
447 httparse::Error::Status => H1DecodeError::InvalidStatus,
448 httparse::Error::Token => H1DecodeError::InvalidMethod,
449 httparse::Error::HeaderName => H1DecodeError::InvalidHeaderName,
450 httparse::Error::HeaderValue => H1DecodeError::InvalidHeaderValue,
451 _ => H1DecodeError::InvalidHeader,
452 }
453}
454
455fn decode_body(
456 bytes: &[u8],
457 header_len: usize,
458 headers: &[HeaderField],
459) -> Result<Option<(Vec<u8>, usize)>, H1DecodeError> {
460 let body_bytes = &bytes[header_len..];
461 if has_chunked_encoding(headers) {
462 return decode_chunked_body(body_bytes);
463 }
464
465 if let Some(len) = content_length(headers)? {
466 if body_bytes.len() < len {
467 return Ok(None);
468 }
469 return Ok(Some((body_bytes[..len].to_vec(), len)));
470 }
471
472 Ok(Some((Vec::new(), 0)))
473}
474
475fn body_kind_from_headers(headers: &[HeaderField]) -> Result<BodyKind, H1DecodeError> {
476 if has_chunked_encoding(headers) {
477 return Ok(BodyKind::Chunked {
478 phase: ChunkPhase::SizeLine,
479 });
480 }
481
482 if let Some(len) = content_length(headers)? {
483 return Ok(BodyKind::Length { remaining: len });
484 }
485
486 Ok(BodyKind::None)
487}
488
489fn read_body_frame(
490 buf: &mut BytesMut,
491 reader: &mut BodyReader,
492 stream_id: u64,
493) -> Result<Option<StreamFrame>, H1DecodeError> {
494 match &mut reader.kind {
495 BodyKind::None => Ok(None),
496 BodyKind::Length { remaining } => {
497 if *remaining == 0 {
498 reader.kind = BodyKind::None;
499 return Ok(Some(StreamFrame::End(StreamEnd { stream_id })));
500 }
501 if buf.is_empty() {
502 return Ok(None);
503 }
504 let take = (*remaining).min(buf.len());
505 let chunk = buf.split_to(take).to_vec();
506 *remaining -= take;
507 Ok(Some(StreamFrame::Body(StreamBody {
508 stream_id,
509 data: chunk.into(),
510 })))
511 }
512 BodyKind::Chunked { phase } => {
513 let frame = read_chunked_frame(buf, phase, stream_id)?;
514 if matches!(frame, Some(StreamFrame::End(_))) {
515 reader.kind = BodyKind::None;
516 }
517 Ok(frame)
518 }
519 }
520}
521
522fn read_chunked_frame(
523 buf: &mut BytesMut,
524 phase: &mut ChunkPhase,
525 stream_id: u64,
526) -> Result<Option<StreamFrame>, H1DecodeError> {
527 loop {
528 match phase {
529 ChunkPhase::SizeLine => {
530 let line_end = match find_crlf(buf, 0) {
531 Some(value) => value,
532 None => return Ok(None),
533 };
534 let line = &buf[..line_end];
535 let size = parse_chunk_size(line)?;
536 buf.advance(line_end + 2);
537 if size == 0 {
538 *phase = ChunkPhase::Trailers;
539 continue;
540 }
541 let size = usize::try_from(size)
542 .map_err(|_| H1DecodeError::InvalidChunkedEncoding)?;
543 *phase = ChunkPhase::Data { remaining: size };
544 }
545 ChunkPhase::Data { remaining } => {
546 if buf.is_empty() {
547 return Ok(None);
548 }
549 let take = (*remaining).min(buf.len());
550 let chunk = buf.split_to(take).to_vec();
551 *remaining -= take;
552 if *remaining == 0 {
553 *phase = ChunkPhase::DataCrlf;
554 }
555 if chunk.is_empty() {
556 return Ok(None);
557 }
558 return Ok(Some(StreamFrame::Body(StreamBody {
559 stream_id,
560 data: chunk.into(),
561 })));
562 }
563 ChunkPhase::DataCrlf => {
564 if buf.len() < 2 {
565 return Ok(None);
566 }
567 if buf[0] != b'\r' || buf[1] != b'\n' {
568 return Err(H1DecodeError::InvalidChunkedEncoding);
569 }
570 buf.advance(2);
571 *phase = ChunkPhase::SizeLine;
572 }
573 ChunkPhase::Trailers => {
574 let trailer_end = match find_double_crlf(buf, 0) {
575 Some(value) => value,
576 None => return Ok(None),
577 };
578 buf.advance(trailer_end + 4);
579 return Ok(Some(StreamFrame::End(StreamEnd { stream_id })));
580 }
581 }
582 }
583}
584
585fn content_length(headers: &[HeaderField]) -> Result<Option<usize>, H1DecodeError> {
586 let mut value = None;
587 for header in headers {
588 if !crate::eq_ignore_ascii_case(&header.name, b"content-length") {
589 continue;
590 }
591 let trimmed = trim_ascii(&header.value);
592 if trimmed.is_empty() {
593 return Err(H1DecodeError::InvalidContentLength);
594 }
595 let parsed = parse_usize_ascii(trimmed)?;
596 if let Some(existing) = value {
597 if existing != parsed {
598 return Err(H1DecodeError::InvalidContentLength);
599 }
600 } else {
601 value = Some(parsed);
602 }
603 }
604 Ok(value)
605}
606
607fn has_chunked_encoding(headers: &[HeaderField]) -> bool {
608 headers.iter().any(|header| {
609 crate::eq_ignore_ascii_case(&header.name, b"transfer-encoding")
610 && contains_token(&header.value, b"chunked")
611 })
612}
613
614fn contains_token(value: &[u8], token: &[u8]) -> bool {
615 let mut start = 0;
616 while start <= value.len() {
617 let mut end = start;
618 while end < value.len() && value[end] != b',' {
619 end += 1;
620 }
621 let part = trim_ascii(&value[start..end]);
622 if crate::eq_ignore_ascii_case(part, token) {
623 return true;
624 }
625 if end == value.len() {
626 break;
627 }
628 start = end + 1;
629 }
630 false
631}
632
633fn decode_chunked_body(bytes: &[u8]) -> Result<Option<(Vec<u8>, usize)>, H1DecodeError> {
634 let mut out = Vec::new();
635 let mut offset = 0usize;
636
637 loop {
638 let line_end = match find_crlf(bytes, offset) {
639 Some(value) => value,
640 None => return Ok(None),
641 };
642 let line = &bytes[offset..line_end];
643 let size = parse_chunk_size(line)?;
644 offset = line_end + 2;
645
646 if size == 0 {
647 if bytes.len() < offset + 2 {
648 return Ok(None);
649 }
650 if bytes.get(offset) == Some(&b'\r') && bytes.get(offset + 1) == Some(&b'\n') {
651 offset += 2;
652 break;
653 }
654 let trailer_end = match find_double_crlf(bytes, offset) {
655 Some(value) => value,
656 None => return Ok(None),
657 };
658 offset = trailer_end + 4;
659 break;
660 }
661
662 let size_usize = usize::try_from(size).map_err(|_| H1DecodeError::InvalidChunkedEncoding)?;
663 if bytes.len() < offset + size_usize + 2 {
664 return Ok(None);
665 }
666 out.extend_from_slice(&bytes[offset..offset + size_usize]);
667 offset += size_usize;
668 if bytes.get(offset) != Some(&b'\r') || bytes.get(offset + 1) != Some(&b'\n') {
669 return Err(H1DecodeError::InvalidChunkedEncoding);
670 }
671 offset += 2;
672 }
673
674 Ok(Some((out, offset)))
675}
676
677fn parse_chunk_size(line: &[u8]) -> Result<u64, H1DecodeError> {
678 let mut end = line.len();
679 for (idx, byte) in line.iter().enumerate() {
680 if *byte == b';' {
681 end = idx;
682 break;
683 }
684 }
685 let trimmed = trim_ascii(&line[..end]);
686 if trimmed.is_empty() {
687 return Err(H1DecodeError::InvalidChunkedEncoding);
688 }
689
690 let mut value: u64 = 0;
691 for &byte in trimmed {
692 let digit = match byte {
693 b'0'..=b'9' => (byte - b'0') as u64,
694 b'a'..=b'f' => (byte - b'a' + 10) as u64,
695 b'A'..=b'F' => (byte - b'A' + 10) as u64,
696 _ => return Err(H1DecodeError::InvalidChunkedEncoding),
697 };
698 value = value
699 .checked_mul(16)
700 .and_then(|v| v.checked_add(digit))
701 .ok_or(H1DecodeError::InvalidChunkedEncoding)?;
702 }
703
704 Ok(value)
705}
706
707fn find_crlf(bytes: &[u8], start: usize) -> Option<usize> {
708 let mut idx = start;
709 while idx + 1 < bytes.len() {
710 if bytes[idx] == b'\r' && bytes[idx + 1] == b'\n' {
711 return Some(idx);
712 }
713 idx += 1;
714 }
715 None
716}
717
718fn find_double_crlf(bytes: &[u8], start: usize) -> Option<usize> {
719 let mut idx = start;
720 while idx + 3 < bytes.len() {
721 if bytes[idx] == b'\r'
722 && bytes[idx + 1] == b'\n'
723 && bytes[idx + 2] == b'\r'
724 && bytes[idx + 3] == b'\n'
725 {
726 return Some(idx);
727 }
728 idx += 1;
729 }
730 None
731}
732
733fn trim_ascii(value: &[u8]) -> &[u8] {
734 let mut start = 0;
735 let mut end = value.len();
736 while start < end {
737 let byte = value[start];
738 if byte != b' ' && byte != b'\t' {
739 break;
740 }
741 start += 1;
742 }
743 while end > start {
744 let byte = value[end - 1];
745 if byte != b' ' && byte != b'\t' {
746 break;
747 }
748 end -= 1;
749 }
750 &value[start..end]
751}
752
753fn parse_usize_ascii(value: &[u8]) -> Result<usize, H1DecodeError> {
754 if value.is_empty() {
755 return Err(H1DecodeError::InvalidContentLength);
756 }
757 let mut out: usize = 0;
758 for &byte in value {
759 if !byte.is_ascii_digit() {
760 return Err(H1DecodeError::InvalidContentLength);
761 }
762 let digit = (byte - b'0') as usize;
763 out = out
764 .checked_mul(10)
765 .and_then(|v| v.checked_add(digit))
766 .ok_or(H1DecodeError::InvalidContentLength)?;
767 }
768 Ok(out)
769}
770
771fn find_header_value<'a>(headers: &'a [HeaderField], name: &[u8]) -> Option<&'a [u8]> {
772 headers
773 .iter()
774 .find(|header| crate::eq_ignore_ascii_case(&header.name, name))
775 .map(|header| header.value.as_slice())
776}
777
778#[cfg(test)]
779mod tests {
780 use super::*;
781
782 #[test]
783 fn decode_simple_request() {
784 let input = b"GET /hello HTTP/1.1\r\nHost: example.com\r\n\r\n";
785 let (req, consumed) = decode_request(input).unwrap().unwrap();
786
787 assert_eq!(consumed, input.len());
788 assert_eq!(req.method, b"GET".to_vec());
789 assert_eq!(req.path, b"/hello".to_vec());
790 assert_eq!(req.authority.unwrap(), b"example.com".to_vec());
791 assert!(req.body.is_empty());
792 }
793
794 #[test]
795 fn decode_request_with_body() {
796 let input = b"POST /submit HTTP/1.1\r\nHost: example.com\r\nContent-Length: 5\r\n\r\nhello";
797 let (req, consumed) = decode_request(input).unwrap().unwrap();
798
799 assert_eq!(consumed, input.len());
800 assert_eq!(req.method, b"POST".to_vec());
801 assert_eq!(req.body, b"hello".to_vec());
802 }
803
804 #[test]
805 fn decode_chunked_response() {
806 let input = b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nWiki\r\n5\r\npedia\r\n0\r\n\r\n";
807 let (resp, consumed) = decode_response(input).unwrap().unwrap();
808
809 assert_eq!(consumed, input.len());
810 assert_eq!(resp.status, 200);
811 assert_eq!(resp.body, b"Wikipedia".to_vec());
812 }
813
814 #[test]
815 fn decoder_streaming() {
816 let input = b"GET /a HTTP/1.1\r\nHost: example.com\r\n\r\n";
817 let mut decoder = H1Decoder::new(H1MessageKind::Request);
818 decoder.push(&input[..10]);
819 assert!(decoder.try_decode().unwrap().is_none());
820
821 decoder.push(&input[10..]);
822 let msg = decoder.try_decode().unwrap();
823 assert!(matches!(msg, Some(PackedMessage::Request(_))));
824 assert_eq!(decoder.buffer_len(), 0);
825 }
826
827 #[test]
828 fn stream_decoder_content_length() {
829 let input = b"POST /upload HTTP/1.1\r\nHost: example.com\r\nContent-Length: 5\r\n\r\nhello";
830 let mut decoder = H1StreamDecoder::new(H1MessageKind::Request, 42);
831 decoder.push(input);
832
833 let frame = decoder.try_decode().unwrap();
834 assert!(matches!(frame, Some(StreamFrame::Headers(_))));
835
836 let frame = decoder.try_decode().unwrap();
837 match frame {
838 Some(StreamFrame::Body(body)) => {
839 assert_eq!(body.stream_id, 42);
840 assert_eq!(body.data, b"hello".to_vec());
841 }
842 _ => panic!("expected body frame"),
843 }
844
845 let frame = decoder.try_decode().unwrap();
846 assert!(matches!(frame, Some(StreamFrame::End(_))));
847 }
848}