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