Skip to main content

hyper/proto/h1/
role.rs

1use std::mem::MaybeUninit;
2
3#[cfg(feature = "client")]
4use std::fmt::{self, Write as _};
5
6use bytes::Bytes;
7use bytes::BytesMut;
8#[cfg(feature = "client")]
9use http::header::Entry;
10#[cfg(feature = "server")]
11use http::header::ValueIter;
12use http::header::{self, HeaderMap, HeaderName, HeaderValue};
13use http::{Method, StatusCode, Version};
14use smallvec::{smallvec, smallvec_inline, SmallVec};
15
16use crate::body::DecodedLength;
17#[cfg(feature = "server")]
18use crate::common::date;
19use crate::error::Parse;
20use crate::ext::HeaderCaseMap;
21#[cfg(feature = "ffi")]
22use crate::ext::OriginalHeaderOrder;
23use crate::headers;
24use crate::proto::h1::{
25    Encode, Encoder, Http1Transaction, ParseContext, ParseResult, ParsedMessage,
26};
27#[cfg(feature = "client")]
28use crate::proto::RequestHead;
29use crate::proto::{BodyLength, MessageHead, RequestLine};
30
31pub(crate) const DEFAULT_MAX_HEADERS: usize = 100;
32const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
33#[cfg(feature = "server")]
34const MAX_URI_LEN: usize = (u16::MAX - 1) as usize;
35
36macro_rules! header_name {
37    ($bytes:expr) => {{
38        {
39            match HeaderName::from_bytes($bytes) {
40                Ok(name) => name,
41                Err(e) => maybe_panic!(e),
42            }
43        }
44    }};
45}
46
47macro_rules! header_value {
48    ($bytes:expr) => {{
49        {
50            unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) }
51        }
52    }};
53}
54
55macro_rules! maybe_panic {
56    ($($arg:tt)*) => ({
57        let _err = ($($arg)*);
58        if cfg!(debug_assertions) {
59            panic!("{:?}", _err);
60        } else {
61            error!("Internal Hyper error, please report {:?}", _err);
62            return Err(Parse::Internal)
63        }
64    })
65}
66
67pub(super) fn parse_headers<T>(
68    bytes: &mut BytesMut,
69    prev_len: Option<usize>,
70    ctx: ParseContext<'_>,
71) -> ParseResult<T::Incoming>
72where
73    T: Http1Transaction,
74{
75    // If the buffer is empty, don't bother entering the span, it's just noise.
76    if bytes.is_empty() {
77        return Ok(None);
78    }
79
80    let _entered = trace_span!("parse_headers");
81
82    if let Some(prev_len) = prev_len {
83        if !is_complete_fast(bytes, prev_len) {
84            return Ok(None);
85        }
86    }
87
88    T::parse(bytes, ctx)
89}
90
91/// A fast scan for the end of a message.
92/// Used when there was a partial read, to skip full parsing on a
93/// a slow connection.
94fn is_complete_fast(bytes: &[u8], prev_len: usize) -> bool {
95    let start = prev_len.saturating_sub(3);
96    let bytes = &bytes[start..];
97
98    for (i, b) in bytes.iter().copied().enumerate() {
99        if b == b'\r' {
100            if bytes[i + 1..].chunks(3).next() == Some(&b"\n\r\n"[..]) {
101                return true;
102            }
103        } else if b == b'\n' && bytes.get(i + 1) == Some(&b'\n') {
104            return true;
105        }
106    }
107
108    false
109}
110
111pub(super) fn encode_headers<T>(
112    enc: Encode<'_, T::Outgoing>,
113    dst: &mut Vec<u8>,
114) -> crate::Result<Encoder>
115where
116    T: Http1Transaction,
117{
118    let _entered = trace_span!("encode_headers");
119    T::encode(enc, dst)
120}
121
122// There are 2 main roles, Client and Server.
123
124#[cfg(feature = "client")]
125pub(crate) enum Client {}
126
127#[cfg(feature = "server")]
128pub(crate) enum Server {}
129
130#[cfg(feature = "server")]
131impl Http1Transaction for Server {
132    type Incoming = RequestLine;
133    type Outgoing = StatusCode;
134    #[cfg(feature = "tracing")]
135    const LOG: &'static str = "{role=server}";
136
137    fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<RequestLine> {
138        debug_assert!(!buf.is_empty(), "parse called with empty buf");
139
140        let mut keep_alive;
141        let is_http_11;
142        let subject;
143        let version;
144        let len;
145        let headers_len;
146        let method;
147        let path_range;
148
149        // Both headers_indices and headers are using uninitialized memory,
150        // but we *never* read any of it until after httparse has assigned
151        // values into it. By not zeroing out the stack memory, this saves
152        // a good ~5% on pipeline benchmarks.
153        let mut headers_indices: SmallVec<[MaybeUninit<HeaderIndices>; DEFAULT_MAX_HEADERS]> =
154            match ctx.h1_max_headers {
155                Some(cap) => smallvec![MaybeUninit::uninit(); cap],
156                None => smallvec_inline![MaybeUninit::uninit(); DEFAULT_MAX_HEADERS],
157            };
158        {
159            let mut headers: SmallVec<[MaybeUninit<httparse::Header<'_>>; DEFAULT_MAX_HEADERS]> =
160                match ctx.h1_max_headers {
161                    Some(cap) => smallvec![MaybeUninit::uninit(); cap],
162                    None => smallvec_inline![MaybeUninit::uninit(); DEFAULT_MAX_HEADERS],
163                };
164            trace!(bytes = buf.len(), "Request.parse");
165            let mut req = httparse::Request::new(&mut []);
166            let bytes = buf.as_ref();
167            match ctx.h1_parser_config.parse_request_with_uninit_headers(
168                &mut req,
169                bytes,
170                &mut headers,
171            ) {
172                Ok(httparse::Status::Complete(parsed_len)) => {
173                    trace!("Request.parse Complete({})", parsed_len);
174                    len = parsed_len;
175                    let uri = req.path.expect("httparse completed");
176                    if uri.len() > MAX_URI_LEN {
177                        return Err(Parse::UriTooLong);
178                    }
179                    method =
180                        Method::from_bytes(req.method.expect("httparse completed").as_bytes())?;
181                    path_range = Server::record_path_range(bytes, uri);
182                    version = if req.version.expect("httparse completed") == 1 {
183                        keep_alive = true;
184                        is_http_11 = true;
185                        Version::HTTP_11
186                    } else {
187                        keep_alive = false;
188                        is_http_11 = false;
189                        Version::HTTP_10
190                    };
191
192                    record_header_indices(bytes, req.headers, &mut headers_indices)?;
193                    headers_len = req.headers.len();
194                }
195                Ok(httparse::Status::Partial) => return Ok(None),
196                // if invalid Token, try to determine if for method or path
197                Err(httparse::Error::Token) => {
198                    return Err({
199                        if req.method.is_none() {
200                            Parse::Method
201                        } else {
202                            debug_assert!(req.path.is_none());
203                            Parse::Uri
204                        }
205                    })
206                }
207                Err(err) => return Err(err.into()),
208            }
209        };
210
211        let slice = buf.split_to(len).freeze();
212        let uri = {
213            let uri_bytes = slice.slice_ref(&slice[path_range]);
214            // TODO(lucab): switch to `Uri::from_shared()` once public.
215            http::Uri::from_maybe_shared(uri_bytes)?
216        };
217        subject = RequestLine(method, uri);
218
219        // According to https://tools.ietf.org/html/rfc7230#section-3.3.3
220        // 1. (irrelevant to Request)
221        // 2. (irrelevant to Request)
222        // 3. Transfer-Encoding: chunked has a chunked body.
223        // 4. If multiple differing Content-Length headers or invalid, close connection.
224        // 5. Content-Length header has a sized body.
225        // 6. Length 0.
226        // 7. (irrelevant to Request)
227
228        let mut decoder = DecodedLength::ZERO;
229        let mut expect_continue = false;
230        let mut con_len = None;
231        let mut is_te = false;
232        let mut is_te_chunked = false;
233        let mut wants_upgrade = subject.0 == Method::CONNECT;
234
235        let mut header_case_map = if ctx.preserve_header_case {
236            Some(HeaderCaseMap::default())
237        } else {
238            None
239        };
240
241        #[cfg(feature = "ffi")]
242        let mut header_order = if ctx.preserve_header_order {
243            Some(OriginalHeaderOrder::default())
244        } else {
245            None
246        };
247
248        let mut headers = ctx.cached_headers.take().unwrap_or_default();
249
250        headers.reserve(headers_len);
251
252        for header in &headers_indices[..headers_len] {
253            // SAFETY: array is valid up to `headers_len`
254            let header = unsafe { header.assume_init_ref() };
255            let name = header_name!(&slice[header.name.0..header.name.1]);
256            let value = header_value!(slice.slice(header.value.0..header.value.1));
257
258            match name {
259                header::TRANSFER_ENCODING => {
260                    // https://tools.ietf.org/html/rfc7230#section-3.3.3
261                    // If Transfer-Encoding header is present, and 'chunked' is
262                    // not the final encoding, and this is a Request, then it is
263                    // malformed. A server should respond with 400 Bad Request.
264                    if !is_http_11 {
265                        debug!("HTTP/1.0 cannot have Transfer-Encoding header");
266                        return Err(Parse::transfer_encoding_unexpected());
267                    }
268                    is_te = true;
269                    if headers::is_chunked_(&value) {
270                        is_te_chunked = true;
271                        decoder = DecodedLength::CHUNKED;
272                    } else {
273                        is_te_chunked = false;
274                    }
275                }
276                header::CONTENT_LENGTH => {
277                    if is_te {
278                        continue;
279                    }
280                    let len = headers::content_length_parse(&value)
281                        .ok_or_else(Parse::content_length_invalid)?;
282                    if let Some(prev) = con_len {
283                        if prev != len {
284                            debug!(
285                                "multiple Content-Length headers with different values: [{}, {}]",
286                                prev, len,
287                            );
288                            return Err(Parse::content_length_invalid());
289                        }
290                        // we don't need to append this secondary length
291                        continue;
292                    }
293                    decoder = DecodedLength::checked_new(len)?;
294                    con_len = Some(len);
295                }
296                header::CONNECTION => {
297                    // keep_alive was previously set to default for Version
298                    if keep_alive {
299                        // HTTP/1.1
300                        keep_alive = !headers::connection_close(&value);
301                    } else {
302                        // HTTP/1.0
303                        keep_alive = headers::connection_keep_alive(&value);
304                    }
305                }
306                header::EXPECT => {
307                    // According to https://datatracker.ietf.org/doc/html/rfc2616#section-14.20
308                    // Comparison of expectation values is case-insensitive for unquoted tokens
309                    // (including the 100-continue token)
310                    expect_continue = value.as_bytes().eq_ignore_ascii_case(b"100-continue");
311                }
312                header::UPGRADE => {
313                    // Upgrades are only allowed with HTTP/1.1
314                    wants_upgrade = is_http_11;
315                }
316
317                _ => (),
318            }
319
320            if let Some(ref mut header_case_map) = header_case_map {
321                header_case_map.append(&name, slice.slice(header.name.0..header.name.1));
322            }
323
324            #[cfg(feature = "ffi")]
325            if let Some(ref mut header_order) = header_order {
326                header_order.append(&name);
327            }
328
329            headers.append(name, value);
330        }
331
332        if is_te && !is_te_chunked {
333            debug!("request with transfer-encoding header, but not chunked, bad request");
334            return Err(Parse::transfer_encoding_invalid());
335        }
336
337        let mut extensions = http::Extensions::default();
338
339        if let Some(header_case_map) = header_case_map {
340            extensions.insert(header_case_map);
341        }
342
343        #[cfg(feature = "ffi")]
344        if let Some(header_order) = header_order {
345            extensions.insert(header_order);
346        }
347
348        *ctx.req_method = Some(subject.0.clone());
349
350        Ok(Some(ParsedMessage {
351            head: MessageHead {
352                version,
353                subject,
354                headers,
355                extensions,
356            },
357            decode: decoder,
358            expect_continue,
359            keep_alive,
360            wants_upgrade,
361        }))
362    }
363
364    fn encode(mut msg: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder> {
365        trace!(
366            "Server::encode status={:?}, body={:?}, req_method={:?}",
367            msg.head.subject,
368            msg.body,
369            msg.req_method
370        );
371
372        let mut wrote_len = false;
373
374        // hyper currently doesn't support returning 1xx status codes as a Response
375        // This is because Service only allows returning a single Response, and
376        // so if you try to reply with a e.g. 100 Continue, you have no way of
377        // replying with the latter status code response.
378        let (ret, is_last) = if msg.head.subject == StatusCode::SWITCHING_PROTOCOLS {
379            (Ok(()), true)
380        } else if msg.req_method == &Some(Method::CONNECT) && msg.head.subject.is_success() {
381            // Sending content-length or transfer-encoding header on 2xx response
382            // to CONNECT is forbidden in RFC 7231.
383            wrote_len = true;
384            (Ok(()), true)
385        } else if msg.head.subject.is_informational() {
386            warn!("response with 1xx status code not supported");
387            *msg.head = MessageHead::default();
388            msg.head.subject = StatusCode::INTERNAL_SERVER_ERROR;
389            msg.body = None;
390            (Err(crate::Error::new_user_unsupported_status_code()), true)
391        } else {
392            (Ok(()), !msg.keep_alive)
393        };
394
395        // In some error cases, we don't know about the invalid message until already
396        // pushing some bytes onto the `dst`. In those cases, we don't want to send
397        // the half-pushed message, so rewind to before.
398        let orig_len = dst.len();
399
400        let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE;
401        dst.reserve(init_cap);
402
403        let custom_reason_phrase = msg.head.extensions.get::<crate::ext::ReasonPhrase>();
404
405        if msg.head.version == Version::HTTP_11
406            && msg.head.subject == StatusCode::OK
407            && custom_reason_phrase.is_none()
408        {
409            extend(dst, b"HTTP/1.1 200 OK\r\n");
410        } else {
411            match msg.head.version {
412                Version::HTTP_10 => extend(dst, b"HTTP/1.0 "),
413                Version::HTTP_11 => extend(dst, b"HTTP/1.1 "),
414                Version::HTTP_2 => {
415                    debug!("response with HTTP2 version coerced to HTTP/1.1");
416                    extend(dst, b"HTTP/1.1 ");
417                }
418                other => panic!("unexpected response version: {:?}", other),
419            }
420
421            extend(dst, msg.head.subject.as_str().as_bytes());
422            extend(dst, b" ");
423
424            if let Some(reason) = custom_reason_phrase {
425                extend(dst, reason.as_bytes());
426            } else {
427                // a reason MUST be written, as many parsers will expect it.
428                extend(
429                    dst,
430                    msg.head
431                        .subject
432                        .canonical_reason()
433                        .unwrap_or("<none>")
434                        .as_bytes(),
435                );
436            }
437
438            extend(dst, b"\r\n");
439        }
440
441        let orig_headers;
442        let extensions = std::mem::take(&mut msg.head.extensions);
443        let orig_headers = match extensions.get::<HeaderCaseMap>() {
444            None if msg.title_case_headers => {
445                orig_headers = HeaderCaseMap::default();
446                Some(&orig_headers)
447            }
448            orig_headers => orig_headers,
449        };
450        let encoder = if let Some(orig_headers) = orig_headers {
451            Self::encode_headers_with_original_case(
452                msg,
453                dst,
454                is_last,
455                orig_len,
456                wrote_len,
457                orig_headers,
458            )?
459        } else {
460            Self::encode_headers_with_lower_case(msg, dst, is_last, orig_len, wrote_len)?
461        };
462
463        ret.map(|()| encoder)
464    }
465
466    fn on_error(err: &crate::Error) -> Option<MessageHead<Self::Outgoing>> {
467        use crate::error::Kind;
468        let status = match *err.kind() {
469            Kind::Parse(Parse::Method)
470            | Kind::Parse(Parse::Header(_))
471            | Kind::Parse(Parse::Uri)
472            | Kind::Parse(Parse::Version) => StatusCode::BAD_REQUEST,
473            Kind::Parse(Parse::TooLarge) => StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
474            Kind::Parse(Parse::UriTooLong) => StatusCode::URI_TOO_LONG,
475            _ => return None,
476        };
477
478        debug!("sending automatic response ({}) for parse error", status);
479        let msg = MessageHead {
480            subject: status,
481            ..Default::default()
482        };
483        Some(msg)
484    }
485
486    fn is_server() -> bool {
487        true
488    }
489
490    fn update_date() {
491        date::update();
492    }
493}
494
495#[cfg(feature = "server")]
496impl Server {
497    fn can_have_body(method: &Option<Method>, status: StatusCode) -> bool {
498        Server::can_chunked(method, status)
499    }
500
501    fn can_chunked(method: &Option<Method>, status: StatusCode) -> bool {
502        if method == &Some(Method::HEAD)
503            || method == &Some(Method::CONNECT) && status.is_success()
504            || status.is_informational()
505        {
506            false
507        } else {
508            !matches!(status, StatusCode::NO_CONTENT | StatusCode::NOT_MODIFIED)
509        }
510    }
511
512    fn can_have_content_length(method: &Option<Method>, status: StatusCode) -> bool {
513        if status.is_informational() || method == &Some(Method::CONNECT) && status.is_success() {
514            false
515        } else {
516            !matches!(status, StatusCode::NO_CONTENT | StatusCode::NOT_MODIFIED)
517        }
518    }
519
520    fn can_have_implicit_zero_content_length(method: &Option<Method>, status: StatusCode) -> bool {
521        Server::can_have_content_length(method, status) && method != &Some(Method::HEAD)
522    }
523
524    fn encode_headers_with_lower_case(
525        msg: Encode<'_, StatusCode>,
526        dst: &mut Vec<u8>,
527        is_last: bool,
528        orig_len: usize,
529        wrote_len: bool,
530    ) -> crate::Result<Encoder> {
531        struct LowercaseWriter;
532
533        impl HeaderNameWriter for LowercaseWriter {
534            #[inline]
535            fn write_full_header_line(
536                &mut self,
537                dst: &mut Vec<u8>,
538                line: &str,
539                _: (HeaderName, &str),
540            ) {
541                extend(dst, line.as_bytes())
542            }
543
544            #[inline]
545            fn write_header_name_with_colon(
546                &mut self,
547                dst: &mut Vec<u8>,
548                name_with_colon: &str,
549                _: HeaderName,
550            ) {
551                extend(dst, name_with_colon.as_bytes())
552            }
553
554            #[inline]
555            fn write_header_name(&mut self, dst: &mut Vec<u8>, name: &HeaderName) {
556                extend(dst, name.as_str().as_bytes())
557            }
558        }
559
560        Self::encode_headers(msg, dst, is_last, orig_len, wrote_len, LowercaseWriter)
561    }
562
563    #[cold]
564    #[inline(never)]
565    fn encode_headers_with_original_case(
566        msg: Encode<'_, StatusCode>,
567        dst: &mut Vec<u8>,
568        is_last: bool,
569        orig_len: usize,
570        wrote_len: bool,
571        orig_headers: &HeaderCaseMap,
572    ) -> crate::Result<Encoder> {
573        struct OrigCaseWriter<'map> {
574            map: &'map HeaderCaseMap,
575            current: Option<(HeaderName, ValueIter<'map, Bytes>)>,
576            title_case_headers: bool,
577        }
578
579        impl HeaderNameWriter for OrigCaseWriter<'_> {
580            #[inline]
581            fn write_full_header_line(
582                &mut self,
583                dst: &mut Vec<u8>,
584                _: &str,
585                (name, rest): (HeaderName, &str),
586            ) {
587                self.write_header_name(dst, &name);
588                extend(dst, rest.as_bytes());
589            }
590
591            #[inline]
592            fn write_header_name_with_colon(
593                &mut self,
594                dst: &mut Vec<u8>,
595                _: &str,
596                name: HeaderName,
597            ) {
598                self.write_header_name(dst, &name);
599                extend(dst, b": ");
600            }
601
602            #[inline]
603            fn write_header_name(&mut self, dst: &mut Vec<u8>, name: &HeaderName) {
604                let Self {
605                    map,
606                    ref mut current,
607                    title_case_headers,
608                } = *self;
609                if current.as_ref().map_or(true, |(last, _)| last != name) {
610                    *current = None;
611                }
612                let (_, values) =
613                    current.get_or_insert_with(|| (name.clone(), map.get_all_internal(name)));
614
615                if let Some(orig_name) = values.next() {
616                    extend(dst, orig_name);
617                } else if title_case_headers {
618                    title_case(dst, name.as_str().as_bytes());
619                } else {
620                    extend(dst, name.as_str().as_bytes());
621                }
622            }
623        }
624
625        let header_name_writer = OrigCaseWriter {
626            map: orig_headers,
627            current: None,
628            title_case_headers: msg.title_case_headers,
629        };
630
631        Self::encode_headers(msg, dst, is_last, orig_len, wrote_len, header_name_writer)
632    }
633
634    #[inline]
635    fn encode_headers<W>(
636        msg: Encode<'_, StatusCode>,
637        dst: &mut Vec<u8>,
638        mut is_last: bool,
639        orig_len: usize,
640        mut wrote_len: bool,
641        mut header_name_writer: W,
642    ) -> crate::Result<Encoder>
643    where
644        W: HeaderNameWriter,
645    {
646        // In some error cases, we don't know about the invalid message until already
647        // pushing some bytes onto the `dst`. In those cases, we don't want to send
648        // the half-pushed message, so rewind to before.
649        let rewind = |dst: &mut Vec<u8>| {
650            dst.truncate(orig_len);
651        };
652
653        let mut encoder = Encoder::length(0);
654        let mut allowed_trailer_fields: Option<Vec<HeaderName>> = None;
655        let mut wrote_date = false;
656        let mut cur_name = None;
657        let mut is_name_written = false;
658        let mut must_write_chunked = false;
659        let mut prev_con_len = None;
660
661        macro_rules! handle_is_name_written {
662            () => {{
663                if is_name_written {
664                    // we need to clean up and write the newline
665                    debug_assert_ne!(
666                        &dst[dst.len() - 2..],
667                        b"\r\n",
668                        "previous header wrote newline but set is_name_written"
669                    );
670
671                    if must_write_chunked {
672                        extend(dst, b", chunked\r\n");
673                    } else {
674                        extend(dst, b"\r\n");
675                    }
676                }
677            }};
678        }
679
680        'headers: for (opt_name, value) in msg.head.headers.drain() {
681            if let Some(n) = opt_name {
682                cur_name = Some(n);
683                handle_is_name_written!();
684                is_name_written = false;
685            }
686            let name = cur_name.as_ref().expect("current header name");
687            match *name {
688                header::CONTENT_LENGTH => {
689                    if wrote_len && !is_name_written {
690                        warn!("unexpected content-length found, canceling");
691                        rewind(dst);
692                        return Err(crate::Error::new_user_header());
693                    }
694                    match msg.body {
695                        Some(BodyLength::Known(known_len)) => {
696                            // The Body claims to know a length, and
697                            // the headers are already set. For performance
698                            // reasons, we are just going to trust that
699                            // the values match.
700                            //
701                            // In debug builds, we'll assert they are the
702                            // same to help developers find bugs.
703                            #[cfg(debug_assertions)]
704                            {
705                                if let Some(len) = headers::content_length_parse(&value) {
706                                    if msg.req_method != &Some(Method::HEAD) || known_len != 0 {
707                                        assert!(
708                                        len == known_len,
709                                        "payload claims content-length of {}, custom content-length header claims {}",
710                                        known_len,
711                                        len,
712                                    );
713                                    }
714                                }
715                            }
716
717                            if !is_name_written {
718                                encoder = Encoder::length(known_len);
719                                header_name_writer.write_header_name_with_colon(
720                                    dst,
721                                    "content-length: ",
722                                    header::CONTENT_LENGTH,
723                                );
724                                extend(dst, value.as_bytes());
725                                wrote_len = true;
726                                is_name_written = true;
727                            }
728                            continue 'headers;
729                        }
730                        Some(BodyLength::Unknown) => {
731                            // The Body impl didn't know how long the
732                            // body is, but a length header was included.
733                            // We have to parse the value to return our
734                            // Encoder...
735
736                            if let Some(len) = headers::content_length_parse(&value) {
737                                if let Some(prev) = prev_con_len {
738                                    if prev != len {
739                                        warn!(
740                                            "multiple Content-Length values found: [{}, {}]",
741                                            prev, len
742                                        );
743                                        rewind(dst);
744                                        return Err(crate::Error::new_user_header());
745                                    }
746                                    debug_assert!(is_name_written);
747                                    continue 'headers;
748                                } else {
749                                    // we haven't written content-length yet!
750                                    encoder = Encoder::length(len);
751                                    header_name_writer.write_header_name_with_colon(
752                                        dst,
753                                        "content-length: ",
754                                        header::CONTENT_LENGTH,
755                                    );
756                                    extend(dst, value.as_bytes());
757                                    wrote_len = true;
758                                    is_name_written = true;
759                                    prev_con_len = Some(len);
760                                    continue 'headers;
761                                }
762                            } else {
763                                warn!("illegal Content-Length value: {:?}", value);
764                                rewind(dst);
765                                return Err(crate::Error::new_user_header());
766                            }
767                        }
768                        None => {
769                            // We have no body to actually send,
770                            // but the headers claim a content-length.
771                            // There's only 2 ways this makes sense:
772                            //
773                            // - The header says the length is `0`.
774                            // - This is a response to a `HEAD` request.
775                            if msg.req_method == &Some(Method::HEAD) {
776                                debug_assert_eq!(encoder, Encoder::length(0));
777                            } else {
778                                if value.as_bytes() != b"0" {
779                                    warn!(
780                                        "content-length value found, but empty body provided: {:?}",
781                                        value
782                                    );
783                                }
784                                continue 'headers;
785                            }
786                        }
787                    }
788                    wrote_len = true;
789                }
790                header::TRANSFER_ENCODING => {
791                    if wrote_len && !is_name_written {
792                        warn!("unexpected transfer-encoding found, canceling");
793                        rewind(dst);
794                        return Err(crate::Error::new_user_header());
795                    }
796                    // check that we actually can send a chunked body...
797                    if msg.head.version == Version::HTTP_10
798                        || !Server::can_chunked(msg.req_method, msg.head.subject)
799                    {
800                        continue;
801                    }
802                    wrote_len = true;
803                    // Must check each value, because `chunked` needs to be the
804                    // last encoding, or else we add it.
805                    must_write_chunked = !headers::is_chunked_(&value);
806
807                    if !is_name_written {
808                        encoder = Encoder::chunked();
809                        is_name_written = true;
810                        header_name_writer.write_header_name_with_colon(
811                            dst,
812                            "transfer-encoding: ",
813                            header::TRANSFER_ENCODING,
814                        );
815                        extend(dst, value.as_bytes());
816                    } else {
817                        extend(dst, b", ");
818                        extend(dst, value.as_bytes());
819                    }
820                    continue 'headers;
821                }
822                header::CONNECTION => {
823                    if !is_last && headers::connection_close(&value) {
824                        is_last = true;
825                    }
826                    if !is_name_written {
827                        is_name_written = true;
828                        header_name_writer.write_header_name_with_colon(
829                            dst,
830                            "connection: ",
831                            header::CONNECTION,
832                        );
833                        extend(dst, value.as_bytes());
834                    } else {
835                        extend(dst, b", ");
836                        extend(dst, value.as_bytes());
837                    }
838                    continue 'headers;
839                }
840                header::DATE => {
841                    wrote_date = true;
842                }
843                header::TRAILER => {
844                    // check that we actually can send a chunked body...
845                    if msg.head.version == Version::HTTP_10
846                        || !Server::can_chunked(msg.req_method, msg.head.subject)
847                    {
848                        continue;
849                    }
850
851                    if !is_name_written {
852                        is_name_written = true;
853                        header_name_writer.write_header_name_with_colon(
854                            dst,
855                            "trailer: ",
856                            header::TRAILER,
857                        );
858                        extend(dst, value.as_bytes());
859                    } else {
860                        extend(dst, b", ");
861                        extend(dst, value.as_bytes());
862                    }
863
864                    // Parse the Trailer header value into HeaderNames.
865                    // The value may contain comma-separated names.
866                    // HeaderName normalizes to lowercase for case-insensitive matching.
867                    if let Ok(value_str) = value.to_str() {
868                        let names: Vec<HeaderName> = value_str
869                            .split(',')
870                            .filter_map(|s| HeaderName::from_bytes(s.trim().as_bytes()).ok())
871                            .collect();
872
873                        match allowed_trailer_fields {
874                            Some(ref mut fields) => {
875                                fields.extend(names);
876                            }
877                            None => {
878                                allowed_trailer_fields = Some(names);
879                            }
880                        }
881                    }
882
883                    continue 'headers;
884                }
885                _ => (),
886            }
887            //TODO: this should perhaps instead combine them into
888            //single lines, as RFC7230 suggests is preferable.
889
890            // non-special write Name and Value
891            debug_assert!(
892                !is_name_written,
893                "{:?} set is_name_written and didn't continue loop",
894                name,
895            );
896            header_name_writer.write_header_name(dst, name);
897            extend(dst, b": ");
898            extend(dst, value.as_bytes());
899            extend(dst, b"\r\n");
900        }
901
902        handle_is_name_written!();
903
904        if !wrote_len {
905            encoder = match msg.body {
906                Some(BodyLength::Unknown) => {
907                    if msg.head.version == Version::HTTP_10
908                        || !Server::can_chunked(msg.req_method, msg.head.subject)
909                    {
910                        Encoder::close_delimited()
911                    } else {
912                        header_name_writer.write_full_header_line(
913                            dst,
914                            "transfer-encoding: chunked\r\n",
915                            (header::TRANSFER_ENCODING, ": chunked\r\n"),
916                        );
917                        Encoder::chunked()
918                    }
919                }
920                None | Some(BodyLength::Known(0)) => {
921                    if Server::can_have_implicit_zero_content_length(
922                        msg.req_method,
923                        msg.head.subject,
924                    ) {
925                        header_name_writer.write_full_header_line(
926                            dst,
927                            "content-length: 0\r\n",
928                            (header::CONTENT_LENGTH, ": 0\r\n"),
929                        )
930                    }
931                    Encoder::length(0)
932                }
933                Some(BodyLength::Known(len)) => {
934                    if !Server::can_have_content_length(msg.req_method, msg.head.subject) {
935                        Encoder::length(0)
936                    } else {
937                        header_name_writer.write_header_name_with_colon(
938                            dst,
939                            "content-length: ",
940                            header::CONTENT_LENGTH,
941                        );
942                        extend(dst, ::itoa::Buffer::new().format(len).as_bytes());
943                        extend(dst, b"\r\n");
944                        Encoder::length(len)
945                    }
946                }
947            };
948        }
949
950        if !Server::can_have_body(msg.req_method, msg.head.subject) {
951            trace!(
952                "server body forced to 0; method={:?}, status={:?}",
953                msg.req_method,
954                msg.head.subject
955            );
956            encoder = Encoder::length(0);
957        }
958
959        // cached date is much faster than formatting every request
960        // don't force the write if disabled
961        if !wrote_date && msg.date_header {
962            dst.reserve(date::DATE_VALUE_LENGTH + 8);
963            header_name_writer.write_header_name_with_colon(dst, "date: ", header::DATE);
964            date::extend(dst);
965            extend(dst, b"\r\n\r\n");
966        } else {
967            extend(dst, b"\r\n");
968        }
969
970        if encoder.is_chunked() {
971            if let Some(allowed_trailer_fields) = allowed_trailer_fields {
972                encoder = encoder.into_chunked_with_trailing_fields(allowed_trailer_fields);
973            }
974        }
975
976        Ok(encoder.set_last(is_last))
977    }
978
979    /// Helper for zero-copy parsing of request path URI.
980    #[inline]
981    fn record_path_range(bytes: &[u8], req_path: &str) -> std::ops::Range<usize> {
982        let bytes_ptr = bytes.as_ptr() as usize;
983        let start = req_path.as_ptr() as usize - bytes_ptr;
984        let end = start + req_path.len();
985        std::ops::Range { start, end }
986    }
987}
988
989#[cfg(feature = "server")]
990trait HeaderNameWriter {
991    fn write_full_header_line(
992        &mut self,
993        dst: &mut Vec<u8>,
994        line: &str,
995        name_value_pair: (HeaderName, &str),
996    );
997    fn write_header_name_with_colon(
998        &mut self,
999        dst: &mut Vec<u8>,
1000        name_with_colon: &str,
1001        name: HeaderName,
1002    );
1003    fn write_header_name(&mut self, dst: &mut Vec<u8>, name: &HeaderName);
1004}
1005
1006#[cfg(feature = "client")]
1007impl Http1Transaction for Client {
1008    type Incoming = StatusCode;
1009    type Outgoing = RequestLine;
1010    #[cfg(feature = "tracing")]
1011    const LOG: &'static str = "{role=client}";
1012
1013    fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<StatusCode> {
1014        debug_assert!(!buf.is_empty(), "parse called with empty buf");
1015
1016        // Loop to skip information status code headers (100 Continue, etc).
1017        loop {
1018            let mut headers_indices: SmallVec<[MaybeUninit<HeaderIndices>; DEFAULT_MAX_HEADERS]> =
1019                match ctx.h1_max_headers {
1020                    Some(cap) => smallvec![MaybeUninit::uninit(); cap],
1021                    None => smallvec_inline![MaybeUninit::uninit(); DEFAULT_MAX_HEADERS],
1022                };
1023            let (len, status, reason, version, headers_len) = {
1024                let mut headers: SmallVec<
1025                    [MaybeUninit<httparse::Header<'_>>; DEFAULT_MAX_HEADERS],
1026                > = match ctx.h1_max_headers {
1027                    Some(cap) => smallvec![MaybeUninit::uninit(); cap],
1028                    None => smallvec_inline![MaybeUninit::uninit(); DEFAULT_MAX_HEADERS],
1029                };
1030                trace!(bytes = buf.len(), "Response.parse");
1031                let mut res = httparse::Response::new(&mut []);
1032                let bytes = buf.as_ref();
1033                match ctx.h1_parser_config.parse_response_with_uninit_headers(
1034                    &mut res,
1035                    bytes,
1036                    &mut headers,
1037                ) {
1038                    Ok(httparse::Status::Complete(len)) => {
1039                        trace!("Response.parse Complete({})", len);
1040                        let status = StatusCode::from_u16(res.code.expect("httparse completed"))?;
1041
1042                        let reason = {
1043                            let reason = res.reason.expect("httparse completed");
1044                            // Only save the reason phrase if it isn't the canonical reason
1045                            if Some(reason) != status.canonical_reason() {
1046                                Some(Bytes::copy_from_slice(reason.as_bytes()))
1047                            } else {
1048                                None
1049                            }
1050                        };
1051
1052                        let version = if res.version.expect("httparse completed") == 1 {
1053                            Version::HTTP_11
1054                        } else {
1055                            Version::HTTP_10
1056                        };
1057                        record_header_indices(bytes, res.headers, &mut headers_indices)?;
1058                        let headers_len = res.headers.len();
1059                        (len, status, reason, version, headers_len)
1060                    }
1061                    Ok(httparse::Status::Partial) => return Ok(None),
1062                    Err(httparse::Error::Version) if ctx.h09_responses => {
1063                        trace!("Response.parse accepted HTTP/0.9 response");
1064
1065                        (0, StatusCode::OK, None, Version::HTTP_09, 0)
1066                    }
1067                    Err(e) => return Err(e.into()),
1068                }
1069            };
1070
1071            let mut slice = buf.split_to(len);
1072
1073            if ctx
1074                .h1_parser_config
1075                .obsolete_multiline_headers_in_responses_are_allowed()
1076            {
1077                for header in &mut headers_indices[..headers_len] {
1078                    // SAFETY: array is valid up to `headers_len`
1079                    let header = unsafe { header.assume_init_mut() };
1080                    Client::obs_fold_line(&mut slice, header);
1081                }
1082            }
1083
1084            let slice = slice.freeze();
1085
1086            let mut headers = ctx.cached_headers.take().unwrap_or_default();
1087
1088            let mut keep_alive = version == Version::HTTP_11;
1089
1090            let mut header_case_map = if ctx.preserve_header_case {
1091                Some(HeaderCaseMap::default())
1092            } else {
1093                None
1094            };
1095
1096            #[cfg(feature = "ffi")]
1097            let mut header_order = if ctx.preserve_header_order {
1098                Some(OriginalHeaderOrder::default())
1099            } else {
1100                None
1101            };
1102
1103            headers.reserve(headers_len);
1104            for header in &headers_indices[..headers_len] {
1105                // SAFETY: array is valid up to `headers_len`
1106                let header = unsafe { header.assume_init_ref() };
1107                let name = header_name!(&slice[header.name.0..header.name.1]);
1108                let value = header_value!(slice.slice(header.value.0..header.value.1));
1109
1110                if let header::CONNECTION = name {
1111                    // keep_alive was previously set to default for Version
1112                    if keep_alive {
1113                        // HTTP/1.1
1114                        keep_alive = !headers::connection_close(&value);
1115                    } else {
1116                        // HTTP/1.0
1117                        keep_alive = headers::connection_keep_alive(&value);
1118                    }
1119                }
1120
1121                if let Some(ref mut header_case_map) = header_case_map {
1122                    header_case_map.append(&name, slice.slice(header.name.0..header.name.1));
1123                }
1124
1125                #[cfg(feature = "ffi")]
1126                if let Some(ref mut header_order) = header_order {
1127                    header_order.append(&name);
1128                }
1129
1130                headers.append(name, value);
1131            }
1132
1133            let mut extensions = http::Extensions::default();
1134
1135            if let Some(header_case_map) = header_case_map {
1136                extensions.insert(header_case_map);
1137            }
1138
1139            #[cfg(feature = "ffi")]
1140            if let Some(header_order) = header_order {
1141                extensions.insert(header_order);
1142            }
1143
1144            if let Some(reason) = reason {
1145                // Safety: httparse ensures that only valid reason phrase bytes are present in this
1146                // field.
1147                let reason = crate::ext::ReasonPhrase::from_bytes_unchecked(reason);
1148                extensions.insert(reason);
1149            }
1150
1151            let head = MessageHead {
1152                version,
1153                subject: status,
1154                headers,
1155                extensions,
1156            };
1157            if let Some((decode, is_upgrade)) = Client::decoder(&head, ctx.req_method)? {
1158                return Ok(Some(ParsedMessage {
1159                    head,
1160                    decode,
1161                    expect_continue: false,
1162                    // a client upgrade means the connection can't be used
1163                    // again, as it is definitely upgrading.
1164                    keep_alive: keep_alive && !is_upgrade,
1165                    wants_upgrade: is_upgrade,
1166                }));
1167            }
1168
1169            if head.subject.is_informational() {
1170                if let Some(callback) = ctx.on_informational {
1171                    callback.call(head.into_response(()));
1172                }
1173            }
1174
1175            // Parsing a 1xx response could have consumed the buffer, check if
1176            // it is empty now...
1177            if buf.is_empty() {
1178                return Ok(None);
1179            }
1180        }
1181    }
1182
1183    fn encode(msg: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder> {
1184        trace!(
1185            "Client::encode method={:?}, body={:?}",
1186            msg.head.subject.0,
1187            msg.body
1188        );
1189
1190        *msg.req_method = Some(msg.head.subject.0.clone());
1191
1192        let body = Client::set_length(msg.head, msg.body);
1193
1194        let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE;
1195        dst.reserve(init_cap);
1196
1197        extend(dst, msg.head.subject.0.as_str().as_bytes());
1198        extend(dst, b" ");
1199        //TODO: add API to http::Uri to encode without std::fmt
1200        let _ = write!(FastWrite(dst), "{} ", msg.head.subject.1);
1201
1202        match msg.head.version {
1203            Version::HTTP_10 => extend(dst, b"HTTP/1.0"),
1204            Version::HTTP_11 => extend(dst, b"HTTP/1.1"),
1205            Version::HTTP_2 => {
1206                debug!("request with HTTP2 version coerced to HTTP/1.1");
1207                extend(dst, b"HTTP/1.1");
1208            }
1209            other => panic!("unexpected request version: {:?}", other),
1210        }
1211        extend(dst, b"\r\n");
1212
1213        if let Some(orig_headers) = msg.head.extensions.get::<HeaderCaseMap>() {
1214            write_headers_original_case(
1215                &msg.head.headers,
1216                orig_headers,
1217                dst,
1218                msg.title_case_headers,
1219            );
1220        } else if msg.title_case_headers {
1221            write_headers_title_case(&msg.head.headers, dst);
1222        } else {
1223            write_headers(&msg.head.headers, dst);
1224        }
1225
1226        extend(dst, b"\r\n");
1227        msg.head.headers.clear(); //TODO: remove when switching to drain()
1228
1229        Ok(body)
1230    }
1231
1232    fn on_error(_err: &crate::Error) -> Option<MessageHead<Self::Outgoing>> {
1233        // we can't tell the server about any errors it creates
1234        None
1235    }
1236
1237    fn is_client() -> bool {
1238        true
1239    }
1240}
1241
1242#[cfg(feature = "client")]
1243impl Client {
1244    /// Returns `Some(length, wants_upgrade)` if successful.
1245    ///
1246    /// Returns `None` if this message head should be skipped (like a 100 status).
1247    fn decoder(
1248        inc: &MessageHead<StatusCode>,
1249        method: &mut Option<Method>,
1250    ) -> Result<Option<(DecodedLength, bool)>, Parse> {
1251        // According to https://tools.ietf.org/html/rfc7230#section-3.3.3
1252        // 1. HEAD responses, and Status 1xx, 204, and 304 cannot have a body.
1253        // 2. Status 2xx to a CONNECT cannot have a body.
1254        // 3. Transfer-Encoding: chunked has a chunked body.
1255        // 4. If multiple differing Content-Length headers or invalid, close connection.
1256        // 5. Content-Length header has a sized body.
1257        // 6. (irrelevant to Response)
1258        // 7. Read till EOF.
1259
1260        match inc.subject.as_u16() {
1261            101 => {
1262                return Ok(Some((DecodedLength::ZERO, true)));
1263            }
1264            100 | 102..=199 => {
1265                trace!("ignoring informational response: {}", inc.subject.as_u16());
1266                return Ok(None);
1267            }
1268            204 | 304 => return Ok(Some((DecodedLength::ZERO, false))),
1269            _ => (),
1270        }
1271        match *method {
1272            Some(Method::HEAD) => {
1273                return Ok(Some((DecodedLength::ZERO, false)));
1274            }
1275            Some(Method::CONNECT) => {
1276                if let 200..=299 = inc.subject.as_u16() {
1277                    return Ok(Some((DecodedLength::ZERO, true)));
1278                }
1279            }
1280            Some(_) => {}
1281            None => {
1282                trace!("Client::decoder is missing the Method");
1283            }
1284        }
1285
1286        if inc.headers.contains_key(header::TRANSFER_ENCODING) {
1287            // https://tools.ietf.org/html/rfc7230#section-3.3.3
1288            // If Transfer-Encoding header is present, and 'chunked' is
1289            // not the final encoding, and this is a Request, then it is
1290            // malformed. A server should respond with 400 Bad Request.
1291            if inc.version == Version::HTTP_10 {
1292                debug!("HTTP/1.0 cannot have Transfer-Encoding header");
1293                Err(Parse::transfer_encoding_unexpected())
1294            } else if headers::transfer_encoding_is_chunked(&inc.headers) {
1295                Ok(Some((DecodedLength::CHUNKED, false)))
1296            } else {
1297                trace!("not chunked, read till eof");
1298                Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))
1299            }
1300        } else if let Some(len) = headers::content_length_parse_all(&inc.headers) {
1301            Ok(Some((DecodedLength::checked_new(len)?, false)))
1302        } else if inc.headers.contains_key(header::CONTENT_LENGTH) {
1303            debug!("illegal Content-Length header");
1304            Err(Parse::content_length_invalid())
1305        } else {
1306            trace!("neither Transfer-Encoding nor Content-Length");
1307            Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))
1308        }
1309    }
1310    fn set_length(head: &mut RequestHead, body: Option<BodyLength>) -> Encoder {
1311        let body = if let Some(body) = body {
1312            body
1313        } else {
1314            head.headers.remove(header::TRANSFER_ENCODING);
1315            return Encoder::length(0);
1316        };
1317
1318        // HTTP/1.0 doesn't know about chunked
1319        let can_chunked = head.version == Version::HTTP_11;
1320        let headers = &mut head.headers;
1321
1322        // If the user already set specific headers, we should respect them, regardless
1323        // of what the Body knows about itself. They set them for a reason.
1324
1325        // Because of the borrow checker, we can't check the for an existing
1326        // Content-Length header while holding an `Entry` for the Transfer-Encoding
1327        // header, so unfortunately, we must do the check here, first.
1328
1329        let existing_con_len = headers::content_length_parse_all(headers);
1330        let mut should_remove_con_len = false;
1331
1332        if !can_chunked {
1333            // Chunked isn't legal, so if it is set, we need to remove it.
1334            if headers.remove(header::TRANSFER_ENCODING).is_some() {
1335                trace!("removing illegal transfer-encoding header");
1336            }
1337
1338            return if let Some(len) = existing_con_len {
1339                Encoder::length(len)
1340            } else if let BodyLength::Known(len) = body {
1341                set_content_length(headers, len)
1342            } else {
1343                // HTTP/1.0 client requests without a content-length
1344                // cannot have any body at all.
1345                Encoder::length(0)
1346            };
1347        }
1348
1349        // If the user set a transfer-encoding, respect that. Let's just
1350        // make sure `chunked` is the final encoding.
1351        let encoder = match headers.entry(header::TRANSFER_ENCODING) {
1352            Entry::Occupied(te) => {
1353                should_remove_con_len = true;
1354                if headers::is_chunked(te.iter()) {
1355                    Some(Encoder::chunked())
1356                } else {
1357                    warn!("user provided transfer-encoding does not end in 'chunked'");
1358
1359                    // There's a Transfer-Encoding, but it doesn't end in 'chunked'!
1360                    // An example that could trigger this:
1361                    //
1362                    //     Transfer-Encoding: gzip
1363                    //
1364                    // This can be bad, depending on if this is a request or a
1365                    // response.
1366                    //
1367                    // - A request is illegal if there is a `Transfer-Encoding`
1368                    //   but it doesn't end in `chunked`.
1369                    // - A response that has `Transfer-Encoding` but doesn't
1370                    //   end in `chunked` isn't illegal, it just forces this
1371                    //   to be close-delimited.
1372                    //
1373                    // We can try to repair this, by adding `chunked` ourselves.
1374
1375                    headers::add_chunked(te);
1376                    Some(Encoder::chunked())
1377                }
1378            }
1379            Entry::Vacant(te) => {
1380                if let Some(len) = existing_con_len {
1381                    Some(Encoder::length(len))
1382                } else if let BodyLength::Unknown = body {
1383                    // GET, HEAD, and CONNECT almost never have bodies.
1384                    //
1385                    // So instead of sending a "chunked" body with a 0-chunk,
1386                    // assume no body here. If you *must* send a body,
1387                    // set the headers explicitly.
1388                    match head.subject.0 {
1389                        Method::GET | Method::HEAD | Method::CONNECT => Some(Encoder::length(0)),
1390                        _ => {
1391                            te.insert(HeaderValue::from_static("chunked"));
1392                            Some(Encoder::chunked())
1393                        }
1394                    }
1395                } else {
1396                    None
1397                }
1398            }
1399        };
1400
1401        let encoder = encoder.map(|enc| {
1402            if enc.is_chunked() {
1403                // Parse Trailer header values into HeaderNames.
1404                // Each Trailer header value may contain comma-separated names.
1405                // HeaderName normalizes to lowercase, enabling case-insensitive matching.
1406                let allowed_trailer_fields: Vec<HeaderName> = headers
1407                    .get_all(header::TRAILER)
1408                    .iter()
1409                    .filter_map(|hv| hv.to_str().ok())
1410                    .flat_map(|s| s.split(','))
1411                    .filter_map(|s| HeaderName::from_bytes(s.trim().as_bytes()).ok())
1412                    .collect();
1413
1414                if !allowed_trailer_fields.is_empty() {
1415                    return enc.into_chunked_with_trailing_fields(allowed_trailer_fields);
1416                }
1417            }
1418
1419            enc
1420        });
1421
1422        // This is because we need a second mutable borrow to remove
1423        // content-length header.
1424        if let Some(encoder) = encoder {
1425            if should_remove_con_len && existing_con_len.is_some() {
1426                headers.remove(header::CONTENT_LENGTH);
1427            }
1428            return encoder;
1429        }
1430
1431        // User didn't set transfer-encoding, AND we know body length,
1432        // so we can just set the Content-Length automatically.
1433
1434        let len = if let BodyLength::Known(len) = body {
1435            len
1436        } else {
1437            unreachable!("BodyLength::Unknown would set chunked");
1438        };
1439
1440        set_content_length(headers, len)
1441    }
1442
1443    fn obs_fold_line(all: &mut [u8], idx: &mut HeaderIndices) {
1444        // If the value has obs-folded text, then in-place shift the bytes out
1445        // of here.
1446        //
1447        // https://httpwg.org/specs/rfc9112.html#line.folding
1448        //
1449        // > A user agent that receives an obs-fold MUST replace each received
1450        // > obs-fold with one or more SP octets prior to interpreting the
1451        // > field value.
1452        //
1453        // This means strings like "\r\n\t foo" must replace the "\r\n\t " with
1454        // a single space.
1455
1456        let buf = &mut all[idx.value.0..idx.value.1];
1457
1458        // look for a newline, otherwise bail out
1459        let first_nl = match buf.iter().position(|b| *b == b'\n') {
1460            Some(i) => i,
1461            None => return,
1462        };
1463
1464        // not on standard slices because whatever, sigh
1465        fn trim_start(mut s: &[u8]) -> &[u8] {
1466            while let [first, rest @ ..] = s {
1467                if first.is_ascii_whitespace() {
1468                    s = rest;
1469                } else {
1470                    break;
1471                }
1472            }
1473            s
1474        }
1475
1476        fn trim_end(mut s: &[u8]) -> &[u8] {
1477            while let [rest @ .., last] = s {
1478                if last.is_ascii_whitespace() {
1479                    s = rest;
1480                } else {
1481                    break;
1482                }
1483            }
1484            s
1485        }
1486
1487        fn trim(s: &[u8]) -> &[u8] {
1488            trim_start(trim_end(s))
1489        }
1490
1491        // TODO(perf): we could do the moves in-place, but this is so uncommon
1492        // that it shouldn't matter.
1493        let mut unfolded = trim_end(&buf[..first_nl]).to_vec();
1494        for line in buf[first_nl + 1..].split(|b| *b == b'\n') {
1495            unfolded.push(b' ');
1496            unfolded.extend_from_slice(trim(line));
1497        }
1498        buf[..unfolded.len()].copy_from_slice(&unfolded);
1499        idx.value.1 = idx.value.0 + unfolded.len();
1500    }
1501}
1502
1503#[cfg(feature = "client")]
1504fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder {
1505    // At this point, there should not be a valid Content-Length
1506    // header. However, since we'll be indexing in anyways, we can
1507    // warn the user if there was an existing illegal header.
1508    //
1509    // Or at least, we can in theory. It's actually a little bit slower,
1510    // so perhaps only do that while the user is developing/testing.
1511
1512    if cfg!(debug_assertions) {
1513        match headers.entry(header::CONTENT_LENGTH) {
1514            Entry::Occupied(mut cl) => {
1515                // Internal sanity check, we should have already determined
1516                // that the header was illegal before calling this function.
1517                debug_assert!(headers::content_length_parse_all_values(cl.iter()).is_none());
1518                // Uh oh, the user set `Content-Length` headers, but set bad ones.
1519                // This would be an illegal message anyways, so let's try to repair
1520                // with our known good length.
1521                error!("user provided content-length header was invalid");
1522
1523                cl.insert(HeaderValue::from(len));
1524                Encoder::length(len)
1525            }
1526            Entry::Vacant(cl) => {
1527                cl.insert(HeaderValue::from(len));
1528                Encoder::length(len)
1529            }
1530        }
1531    } else {
1532        headers.insert(header::CONTENT_LENGTH, HeaderValue::from(len));
1533        Encoder::length(len)
1534    }
1535}
1536
1537#[derive(Clone, Copy)]
1538struct HeaderIndices {
1539    name: (usize, usize),
1540    value: (usize, usize),
1541}
1542
1543fn record_header_indices(
1544    bytes: &[u8],
1545    headers: &[httparse::Header<'_>],
1546    indices: &mut [MaybeUninit<HeaderIndices>],
1547) -> Result<(), crate::error::Parse> {
1548    let bytes_ptr = bytes.as_ptr() as usize;
1549
1550    for (header, indices) in headers.iter().zip(indices.iter_mut()) {
1551        if header.name.len() >= (1 << 16) {
1552            debug!("header name larger than 64kb: {:?}", header.name);
1553            return Err(crate::error::Parse::TooLarge);
1554        }
1555        let name_start = header.name.as_ptr() as usize - bytes_ptr;
1556        let name_end = name_start + header.name.len();
1557        let value_start = header.value.as_ptr() as usize - bytes_ptr;
1558        let value_end = value_start + header.value.len();
1559
1560        indices.write(HeaderIndices {
1561            name: (name_start, name_end),
1562            value: (value_start, value_end),
1563        });
1564    }
1565
1566    Ok(())
1567}
1568
1569// Write header names as title case. The header name is assumed to be ASCII.
1570fn title_case(dst: &mut Vec<u8>, name: &[u8]) {
1571    dst.reserve(name.len());
1572
1573    // Ensure first character is uppercased
1574    let mut prev = b'-';
1575    for &(mut c) in name {
1576        if prev == b'-' {
1577            c.make_ascii_uppercase();
1578        }
1579        dst.push(c);
1580        prev = c;
1581    }
1582}
1583
1584pub(crate) fn write_headers_title_case(headers: &HeaderMap, dst: &mut Vec<u8>) {
1585    for (name, value) in headers {
1586        title_case(dst, name.as_str().as_bytes());
1587        extend(dst, b": ");
1588        extend(dst, value.as_bytes());
1589        extend(dst, b"\r\n");
1590    }
1591}
1592
1593pub(crate) fn write_headers(headers: &HeaderMap, dst: &mut Vec<u8>) {
1594    for (name, value) in headers {
1595        extend(dst, name.as_str().as_bytes());
1596        extend(dst, b": ");
1597        extend(dst, value.as_bytes());
1598        extend(dst, b"\r\n");
1599    }
1600}
1601
1602#[cold]
1603#[cfg(feature = "client")]
1604fn write_headers_original_case(
1605    headers: &HeaderMap,
1606    orig_case: &HeaderCaseMap,
1607    dst: &mut Vec<u8>,
1608    title_case_headers: bool,
1609) {
1610    // For each header name/value pair, there may be a value in the casemap
1611    // that corresponds to the HeaderValue. So, we iterator all the keys,
1612    // and for each one, try to pair the originally cased name with the value.
1613    //
1614    // TODO: consider adding http::HeaderMap::entries() iterator
1615    for name in headers.keys() {
1616        let mut names = orig_case.get_all(name);
1617
1618        for value in headers.get_all(name) {
1619            if let Some(orig_name) = names.next() {
1620                extend(dst, orig_name.as_ref());
1621            } else if title_case_headers {
1622                title_case(dst, name.as_str().as_bytes());
1623            } else {
1624                extend(dst, name.as_str().as_bytes());
1625            }
1626
1627            // Wanted for curl test cases that send `X-Custom-Header:\r\n`
1628            if value.is_empty() {
1629                extend(dst, b":\r\n");
1630            } else {
1631                extend(dst, b": ");
1632                extend(dst, value.as_bytes());
1633                extend(dst, b"\r\n");
1634            }
1635        }
1636    }
1637}
1638
1639#[cfg(feature = "client")]
1640struct FastWrite<'a>(&'a mut Vec<u8>);
1641
1642#[cfg(feature = "client")]
1643impl fmt::Write for FastWrite<'_> {
1644    #[inline]
1645    fn write_str(&mut self, s: &str) -> fmt::Result {
1646        extend(self.0, s.as_bytes());
1647        Ok(())
1648    }
1649
1650    #[inline]
1651    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
1652        fmt::write(self, args)
1653    }
1654}
1655
1656#[inline]
1657fn extend(dst: &mut Vec<u8>, data: &[u8]) {
1658    dst.extend_from_slice(data);
1659}
1660
1661#[cfg(test)]
1662mod tests {
1663    use bytes::BytesMut;
1664
1665    use super::*;
1666
1667    #[cfg(feature = "server")]
1668    #[test]
1669    fn test_parse_request() {
1670        let _ = pretty_env_logger::try_init();
1671        let mut raw = BytesMut::from("GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
1672        let mut method = None;
1673        let msg = Server::parse(
1674            &mut raw,
1675            ParseContext {
1676                cached_headers: &mut None,
1677                req_method: &mut method,
1678                h1_parser_config: Default::default(),
1679                h1_max_headers: None,
1680                preserve_header_case: false,
1681                #[cfg(feature = "ffi")]
1682                preserve_header_order: false,
1683                h09_responses: false,
1684                #[cfg(feature = "client")]
1685                on_informational: &mut None,
1686            },
1687        )
1688        .unwrap()
1689        .unwrap();
1690        assert_eq!(raw.len(), 0);
1691        assert_eq!(msg.head.subject.0, crate::Method::GET);
1692        assert_eq!(msg.head.subject.1, "/echo");
1693        assert_eq!(msg.head.version, crate::Version::HTTP_11);
1694        assert_eq!(msg.head.headers.len(), 1);
1695        assert_eq!(msg.head.headers["Host"], "hyper.rs");
1696        assert_eq!(method, Some(crate::Method::GET));
1697    }
1698
1699    #[test]
1700    fn test_parse_response() {
1701        let _ = pretty_env_logger::try_init();
1702        let mut raw = BytesMut::from("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1703        let ctx = ParseContext {
1704            cached_headers: &mut None,
1705            req_method: &mut Some(crate::Method::GET),
1706            h1_parser_config: Default::default(),
1707            h1_max_headers: None,
1708            preserve_header_case: false,
1709            #[cfg(feature = "ffi")]
1710            preserve_header_order: false,
1711            h09_responses: false,
1712            #[cfg(feature = "client")]
1713            on_informational: &mut None,
1714        };
1715        let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
1716        assert_eq!(raw.len(), 0);
1717        assert_eq!(msg.head.subject, crate::StatusCode::OK);
1718        assert_eq!(msg.head.version, crate::Version::HTTP_11);
1719        assert_eq!(msg.head.headers.len(), 1);
1720        assert_eq!(msg.head.headers["Content-Length"], "0");
1721    }
1722
1723    #[cfg(feature = "server")]
1724    #[test]
1725    fn test_parse_request_errors() {
1726        let mut raw = BytesMut::from("GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
1727        let ctx = ParseContext {
1728            cached_headers: &mut None,
1729            req_method: &mut None,
1730            h1_parser_config: Default::default(),
1731            h1_max_headers: None,
1732            preserve_header_case: false,
1733            #[cfg(feature = "ffi")]
1734            preserve_header_order: false,
1735            h09_responses: false,
1736            #[cfg(feature = "client")]
1737            on_informational: &mut None,
1738        };
1739        Server::parse(&mut raw, ctx).unwrap_err();
1740    }
1741
1742    const H09_RESPONSE: &str = "Baguettes are super delicious, don't you agree?";
1743
1744    #[test]
1745    fn test_parse_response_h09_allowed() {
1746        let _ = pretty_env_logger::try_init();
1747        let mut raw = BytesMut::from(H09_RESPONSE);
1748        let ctx = ParseContext {
1749            cached_headers: &mut None,
1750            req_method: &mut Some(crate::Method::GET),
1751            h1_parser_config: Default::default(),
1752            h1_max_headers: None,
1753            preserve_header_case: false,
1754            #[cfg(feature = "ffi")]
1755            preserve_header_order: false,
1756            h09_responses: true,
1757            #[cfg(feature = "client")]
1758            on_informational: &mut None,
1759        };
1760        let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
1761        assert_eq!(raw, H09_RESPONSE);
1762        assert_eq!(msg.head.subject, crate::StatusCode::OK);
1763        assert_eq!(msg.head.version, crate::Version::HTTP_09);
1764        assert_eq!(msg.head.headers.len(), 0);
1765    }
1766
1767    #[test]
1768    fn test_parse_response_h09_rejected() {
1769        let _ = pretty_env_logger::try_init();
1770        let mut raw = BytesMut::from(H09_RESPONSE);
1771        let ctx = ParseContext {
1772            cached_headers: &mut None,
1773            req_method: &mut Some(crate::Method::GET),
1774            h1_parser_config: Default::default(),
1775            h1_max_headers: None,
1776            preserve_header_case: false,
1777            #[cfg(feature = "ffi")]
1778            preserve_header_order: false,
1779            h09_responses: false,
1780            #[cfg(feature = "client")]
1781            on_informational: &mut None,
1782        };
1783        Client::parse(&mut raw, ctx).unwrap_err();
1784        assert_eq!(raw, H09_RESPONSE);
1785    }
1786
1787    const RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &str =
1788        "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials : true\r\n\r\n";
1789
1790    #[test]
1791    fn test_parse_allow_response_with_spaces_before_colons() {
1792        use httparse::ParserConfig;
1793
1794        let _ = pretty_env_logger::try_init();
1795        let mut raw = BytesMut::from(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1796        let mut h1_parser_config = ParserConfig::default();
1797        h1_parser_config.allow_spaces_after_header_name_in_responses(true);
1798        let ctx = ParseContext {
1799            cached_headers: &mut None,
1800            req_method: &mut Some(crate::Method::GET),
1801            h1_parser_config,
1802            h1_max_headers: None,
1803            preserve_header_case: false,
1804            #[cfg(feature = "ffi")]
1805            preserve_header_order: false,
1806            h09_responses: false,
1807            #[cfg(feature = "client")]
1808            on_informational: &mut None,
1809        };
1810        let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
1811        assert_eq!(raw.len(), 0);
1812        assert_eq!(msg.head.subject, crate::StatusCode::OK);
1813        assert_eq!(msg.head.version, crate::Version::HTTP_11);
1814        assert_eq!(msg.head.headers.len(), 1);
1815        assert_eq!(msg.head.headers["Access-Control-Allow-Credentials"], "true");
1816    }
1817
1818    #[test]
1819    fn test_parse_reject_response_with_spaces_before_colons() {
1820        let _ = pretty_env_logger::try_init();
1821        let mut raw = BytesMut::from(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1822        let ctx = ParseContext {
1823            cached_headers: &mut None,
1824            req_method: &mut Some(crate::Method::GET),
1825            h1_parser_config: Default::default(),
1826            h1_max_headers: None,
1827            preserve_header_case: false,
1828            #[cfg(feature = "ffi")]
1829            preserve_header_order: false,
1830            h09_responses: false,
1831            #[cfg(feature = "client")]
1832            on_informational: &mut None,
1833        };
1834        Client::parse(&mut raw, ctx).unwrap_err();
1835    }
1836
1837    const REQUEST_WITH_MULTIPLE_SPACES_IN_REQUEST_LINE: &str =
1838        "GET  /echo  HTTP/1.1\r\nHost: hyper.rs\r\n\r\n";
1839
1840    #[cfg(feature = "server")]
1841    #[test]
1842    fn test_parse_allow_request_with_multiple_spaces_in_request_line() {
1843        use httparse::ParserConfig;
1844
1845        let _ = pretty_env_logger::try_init();
1846        let mut raw = BytesMut::from(REQUEST_WITH_MULTIPLE_SPACES_IN_REQUEST_LINE);
1847        let mut h1_parser_config = ParserConfig::default();
1848        h1_parser_config.allow_multiple_spaces_in_request_line_delimiters(true);
1849        let mut method = None;
1850        let ctx = ParseContext {
1851            cached_headers: &mut None,
1852            req_method: &mut method,
1853            h1_parser_config,
1854            h1_max_headers: None,
1855            preserve_header_case: false,
1856            #[cfg(feature = "ffi")]
1857            preserve_header_order: false,
1858            h09_responses: false,
1859            #[cfg(feature = "client")]
1860            on_informational: &mut None,
1861        };
1862        let msg = Server::parse(&mut raw, ctx).unwrap().unwrap();
1863        assert_eq!(raw.len(), 0);
1864        assert_eq!(msg.head.subject.0, crate::Method::GET);
1865        assert_eq!(msg.head.subject.1, "/echo");
1866        assert_eq!(msg.head.version, crate::Version::HTTP_11);
1867        assert_eq!(msg.head.headers.len(), 1);
1868        assert_eq!(msg.head.headers["Host"], "hyper.rs");
1869        assert_eq!(method, Some(crate::Method::GET));
1870    }
1871
1872    #[cfg(feature = "server")]
1873    #[test]
1874    fn test_parse_reject_request_with_multiple_spaces_in_request_line() {
1875        let _ = pretty_env_logger::try_init();
1876        let mut raw = BytesMut::from(REQUEST_WITH_MULTIPLE_SPACES_IN_REQUEST_LINE);
1877        let ctx = ParseContext {
1878            cached_headers: &mut None,
1879            req_method: &mut None,
1880            h1_parser_config: Default::default(),
1881            h1_max_headers: None,
1882            preserve_header_case: false,
1883            #[cfg(feature = "ffi")]
1884            preserve_header_order: false,
1885            h09_responses: false,
1886            #[cfg(feature = "client")]
1887            on_informational: &mut None,
1888        };
1889        Server::parse(&mut raw, ctx).unwrap_err();
1890    }
1891
1892    #[cfg(feature = "server")]
1893    #[test]
1894    fn test_parse_preserve_header_case_in_request() {
1895        let mut raw =
1896            BytesMut::from("GET / HTTP/1.1\r\nHost: hyper.rs\r\nX-BREAD: baguette\r\n\r\n");
1897        let ctx = ParseContext {
1898            cached_headers: &mut None,
1899            req_method: &mut None,
1900            h1_parser_config: Default::default(),
1901            h1_max_headers: None,
1902            preserve_header_case: true,
1903            #[cfg(feature = "ffi")]
1904            preserve_header_order: false,
1905            h09_responses: false,
1906            #[cfg(feature = "client")]
1907            on_informational: &mut None,
1908        };
1909        let parsed_message = Server::parse(&mut raw, ctx).unwrap().unwrap();
1910        let orig_headers = parsed_message
1911            .head
1912            .extensions
1913            .get::<HeaderCaseMap>()
1914            .unwrap();
1915        assert_eq!(
1916            orig_headers
1917                .get_all_internal(&HeaderName::from_static("host"))
1918                .collect::<Vec<_>>(),
1919            vec![&Bytes::from("Host")]
1920        );
1921        assert_eq!(
1922            orig_headers
1923                .get_all_internal(&HeaderName::from_static("x-bread"))
1924                .collect::<Vec<_>>(),
1925            vec![&Bytes::from("X-BREAD")]
1926        );
1927    }
1928
1929    #[cfg(feature = "server")]
1930    #[test]
1931    fn test_decoder_request() {
1932        fn parse(s: &str) -> ParsedMessage<RequestLine> {
1933            let mut bytes = BytesMut::from(s);
1934            Server::parse(
1935                &mut bytes,
1936                ParseContext {
1937                    cached_headers: &mut None,
1938                    req_method: &mut None,
1939                    h1_parser_config: Default::default(),
1940                    h1_max_headers: None,
1941                    preserve_header_case: false,
1942                    #[cfg(feature = "ffi")]
1943                    preserve_header_order: false,
1944                    h09_responses: false,
1945                    #[cfg(feature = "client")]
1946                    on_informational: &mut None,
1947                },
1948            )
1949            .expect("parse ok")
1950            .expect("parse complete")
1951        }
1952
1953        fn parse_err(s: &str, comment: &str) -> crate::error::Parse {
1954            let mut bytes = BytesMut::from(s);
1955            Server::parse(
1956                &mut bytes,
1957                ParseContext {
1958                    cached_headers: &mut None,
1959                    req_method: &mut None,
1960                    h1_parser_config: Default::default(),
1961                    h1_max_headers: None,
1962                    preserve_header_case: false,
1963                    #[cfg(feature = "ffi")]
1964                    preserve_header_order: false,
1965                    h09_responses: false,
1966                    #[cfg(feature = "client")]
1967                    on_informational: &mut None,
1968                },
1969            )
1970            .expect_err(comment)
1971        }
1972
1973        // no length or transfer-encoding means 0-length body
1974        assert_eq!(
1975            parse(
1976                "\
1977                 GET / HTTP/1.1\r\n\
1978                 \r\n\
1979                 "
1980            )
1981            .decode,
1982            DecodedLength::ZERO
1983        );
1984
1985        assert_eq!(
1986            parse(
1987                "\
1988                 POST / HTTP/1.1\r\n\
1989                 \r\n\
1990                 "
1991            )
1992            .decode,
1993            DecodedLength::ZERO
1994        );
1995
1996        // transfer-encoding: chunked
1997        assert_eq!(
1998            parse(
1999                "\
2000                 POST / HTTP/1.1\r\n\
2001                 transfer-encoding: chunked\r\n\
2002                 \r\n\
2003                 "
2004            )
2005            .decode,
2006            DecodedLength::CHUNKED
2007        );
2008
2009        assert_eq!(
2010            parse(
2011                "\
2012                 POST / HTTP/1.1\r\n\
2013                 transfer-encoding: gzip, chunked\r\n\
2014                 \r\n\
2015                 "
2016            )
2017            .decode,
2018            DecodedLength::CHUNKED
2019        );
2020
2021        assert_eq!(
2022            parse(
2023                "\
2024                 POST / HTTP/1.1\r\n\
2025                 transfer-encoding: gzip\r\n\
2026                 transfer-encoding: chunked\r\n\
2027                 \r\n\
2028                 "
2029            )
2030            .decode,
2031            DecodedLength::CHUNKED
2032        );
2033
2034        // content-length
2035        assert_eq!(
2036            parse(
2037                "\
2038                 POST / HTTP/1.1\r\n\
2039                 content-length: 10\r\n\
2040                 \r\n\
2041                 "
2042            )
2043            .decode,
2044            DecodedLength::new(10)
2045        );
2046
2047        // transfer-encoding and content-length = chunked
2048        assert_eq!(
2049            parse(
2050                "\
2051                 POST / HTTP/1.1\r\n\
2052                 content-length: 10\r\n\
2053                 transfer-encoding: chunked\r\n\
2054                 \r\n\
2055                 "
2056            )
2057            .decode,
2058            DecodedLength::CHUNKED
2059        );
2060
2061        assert_eq!(
2062            parse(
2063                "\
2064                 POST / HTTP/1.1\r\n\
2065                 transfer-encoding: chunked\r\n\
2066                 content-length: 10\r\n\
2067                 \r\n\
2068                 "
2069            )
2070            .decode,
2071            DecodedLength::CHUNKED
2072        );
2073
2074        assert_eq!(
2075            parse(
2076                "\
2077                 POST / HTTP/1.1\r\n\
2078                 transfer-encoding: gzip\r\n\
2079                 content-length: 10\r\n\
2080                 transfer-encoding: chunked\r\n\
2081                 \r\n\
2082                 "
2083            )
2084            .decode,
2085            DecodedLength::CHUNKED
2086        );
2087
2088        // multiple content-lengths of same value are fine
2089        assert_eq!(
2090            parse(
2091                "\
2092                 POST / HTTP/1.1\r\n\
2093                 content-length: 10\r\n\
2094                 content-length: 10\r\n\
2095                 \r\n\
2096                 "
2097            )
2098            .decode,
2099            DecodedLength::new(10)
2100        );
2101
2102        // multiple content-lengths with different values is an error
2103        parse_err(
2104            "\
2105             POST / HTTP/1.1\r\n\
2106             content-length: 10\r\n\
2107             content-length: 11\r\n\
2108             \r\n\
2109             ",
2110            "multiple content-lengths",
2111        );
2112
2113        // content-length with prefix is not allowed
2114        parse_err(
2115            "\
2116             POST / HTTP/1.1\r\n\
2117             content-length: +10\r\n\
2118             \r\n\
2119             ",
2120            "prefixed content-length",
2121        );
2122
2123        // transfer-encoding that isn't chunked is an error
2124        parse_err(
2125            "\
2126             POST / HTTP/1.1\r\n\
2127             transfer-encoding: gzip\r\n\
2128             \r\n\
2129             ",
2130            "transfer-encoding but not chunked",
2131        );
2132
2133        parse_err(
2134            "\
2135             POST / HTTP/1.1\r\n\
2136             transfer-encoding: chunked, gzip\r\n\
2137             \r\n\
2138             ",
2139            "transfer-encoding doesn't end in chunked",
2140        );
2141
2142        parse_err(
2143            "\
2144             POST / HTTP/1.1\r\n\
2145             transfer-encoding: chunked\r\n\
2146             transfer-encoding: afterlol\r\n\
2147             \r\n\
2148             ",
2149            "transfer-encoding multiple lines doesn't end in chunked",
2150        );
2151
2152        // http/1.0
2153
2154        assert_eq!(
2155            parse(
2156                "\
2157                 POST / HTTP/1.0\r\n\
2158                 content-length: 10\r\n\
2159                 \r\n\
2160                 "
2161            )
2162            .decode,
2163            DecodedLength::new(10)
2164        );
2165
2166        // 1.0 doesn't understand chunked, so its an error
2167        parse_err(
2168            "\
2169             POST / HTTP/1.0\r\n\
2170             transfer-encoding: chunked\r\n\
2171             \r\n\
2172             ",
2173            "1.0 chunked",
2174        );
2175    }
2176
2177    #[test]
2178    fn test_decoder_response() {
2179        fn parse(s: &str) -> ParsedMessage<StatusCode> {
2180            parse_with_method(s, Method::GET)
2181        }
2182
2183        fn parse_ignores(s: &str) {
2184            let mut bytes = BytesMut::from(s);
2185            assert!(Client::parse(
2186                &mut bytes,
2187                ParseContext {
2188                    cached_headers: &mut None,
2189                    req_method: &mut Some(Method::GET),
2190                    h1_parser_config: Default::default(),
2191                    h1_max_headers: None,
2192                    preserve_header_case: false,
2193                    #[cfg(feature = "ffi")]
2194                    preserve_header_order: false,
2195                    h09_responses: false,
2196                    #[cfg(feature = "client")]
2197                    on_informational: &mut None,
2198                }
2199            )
2200            .expect("parse ok")
2201            .is_none())
2202        }
2203
2204        fn parse_with_method(s: &str, m: Method) -> ParsedMessage<StatusCode> {
2205            let mut bytes = BytesMut::from(s);
2206            Client::parse(
2207                &mut bytes,
2208                ParseContext {
2209                    cached_headers: &mut None,
2210                    req_method: &mut Some(m),
2211                    h1_parser_config: Default::default(),
2212                    h1_max_headers: None,
2213                    preserve_header_case: false,
2214                    #[cfg(feature = "ffi")]
2215                    preserve_header_order: false,
2216                    h09_responses: false,
2217                    #[cfg(feature = "client")]
2218                    on_informational: &mut None,
2219                },
2220            )
2221            .expect("parse ok")
2222            .expect("parse complete")
2223        }
2224
2225        fn parse_err(s: &str) -> crate::error::Parse {
2226            let mut bytes = BytesMut::from(s);
2227            Client::parse(
2228                &mut bytes,
2229                ParseContext {
2230                    cached_headers: &mut None,
2231                    req_method: &mut Some(Method::GET),
2232                    h1_parser_config: Default::default(),
2233                    h1_max_headers: None,
2234                    preserve_header_case: false,
2235                    #[cfg(feature = "ffi")]
2236                    preserve_header_order: false,
2237                    h09_responses: false,
2238                    #[cfg(feature = "client")]
2239                    on_informational: &mut None,
2240                },
2241            )
2242            .expect_err("parse should err")
2243        }
2244
2245        // no content-length or transfer-encoding means close-delimited
2246        assert_eq!(
2247            parse(
2248                "\
2249                 HTTP/1.1 200 OK\r\n\
2250                 \r\n\
2251                 "
2252            )
2253            .decode,
2254            DecodedLength::CLOSE_DELIMITED
2255        );
2256
2257        // 204 and 304 never have a body
2258        assert_eq!(
2259            parse(
2260                "\
2261                 HTTP/1.1 204 No Content\r\n\
2262                 \r\n\
2263                 "
2264            )
2265            .decode,
2266            DecodedLength::ZERO
2267        );
2268
2269        assert_eq!(
2270            parse(
2271                "\
2272                 HTTP/1.1 304 Not Modified\r\n\
2273                 \r\n\
2274                 "
2275            )
2276            .decode,
2277            DecodedLength::ZERO
2278        );
2279
2280        // content-length
2281        assert_eq!(
2282            parse(
2283                "\
2284                 HTTP/1.1 200 OK\r\n\
2285                 content-length: 8\r\n\
2286                 \r\n\
2287                 "
2288            )
2289            .decode,
2290            DecodedLength::new(8)
2291        );
2292
2293        assert_eq!(
2294            parse(
2295                "\
2296                 HTTP/1.1 200 OK\r\n\
2297                 content-length: 8\r\n\
2298                 content-length: 8\r\n\
2299                 \r\n\
2300                 "
2301            )
2302            .decode,
2303            DecodedLength::new(8)
2304        );
2305
2306        parse_err(
2307            "\
2308             HTTP/1.1 200 OK\r\n\
2309             content-length: 8\r\n\
2310             content-length: 9\r\n\
2311             \r\n\
2312             ",
2313        );
2314
2315        parse_err(
2316            "\
2317             HTTP/1.1 200 OK\r\n\
2318             content-length: +8\r\n\
2319             \r\n\
2320             ",
2321        );
2322
2323        // transfer-encoding: chunked
2324        assert_eq!(
2325            parse(
2326                "\
2327                 HTTP/1.1 200 OK\r\n\
2328                 transfer-encoding: chunked\r\n\
2329                 \r\n\
2330                 "
2331            )
2332            .decode,
2333            DecodedLength::CHUNKED
2334        );
2335
2336        // transfer-encoding not-chunked is close-delimited
2337        assert_eq!(
2338            parse(
2339                "\
2340                 HTTP/1.1 200 OK\r\n\
2341                 transfer-encoding: yolo\r\n\
2342                 \r\n\
2343                 "
2344            )
2345            .decode,
2346            DecodedLength::CLOSE_DELIMITED
2347        );
2348
2349        // transfer-encoding and content-length = chunked
2350        assert_eq!(
2351            parse(
2352                "\
2353                 HTTP/1.1 200 OK\r\n\
2354                 content-length: 10\r\n\
2355                 transfer-encoding: chunked\r\n\
2356                 \r\n\
2357                 "
2358            )
2359            .decode,
2360            DecodedLength::CHUNKED
2361        );
2362
2363        // HEAD can have content-length, but not body
2364        assert_eq!(
2365            parse_with_method(
2366                "\
2367                 HTTP/1.1 200 OK\r\n\
2368                 content-length: 8\r\n\
2369                 \r\n\
2370                 ",
2371                Method::HEAD
2372            )
2373            .decode,
2374            DecodedLength::ZERO
2375        );
2376
2377        // CONNECT with 200 never has body
2378        {
2379            let msg = parse_with_method(
2380                "\
2381                 HTTP/1.1 200 OK\r\n\
2382                 \r\n\
2383                 ",
2384                Method::CONNECT,
2385            );
2386            assert_eq!(msg.decode, DecodedLength::ZERO);
2387            assert!(!msg.keep_alive, "should be upgrade");
2388            assert!(msg.wants_upgrade, "should be upgrade");
2389        }
2390
2391        // CONNECT receiving non 200 can have a body
2392        assert_eq!(
2393            parse_with_method(
2394                "\
2395                 HTTP/1.1 400 Bad Request\r\n\
2396                 \r\n\
2397                 ",
2398                Method::CONNECT
2399            )
2400            .decode,
2401            DecodedLength::CLOSE_DELIMITED
2402        );
2403
2404        // 1xx status codes
2405        parse_ignores(
2406            "\
2407             HTTP/1.1 100 Continue\r\n\
2408             \r\n\
2409             ",
2410        );
2411
2412        parse_ignores(
2413            "\
2414             HTTP/1.1 103 Early Hints\r\n\
2415             \r\n\
2416             ",
2417        );
2418
2419        // 101 upgrade not supported yet
2420        {
2421            let msg = parse(
2422                "\
2423                 HTTP/1.1 101 Switching Protocols\r\n\
2424                 \r\n\
2425                 ",
2426            );
2427            assert_eq!(msg.decode, DecodedLength::ZERO);
2428            assert!(!msg.keep_alive, "should be last");
2429            assert!(msg.wants_upgrade, "should be upgrade");
2430        }
2431
2432        // http/1.0
2433        assert_eq!(
2434            parse(
2435                "\
2436                 HTTP/1.0 200 OK\r\n\
2437                 \r\n\
2438                 "
2439            )
2440            .decode,
2441            DecodedLength::CLOSE_DELIMITED
2442        );
2443
2444        // 1.0 doesn't understand chunked
2445        parse_err(
2446            "\
2447             HTTP/1.0 200 OK\r\n\
2448             transfer-encoding: chunked\r\n\
2449             \r\n\
2450             ",
2451        );
2452
2453        // keep-alive
2454        assert!(
2455            parse(
2456                "\
2457                 HTTP/1.1 200 OK\r\n\
2458                 content-length: 0\r\n\
2459                 \r\n\
2460                 "
2461            )
2462            .keep_alive,
2463            "HTTP/1.1 keep-alive is default"
2464        );
2465
2466        assert!(
2467            !parse(
2468                "\
2469                 HTTP/1.1 200 OK\r\n\
2470                 content-length: 0\r\n\
2471                 connection: foo, close, bar\r\n\
2472                 \r\n\
2473                 "
2474            )
2475            .keep_alive,
2476            "connection close is always close"
2477        );
2478
2479        assert!(
2480            !parse(
2481                "\
2482                 HTTP/1.0 200 OK\r\n\
2483                 content-length: 0\r\n\
2484                 \r\n\
2485                 "
2486            )
2487            .keep_alive,
2488            "HTTP/1.0 close is default"
2489        );
2490
2491        assert!(
2492            parse(
2493                "\
2494                 HTTP/1.0 200 OK\r\n\
2495                 content-length: 0\r\n\
2496                 connection: foo, keep-alive, bar\r\n\
2497                 \r\n\
2498                 "
2499            )
2500            .keep_alive,
2501            "connection keep-alive is always keep-alive"
2502        );
2503    }
2504
2505    #[cfg(feature = "client")]
2506    #[test]
2507    fn test_client_obs_fold_line() {
2508        fn unfold(src: &str) -> String {
2509            let mut buf = src.as_bytes().to_vec();
2510            let mut idx = HeaderIndices {
2511                name: (0, 0),
2512                value: (0, buf.len()),
2513            };
2514            Client::obs_fold_line(&mut buf, &mut idx);
2515            String::from_utf8(buf[idx.value.0..idx.value.1].to_vec()).unwrap()
2516        }
2517
2518        assert_eq!(unfold("a normal line"), "a normal line",);
2519
2520        assert_eq!(unfold("obs\r\n fold\r\n\t line"), "obs fold line",);
2521    }
2522
2523    #[test]
2524    fn test_client_request_encode_title_case() {
2525        use crate::proto::BodyLength;
2526        use http::header::HeaderValue;
2527
2528        let mut head = MessageHead::default();
2529        head.headers
2530            .insert("content-length", HeaderValue::from_static("10"));
2531        head.headers
2532            .insert("content-type", HeaderValue::from_static("application/json"));
2533        head.headers.insert("*-*", HeaderValue::from_static("o_o"));
2534
2535        let mut vec = Vec::new();
2536        Client::encode(
2537            Encode {
2538                head: &mut head,
2539                body: Some(BodyLength::Known(10)),
2540                #[cfg(feature = "server")]
2541                keep_alive: true,
2542                req_method: &mut None,
2543                title_case_headers: true,
2544                #[cfg(feature = "server")]
2545                date_header: true,
2546            },
2547            &mut vec,
2548        )
2549        .unwrap();
2550
2551        assert_eq!(vec, b"GET / HTTP/1.1\r\nContent-Length: 10\r\nContent-Type: application/json\r\n*-*: o_o\r\n\r\n".to_vec());
2552    }
2553
2554    #[test]
2555    fn test_client_request_encode_orig_case() {
2556        use crate::proto::BodyLength;
2557        use http::header::{HeaderValue, CONTENT_LENGTH};
2558
2559        let mut head = MessageHead::default();
2560        head.headers
2561            .insert("content-length", HeaderValue::from_static("10"));
2562        head.headers
2563            .insert("content-type", HeaderValue::from_static("application/json"));
2564
2565        let mut orig_headers = HeaderCaseMap::default();
2566        orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2567        head.extensions.insert(orig_headers);
2568
2569        let mut vec = Vec::new();
2570        Client::encode(
2571            Encode {
2572                head: &mut head,
2573                body: Some(BodyLength::Known(10)),
2574                #[cfg(feature = "server")]
2575                keep_alive: true,
2576                req_method: &mut None,
2577                title_case_headers: false,
2578                #[cfg(feature = "server")]
2579                date_header: true,
2580            },
2581            &mut vec,
2582        )
2583        .unwrap();
2584
2585        assert_eq!(
2586            &*vec,
2587            b"GET / HTTP/1.1\r\nCONTENT-LENGTH: 10\r\ncontent-type: application/json\r\n\r\n"
2588                .as_ref(),
2589        );
2590    }
2591    #[test]
2592    fn test_client_request_encode_orig_and_title_case() {
2593        use crate::proto::BodyLength;
2594        use http::header::{HeaderValue, CONTENT_LENGTH};
2595
2596        let mut head = MessageHead::default();
2597        head.headers
2598            .insert("content-length", HeaderValue::from_static("10"));
2599        head.headers
2600            .insert("content-type", HeaderValue::from_static("application/json"));
2601
2602        let mut orig_headers = HeaderCaseMap::default();
2603        orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2604        head.extensions.insert(orig_headers);
2605
2606        let mut vec = Vec::new();
2607        Client::encode(
2608            Encode {
2609                head: &mut head,
2610                body: Some(BodyLength::Known(10)),
2611                #[cfg(feature = "server")]
2612                keep_alive: true,
2613                req_method: &mut None,
2614                title_case_headers: true,
2615                #[cfg(feature = "server")]
2616                date_header: true,
2617            },
2618            &mut vec,
2619        )
2620        .unwrap();
2621
2622        assert_eq!(
2623            &*vec,
2624            b"GET / HTTP/1.1\r\nCONTENT-LENGTH: 10\r\nContent-Type: application/json\r\n\r\n"
2625                .as_ref(),
2626        );
2627    }
2628
2629    #[cfg(feature = "server")]
2630    #[test]
2631    fn test_server_encode_connect_method() {
2632        let mut head = MessageHead::default();
2633
2634        let mut vec = Vec::new();
2635        let encoder = Server::encode(
2636            Encode {
2637                head: &mut head,
2638                body: None,
2639                keep_alive: true,
2640                req_method: &mut Some(Method::CONNECT),
2641                title_case_headers: false,
2642                date_header: true,
2643            },
2644            &mut vec,
2645        )
2646        .unwrap();
2647
2648        assert!(encoder.is_last());
2649    }
2650
2651    #[cfg(feature = "server")]
2652    #[test]
2653    fn test_server_response_encode_title_case() {
2654        use crate::proto::BodyLength;
2655        use http::header::HeaderValue;
2656
2657        let mut head = MessageHead::default();
2658        head.headers
2659            .insert("content-length", HeaderValue::from_static("10"));
2660        head.headers
2661            .insert("content-type", HeaderValue::from_static("application/json"));
2662        head.headers
2663            .insert("weird--header", HeaderValue::from_static(""));
2664
2665        let mut vec = Vec::new();
2666        Server::encode(
2667            Encode {
2668                head: &mut head,
2669                body: Some(BodyLength::Known(10)),
2670                keep_alive: true,
2671                req_method: &mut None,
2672                title_case_headers: true,
2673                date_header: true,
2674            },
2675            &mut vec,
2676        )
2677        .unwrap();
2678
2679        let expected_response =
2680            b"HTTP/1.1 200 OK\r\nContent-Length: 10\r\nContent-Type: application/json\r\nWeird--Header: \r\n";
2681
2682        assert_eq!(&vec[..expected_response.len()], &expected_response[..]);
2683    }
2684
2685    #[cfg(feature = "server")]
2686    #[test]
2687    fn test_server_response_encode_orig_case() {
2688        use crate::proto::BodyLength;
2689        use http::header::{HeaderValue, CONTENT_LENGTH};
2690
2691        let mut head = MessageHead::default();
2692        head.headers
2693            .insert("content-length", HeaderValue::from_static("10"));
2694        head.headers
2695            .insert("content-type", HeaderValue::from_static("application/json"));
2696
2697        let mut orig_headers = HeaderCaseMap::default();
2698        orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2699        head.extensions.insert(orig_headers);
2700
2701        let mut vec = Vec::new();
2702        Server::encode(
2703            Encode {
2704                head: &mut head,
2705                body: Some(BodyLength::Known(10)),
2706                keep_alive: true,
2707                req_method: &mut None,
2708                title_case_headers: false,
2709                date_header: true,
2710            },
2711            &mut vec,
2712        )
2713        .unwrap();
2714
2715        let expected_response =
2716            b"HTTP/1.1 200 OK\r\nCONTENT-LENGTH: 10\r\ncontent-type: application/json\r\ndate: ";
2717
2718        assert_eq!(&vec[..expected_response.len()], &expected_response[..]);
2719    }
2720
2721    #[cfg(feature = "server")]
2722    #[test]
2723    fn test_server_response_encode_orig_and_title_case() {
2724        use crate::proto::BodyLength;
2725        use http::header::{HeaderValue, CONTENT_LENGTH};
2726
2727        let mut head = MessageHead::default();
2728        head.headers
2729            .insert("content-length", HeaderValue::from_static("10"));
2730        head.headers
2731            .insert("content-type", HeaderValue::from_static("application/json"));
2732
2733        let mut orig_headers = HeaderCaseMap::default();
2734        orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2735        head.extensions.insert(orig_headers);
2736
2737        let mut vec = Vec::new();
2738        Server::encode(
2739            Encode {
2740                head: &mut head,
2741                body: Some(BodyLength::Known(10)),
2742                keep_alive: true,
2743                req_method: &mut None,
2744                title_case_headers: true,
2745                date_header: true,
2746            },
2747            &mut vec,
2748        )
2749        .unwrap();
2750
2751        // this will also test that the date does exist
2752        let expected_response =
2753            b"HTTP/1.1 200 OK\r\nCONTENT-LENGTH: 10\r\nContent-Type: application/json\r\nDate: ";
2754
2755        assert_eq!(&vec[..expected_response.len()], &expected_response[..]);
2756    }
2757
2758    #[cfg(feature = "server")]
2759    #[test]
2760    fn test_disabled_date_header() {
2761        use crate::proto::BodyLength;
2762        use http::header::{HeaderValue, CONTENT_LENGTH};
2763
2764        let mut head = MessageHead::default();
2765        head.headers
2766            .insert("content-length", HeaderValue::from_static("10"));
2767        head.headers
2768            .insert("content-type", HeaderValue::from_static("application/json"));
2769
2770        let mut orig_headers = HeaderCaseMap::default();
2771        orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2772        head.extensions.insert(orig_headers);
2773
2774        let mut vec = Vec::new();
2775        Server::encode(
2776            Encode {
2777                head: &mut head,
2778                body: Some(BodyLength::Known(10)),
2779                keep_alive: true,
2780                req_method: &mut None,
2781                title_case_headers: true,
2782                date_header: false,
2783            },
2784            &mut vec,
2785        )
2786        .unwrap();
2787
2788        let expected_response =
2789            b"HTTP/1.1 200 OK\r\nCONTENT-LENGTH: 10\r\nContent-Type: application/json\r\n\r\n";
2790
2791        assert_eq!(&vec, &expected_response);
2792    }
2793
2794    #[test]
2795    fn parse_header_htabs() {
2796        let mut bytes = BytesMut::from("HTTP/1.1 200 OK\r\nserver: hello\tworld\r\n\r\n");
2797        let parsed = Client::parse(
2798            &mut bytes,
2799            ParseContext {
2800                cached_headers: &mut None,
2801                req_method: &mut Some(Method::GET),
2802                h1_parser_config: Default::default(),
2803                h1_max_headers: None,
2804                preserve_header_case: false,
2805                #[cfg(feature = "ffi")]
2806                preserve_header_order: false,
2807                h09_responses: false,
2808                #[cfg(feature = "client")]
2809                on_informational: &mut None,
2810            },
2811        )
2812        .expect("parse ok")
2813        .expect("parse complete");
2814
2815        assert_eq!(parsed.head.headers["server"], "hello\tworld");
2816    }
2817
2818    #[cfg(feature = "server")]
2819    #[test]
2820    fn parse_too_large_headers() {
2821        fn gen_req_with_headers(num: usize) -> String {
2822            let mut req = String::from("GET / HTTP/1.1\r\n");
2823            for i in 0..num {
2824                req.push_str(&format!("key{i}: val{i}\r\n"));
2825            }
2826            req.push_str("\r\n");
2827            req
2828        }
2829        fn gen_resp_with_headers(num: usize) -> String {
2830            let mut req = String::from("HTTP/1.1 200 OK\r\n");
2831            for i in 0..num {
2832                req.push_str(&format!("key{i}: val{i}\r\n"));
2833            }
2834            req.push_str("\r\n");
2835            req
2836        }
2837        fn parse(max_headers: Option<usize>, gen_size: usize, should_success: bool) {
2838            {
2839                // server side
2840                let mut bytes = BytesMut::from(gen_req_with_headers(gen_size).as_str());
2841                let result = Server::parse(
2842                    &mut bytes,
2843                    ParseContext {
2844                        cached_headers: &mut None,
2845                        req_method: &mut None,
2846                        h1_parser_config: Default::default(),
2847                        h1_max_headers: max_headers,
2848                        preserve_header_case: false,
2849                        #[cfg(feature = "ffi")]
2850                        preserve_header_order: false,
2851                        h09_responses: false,
2852                        #[cfg(feature = "client")]
2853                        on_informational: &mut None,
2854                    },
2855                );
2856                if should_success {
2857                    result.expect("parse ok").expect("parse complete");
2858                } else {
2859                    result.expect_err("parse should err");
2860                }
2861            }
2862            {
2863                // client side
2864                let mut bytes = BytesMut::from(gen_resp_with_headers(gen_size).as_str());
2865                let result = Client::parse(
2866                    &mut bytes,
2867                    ParseContext {
2868                        cached_headers: &mut None,
2869                        req_method: &mut None,
2870                        h1_parser_config: Default::default(),
2871                        h1_max_headers: max_headers,
2872                        preserve_header_case: false,
2873                        #[cfg(feature = "ffi")]
2874                        preserve_header_order: false,
2875                        h09_responses: false,
2876                        #[cfg(feature = "client")]
2877                        on_informational: &mut None,
2878                    },
2879                );
2880                if should_success {
2881                    result.expect("parse ok").expect("parse complete");
2882                } else {
2883                    result.expect_err("parse should err");
2884                }
2885            }
2886        }
2887
2888        // check generator
2889        assert_eq!(
2890            gen_req_with_headers(0),
2891            String::from("GET / HTTP/1.1\r\n\r\n")
2892        );
2893        assert_eq!(
2894            gen_req_with_headers(1),
2895            String::from("GET / HTTP/1.1\r\nkey0: val0\r\n\r\n")
2896        );
2897        assert_eq!(
2898            gen_req_with_headers(2),
2899            String::from("GET / HTTP/1.1\r\nkey0: val0\r\nkey1: val1\r\n\r\n")
2900        );
2901        assert_eq!(
2902            gen_req_with_headers(3),
2903            String::from("GET / HTTP/1.1\r\nkey0: val0\r\nkey1: val1\r\nkey2: val2\r\n\r\n")
2904        );
2905
2906        // default max_headers is 100, so
2907        //
2908        // - less than or equal to 100, accepted
2909        //
2910        parse(None, 0, true);
2911        parse(None, 1, true);
2912        parse(None, 50, true);
2913        parse(None, 99, true);
2914        parse(None, 100, true);
2915        //
2916        // - more than 100, rejected
2917        //
2918        parse(None, 101, false);
2919        parse(None, 102, false);
2920        parse(None, 200, false);
2921
2922        // max_headers is 0, parser will reject any headers
2923        //
2924        // - without header, accepted
2925        //
2926        parse(Some(0), 0, true);
2927        //
2928        // - with header(s), rejected
2929        //
2930        parse(Some(0), 1, false);
2931        parse(Some(0), 100, false);
2932
2933        // max_headers is 200
2934        //
2935        // - less than or equal to 200, accepted
2936        //
2937        parse(Some(200), 0, true);
2938        parse(Some(200), 1, true);
2939        parse(Some(200), 100, true);
2940        parse(Some(200), 200, true);
2941        //
2942        // - more than 200, rejected
2943        //
2944        parse(Some(200), 201, false);
2945        parse(Some(200), 210, false);
2946    }
2947
2948    #[test]
2949    fn test_is_complete_fast() {
2950        let s = b"GET / HTTP/1.1\r\na: b\r\n\r\n";
2951        for n in 0..s.len() {
2952            assert!(is_complete_fast(s, n), "{:?}; {}", s, n);
2953        }
2954        let s = b"GET / HTTP/1.1\na: b\n\n";
2955        for n in 0..s.len() {
2956            assert!(is_complete_fast(s, n));
2957        }
2958
2959        // Not
2960        let s = b"GET / HTTP/1.1\r\na: b\r\n\r";
2961        for n in 0..s.len() {
2962            assert!(!is_complete_fast(s, n));
2963        }
2964        let s = b"GET / HTTP/1.1\na: b\n";
2965        for n in 0..s.len() {
2966            assert!(!is_complete_fast(s, n));
2967        }
2968    }
2969
2970    #[test]
2971    fn test_write_headers_orig_case_empty_value() {
2972        let mut headers = HeaderMap::new();
2973        let name = http::header::HeaderName::from_static("x-empty");
2974        headers.insert(&name, "".parse().expect("parse empty"));
2975        let mut orig_cases = HeaderCaseMap::default();
2976        orig_cases.insert(name, Bytes::from_static(b"X-EmptY"));
2977
2978        let mut dst = Vec::new();
2979        super::write_headers_original_case(&headers, &orig_cases, &mut dst, false);
2980
2981        assert_eq!(
2982            dst, b"X-EmptY:\r\n",
2983            "there should be no space between the colon and CRLF"
2984        );
2985    }
2986
2987    #[test]
2988    fn test_write_headers_orig_case_multiple_entries() {
2989        let mut headers = HeaderMap::new();
2990        let name = http::header::HeaderName::from_static("x-empty");
2991        headers.insert(&name, "a".parse().unwrap());
2992        headers.append(&name, "b".parse().unwrap());
2993
2994        let mut orig_cases = HeaderCaseMap::default();
2995        orig_cases.insert(name.clone(), Bytes::from_static(b"X-Empty"));
2996        orig_cases.append(name, Bytes::from_static(b"X-EMPTY"));
2997
2998        let mut dst = Vec::new();
2999        super::write_headers_original_case(&headers, &orig_cases, &mut dst, false);
3000
3001        assert_eq!(dst, b"X-Empty: a\r\nX-EMPTY: b\r\n");
3002    }
3003
3004    #[cfg(feature = "nightly")]
3005    use test::Bencher;
3006
3007    #[cfg(feature = "nightly")]
3008    #[bench]
3009    fn bench_parse_incoming(b: &mut Bencher) {
3010        let mut raw = BytesMut::from(
3011            &b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\
3012            I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\
3013            _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\
3014            foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \
3015            hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \
3016            utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\
3017            Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\
3018            Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\
3019            Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\
3020            Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\
3021            \r\nSec-Websocket-Extensions: It looks super important!\r\n\
3022            Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\
3023            \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\
3024            X-Content-Duration: None\r\nX-Content-Security-Policy: None\
3025            \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \
3026            Something important obviously\r\nX-Requested-With: Nothing\
3027            \r\n\r\n"[..],
3028        );
3029        let len = raw.len();
3030        let mut headers = Some(HeaderMap::new());
3031
3032        b.bytes = len as u64;
3033        b.iter(|| {
3034            let mut msg = Server::parse(
3035                &mut raw,
3036                ParseContext {
3037                    cached_headers: &mut headers,
3038                    req_method: &mut None,
3039                    h1_parser_config: Default::default(),
3040                    h1_max_headers: None,
3041                    preserve_header_case: false,
3042                    #[cfg(feature = "ffi")]
3043                    preserve_header_order: false,
3044                    h09_responses: false,
3045                    #[cfg(feature = "client")]
3046                    on_informational: &mut None,
3047                },
3048            )
3049            .unwrap()
3050            .unwrap();
3051            ::test::black_box(&msg);
3052
3053            // Remove all references pointing into BytesMut.
3054            msg.head.headers.clear();
3055            headers = Some(msg.head.headers);
3056            std::mem::take(&mut msg.head.subject);
3057
3058            restart(&mut raw, len);
3059        });
3060
3061        fn restart(b: &mut BytesMut, len: usize) {
3062            b.reserve(1);
3063            unsafe {
3064                b.set_len(len);
3065            }
3066        }
3067    }
3068
3069    #[cfg(feature = "nightly")]
3070    #[bench]
3071    fn bench_parse_short(b: &mut Bencher) {
3072        let s = &b"GET / HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"[..];
3073        let mut raw = BytesMut::from(s);
3074        let len = raw.len();
3075        let mut headers = Some(HeaderMap::new());
3076
3077        b.bytes = len as u64;
3078        b.iter(|| {
3079            let mut msg = Server::parse(
3080                &mut raw,
3081                ParseContext {
3082                    cached_headers: &mut headers,
3083                    req_method: &mut None,
3084                    h1_parser_config: Default::default(),
3085                    h1_max_headers: None,
3086                    preserve_header_case: false,
3087                    #[cfg(feature = "ffi")]
3088                    preserve_header_order: false,
3089                    h09_responses: false,
3090                    #[cfg(feature = "client")]
3091                    on_informational: &mut None,
3092                },
3093            )
3094            .unwrap()
3095            .unwrap();
3096            ::test::black_box(&msg);
3097            msg.head.headers.clear();
3098            headers = Some(msg.head.headers);
3099            restart(&mut raw, len);
3100        });
3101
3102        fn restart(b: &mut BytesMut, len: usize) {
3103            b.reserve(1);
3104            unsafe {
3105                b.set_len(len);
3106            }
3107        }
3108    }
3109
3110    #[cfg(feature = "nightly")]
3111    #[bench]
3112    fn bench_server_encode_headers_preset(b: &mut Bencher) {
3113        use crate::proto::BodyLength;
3114        use http::header::HeaderValue;
3115
3116        let len = 108;
3117        b.bytes = len as u64;
3118
3119        let mut head = MessageHead::default();
3120        let mut headers = HeaderMap::new();
3121        headers.insert("content-length", HeaderValue::from_static("10"));
3122        headers.insert("content-type", HeaderValue::from_static("application/json"));
3123
3124        b.iter(|| {
3125            let mut vec = Vec::new();
3126            head.headers = headers.clone();
3127            Server::encode(
3128                Encode {
3129                    head: &mut head,
3130                    body: Some(BodyLength::Known(10)),
3131                    keep_alive: true,
3132                    req_method: &mut Some(Method::GET),
3133                    title_case_headers: false,
3134                    date_header: true,
3135                },
3136                &mut vec,
3137            )
3138            .unwrap();
3139            assert_eq!(vec.len(), len);
3140            ::test::black_box(vec);
3141        })
3142    }
3143
3144    #[cfg(feature = "nightly")]
3145    #[bench]
3146    fn bench_server_encode_no_headers(b: &mut Bencher) {
3147        use crate::proto::BodyLength;
3148
3149        let len = 76;
3150        b.bytes = len as u64;
3151
3152        let mut head = MessageHead::default();
3153        let mut vec = Vec::with_capacity(128);
3154
3155        b.iter(|| {
3156            Server::encode(
3157                Encode {
3158                    head: &mut head,
3159                    body: Some(BodyLength::Known(10)),
3160                    keep_alive: true,
3161                    req_method: &mut Some(Method::GET),
3162                    title_case_headers: false,
3163                    date_header: true,
3164                },
3165                &mut vec,
3166            )
3167            .unwrap();
3168            assert_eq!(vec.len(), len);
3169            ::test::black_box(&vec);
3170
3171            vec.clear();
3172        })
3173    }
3174}