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