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