1 // `mem::uninitialized` replaced with `mem::MaybeUninit`,
2 // can't upgrade yet
3 #![allow(deprecated)]
4 
5 use std::fmt::{self, Write};
6 use std::mem;
7 
8 use bytes::BytesMut;
9 use http::header::{self, Entry, HeaderName, HeaderValue};
10 use http::{HeaderMap, Method, StatusCode, Version};
11 
12 use crate::error::Parse;
13 use crate::headers;
14 use crate::proto::h1::{
15     date, Encode, Encoder, Http1Transaction, ParseContext, ParseResult, ParsedMessage,
16 };
17 use crate::proto::{BodyLength, DecodedLength, MessageHead, RequestHead, RequestLine};
18 
19 const MAX_HEADERS: usize = 100;
20 const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
21 
22 macro_rules! header_name {
23     ($bytes:expr) => {{
24         #[cfg(debug_assertions)]
25         {
26             match HeaderName::from_bytes($bytes) {
27                 Ok(name) => name,
28                 Err(_) => panic!(
29                     "illegal header name from httparse: {:?}",
30                     ::bytes::Bytes::copy_from_slice($bytes)
31                 ),
32             }
33         }
34 
35         #[cfg(not(debug_assertions))]
36         {
37             HeaderName::from_bytes($bytes).expect("header name validated by httparse")
38         }
39     }};
40 }
41 
42 macro_rules! header_value {
43     ($bytes:expr) => {{
44         #[cfg(debug_assertions)]
45         {
46             let __hvb: ::bytes::Bytes = $bytes;
47             match HeaderValue::from_maybe_shared(__hvb.clone()) {
48                 Ok(name) => name,
49                 Err(_) => panic!("illegal header value from httparse: {:?}", __hvb),
50             }
51         }
52 
53         #[cfg(not(debug_assertions))]
54         {
55             // Unsafe: httparse already validated header value
56             unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) }
57         }
58     }};
59 }
60 
61 // There are 2 main roles, Client and Server.
62 
63 pub(crate) enum Client {}
64 
65 pub(crate) enum Server {}
66 
67 impl Http1Transaction for Server {
68     type Incoming = RequestLine;
69     type Outgoing = StatusCode;
70     const LOG: &'static str = "{role=server}";
71 
parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<RequestLine>72     fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<RequestLine> {
73         if buf.is_empty() {
74             return Ok(None);
75         }
76 
77         let mut keep_alive;
78         let is_http_11;
79         let subject;
80         let version;
81         let len;
82         let headers_len;
83 
84         // Unsafe: both headers_indices and headers are using uninitialized memory,
85         // but we *never* read any of it until after httparse has assigned
86         // values into it. By not zeroing out the stack memory, this saves
87         // a good ~5% on pipeline benchmarks.
88         let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() };
89         {
90             let mut headers: [httparse::Header<'_>; MAX_HEADERS] = unsafe { mem::uninitialized() };
91             trace!(
92                 "Request.parse([Header; {}], [u8; {}])",
93                 headers.len(),
94                 buf.len()
95             );
96             let mut req = httparse::Request::new(&mut headers);
97             let bytes = buf.as_ref();
98             match req.parse(bytes) {
99                 Ok(httparse::Status::Complete(parsed_len)) => {
100                     trace!("Request.parse Complete({})", parsed_len);
101                     len = parsed_len;
102                     subject = RequestLine(
103                         Method::from_bytes(req.method.unwrap().as_bytes())?,
104                         req.path.unwrap().parse()?,
105                     );
106                     version = if req.version.unwrap() == 1 {
107                         keep_alive = true;
108                         is_http_11 = true;
109                         Version::HTTP_11
110                     } else {
111                         keep_alive = false;
112                         is_http_11 = false;
113                         Version::HTTP_10
114                     };
115 
116                     record_header_indices(bytes, &req.headers, &mut headers_indices)?;
117                     headers_len = req.headers.len();
118                 }
119                 Ok(httparse::Status::Partial) => return Ok(None),
120                 Err(err) => {
121                     return Err(match err {
122                         // if invalid Token, try to determine if for method or path
123                         httparse::Error::Token => {
124                             if req.method.is_none() {
125                                 Parse::Method
126                             } else {
127                                 debug_assert!(req.path.is_none());
128                                 Parse::Uri
129                             }
130                         }
131                         other => other.into(),
132                     });
133                 }
134             }
135         };
136 
137         let slice = buf.split_to(len).freeze();
138 
139         // According to https://tools.ietf.org/html/rfc7230#section-3.3.3
140         // 1. (irrelevant to Request)
141         // 2. (irrelevant to Request)
142         // 3. Transfer-Encoding: chunked has a chunked body.
143         // 4. If multiple differing Content-Length headers or invalid, close connection.
144         // 5. Content-Length header has a sized body.
145         // 6. Length 0.
146         // 7. (irrelevant to Request)
147 
148         let mut decoder = DecodedLength::ZERO;
149         let mut expect_continue = false;
150         let mut con_len = None;
151         let mut is_te = false;
152         let mut is_te_chunked = false;
153         let mut wants_upgrade = subject.0 == Method::CONNECT;
154 
155         let mut headers = ctx.cached_headers.take().unwrap_or_else(HeaderMap::new);
156 
157         headers.reserve(headers_len);
158 
159         for header in &headers_indices[..headers_len] {
160             let name = header_name!(&slice[header.name.0..header.name.1]);
161             let value = header_value!(slice.slice(header.value.0..header.value.1));
162 
163             match name {
164                 header::TRANSFER_ENCODING => {
165                     // https://tools.ietf.org/html/rfc7230#section-3.3.3
166                     // If Transfer-Encoding header is present, and 'chunked' is
167                     // not the final encoding, and this is a Request, then it is
168                     // malformed. A server should respond with 400 Bad Request.
169                     if !is_http_11 {
170                         debug!("HTTP/1.0 cannot have Transfer-Encoding header");
171                         return Err(Parse::Header);
172                     }
173                     is_te = true;
174                     if headers::is_chunked_(&value) {
175                         is_te_chunked = true;
176                         decoder = DecodedLength::CHUNKED;
177                     }
178                 }
179                 header::CONTENT_LENGTH => {
180                     if is_te {
181                         continue;
182                     }
183                     let len = value
184                         .to_str()
185                         .map_err(|_| Parse::Header)
186                         .and_then(|s| s.parse().map_err(|_| Parse::Header))?;
187                     if let Some(prev) = con_len {
188                         if prev != len {
189                             debug!(
190                                 "multiple Content-Length headers with different values: [{}, {}]",
191                                 prev, len,
192                             );
193                             return Err(Parse::Header);
194                         }
195                         // we don't need to append this secondary length
196                         continue;
197                     }
198                     decoder = DecodedLength::checked_new(len)?;
199                     con_len = Some(len);
200                 }
201                 header::CONNECTION => {
202                     // keep_alive was previously set to default for Version
203                     if keep_alive {
204                         // HTTP/1.1
205                         keep_alive = !headers::connection_close(&value);
206                     } else {
207                         // HTTP/1.0
208                         keep_alive = headers::connection_keep_alive(&value);
209                     }
210                 }
211                 header::EXPECT => {
212                     expect_continue = value.as_bytes() == b"100-continue";
213                 }
214                 header::UPGRADE => {
215                     // Upgrades are only allowed with HTTP/1.1
216                     wants_upgrade = is_http_11;
217                 }
218 
219                 _ => (),
220             }
221 
222             headers.append(name, value);
223         }
224 
225         if is_te && !is_te_chunked {
226             debug!("request with transfer-encoding header, but not chunked, bad request");
227             return Err(Parse::Header);
228         }
229 
230         *ctx.req_method = Some(subject.0.clone());
231 
232         Ok(Some(ParsedMessage {
233             head: MessageHead {
234                 version,
235                 subject,
236                 headers,
237             },
238             decode: decoder,
239             expect_continue,
240             keep_alive,
241             wants_upgrade,
242         }))
243     }
244 
encode( mut msg: Encode<'_, Self::Outgoing>, mut dst: &mut Vec<u8>, ) -> crate::Result<Encoder>245     fn encode(
246         mut msg: Encode<'_, Self::Outgoing>,
247         mut dst: &mut Vec<u8>,
248     ) -> crate::Result<Encoder> {
249         trace!(
250             "Server::encode status={:?}, body={:?}, req_method={:?}",
251             msg.head.subject,
252             msg.body,
253             msg.req_method
254         );
255         debug_assert!(
256             !msg.title_case_headers,
257             "no server config for title case headers"
258         );
259 
260         let mut wrote_len = false;
261 
262         // hyper currently doesn't support returning 1xx status codes as a Response
263         // This is because Service only allows returning a single Response, and
264         // so if you try to reply with a e.g. 100 Continue, you have no way of
265         // replying with the latter status code response.
266         let (ret, mut is_last) = if msg.head.subject == StatusCode::SWITCHING_PROTOCOLS {
267             (Ok(()), true)
268         } else if msg.req_method == &Some(Method::CONNECT) && msg.head.subject.is_success() {
269             // Sending content-length or transfer-encoding header on 2xx response
270             // to CONNECT is forbidden in RFC 7231.
271             wrote_len = true;
272             (Ok(()), true)
273         } else if msg.head.subject.is_informational() {
274             warn!("response with 1xx status code not supported");
275             *msg.head = MessageHead::default();
276             msg.head.subject = StatusCode::INTERNAL_SERVER_ERROR;
277             msg.body = None;
278             (Err(crate::Error::new_user_unsupported_status_code()), true)
279         } else {
280             (Ok(()), !msg.keep_alive)
281         };
282 
283         // In some error cases, we don't know about the invalid message until already
284         // pushing some bytes onto the `dst`. In those cases, we don't want to send
285         // the half-pushed message, so rewind to before.
286         let orig_len = dst.len();
287         let rewind = |dst: &mut Vec<u8>| {
288             dst.truncate(orig_len);
289         };
290 
291         let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE;
292         dst.reserve(init_cap);
293         if msg.head.version == Version::HTTP_11 && msg.head.subject == StatusCode::OK {
294             extend(dst, b"HTTP/1.1 200 OK\r\n");
295         } else {
296             match msg.head.version {
297                 Version::HTTP_10 => extend(dst, b"HTTP/1.0 "),
298                 Version::HTTP_11 => extend(dst, b"HTTP/1.1 "),
299                 Version::HTTP_2 => {
300                     warn!("response with HTTP2 version coerced to HTTP/1.1");
301                     extend(dst, b"HTTP/1.1 ");
302                 }
303                 other => panic!("unexpected response version: {:?}", other),
304             }
305 
306             extend(dst, msg.head.subject.as_str().as_bytes());
307             extend(dst, b" ");
308             // a reason MUST be written, as many parsers will expect it.
309             extend(
310                 dst,
311                 msg.head
312                     .subject
313                     .canonical_reason()
314                     .unwrap_or("<none>")
315                     .as_bytes(),
316             );
317             extend(dst, b"\r\n");
318         }
319 
320         let mut encoder = Encoder::length(0);
321         let mut wrote_date = false;
322         let mut cur_name = None;
323         let mut is_name_written = false;
324         let mut must_write_chunked = false;
325         let mut prev_con_len = None;
326 
327         macro_rules! handle_is_name_written {
328             () => {{
329                 if is_name_written {
330                     // we need to clean up and write the newline
331                     debug_assert_ne!(
332                         &dst[dst.len() - 2..],
333                         b"\r\n",
334                         "previous header wrote newline but set is_name_written"
335                     );
336 
337                     if must_write_chunked {
338                         extend(dst, b", chunked\r\n");
339                     } else {
340                         extend(dst, b"\r\n");
341                     }
342                 }
343             }};
344         }
345 
346         'headers: for (opt_name, value) in msg.head.headers.drain() {
347             if let Some(n) = opt_name {
348                 cur_name = Some(n);
349                 handle_is_name_written!();
350                 is_name_written = false;
351             }
352             let name = cur_name.as_ref().expect("current header name");
353             match *name {
354                 header::CONTENT_LENGTH => {
355                     if wrote_len && !is_name_written {
356                         warn!("unexpected content-length found, canceling");
357                         rewind(dst);
358                         return Err(crate::Error::new_user_header());
359                     }
360                     match msg.body {
361                         Some(BodyLength::Known(known_len)) => {
362                             // The HttpBody claims to know a length, and
363                             // the headers are already set. For performance
364                             // reasons, we are just going to trust that
365                             // the values match.
366                             //
367                             // In debug builds, we'll assert they are the
368                             // same to help developers find bugs.
369                             #[cfg(debug_assertions)]
370                             {
371                                 if let Some(len) = headers::content_length_parse(&value) {
372                                     assert!(
373                                         len == known_len,
374                                         "payload claims content-length of {}, custom content-length header claims {}",
375                                         known_len,
376                                         len,
377                                     );
378                                 }
379                             }
380 
381                             if !is_name_written {
382                                 encoder = Encoder::length(known_len);
383                                 extend(dst, b"content-length: ");
384                                 extend(dst, value.as_bytes());
385                                 wrote_len = true;
386                                 is_name_written = true;
387                             }
388                             continue 'headers;
389                         }
390                         Some(BodyLength::Unknown) => {
391                             // The HttpBody impl didn't know how long the
392                             // body is, but a length header was included.
393                             // We have to parse the value to return our
394                             // Encoder...
395 
396                             if let Some(len) = headers::content_length_parse(&value) {
397                                 if let Some(prev) = prev_con_len {
398                                     if prev != len {
399                                         warn!(
400                                             "multiple Content-Length values found: [{}, {}]",
401                                             prev, len
402                                         );
403                                         rewind(dst);
404                                         return Err(crate::Error::new_user_header());
405                                     }
406                                     debug_assert!(is_name_written);
407                                     continue 'headers;
408                                 } else {
409                                     // we haven't written content-length yet!
410                                     encoder = Encoder::length(len);
411                                     extend(dst, b"content-length: ");
412                                     extend(dst, value.as_bytes());
413                                     wrote_len = true;
414                                     is_name_written = true;
415                                     prev_con_len = Some(len);
416                                     continue 'headers;
417                                 }
418                             } else {
419                                 warn!("illegal Content-Length value: {:?}", value);
420                                 rewind(dst);
421                                 return Err(crate::Error::new_user_header());
422                             }
423                         }
424                         None => {
425                             // We have no body to actually send,
426                             // but the headers claim a content-length.
427                             // There's only 2 ways this makes sense:
428                             //
429                             // - The header says the length is `0`.
430                             // - This is a response to a `HEAD` request.
431                             if msg.req_method == &Some(Method::HEAD) {
432                                 debug_assert_eq!(encoder, Encoder::length(0));
433                             } else {
434                                 if value.as_bytes() != b"0" {
435                                     warn!(
436                                         "content-length value found, but empty body provided: {:?}",
437                                         value
438                                     );
439                                 }
440                                 continue 'headers;
441                             }
442                         }
443                     }
444                     wrote_len = true;
445                 }
446                 header::TRANSFER_ENCODING => {
447                     if wrote_len && !is_name_written {
448                         warn!("unexpected transfer-encoding found, canceling");
449                         rewind(dst);
450                         return Err(crate::Error::new_user_header());
451                     }
452                     // check that we actually can send a chunked body...
453                     if msg.head.version == Version::HTTP_10
454                         || !Server::can_chunked(msg.req_method, msg.head.subject)
455                     {
456                         continue;
457                     }
458                     wrote_len = true;
459                     // Must check each value, because `chunked` needs to be the
460                     // last encoding, or else we add it.
461                     must_write_chunked = !headers::is_chunked_(&value);
462 
463                     if !is_name_written {
464                         encoder = Encoder::chunked();
465                         is_name_written = true;
466                         extend(dst, b"transfer-encoding: ");
467                         extend(dst, value.as_bytes());
468                     } else {
469                         extend(dst, b", ");
470                         extend(dst, value.as_bytes());
471                     }
472                     continue 'headers;
473                 }
474                 header::CONNECTION => {
475                     if !is_last && headers::connection_close(&value) {
476                         is_last = true;
477                     }
478                     if !is_name_written {
479                         is_name_written = true;
480                         extend(dst, b"connection: ");
481                         extend(dst, value.as_bytes());
482                     } else {
483                         extend(dst, b", ");
484                         extend(dst, value.as_bytes());
485                     }
486                     continue 'headers;
487                 }
488                 header::DATE => {
489                     wrote_date = true;
490                 }
491                 _ => (),
492             }
493             //TODO: this should perhaps instead combine them into
494             //single lines, as RFC7230 suggests is preferable.
495 
496             // non-special write Name and Value
497             debug_assert!(
498                 !is_name_written,
499                 "{:?} set is_name_written and didn't continue loop",
500                 name,
501             );
502             extend(dst, name.as_str().as_bytes());
503             extend(dst, b": ");
504             extend(dst, value.as_bytes());
505             extend(dst, b"\r\n");
506         }
507 
508         handle_is_name_written!();
509 
510         if !wrote_len {
511             encoder = match msg.body {
512                 Some(BodyLength::Unknown) => {
513                     if msg.head.version == Version::HTTP_10
514                         || !Server::can_chunked(msg.req_method, msg.head.subject)
515                     {
516                         Encoder::close_delimited()
517                     } else {
518                         extend(dst, b"transfer-encoding: chunked\r\n");
519                         Encoder::chunked()
520                     }
521                 }
522                 None | Some(BodyLength::Known(0)) => {
523                     if msg.head.subject != StatusCode::NOT_MODIFIED {
524                         extend(dst, b"content-length: 0\r\n");
525                     }
526                     Encoder::length(0)
527                 }
528                 Some(BodyLength::Known(len)) => {
529                     if msg.head.subject == StatusCode::NOT_MODIFIED {
530                         Encoder::length(0)
531                     } else {
532                         extend(dst, b"content-length: ");
533                         let _ = ::itoa::write(&mut dst, len);
534                         extend(dst, b"\r\n");
535                         Encoder::length(len)
536                     }
537                 }
538             };
539         }
540 
541         if !Server::can_have_body(msg.req_method, msg.head.subject) {
542             trace!(
543                 "server body forced to 0; method={:?}, status={:?}",
544                 msg.req_method,
545                 msg.head.subject
546             );
547             encoder = Encoder::length(0);
548         }
549 
550         // cached date is much faster than formatting every request
551         if !wrote_date {
552             dst.reserve(date::DATE_VALUE_LENGTH + 8);
553             extend(dst, b"date: ");
554             date::extend(dst);
555             extend(dst, b"\r\n\r\n");
556         } else {
557             extend(dst, b"\r\n");
558         }
559 
560         ret.map(|()| encoder.set_last(is_last))
561     }
562 
on_error(err: &crate::Error) -> Option<MessageHead<Self::Outgoing>>563     fn on_error(err: &crate::Error) -> Option<MessageHead<Self::Outgoing>> {
564         use crate::error::Kind;
565         let status = match *err.kind() {
566             Kind::Parse(Parse::Method)
567             | Kind::Parse(Parse::Header)
568             | Kind::Parse(Parse::Uri)
569             | Kind::Parse(Parse::Version) => StatusCode::BAD_REQUEST,
570             Kind::Parse(Parse::TooLarge) => StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
571             _ => return None,
572         };
573 
574         debug!("sending automatic response ({}) for parse error", status);
575         let mut msg = MessageHead::default();
576         msg.subject = status;
577         Some(msg)
578     }
579 
is_server() -> bool580     fn is_server() -> bool {
581         true
582     }
583 
update_date()584     fn update_date() {
585         date::update();
586     }
587 }
588 
589 impl Server {
can_have_body(method: &Option<Method>, status: StatusCode) -> bool590     fn can_have_body(method: &Option<Method>, status: StatusCode) -> bool {
591         Server::can_chunked(method, status)
592     }
593 
can_chunked(method: &Option<Method>, status: StatusCode) -> bool594     fn can_chunked(method: &Option<Method>, status: StatusCode) -> bool {
595         if method == &Some(Method::HEAD) || method == &Some(Method::CONNECT) && status.is_success()
596         {
597             false
598         } else {
599             match status {
600                 // TODO: support for 1xx codes needs improvement everywhere
601                 // would be 100...199 => false
602                 StatusCode::SWITCHING_PROTOCOLS
603                 | StatusCode::NO_CONTENT
604                 | StatusCode::NOT_MODIFIED => false,
605                 _ => true,
606             }
607         }
608     }
609 }
610 
611 impl Http1Transaction for Client {
612     type Incoming = StatusCode;
613     type Outgoing = RequestLine;
614     const LOG: &'static str = "{role=client}";
615 
parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<StatusCode>616     fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<StatusCode> {
617         // Loop to skip information status code headers (100 Continue, etc).
618         loop {
619             if buf.is_empty() {
620                 return Ok(None);
621             }
622             // Unsafe: see comment in Server Http1Transaction, above.
623             let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() };
624             let (len, status, version, headers_len) = {
625                 let mut headers: [httparse::Header<'_>; MAX_HEADERS] =
626                     unsafe { mem::uninitialized() };
627                 trace!(
628                     "Response.parse([Header; {}], [u8; {}])",
629                     headers.len(),
630                     buf.len()
631                 );
632                 let mut res = httparse::Response::new(&mut headers);
633                 let bytes = buf.as_ref();
634                 match res.parse(bytes)? {
635                     httparse::Status::Complete(len) => {
636                         trace!("Response.parse Complete({})", len);
637                         let status = StatusCode::from_u16(res.code.unwrap())?;
638                         let version = if res.version.unwrap() == 1 {
639                             Version::HTTP_11
640                         } else {
641                             Version::HTTP_10
642                         };
643                         record_header_indices(bytes, &res.headers, &mut headers_indices)?;
644                         let headers_len = res.headers.len();
645                         (len, status, version, headers_len)
646                     }
647                     httparse::Status::Partial => return Ok(None),
648                 }
649             };
650 
651             let slice = buf.split_to(len).freeze();
652 
653             let mut headers = ctx.cached_headers.take().unwrap_or_else(HeaderMap::new);
654 
655             let mut keep_alive = version == Version::HTTP_11;
656 
657             headers.reserve(headers_len);
658             for header in &headers_indices[..headers_len] {
659                 let name = header_name!(&slice[header.name.0..header.name.1]);
660                 let value = header_value!(slice.slice(header.value.0..header.value.1));
661 
662                 if let header::CONNECTION = name {
663                     // keep_alive was previously set to default for Version
664                     if keep_alive {
665                         // HTTP/1.1
666                         keep_alive = !headers::connection_close(&value);
667                     } else {
668                         // HTTP/1.0
669                         keep_alive = headers::connection_keep_alive(&value);
670                     }
671                 }
672                 headers.append(name, value);
673             }
674 
675             let head = MessageHead {
676                 version,
677                 subject: status,
678                 headers,
679             };
680             if let Some((decode, is_upgrade)) = Client::decoder(&head, ctx.req_method)? {
681                 return Ok(Some(ParsedMessage {
682                     head,
683                     decode,
684                     expect_continue: false,
685                     // a client upgrade means the connection can't be used
686                     // again, as it is definitely upgrading.
687                     keep_alive: keep_alive && !is_upgrade,
688                     wants_upgrade: is_upgrade,
689                 }));
690             }
691         }
692     }
693 
encode(msg: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder>694     fn encode(msg: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder> {
695         trace!(
696             "Client::encode method={:?}, body={:?}",
697             msg.head.subject.0,
698             msg.body
699         );
700 
701         *msg.req_method = Some(msg.head.subject.0.clone());
702 
703         let body = Client::set_length(msg.head, msg.body);
704 
705         let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE;
706         dst.reserve(init_cap);
707 
708         extend(dst, msg.head.subject.0.as_str().as_bytes());
709         extend(dst, b" ");
710         //TODO: add API to http::Uri to encode without std::fmt
711         let _ = write!(FastWrite(dst), "{} ", msg.head.subject.1);
712 
713         match msg.head.version {
714             Version::HTTP_10 => extend(dst, b"HTTP/1.0"),
715             Version::HTTP_11 => extend(dst, b"HTTP/1.1"),
716             Version::HTTP_2 => {
717                 warn!("request with HTTP2 version coerced to HTTP/1.1");
718                 extend(dst, b"HTTP/1.1");
719             }
720             other => panic!("unexpected request version: {:?}", other),
721         }
722         extend(dst, b"\r\n");
723 
724         if msg.title_case_headers {
725             write_headers_title_case(&msg.head.headers, dst);
726         } else {
727             write_headers(&msg.head.headers, dst);
728         }
729         extend(dst, b"\r\n");
730         msg.head.headers.clear(); //TODO: remove when switching to drain()
731 
732         Ok(body)
733     }
734 
on_error(_err: &crate::Error) -> Option<MessageHead<Self::Outgoing>>735     fn on_error(_err: &crate::Error) -> Option<MessageHead<Self::Outgoing>> {
736         // we can't tell the server about any errors it creates
737         None
738     }
739 
is_client() -> bool740     fn is_client() -> bool {
741         true
742     }
743 }
744 
745 impl Client {
746     /// Returns Some(length, wants_upgrade) if successful.
747     ///
748     /// Returns None if this message head should be skipped (like a 100 status).
decoder( inc: &MessageHead<StatusCode>, method: &mut Option<Method>, ) -> Result<Option<(DecodedLength, bool)>, Parse>749     fn decoder(
750         inc: &MessageHead<StatusCode>,
751         method: &mut Option<Method>,
752     ) -> Result<Option<(DecodedLength, bool)>, Parse> {
753         // According to https://tools.ietf.org/html/rfc7230#section-3.3.3
754         // 1. HEAD responses, and Status 1xx, 204, and 304 cannot have a body.
755         // 2. Status 2xx to a CONNECT cannot have a body.
756         // 3. Transfer-Encoding: chunked has a chunked body.
757         // 4. If multiple differing Content-Length headers or invalid, close connection.
758         // 5. Content-Length header has a sized body.
759         // 6. (irrelevant to Response)
760         // 7. Read till EOF.
761 
762         match inc.subject.as_u16() {
763             101 => {
764                 return Ok(Some((DecodedLength::ZERO, true)));
765             }
766             100 | 102..=199 => {
767                 trace!("ignoring informational response: {}", inc.subject.as_u16());
768                 return Ok(None);
769             }
770             204 | 304 => return Ok(Some((DecodedLength::ZERO, false))),
771             _ => (),
772         }
773         match *method {
774             Some(Method::HEAD) => {
775                 return Ok(Some((DecodedLength::ZERO, false)));
776             }
777             Some(Method::CONNECT) => {
778                 if let 200..=299 = inc.subject.as_u16() {
779                     return Ok(Some((DecodedLength::ZERO, true)));
780                 }
781             }
782             Some(_) => {}
783             None => {
784                 trace!("Client::decoder is missing the Method");
785             }
786         }
787 
788         if inc.headers.contains_key(header::TRANSFER_ENCODING) {
789             // https://tools.ietf.org/html/rfc7230#section-3.3.3
790             // If Transfer-Encoding header is present, and 'chunked' is
791             // not the final encoding, and this is a Request, then it is
792             // malformed. A server should respond with 400 Bad Request.
793             if inc.version == Version::HTTP_10 {
794                 debug!("HTTP/1.0 cannot have Transfer-Encoding header");
795                 Err(Parse::Header)
796             } else if headers::transfer_encoding_is_chunked(&inc.headers) {
797                 Ok(Some((DecodedLength::CHUNKED, false)))
798             } else {
799                 trace!("not chunked, read till eof");
800                 Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))
801             }
802         } else if let Some(len) = headers::content_length_parse_all(&inc.headers) {
803             Ok(Some((DecodedLength::checked_new(len)?, false)))
804         } else if inc.headers.contains_key(header::CONTENT_LENGTH) {
805             debug!("illegal Content-Length header");
806             Err(Parse::Header)
807         } else {
808             trace!("neither Transfer-Encoding nor Content-Length");
809             Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))
810         }
811     }
812 }
813 
814 impl Client {
set_length(head: &mut RequestHead, body: Option<BodyLength>) -> Encoder815     fn set_length(head: &mut RequestHead, body: Option<BodyLength>) -> Encoder {
816         let body = if let Some(body) = body {
817             body
818         } else {
819             head.headers.remove(header::TRANSFER_ENCODING);
820             return Encoder::length(0);
821         };
822 
823         // HTTP/1.0 doesn't know about chunked
824         let can_chunked = head.version == Version::HTTP_11;
825         let headers = &mut head.headers;
826 
827         // If the user already set specific headers, we should respect them, regardless
828         // of what the HttpBody knows about itself. They set them for a reason.
829 
830         // Because of the borrow checker, we can't check the for an existing
831         // Content-Length header while holding an `Entry` for the Transfer-Encoding
832         // header, so unfortunately, we must do the check here, first.
833 
834         let existing_con_len = headers::content_length_parse_all(headers);
835         let mut should_remove_con_len = false;
836 
837         if !can_chunked {
838             // Chunked isn't legal, so if it is set, we need to remove it.
839             if headers.remove(header::TRANSFER_ENCODING).is_some() {
840                 trace!("removing illegal transfer-encoding header");
841             }
842 
843             return if let Some(len) = existing_con_len {
844                 Encoder::length(len)
845             } else if let BodyLength::Known(len) = body {
846                 set_content_length(headers, len)
847             } else {
848                 // HTTP/1.0 client requests without a content-length
849                 // cannot have any body at all.
850                 Encoder::length(0)
851             };
852         }
853 
854         // If the user set a transfer-encoding, respect that. Let's just
855         // make sure `chunked` is the final encoding.
856         let encoder = match headers.entry(header::TRANSFER_ENCODING) {
857             Entry::Occupied(te) => {
858                 should_remove_con_len = true;
859                 if headers::is_chunked(te.iter()) {
860                     Some(Encoder::chunked())
861                 } else {
862                     warn!("user provided transfer-encoding does not end in 'chunked'");
863 
864                     // There's a Transfer-Encoding, but it doesn't end in 'chunked'!
865                     // An example that could trigger this:
866                     //
867                     //     Transfer-Encoding: gzip
868                     //
869                     // This can be bad, depending on if this is a request or a
870                     // response.
871                     //
872                     // - A request is illegal if there is a `Transfer-Encoding`
873                     //   but it doesn't end in `chunked`.
874                     // - A response that has `Transfer-Encoding` but doesn't
875                     //   end in `chunked` isn't illegal, it just forces this
876                     //   to be close-delimited.
877                     //
878                     // We can try to repair this, by adding `chunked` ourselves.
879 
880                     headers::add_chunked(te);
881                     Some(Encoder::chunked())
882                 }
883             }
884             Entry::Vacant(te) => {
885                 if let Some(len) = existing_con_len {
886                     Some(Encoder::length(len))
887                 } else if let BodyLength::Unknown = body {
888                     // GET, HEAD, and CONNECT almost never have bodies.
889                     //
890                     // So instead of sending a "chunked" body with a 0-chunk,
891                     // assume no body here. If you *must* send a body,
892                     // set the headers explicitly.
893                     match head.subject.0 {
894                         Method::GET | Method::HEAD | Method::CONNECT => Some(Encoder::length(0)),
895                         _ => {
896                             te.insert(HeaderValue::from_static("chunked"));
897                             Some(Encoder::chunked())
898                         }
899                     }
900                 } else {
901                     None
902                 }
903             }
904         };
905 
906         // This is because we need a second mutable borrow to remove
907         // content-length header.
908         if let Some(encoder) = encoder {
909             if should_remove_con_len && existing_con_len.is_some() {
910                 headers.remove(header::CONTENT_LENGTH);
911             }
912             return encoder;
913         }
914 
915         // User didn't set transfer-encoding, AND we know body length,
916         // so we can just set the Content-Length automatically.
917 
918         let len = if let BodyLength::Known(len) = body {
919             len
920         } else {
921             unreachable!("BodyLength::Unknown would set chunked");
922         };
923 
924         set_content_length(headers, len)
925     }
926 }
927 
set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder928 fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder {
929     // At this point, there should not be a valid Content-Length
930     // header. However, since we'll be indexing in anyways, we can
931     // warn the user if there was an existing illegal header.
932     //
933     // Or at least, we can in theory. It's actually a little bit slower,
934     // so perhaps only do that while the user is developing/testing.
935 
936     if cfg!(debug_assertions) {
937         match headers.entry(header::CONTENT_LENGTH) {
938             Entry::Occupied(mut cl) => {
939                 // Internal sanity check, we should have already determined
940                 // that the header was illegal before calling this function.
941                 debug_assert!(headers::content_length_parse_all_values(cl.iter()).is_none());
942                 // Uh oh, the user set `Content-Length` headers, but set bad ones.
943                 // This would be an illegal message anyways, so let's try to repair
944                 // with our known good length.
945                 error!("user provided content-length header was invalid");
946 
947                 cl.insert(HeaderValue::from(len));
948                 Encoder::length(len)
949             }
950             Entry::Vacant(cl) => {
951                 cl.insert(HeaderValue::from(len));
952                 Encoder::length(len)
953             }
954         }
955     } else {
956         headers.insert(header::CONTENT_LENGTH, HeaderValue::from(len));
957         Encoder::length(len)
958     }
959 }
960 
961 #[derive(Clone, Copy)]
962 struct HeaderIndices {
963     name: (usize, usize),
964     value: (usize, usize),
965 }
966 
record_header_indices( bytes: &[u8], headers: &[httparse::Header<'_>], indices: &mut [HeaderIndices], ) -> Result<(), crate::error::Parse>967 fn record_header_indices(
968     bytes: &[u8],
969     headers: &[httparse::Header<'_>],
970     indices: &mut [HeaderIndices],
971 ) -> Result<(), crate::error::Parse> {
972     let bytes_ptr = bytes.as_ptr() as usize;
973 
974     for (header, indices) in headers.iter().zip(indices.iter_mut()) {
975         if header.name.len() >= (1 << 16) {
976             debug!("header name larger than 64kb: {:?}", header.name);
977             return Err(crate::error::Parse::TooLarge);
978         }
979         let name_start = header.name.as_ptr() as usize - bytes_ptr;
980         let name_end = name_start + header.name.len();
981         indices.name = (name_start, name_end);
982         let value_start = header.value.as_ptr() as usize - bytes_ptr;
983         let value_end = value_start + header.value.len();
984         indices.value = (value_start, value_end);
985     }
986 
987     Ok(())
988 }
989 
990 // Write header names as title case. The header name is assumed to be ASCII,
991 // therefore it is trivial to convert an ASCII character from lowercase to
992 // uppercase. It is as simple as XORing the lowercase character byte with
993 // space.
title_case(dst: &mut Vec<u8>, name: &[u8])994 fn title_case(dst: &mut Vec<u8>, name: &[u8]) {
995     dst.reserve(name.len());
996 
997     let mut iter = name.iter();
998 
999     // Uppercase the first character
1000     if let Some(c) = iter.next() {
1001         if *c >= b'a' && *c <= b'z' {
1002             dst.push(*c ^ b' ');
1003         } else {
1004             dst.push(*c);
1005         }
1006     }
1007 
1008     while let Some(c) = iter.next() {
1009         dst.push(*c);
1010 
1011         if *c == b'-' {
1012             if let Some(c) = iter.next() {
1013                 if *c >= b'a' && *c <= b'z' {
1014                     dst.push(*c ^ b' ');
1015                 } else {
1016                     dst.push(*c);
1017                 }
1018             }
1019         }
1020     }
1021 }
1022 
write_headers_title_case(headers: &HeaderMap, dst: &mut Vec<u8>)1023 fn write_headers_title_case(headers: &HeaderMap, dst: &mut Vec<u8>) {
1024     for (name, value) in headers {
1025         title_case(dst, name.as_str().as_bytes());
1026         extend(dst, b": ");
1027         extend(dst, value.as_bytes());
1028         extend(dst, b"\r\n");
1029     }
1030 }
1031 
write_headers(headers: &HeaderMap, dst: &mut Vec<u8>)1032 fn write_headers(headers: &HeaderMap, dst: &mut Vec<u8>) {
1033     for (name, value) in headers {
1034         extend(dst, name.as_str().as_bytes());
1035         extend(dst, b": ");
1036         extend(dst, value.as_bytes());
1037         extend(dst, b"\r\n");
1038     }
1039 }
1040 
1041 struct FastWrite<'a>(&'a mut Vec<u8>);
1042 
1043 impl<'a> fmt::Write for FastWrite<'a> {
1044     #[inline]
write_str(&mut self, s: &str) -> fmt::Result1045     fn write_str(&mut self, s: &str) -> fmt::Result {
1046         extend(self.0, s.as_bytes());
1047         Ok(())
1048     }
1049 
1050     #[inline]
write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result1051     fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
1052         fmt::write(self, args)
1053     }
1054 }
1055 
1056 #[inline]
extend(dst: &mut Vec<u8>, data: &[u8])1057 fn extend(dst: &mut Vec<u8>, data: &[u8]) {
1058     dst.extend_from_slice(data);
1059 }
1060 
1061 #[cfg(test)]
1062 mod tests {
1063     use bytes::BytesMut;
1064 
1065     use super::*;
1066 
1067     #[test]
test_parse_request()1068     fn test_parse_request() {
1069         let _ = pretty_env_logger::try_init();
1070         let mut raw = BytesMut::from("GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
1071         let mut method = None;
1072         let msg = Server::parse(
1073             &mut raw,
1074             ParseContext {
1075                 cached_headers: &mut None,
1076                 req_method: &mut method,
1077             },
1078         )
1079         .unwrap()
1080         .unwrap();
1081         assert_eq!(raw.len(), 0);
1082         assert_eq!(msg.head.subject.0, crate::Method::GET);
1083         assert_eq!(msg.head.subject.1, "/echo");
1084         assert_eq!(msg.head.version, crate::Version::HTTP_11);
1085         assert_eq!(msg.head.headers.len(), 1);
1086         assert_eq!(msg.head.headers["Host"], "hyper.rs");
1087         assert_eq!(method, Some(crate::Method::GET));
1088     }
1089 
1090     #[test]
test_parse_response()1091     fn test_parse_response() {
1092         let _ = pretty_env_logger::try_init();
1093         let mut raw = BytesMut::from("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1094         let ctx = ParseContext {
1095             cached_headers: &mut None,
1096             req_method: &mut Some(crate::Method::GET),
1097         };
1098         let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
1099         assert_eq!(raw.len(), 0);
1100         assert_eq!(msg.head.subject, crate::StatusCode::OK);
1101         assert_eq!(msg.head.version, crate::Version::HTTP_11);
1102         assert_eq!(msg.head.headers.len(), 1);
1103         assert_eq!(msg.head.headers["Content-Length"], "0");
1104     }
1105 
1106     #[test]
test_parse_request_errors()1107     fn test_parse_request_errors() {
1108         let mut raw = BytesMut::from("GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
1109         let ctx = ParseContext {
1110             cached_headers: &mut None,
1111             req_method: &mut None,
1112         };
1113         Server::parse(&mut raw, ctx).unwrap_err();
1114     }
1115 
1116     #[test]
test_decoder_request()1117     fn test_decoder_request() {
1118         fn parse(s: &str) -> ParsedMessage<RequestLine> {
1119             let mut bytes = BytesMut::from(s);
1120             Server::parse(
1121                 &mut bytes,
1122                 ParseContext {
1123                     cached_headers: &mut None,
1124                     req_method: &mut None,
1125                 },
1126             )
1127             .expect("parse ok")
1128             .expect("parse complete")
1129         }
1130 
1131         fn parse_err(s: &str, comment: &str) -> crate::error::Parse {
1132             let mut bytes = BytesMut::from(s);
1133             Server::parse(
1134                 &mut bytes,
1135                 ParseContext {
1136                     cached_headers: &mut None,
1137                     req_method: &mut None,
1138                 },
1139             )
1140             .expect_err(comment)
1141         }
1142 
1143         // no length or transfer-encoding means 0-length body
1144         assert_eq!(
1145             parse(
1146                 "\
1147                  GET / HTTP/1.1\r\n\
1148                  \r\n\
1149                  "
1150             )
1151             .decode,
1152             DecodedLength::ZERO
1153         );
1154 
1155         assert_eq!(
1156             parse(
1157                 "\
1158                  POST / HTTP/1.1\r\n\
1159                  \r\n\
1160                  "
1161             )
1162             .decode,
1163             DecodedLength::ZERO
1164         );
1165 
1166         // transfer-encoding: chunked
1167         assert_eq!(
1168             parse(
1169                 "\
1170                  POST / HTTP/1.1\r\n\
1171                  transfer-encoding: chunked\r\n\
1172                  \r\n\
1173                  "
1174             )
1175             .decode,
1176             DecodedLength::CHUNKED
1177         );
1178 
1179         assert_eq!(
1180             parse(
1181                 "\
1182                  POST / HTTP/1.1\r\n\
1183                  transfer-encoding: gzip, chunked\r\n\
1184                  \r\n\
1185                  "
1186             )
1187             .decode,
1188             DecodedLength::CHUNKED
1189         );
1190 
1191         assert_eq!(
1192             parse(
1193                 "\
1194                  POST / HTTP/1.1\r\n\
1195                  transfer-encoding: gzip\r\n\
1196                  transfer-encoding: chunked\r\n\
1197                  \r\n\
1198                  "
1199             )
1200             .decode,
1201             DecodedLength::CHUNKED
1202         );
1203 
1204         // content-length
1205         assert_eq!(
1206             parse(
1207                 "\
1208                  POST / HTTP/1.1\r\n\
1209                  content-length: 10\r\n\
1210                  \r\n\
1211                  "
1212             )
1213             .decode,
1214             DecodedLength::new(10)
1215         );
1216 
1217         // transfer-encoding and content-length = chunked
1218         assert_eq!(
1219             parse(
1220                 "\
1221                  POST / HTTP/1.1\r\n\
1222                  content-length: 10\r\n\
1223                  transfer-encoding: chunked\r\n\
1224                  \r\n\
1225                  "
1226             )
1227             .decode,
1228             DecodedLength::CHUNKED
1229         );
1230 
1231         assert_eq!(
1232             parse(
1233                 "\
1234                  POST / HTTP/1.1\r\n\
1235                  transfer-encoding: chunked\r\n\
1236                  content-length: 10\r\n\
1237                  \r\n\
1238                  "
1239             )
1240             .decode,
1241             DecodedLength::CHUNKED
1242         );
1243 
1244         assert_eq!(
1245             parse(
1246                 "\
1247                  POST / HTTP/1.1\r\n\
1248                  transfer-encoding: gzip\r\n\
1249                  content-length: 10\r\n\
1250                  transfer-encoding: chunked\r\n\
1251                  \r\n\
1252                  "
1253             )
1254             .decode,
1255             DecodedLength::CHUNKED
1256         );
1257 
1258         // multiple content-lengths of same value are fine
1259         assert_eq!(
1260             parse(
1261                 "\
1262                  POST / HTTP/1.1\r\n\
1263                  content-length: 10\r\n\
1264                  content-length: 10\r\n\
1265                  \r\n\
1266                  "
1267             )
1268             .decode,
1269             DecodedLength::new(10)
1270         );
1271 
1272         // multiple content-lengths with different values is an error
1273         parse_err(
1274             "\
1275              POST / HTTP/1.1\r\n\
1276              content-length: 10\r\n\
1277              content-length: 11\r\n\
1278              \r\n\
1279              ",
1280             "multiple content-lengths",
1281         );
1282 
1283         // transfer-encoding that isn't chunked is an error
1284         parse_err(
1285             "\
1286              POST / HTTP/1.1\r\n\
1287              transfer-encoding: gzip\r\n\
1288              \r\n\
1289              ",
1290             "transfer-encoding but not chunked",
1291         );
1292 
1293         parse_err(
1294             "\
1295              POST / HTTP/1.1\r\n\
1296              transfer-encoding: chunked, gzip\r\n\
1297              \r\n\
1298              ",
1299             "transfer-encoding doesn't end in chunked",
1300         );
1301 
1302         // http/1.0
1303 
1304         assert_eq!(
1305             parse(
1306                 "\
1307                  POST / HTTP/1.0\r\n\
1308                  content-length: 10\r\n\
1309                  \r\n\
1310                  "
1311             )
1312             .decode,
1313             DecodedLength::new(10)
1314         );
1315 
1316         // 1.0 doesn't understand chunked, so its an error
1317         parse_err(
1318             "\
1319              POST / HTTP/1.0\r\n\
1320              transfer-encoding: chunked\r\n\
1321              \r\n\
1322              ",
1323             "1.0 chunked",
1324         );
1325     }
1326 
1327     #[test]
test_decoder_response()1328     fn test_decoder_response() {
1329         fn parse(s: &str) -> ParsedMessage<StatusCode> {
1330             parse_with_method(s, Method::GET)
1331         }
1332 
1333         fn parse_ignores(s: &str) {
1334             let mut bytes = BytesMut::from(s);
1335             assert!(Client::parse(
1336                 &mut bytes,
1337                 ParseContext {
1338                     cached_headers: &mut None,
1339                     req_method: &mut Some(Method::GET),
1340                 }
1341             )
1342             .expect("parse ok")
1343             .is_none())
1344         }
1345 
1346         fn parse_with_method(s: &str, m: Method) -> ParsedMessage<StatusCode> {
1347             let mut bytes = BytesMut::from(s);
1348             Client::parse(
1349                 &mut bytes,
1350                 ParseContext {
1351                     cached_headers: &mut None,
1352                     req_method: &mut Some(m),
1353                 },
1354             )
1355             .expect("parse ok")
1356             .expect("parse complete")
1357         }
1358 
1359         fn parse_err(s: &str) -> crate::error::Parse {
1360             let mut bytes = BytesMut::from(s);
1361             Client::parse(
1362                 &mut bytes,
1363                 ParseContext {
1364                     cached_headers: &mut None,
1365                     req_method: &mut Some(Method::GET),
1366                 },
1367             )
1368             .expect_err("parse should err")
1369         }
1370 
1371         // no content-length or transfer-encoding means close-delimited
1372         assert_eq!(
1373             parse(
1374                 "\
1375                  HTTP/1.1 200 OK\r\n\
1376                  \r\n\
1377                  "
1378             )
1379             .decode,
1380             DecodedLength::CLOSE_DELIMITED
1381         );
1382 
1383         // 204 and 304 never have a body
1384         assert_eq!(
1385             parse(
1386                 "\
1387                  HTTP/1.1 204 No Content\r\n\
1388                  \r\n\
1389                  "
1390             )
1391             .decode,
1392             DecodedLength::ZERO
1393         );
1394 
1395         assert_eq!(
1396             parse(
1397                 "\
1398                  HTTP/1.1 304 Not Modified\r\n\
1399                  \r\n\
1400                  "
1401             )
1402             .decode,
1403             DecodedLength::ZERO
1404         );
1405 
1406         // content-length
1407         assert_eq!(
1408             parse(
1409                 "\
1410                  HTTP/1.1 200 OK\r\n\
1411                  content-length: 8\r\n\
1412                  \r\n\
1413                  "
1414             )
1415             .decode,
1416             DecodedLength::new(8)
1417         );
1418 
1419         assert_eq!(
1420             parse(
1421                 "\
1422                  HTTP/1.1 200 OK\r\n\
1423                  content-length: 8\r\n\
1424                  content-length: 8\r\n\
1425                  \r\n\
1426                  "
1427             )
1428             .decode,
1429             DecodedLength::new(8)
1430         );
1431 
1432         parse_err(
1433             "\
1434              HTTP/1.1 200 OK\r\n\
1435              content-length: 8\r\n\
1436              content-length: 9\r\n\
1437              \r\n\
1438              ",
1439         );
1440 
1441         // transfer-encoding: chunked
1442         assert_eq!(
1443             parse(
1444                 "\
1445                  HTTP/1.1 200 OK\r\n\
1446                  transfer-encoding: chunked\r\n\
1447                  \r\n\
1448                  "
1449             )
1450             .decode,
1451             DecodedLength::CHUNKED
1452         );
1453 
1454         // transfer-encoding not-chunked is close-delimited
1455         assert_eq!(
1456             parse(
1457                 "\
1458                  HTTP/1.1 200 OK\r\n\
1459                  transfer-encoding: yolo\r\n\
1460                  \r\n\
1461                  "
1462             )
1463             .decode,
1464             DecodedLength::CLOSE_DELIMITED
1465         );
1466 
1467         // transfer-encoding and content-length = chunked
1468         assert_eq!(
1469             parse(
1470                 "\
1471                  HTTP/1.1 200 OK\r\n\
1472                  content-length: 10\r\n\
1473                  transfer-encoding: chunked\r\n\
1474                  \r\n\
1475                  "
1476             )
1477             .decode,
1478             DecodedLength::CHUNKED
1479         );
1480 
1481         // HEAD can have content-length, but not body
1482         assert_eq!(
1483             parse_with_method(
1484                 "\
1485                  HTTP/1.1 200 OK\r\n\
1486                  content-length: 8\r\n\
1487                  \r\n\
1488                  ",
1489                 Method::HEAD
1490             )
1491             .decode,
1492             DecodedLength::ZERO
1493         );
1494 
1495         // CONNECT with 200 never has body
1496         {
1497             let msg = parse_with_method(
1498                 "\
1499                  HTTP/1.1 200 OK\r\n\
1500                  \r\n\
1501                  ",
1502                 Method::CONNECT,
1503             );
1504             assert_eq!(msg.decode, DecodedLength::ZERO);
1505             assert!(!msg.keep_alive, "should be upgrade");
1506             assert!(msg.wants_upgrade, "should be upgrade");
1507         }
1508 
1509         // CONNECT receiving non 200 can have a body
1510         assert_eq!(
1511             parse_with_method(
1512                 "\
1513                  HTTP/1.1 400 Bad Request\r\n\
1514                  \r\n\
1515                  ",
1516                 Method::CONNECT
1517             )
1518             .decode,
1519             DecodedLength::CLOSE_DELIMITED
1520         );
1521 
1522         // 1xx status codes
1523         parse_ignores(
1524             "\
1525              HTTP/1.1 100 Continue\r\n\
1526              \r\n\
1527              ",
1528         );
1529 
1530         parse_ignores(
1531             "\
1532              HTTP/1.1 103 Early Hints\r\n\
1533              \r\n\
1534              ",
1535         );
1536 
1537         // 101 upgrade not supported yet
1538         {
1539             let msg = parse(
1540                 "\
1541                  HTTP/1.1 101 Switching Protocols\r\n\
1542                  \r\n\
1543                  ",
1544             );
1545             assert_eq!(msg.decode, DecodedLength::ZERO);
1546             assert!(!msg.keep_alive, "should be last");
1547             assert!(msg.wants_upgrade, "should be upgrade");
1548         }
1549 
1550         // http/1.0
1551         assert_eq!(
1552             parse(
1553                 "\
1554                  HTTP/1.0 200 OK\r\n\
1555                  \r\n\
1556                  "
1557             )
1558             .decode,
1559             DecodedLength::CLOSE_DELIMITED
1560         );
1561 
1562         // 1.0 doesn't understand chunked
1563         parse_err(
1564             "\
1565              HTTP/1.0 200 OK\r\n\
1566              transfer-encoding: chunked\r\n\
1567              \r\n\
1568              ",
1569         );
1570 
1571         // keep-alive
1572         assert!(
1573             parse(
1574                 "\
1575                  HTTP/1.1 200 OK\r\n\
1576                  content-length: 0\r\n\
1577                  \r\n\
1578                  "
1579             )
1580             .keep_alive,
1581             "HTTP/1.1 keep-alive is default"
1582         );
1583 
1584         assert!(
1585             !parse(
1586                 "\
1587                  HTTP/1.1 200 OK\r\n\
1588                  content-length: 0\r\n\
1589                  connection: foo, close, bar\r\n\
1590                  \r\n\
1591                  "
1592             )
1593             .keep_alive,
1594             "connection close is always close"
1595         );
1596 
1597         assert!(
1598             !parse(
1599                 "\
1600                  HTTP/1.0 200 OK\r\n\
1601                  content-length: 0\r\n\
1602                  \r\n\
1603                  "
1604             )
1605             .keep_alive,
1606             "HTTP/1.0 close is default"
1607         );
1608 
1609         assert!(
1610             parse(
1611                 "\
1612                  HTTP/1.0 200 OK\r\n\
1613                  content-length: 0\r\n\
1614                  connection: foo, keep-alive, bar\r\n\
1615                  \r\n\
1616                  "
1617             )
1618             .keep_alive,
1619             "connection keep-alive is always keep-alive"
1620         );
1621     }
1622 
1623     #[test]
test_client_request_encode_title_case()1624     fn test_client_request_encode_title_case() {
1625         use crate::proto::BodyLength;
1626         use http::header::HeaderValue;
1627 
1628         let mut head = MessageHead::default();
1629         head.headers
1630             .insert("content-length", HeaderValue::from_static("10"));
1631         head.headers
1632             .insert("content-type", HeaderValue::from_static("application/json"));
1633         head.headers.insert("*-*", HeaderValue::from_static("o_o"));
1634 
1635         let mut vec = Vec::new();
1636         Client::encode(
1637             Encode {
1638                 head: &mut head,
1639                 body: Some(BodyLength::Known(10)),
1640                 keep_alive: true,
1641                 req_method: &mut None,
1642                 title_case_headers: true,
1643             },
1644             &mut vec,
1645         )
1646         .unwrap();
1647 
1648         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());
1649     }
1650 
1651     #[test]
test_server_encode_connect_method()1652     fn test_server_encode_connect_method() {
1653         let mut head = MessageHead::default();
1654 
1655         let mut vec = Vec::new();
1656         let encoder = Server::encode(
1657             Encode {
1658                 head: &mut head,
1659                 body: None,
1660                 keep_alive: true,
1661                 req_method: &mut Some(Method::CONNECT),
1662                 title_case_headers: false,
1663             },
1664             &mut vec,
1665         )
1666         .unwrap();
1667 
1668         assert!(encoder.is_last());
1669     }
1670 
1671     #[test]
parse_header_htabs()1672     fn parse_header_htabs() {
1673         let mut bytes = BytesMut::from("HTTP/1.1 200 OK\r\nserver: hello\tworld\r\n\r\n");
1674         let parsed = Client::parse(
1675             &mut bytes,
1676             ParseContext {
1677                 cached_headers: &mut None,
1678                 req_method: &mut Some(Method::GET),
1679             },
1680         )
1681         .expect("parse ok")
1682         .expect("parse complete");
1683 
1684         assert_eq!(parsed.head.headers["server"], "hello\tworld");
1685     }
1686 
1687     #[cfg(feature = "nightly")]
1688     use test::Bencher;
1689 
1690     #[cfg(feature = "nightly")]
1691     #[bench]
bench_parse_incoming(b: &mut Bencher)1692     fn bench_parse_incoming(b: &mut Bencher) {
1693         let mut raw = BytesMut::from(
1694             &b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\
1695             I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\
1696             _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\
1697             foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \
1698             hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \
1699             utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\
1700             Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\
1701             Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\
1702             Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\
1703             Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\
1704             \r\nSec-Websocket-Extensions: It looks super important!\r\n\
1705             Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\
1706             \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\
1707             X-Content-Duration: None\r\nX-Content-Security-Policy: None\
1708             \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \
1709             Something important obviously\r\nX-Requested-With: Nothing\
1710             \r\n\r\n"[..],
1711         );
1712         let len = raw.len();
1713         let mut headers = Some(HeaderMap::new());
1714 
1715         b.bytes = len as u64;
1716         b.iter(|| {
1717             let mut msg = Server::parse(
1718                 &mut raw,
1719                 ParseContext {
1720                     cached_headers: &mut headers,
1721                     req_method: &mut None,
1722                 },
1723             )
1724             .unwrap()
1725             .unwrap();
1726             ::test::black_box(&msg);
1727             msg.head.headers.clear();
1728             headers = Some(msg.head.headers);
1729             restart(&mut raw, len);
1730         });
1731 
1732         fn restart(b: &mut BytesMut, len: usize) {
1733             b.reserve(1);
1734             unsafe {
1735                 b.set_len(len);
1736             }
1737         }
1738     }
1739 
1740     #[cfg(feature = "nightly")]
1741     #[bench]
bench_parse_short(b: &mut Bencher)1742     fn bench_parse_short(b: &mut Bencher) {
1743         let s = &b"GET / HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"[..];
1744         let mut raw = BytesMut::from(s);
1745         let len = raw.len();
1746         let mut headers = Some(HeaderMap::new());
1747 
1748         b.bytes = len as u64;
1749         b.iter(|| {
1750             let mut msg = Server::parse(
1751                 &mut raw,
1752                 ParseContext {
1753                     cached_headers: &mut headers,
1754                     req_method: &mut None,
1755                 },
1756             )
1757             .unwrap()
1758             .unwrap();
1759             ::test::black_box(&msg);
1760             msg.head.headers.clear();
1761             headers = Some(msg.head.headers);
1762             restart(&mut raw, len);
1763         });
1764 
1765         fn restart(b: &mut BytesMut, len: usize) {
1766             b.reserve(1);
1767             unsafe {
1768                 b.set_len(len);
1769             }
1770         }
1771     }
1772 
1773     #[cfg(feature = "nightly")]
1774     #[bench]
bench_server_encode_headers_preset(b: &mut Bencher)1775     fn bench_server_encode_headers_preset(b: &mut Bencher) {
1776         use crate::proto::BodyLength;
1777         use http::header::HeaderValue;
1778 
1779         let len = 108;
1780         b.bytes = len as u64;
1781 
1782         let mut head = MessageHead::default();
1783         let mut headers = HeaderMap::new();
1784         headers.insert("content-length", HeaderValue::from_static("10"));
1785         headers.insert("content-type", HeaderValue::from_static("application/json"));
1786 
1787         b.iter(|| {
1788             let mut vec = Vec::new();
1789             head.headers = headers.clone();
1790             Server::encode(
1791                 Encode {
1792                     head: &mut head,
1793                     body: Some(BodyLength::Known(10)),
1794                     keep_alive: true,
1795                     req_method: &mut Some(Method::GET),
1796                     title_case_headers: false,
1797                 },
1798                 &mut vec,
1799             )
1800             .unwrap();
1801             assert_eq!(vec.len(), len);
1802             ::test::black_box(vec);
1803         })
1804     }
1805 
1806     #[cfg(feature = "nightly")]
1807     #[bench]
bench_server_encode_no_headers(b: &mut Bencher)1808     fn bench_server_encode_no_headers(b: &mut Bencher) {
1809         use crate::proto::BodyLength;
1810 
1811         let len = 76;
1812         b.bytes = len as u64;
1813 
1814         let mut head = MessageHead::default();
1815         let mut vec = Vec::with_capacity(128);
1816 
1817         b.iter(|| {
1818             Server::encode(
1819                 Encode {
1820                     head: &mut head,
1821                     body: Some(BodyLength::Known(10)),
1822                     keep_alive: true,
1823                     req_method: &mut Some(Method::GET),
1824                     title_case_headers: false,
1825                 },
1826                 &mut vec,
1827             )
1828             .unwrap();
1829             assert_eq!(vec.len(), len);
1830             ::test::black_box(&vec);
1831 
1832             vec.clear();
1833         })
1834     }
1835 }
1836