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
12 use crate::body::DecodedLength;
13 #[cfg(feature = "server")]
14 use crate::common::date;
15 use crate::error::Parse;
16 use crate::ext::HeaderCaseMap;
17 use crate::headers;
18 use crate::proto::h1::{
19 Encode, Encoder, Http1Transaction, ParseContext, ParseResult, ParsedMessage,
20 };
21 use crate::proto::{BodyLength, MessageHead, RequestHead, RequestLine};
22
23 const MAX_HEADERS: usize = 100;
24 const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
25
26 macro_rules! header_name {
27 ($bytes:expr) => {{
28 {
29 match HeaderName::from_bytes($bytes) {
30 Ok(name) => name,
31 Err(e) => maybe_panic!(e),
32 }
33 }
34 }};
35 }
36
37 macro_rules! header_value {
38 ($bytes:expr) => {{
39 {
40 unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) }
41 }
42 }};
43 }
44
45 macro_rules! maybe_panic {
46 ($($arg:tt)*) => ({
47 let _err = ($($arg)*);
48 if cfg!(debug_assertions) {
49 panic!("{:?}", _err);
50 } else {
51 error!("Internal Hyper error, please report {:?}", _err);
52 return Err(Parse::Internal)
53 }
54 })
55 }
56
parse_headers<T>( bytes: &mut BytesMut, ctx: ParseContext<'_>, ) -> ParseResult<T::Incoming> where T: Http1Transaction,57 pub(super) fn parse_headers<T>(
58 bytes: &mut BytesMut,
59 ctx: ParseContext<'_>,
60 ) -> ParseResult<T::Incoming>
61 where
62 T: Http1Transaction,
63 {
64 // If the buffer is empty, don't bother entering the span, it's just noise.
65 if bytes.is_empty() {
66 return Ok(None);
67 }
68
69 let span = trace_span!("parse_headers");
70 let _s = span.enter();
71 T::parse(bytes, ctx)
72 }
73
encode_headers<T>( enc: Encode<'_, T::Outgoing>, dst: &mut Vec<u8>, ) -> crate::Result<Encoder> where T: Http1Transaction,74 pub(super) fn encode_headers<T>(
75 enc: Encode<'_, T::Outgoing>,
76 dst: &mut Vec<u8>,
77 ) -> crate::Result<Encoder>
78 where
79 T: Http1Transaction,
80 {
81 let span = trace_span!("encode_headers");
82 let _s = span.enter();
83 T::encode(enc, dst)
84 }
85
86 // There are 2 main roles, Client and Server.
87
88 #[cfg(feature = "client")]
89 pub(crate) enum Client {}
90
91 #[cfg(feature = "server")]
92 pub(crate) enum Server {}
93
94 #[cfg(feature = "server")]
95 impl Http1Transaction for Server {
96 type Incoming = RequestLine;
97 type Outgoing = StatusCode;
98 const LOG: &'static str = "{role=server}";
99
parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<RequestLine>100 fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<RequestLine> {
101 debug_assert!(!buf.is_empty(), "parse called with empty buf");
102
103 let mut keep_alive;
104 let is_http_11;
105 let subject;
106 let version;
107 let len;
108 let headers_len;
109
110 // Unsafe: both headers_indices and headers are using uninitialized memory,
111 // but we *never* read any of it until after httparse has assigned
112 // values into it. By not zeroing out the stack memory, this saves
113 // a good ~5% on pipeline benchmarks.
114 let mut headers_indices: [MaybeUninit<HeaderIndices>; MAX_HEADERS] = unsafe {
115 // SAFETY: We can go safely from MaybeUninit array to array of MaybeUninit
116 MaybeUninit::uninit().assume_init()
117 };
118 {
119 /* SAFETY: it is safe to go from MaybeUninit array to array of MaybeUninit */
120 let mut headers: [MaybeUninit<httparse::Header<'_>>; MAX_HEADERS] = unsafe {
121 MaybeUninit::uninit().assume_init()
122 };
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
890 .parse_response_with_uninit_headers(&mut res, bytes, &mut headers)
891 {
892 Ok(httparse::Status::Complete(len)) => {
893 trace!("Response.parse Complete({})", len);
894 let status = StatusCode::from_u16(res.code.unwrap())?;
895
896 #[cfg(not(feature = "ffi"))]
897 let reason = ();
898 #[cfg(feature = "ffi")]
899 let reason = {
900 let reason = res.reason.unwrap();
901 // Only save the reason phrase if it isnt the canonical reason
902 if Some(reason) != status.canonical_reason() {
903 Some(Bytes::copy_from_slice(reason.as_bytes()))
904 } else {
905 None
906 }
907 };
908
909 let version = if res.version.unwrap() == 1 {
910 Version::HTTP_11
911 } else {
912 Version::HTTP_10
913 };
914 record_header_indices(bytes, &res.headers, &mut headers_indices)?;
915 let headers_len = res.headers.len();
916 (len, status, reason, version, headers_len)
917 }
918 Ok(httparse::Status::Partial) => return Ok(None),
919 Err(httparse::Error::Version) if ctx.h09_responses => {
920 trace!("Response.parse accepted HTTP/0.9 response");
921
922 #[cfg(not(feature = "ffi"))]
923 let reason = ();
924 #[cfg(feature = "ffi")]
925 let reason = None;
926
927 (0, StatusCode::OK, reason, Version::HTTP_09, 0)
928 }
929 Err(e) => return Err(e.into()),
930 }
931 };
932
933 let slice = buf.split_to(len).freeze();
934
935 let mut headers = ctx.cached_headers.take().unwrap_or_else(HeaderMap::new);
936
937 let mut keep_alive = version == Version::HTTP_11;
938
939 let mut header_case_map = if ctx.preserve_header_case {
940 Some(HeaderCaseMap::default())
941 } else {
942 None
943 };
944
945 headers.reserve(headers_len);
946 for header in &headers_indices[..headers_len] {
947 // SAFETY: array is valid up to `headers_len`
948 let header = unsafe { &*header.as_ptr() };
949 let name = header_name!(&slice[header.name.0..header.name.1]);
950 let value = header_value!(slice.slice(header.value.0..header.value.1));
951
952 if let header::CONNECTION = name {
953 // keep_alive was previously set to default for Version
954 if keep_alive {
955 // HTTP/1.1
956 keep_alive = !headers::connection_close(&value);
957 } else {
958 // HTTP/1.0
959 keep_alive = headers::connection_keep_alive(&value);
960 }
961 }
962
963 if let Some(ref mut header_case_map) = header_case_map {
964 header_case_map.append(&name, slice.slice(header.name.0..header.name.1));
965 }
966
967 headers.append(name, value);
968 }
969
970 let mut extensions = http::Extensions::default();
971
972 if let Some(header_case_map) = header_case_map {
973 extensions.insert(header_case_map);
974 }
975
976 #[cfg(feature = "ffi")]
977 if let Some(reason) = reason {
978 extensions.insert(crate::ffi::ReasonPhrase(reason));
979 }
980 #[cfg(not(feature = "ffi"))]
981 drop(reason);
982
983 #[cfg(feature = "ffi")]
984 if ctx.raw_headers {
985 extensions.insert(crate::ffi::RawHeaders(crate::ffi::hyper_buf(slice)));
986 }
987
988 let head = MessageHead {
989 version,
990 subject: status,
991 headers,
992 extensions,
993 };
994 if let Some((decode, is_upgrade)) = Client::decoder(&head, ctx.req_method)? {
995 return Ok(Some(ParsedMessage {
996 head,
997 decode,
998 expect_continue: false,
999 // a client upgrade means the connection can't be used
1000 // again, as it is definitely upgrading.
1001 keep_alive: keep_alive && !is_upgrade,
1002 wants_upgrade: is_upgrade,
1003 }));
1004 }
1005
1006 #[cfg(feature = "ffi")]
1007 if head.subject.is_informational() {
1008 if let Some(callback) = ctx.on_informational {
1009 callback.call(head.into_response(crate::Body::empty()));
1010 }
1011 }
1012
1013 // Parsing a 1xx response could have consumed the buffer, check if
1014 // it is empty now...
1015 if buf.is_empty() {
1016 return Ok(None);
1017 }
1018 }
1019 }
1020
encode(msg: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder>1021 fn encode(msg: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder> {
1022 trace!(
1023 "Client::encode method={:?}, body={:?}",
1024 msg.head.subject.0,
1025 msg.body
1026 );
1027
1028 *msg.req_method = Some(msg.head.subject.0.clone());
1029
1030 let body = Client::set_length(msg.head, msg.body);
1031
1032 let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE;
1033 dst.reserve(init_cap);
1034
1035 extend(dst, msg.head.subject.0.as_str().as_bytes());
1036 extend(dst, b" ");
1037 //TODO: add API to http::Uri to encode without std::fmt
1038 let _ = write!(FastWrite(dst), "{} ", msg.head.subject.1);
1039
1040 match msg.head.version {
1041 Version::HTTP_10 => extend(dst, b"HTTP/1.0"),
1042 Version::HTTP_11 => extend(dst, b"HTTP/1.1"),
1043 Version::HTTP_2 => {
1044 debug!("request with HTTP2 version coerced to HTTP/1.1");
1045 extend(dst, b"HTTP/1.1");
1046 }
1047 other => panic!("unexpected request version: {:?}", other),
1048 }
1049 extend(dst, b"\r\n");
1050
1051 if let Some(orig_headers) = msg.head.extensions.get::<HeaderCaseMap>() {
1052 write_headers_original_case(
1053 &msg.head.headers,
1054 orig_headers,
1055 dst,
1056 msg.title_case_headers,
1057 );
1058 } else if msg.title_case_headers {
1059 write_headers_title_case(&msg.head.headers, dst);
1060 } else {
1061 write_headers(&msg.head.headers, dst);
1062 }
1063
1064 extend(dst, b"\r\n");
1065 msg.head.headers.clear(); //TODO: remove when switching to drain()
1066
1067 Ok(body)
1068 }
1069
on_error(_err: &crate::Error) -> Option<MessageHead<Self::Outgoing>>1070 fn on_error(_err: &crate::Error) -> Option<MessageHead<Self::Outgoing>> {
1071 // we can't tell the server about any errors it creates
1072 None
1073 }
1074
is_client() -> bool1075 fn is_client() -> bool {
1076 true
1077 }
1078 }
1079
1080 #[cfg(feature = "client")]
1081 impl Client {
1082 /// Returns Some(length, wants_upgrade) if successful.
1083 ///
1084 /// 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>1085 fn decoder(
1086 inc: &MessageHead<StatusCode>,
1087 method: &mut Option<Method>,
1088 ) -> Result<Option<(DecodedLength, bool)>, Parse> {
1089 // According to https://tools.ietf.org/html/rfc7230#section-3.3.3
1090 // 1. HEAD responses, and Status 1xx, 204, and 304 cannot have a body.
1091 // 2. Status 2xx to a CONNECT cannot have a body.
1092 // 3. Transfer-Encoding: chunked has a chunked body.
1093 // 4. If multiple differing Content-Length headers or invalid, close connection.
1094 // 5. Content-Length header has a sized body.
1095 // 6. (irrelevant to Response)
1096 // 7. Read till EOF.
1097
1098 match inc.subject.as_u16() {
1099 101 => {
1100 return Ok(Some((DecodedLength::ZERO, true)));
1101 }
1102 100 | 102..=199 => {
1103 trace!("ignoring informational response: {}", inc.subject.as_u16());
1104 return Ok(None);
1105 }
1106 204 | 304 => return Ok(Some((DecodedLength::ZERO, false))),
1107 _ => (),
1108 }
1109 match *method {
1110 Some(Method::HEAD) => {
1111 return Ok(Some((DecodedLength::ZERO, false)));
1112 }
1113 Some(Method::CONNECT) => {
1114 if let 200..=299 = inc.subject.as_u16() {
1115 return Ok(Some((DecodedLength::ZERO, true)));
1116 }
1117 }
1118 Some(_) => {}
1119 None => {
1120 trace!("Client::decoder is missing the Method");
1121 }
1122 }
1123
1124 if inc.headers.contains_key(header::TRANSFER_ENCODING) {
1125 // https://tools.ietf.org/html/rfc7230#section-3.3.3
1126 // If Transfer-Encoding header is present, and 'chunked' is
1127 // not the final encoding, and this is a Request, then it is
1128 // malformed. A server should respond with 400 Bad Request.
1129 if inc.version == Version::HTTP_10 {
1130 debug!("HTTP/1.0 cannot have Transfer-Encoding header");
1131 Err(Parse::transfer_encoding_unexpected())
1132 } else if headers::transfer_encoding_is_chunked(&inc.headers) {
1133 Ok(Some((DecodedLength::CHUNKED, false)))
1134 } else {
1135 trace!("not chunked, read till eof");
1136 Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))
1137 }
1138 } else if let Some(len) = headers::content_length_parse_all(&inc.headers) {
1139 Ok(Some((DecodedLength::checked_new(len)?, false)))
1140 } else if inc.headers.contains_key(header::CONTENT_LENGTH) {
1141 debug!("illegal Content-Length header");
1142 Err(Parse::content_length_invalid())
1143 } else {
1144 trace!("neither Transfer-Encoding nor Content-Length");
1145 Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))
1146 }
1147 }
set_length(head: &mut RequestHead, body: Option<BodyLength>) -> Encoder1148 fn set_length(head: &mut RequestHead, body: Option<BodyLength>) -> Encoder {
1149 let body = if let Some(body) = body {
1150 body
1151 } else {
1152 head.headers.remove(header::TRANSFER_ENCODING);
1153 return Encoder::length(0);
1154 };
1155
1156 // HTTP/1.0 doesn't know about chunked
1157 let can_chunked = head.version == Version::HTTP_11;
1158 let headers = &mut head.headers;
1159
1160 // If the user already set specific headers, we should respect them, regardless
1161 // of what the HttpBody knows about itself. They set them for a reason.
1162
1163 // Because of the borrow checker, we can't check the for an existing
1164 // Content-Length header while holding an `Entry` for the Transfer-Encoding
1165 // header, so unfortunately, we must do the check here, first.
1166
1167 let existing_con_len = headers::content_length_parse_all(headers);
1168 let mut should_remove_con_len = false;
1169
1170 if !can_chunked {
1171 // Chunked isn't legal, so if it is set, we need to remove it.
1172 if headers.remove(header::TRANSFER_ENCODING).is_some() {
1173 trace!("removing illegal transfer-encoding header");
1174 }
1175
1176 return if let Some(len) = existing_con_len {
1177 Encoder::length(len)
1178 } else if let BodyLength::Known(len) = body {
1179 set_content_length(headers, len)
1180 } else {
1181 // HTTP/1.0 client requests without a content-length
1182 // cannot have any body at all.
1183 Encoder::length(0)
1184 };
1185 }
1186
1187 // If the user set a transfer-encoding, respect that. Let's just
1188 // make sure `chunked` is the final encoding.
1189 let encoder = match headers.entry(header::TRANSFER_ENCODING) {
1190 Entry::Occupied(te) => {
1191 should_remove_con_len = true;
1192 if headers::is_chunked(te.iter()) {
1193 Some(Encoder::chunked())
1194 } else {
1195 warn!("user provided transfer-encoding does not end in 'chunked'");
1196
1197 // There's a Transfer-Encoding, but it doesn't end in 'chunked'!
1198 // An example that could trigger this:
1199 //
1200 // Transfer-Encoding: gzip
1201 //
1202 // This can be bad, depending on if this is a request or a
1203 // response.
1204 //
1205 // - A request is illegal if there is a `Transfer-Encoding`
1206 // but it doesn't end in `chunked`.
1207 // - A response that has `Transfer-Encoding` but doesn't
1208 // end in `chunked` isn't illegal, it just forces this
1209 // to be close-delimited.
1210 //
1211 // We can try to repair this, by adding `chunked` ourselves.
1212
1213 headers::add_chunked(te);
1214 Some(Encoder::chunked())
1215 }
1216 }
1217 Entry::Vacant(te) => {
1218 if let Some(len) = existing_con_len {
1219 Some(Encoder::length(len))
1220 } else if let BodyLength::Unknown = body {
1221 // GET, HEAD, and CONNECT almost never have bodies.
1222 //
1223 // So instead of sending a "chunked" body with a 0-chunk,
1224 // assume no body here. If you *must* send a body,
1225 // set the headers explicitly.
1226 match head.subject.0 {
1227 Method::GET | Method::HEAD | Method::CONNECT => Some(Encoder::length(0)),
1228 _ => {
1229 te.insert(HeaderValue::from_static("chunked"));
1230 Some(Encoder::chunked())
1231 }
1232 }
1233 } else {
1234 None
1235 }
1236 }
1237 };
1238
1239 // This is because we need a second mutable borrow to remove
1240 // content-length header.
1241 if let Some(encoder) = encoder {
1242 if should_remove_con_len && existing_con_len.is_some() {
1243 headers.remove(header::CONTENT_LENGTH);
1244 }
1245 return encoder;
1246 }
1247
1248 // User didn't set transfer-encoding, AND we know body length,
1249 // so we can just set the Content-Length automatically.
1250
1251 let len = if let BodyLength::Known(len) = body {
1252 len
1253 } else {
1254 unreachable!("BodyLength::Unknown would set chunked");
1255 };
1256
1257 set_content_length(headers, len)
1258 }
1259 }
1260
set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder1261 fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder {
1262 // At this point, there should not be a valid Content-Length
1263 // header. However, since we'll be indexing in anyways, we can
1264 // warn the user if there was an existing illegal header.
1265 //
1266 // Or at least, we can in theory. It's actually a little bit slower,
1267 // so perhaps only do that while the user is developing/testing.
1268
1269 if cfg!(debug_assertions) {
1270 match headers.entry(header::CONTENT_LENGTH) {
1271 Entry::Occupied(mut cl) => {
1272 // Internal sanity check, we should have already determined
1273 // that the header was illegal before calling this function.
1274 debug_assert!(headers::content_length_parse_all_values(cl.iter()).is_none());
1275 // Uh oh, the user set `Content-Length` headers, but set bad ones.
1276 // This would be an illegal message anyways, so let's try to repair
1277 // with our known good length.
1278 error!("user provided content-length header was invalid");
1279
1280 cl.insert(HeaderValue::from(len));
1281 Encoder::length(len)
1282 }
1283 Entry::Vacant(cl) => {
1284 cl.insert(HeaderValue::from(len));
1285 Encoder::length(len)
1286 }
1287 }
1288 } else {
1289 headers.insert(header::CONTENT_LENGTH, HeaderValue::from(len));
1290 Encoder::length(len)
1291 }
1292 }
1293
1294 #[derive(Clone, Copy)]
1295 struct HeaderIndices {
1296 name: (usize, usize),
1297 value: (usize, usize),
1298 }
1299
record_header_indices( bytes: &[u8], headers: &[httparse::Header<'_>], indices: &mut [MaybeUninit<HeaderIndices>], ) -> Result<(), crate::error::Parse>1300 fn record_header_indices(
1301 bytes: &[u8],
1302 headers: &[httparse::Header<'_>],
1303 indices: &mut [MaybeUninit<HeaderIndices>],
1304 ) -> Result<(), crate::error::Parse> {
1305 let bytes_ptr = bytes.as_ptr() as usize;
1306
1307 for (header, indices) in headers.iter().zip(indices.iter_mut()) {
1308 if header.name.len() >= (1 << 16) {
1309 debug!("header name larger than 64kb: {:?}", header.name);
1310 return Err(crate::error::Parse::TooLarge);
1311 }
1312 let name_start = header.name.as_ptr() as usize - bytes_ptr;
1313 let name_end = name_start + header.name.len();
1314 let value_start = header.value.as_ptr() as usize - bytes_ptr;
1315 let value_end = value_start + header.value.len();
1316
1317 // FIXME(maybe_uninit_extra)
1318 // FIXME(addr_of)
1319 // Currently we don't have `ptr::addr_of_mut` in stable rust or
1320 // MaybeUninit::write, so this is some way of assigning into a MaybeUninit
1321 // safely
1322 let new_header_indices = HeaderIndices {
1323 name: (name_start, name_end),
1324 value: (value_start, value_end),
1325 };
1326 *indices = MaybeUninit::new(new_header_indices);
1327 }
1328
1329 Ok(())
1330 }
1331
1332 // Write header names as title case. The header name is assumed to be ASCII.
title_case(dst: &mut Vec<u8>, name: &[u8])1333 fn title_case(dst: &mut Vec<u8>, name: &[u8]) {
1334 dst.reserve(name.len());
1335
1336 // Ensure first character is uppercased
1337 let mut prev = b'-';
1338 for &(mut c) in name {
1339 if prev == b'-' {
1340 c.make_ascii_uppercase();
1341 }
1342 dst.push(c);
1343 prev = c;
1344 }
1345 }
1346
write_headers_title_case(headers: &HeaderMap, dst: &mut Vec<u8>)1347 fn write_headers_title_case(headers: &HeaderMap, dst: &mut Vec<u8>) {
1348 for (name, value) in headers {
1349 title_case(dst, name.as_str().as_bytes());
1350 extend(dst, b": ");
1351 extend(dst, value.as_bytes());
1352 extend(dst, b"\r\n");
1353 }
1354 }
1355
write_headers(headers: &HeaderMap, dst: &mut Vec<u8>)1356 fn write_headers(headers: &HeaderMap, dst: &mut Vec<u8>) {
1357 for (name, value) in headers {
1358 extend(dst, name.as_str().as_bytes());
1359 extend(dst, b": ");
1360 extend(dst, value.as_bytes());
1361 extend(dst, b"\r\n");
1362 }
1363 }
1364
1365 #[cold]
write_headers_original_case( headers: &HeaderMap, orig_case: &HeaderCaseMap, dst: &mut Vec<u8>, title_case_headers: bool, )1366 fn write_headers_original_case(
1367 headers: &HeaderMap,
1368 orig_case: &HeaderCaseMap,
1369 dst: &mut Vec<u8>,
1370 title_case_headers: bool,
1371 ) {
1372 // For each header name/value pair, there may be a value in the casemap
1373 // that corresponds to the HeaderValue. So, we iterator all the keys,
1374 // and for each one, try to pair the originally cased name with the value.
1375 //
1376 // TODO: consider adding http::HeaderMap::entries() iterator
1377 for name in headers.keys() {
1378 let mut names = orig_case.get_all(name);
1379
1380 for value in headers.get_all(name) {
1381 if let Some(orig_name) = names.next() {
1382 extend(dst, orig_name.as_ref());
1383 } else if title_case_headers {
1384 title_case(dst, name.as_str().as_bytes());
1385 } else {
1386 extend(dst, name.as_str().as_bytes());
1387 }
1388
1389 // Wanted for curl test cases that send `X-Custom-Header:\r\n`
1390 if value.is_empty() {
1391 extend(dst, b":\r\n");
1392 } else {
1393 extend(dst, b": ");
1394 extend(dst, value.as_bytes());
1395 extend(dst, b"\r\n");
1396 }
1397 }
1398 }
1399 }
1400
1401 struct FastWrite<'a>(&'a mut Vec<u8>);
1402
1403 impl<'a> fmt::Write for FastWrite<'a> {
1404 #[inline]
write_str(&mut self, s: &str) -> fmt::Result1405 fn write_str(&mut self, s: &str) -> fmt::Result {
1406 extend(self.0, s.as_bytes());
1407 Ok(())
1408 }
1409
1410 #[inline]
write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result1411 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
1412 fmt::write(self, args)
1413 }
1414 }
1415
1416 #[inline]
extend(dst: &mut Vec<u8>, data: &[u8])1417 fn extend(dst: &mut Vec<u8>, data: &[u8]) {
1418 dst.extend_from_slice(data);
1419 }
1420
1421 #[cfg(test)]
1422 mod tests {
1423 use bytes::BytesMut;
1424
1425 use super::*;
1426
1427 #[test]
test_parse_request()1428 fn test_parse_request() {
1429 let _ = pretty_env_logger::try_init();
1430 let mut raw = BytesMut::from("GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
1431 let mut method = None;
1432 let msg = Server::parse(
1433 &mut raw,
1434 ParseContext {
1435 cached_headers: &mut None,
1436 req_method: &mut method,
1437 h1_parser_config: Default::default(),
1438 preserve_header_case: false,
1439 h09_responses: false,
1440 #[cfg(feature = "ffi")]
1441 on_informational: &mut None,
1442 #[cfg(feature = "ffi")]
1443 raw_headers: false,
1444 },
1445 )
1446 .unwrap()
1447 .unwrap();
1448 assert_eq!(raw.len(), 0);
1449 assert_eq!(msg.head.subject.0, crate::Method::GET);
1450 assert_eq!(msg.head.subject.1, "/echo");
1451 assert_eq!(msg.head.version, crate::Version::HTTP_11);
1452 assert_eq!(msg.head.headers.len(), 1);
1453 assert_eq!(msg.head.headers["Host"], "hyper.rs");
1454 assert_eq!(method, Some(crate::Method::GET));
1455 }
1456
1457 #[test]
test_parse_response()1458 fn test_parse_response() {
1459 let _ = pretty_env_logger::try_init();
1460 let mut raw = BytesMut::from("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1461 let ctx = ParseContext {
1462 cached_headers: &mut None,
1463 req_method: &mut Some(crate::Method::GET),
1464 h1_parser_config: Default::default(),
1465 preserve_header_case: false,
1466 h09_responses: false,
1467 #[cfg(feature = "ffi")]
1468 on_informational: &mut None,
1469 #[cfg(feature = "ffi")]
1470 raw_headers: false,
1471 };
1472 let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
1473 assert_eq!(raw.len(), 0);
1474 assert_eq!(msg.head.subject, crate::StatusCode::OK);
1475 assert_eq!(msg.head.version, crate::Version::HTTP_11);
1476 assert_eq!(msg.head.headers.len(), 1);
1477 assert_eq!(msg.head.headers["Content-Length"], "0");
1478 }
1479
1480 #[test]
test_parse_request_errors()1481 fn test_parse_request_errors() {
1482 let mut raw = BytesMut::from("GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");
1483 let ctx = ParseContext {
1484 cached_headers: &mut None,
1485 req_method: &mut None,
1486 h1_parser_config: Default::default(),
1487 preserve_header_case: false,
1488 h09_responses: false,
1489 #[cfg(feature = "ffi")]
1490 on_informational: &mut None,
1491 #[cfg(feature = "ffi")]
1492 raw_headers: false,
1493 };
1494 Server::parse(&mut raw, ctx).unwrap_err();
1495 }
1496
1497 const H09_RESPONSE: &'static str = "Baguettes are super delicious, don't you agree?";
1498
1499 #[test]
test_parse_response_h09_allowed()1500 fn test_parse_response_h09_allowed() {
1501 let _ = pretty_env_logger::try_init();
1502 let mut raw = BytesMut::from(H09_RESPONSE);
1503 let ctx = ParseContext {
1504 cached_headers: &mut None,
1505 req_method: &mut Some(crate::Method::GET),
1506 h1_parser_config: Default::default(),
1507 preserve_header_case: false,
1508 h09_responses: true,
1509 #[cfg(feature = "ffi")]
1510 on_informational: &mut None,
1511 #[cfg(feature = "ffi")]
1512 raw_headers: false,
1513 };
1514 let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
1515 assert_eq!(raw, H09_RESPONSE);
1516 assert_eq!(msg.head.subject, crate::StatusCode::OK);
1517 assert_eq!(msg.head.version, crate::Version::HTTP_09);
1518 assert_eq!(msg.head.headers.len(), 0);
1519 }
1520
1521 #[test]
test_parse_response_h09_rejected()1522 fn test_parse_response_h09_rejected() {
1523 let _ = pretty_env_logger::try_init();
1524 let mut raw = BytesMut::from(H09_RESPONSE);
1525 let ctx = ParseContext {
1526 cached_headers: &mut None,
1527 req_method: &mut Some(crate::Method::GET),
1528 h1_parser_config: Default::default(),
1529 preserve_header_case: false,
1530 h09_responses: false,
1531 #[cfg(feature = "ffi")]
1532 on_informational: &mut None,
1533 #[cfg(feature = "ffi")]
1534 raw_headers: false,
1535 };
1536 Client::parse(&mut raw, ctx).unwrap_err();
1537 assert_eq!(raw, H09_RESPONSE);
1538 }
1539
1540 const RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &'static str =
1541 "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials : true\r\n\r\n";
1542
1543 #[test]
test_parse_allow_response_with_spaces_before_colons()1544 fn test_parse_allow_response_with_spaces_before_colons() {
1545 use httparse::ParserConfig;
1546
1547 let _ = pretty_env_logger::try_init();
1548 let mut raw = BytesMut::from(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1549 let mut h1_parser_config = ParserConfig::default();
1550 h1_parser_config.allow_spaces_after_header_name_in_responses(true);
1551 let ctx = ParseContext {
1552 cached_headers: &mut None,
1553 req_method: &mut Some(crate::Method::GET),
1554 h1_parser_config,
1555 preserve_header_case: false,
1556 h09_responses: false,
1557 #[cfg(feature = "ffi")]
1558 on_informational: &mut None,
1559 #[cfg(feature = "ffi")]
1560 raw_headers: false,
1561 };
1562 let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();
1563 assert_eq!(raw.len(), 0);
1564 assert_eq!(msg.head.subject, crate::StatusCode::OK);
1565 assert_eq!(msg.head.version, crate::Version::HTTP_11);
1566 assert_eq!(msg.head.headers.len(), 1);
1567 assert_eq!(msg.head.headers["Access-Control-Allow-Credentials"], "true");
1568 }
1569
1570 #[test]
test_parse_reject_response_with_spaces_before_colons()1571 fn test_parse_reject_response_with_spaces_before_colons() {
1572 let _ = pretty_env_logger::try_init();
1573 let mut raw = BytesMut::from(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1574 let ctx = ParseContext {
1575 cached_headers: &mut None,
1576 req_method: &mut Some(crate::Method::GET),
1577 h1_parser_config: Default::default(),
1578 preserve_header_case: false,
1579 h09_responses: false,
1580 #[cfg(feature = "ffi")]
1581 on_informational: &mut None,
1582 #[cfg(feature = "ffi")]
1583 raw_headers: false,
1584 };
1585 Client::parse(&mut raw, ctx).unwrap_err();
1586 }
1587
1588 #[test]
test_parse_preserve_header_case_in_request()1589 fn test_parse_preserve_header_case_in_request() {
1590 let mut raw =
1591 BytesMut::from("GET / HTTP/1.1\r\nHost: hyper.rs\r\nX-BREAD: baguette\r\n\r\n");
1592 let ctx = ParseContext {
1593 cached_headers: &mut None,
1594 req_method: &mut None,
1595 h1_parser_config: Default::default(),
1596 preserve_header_case: true,
1597 h09_responses: false,
1598 #[cfg(feature = "ffi")]
1599 on_informational: &mut None,
1600 #[cfg(feature = "ffi")]
1601 raw_headers: false,
1602 };
1603 let parsed_message = Server::parse(&mut raw, ctx).unwrap().unwrap();
1604 let orig_headers = parsed_message
1605 .head
1606 .extensions
1607 .get::<HeaderCaseMap>()
1608 .unwrap();
1609 assert_eq!(
1610 orig_headers
1611 .get_all_internal(&HeaderName::from_static("host"))
1612 .into_iter()
1613 .collect::<Vec<_>>(),
1614 vec![&Bytes::from("Host")]
1615 );
1616 assert_eq!(
1617 orig_headers
1618 .get_all_internal(&HeaderName::from_static("x-bread"))
1619 .into_iter()
1620 .collect::<Vec<_>>(),
1621 vec![&Bytes::from("X-BREAD")]
1622 );
1623 }
1624
1625 #[test]
test_decoder_request()1626 fn test_decoder_request() {
1627 fn parse(s: &str) -> ParsedMessage<RequestLine> {
1628 let mut bytes = BytesMut::from(s);
1629 Server::parse(
1630 &mut bytes,
1631 ParseContext {
1632 cached_headers: &mut None,
1633 req_method: &mut None,
1634 h1_parser_config: Default::default(),
1635 preserve_header_case: false,
1636 h09_responses: false,
1637 #[cfg(feature = "ffi")]
1638 on_informational: &mut None,
1639 #[cfg(feature = "ffi")]
1640 raw_headers: false,
1641 },
1642 )
1643 .expect("parse ok")
1644 .expect("parse complete")
1645 }
1646
1647 fn parse_err(s: &str, comment: &str) -> crate::error::Parse {
1648 let mut bytes = BytesMut::from(s);
1649 Server::parse(
1650 &mut bytes,
1651 ParseContext {
1652 cached_headers: &mut None,
1653 req_method: &mut None,
1654 h1_parser_config: Default::default(),
1655 preserve_header_case: false,
1656 h09_responses: false,
1657 #[cfg(feature = "ffi")]
1658 on_informational: &mut None,
1659 #[cfg(feature = "ffi")]
1660 raw_headers: false,
1661 },
1662 )
1663 .expect_err(comment)
1664 }
1665
1666 // no length or transfer-encoding means 0-length body
1667 assert_eq!(
1668 parse(
1669 "\
1670 GET / HTTP/1.1\r\n\
1671 \r\n\
1672 "
1673 )
1674 .decode,
1675 DecodedLength::ZERO
1676 );
1677
1678 assert_eq!(
1679 parse(
1680 "\
1681 POST / HTTP/1.1\r\n\
1682 \r\n\
1683 "
1684 )
1685 .decode,
1686 DecodedLength::ZERO
1687 );
1688
1689 // transfer-encoding: chunked
1690 assert_eq!(
1691 parse(
1692 "\
1693 POST / HTTP/1.1\r\n\
1694 transfer-encoding: chunked\r\n\
1695 \r\n\
1696 "
1697 )
1698 .decode,
1699 DecodedLength::CHUNKED
1700 );
1701
1702 assert_eq!(
1703 parse(
1704 "\
1705 POST / HTTP/1.1\r\n\
1706 transfer-encoding: gzip, chunked\r\n\
1707 \r\n\
1708 "
1709 )
1710 .decode,
1711 DecodedLength::CHUNKED
1712 );
1713
1714 assert_eq!(
1715 parse(
1716 "\
1717 POST / HTTP/1.1\r\n\
1718 transfer-encoding: gzip\r\n\
1719 transfer-encoding: chunked\r\n\
1720 \r\n\
1721 "
1722 )
1723 .decode,
1724 DecodedLength::CHUNKED
1725 );
1726
1727 // content-length
1728 assert_eq!(
1729 parse(
1730 "\
1731 POST / HTTP/1.1\r\n\
1732 content-length: 10\r\n\
1733 \r\n\
1734 "
1735 )
1736 .decode,
1737 DecodedLength::new(10)
1738 );
1739
1740 // transfer-encoding and content-length = chunked
1741 assert_eq!(
1742 parse(
1743 "\
1744 POST / HTTP/1.1\r\n\
1745 content-length: 10\r\n\
1746 transfer-encoding: chunked\r\n\
1747 \r\n\
1748 "
1749 )
1750 .decode,
1751 DecodedLength::CHUNKED
1752 );
1753
1754 assert_eq!(
1755 parse(
1756 "\
1757 POST / HTTP/1.1\r\n\
1758 transfer-encoding: chunked\r\n\
1759 content-length: 10\r\n\
1760 \r\n\
1761 "
1762 )
1763 .decode,
1764 DecodedLength::CHUNKED
1765 );
1766
1767 assert_eq!(
1768 parse(
1769 "\
1770 POST / HTTP/1.1\r\n\
1771 transfer-encoding: gzip\r\n\
1772 content-length: 10\r\n\
1773 transfer-encoding: chunked\r\n\
1774 \r\n\
1775 "
1776 )
1777 .decode,
1778 DecodedLength::CHUNKED
1779 );
1780
1781 // multiple content-lengths of same value are fine
1782 assert_eq!(
1783 parse(
1784 "\
1785 POST / HTTP/1.1\r\n\
1786 content-length: 10\r\n\
1787 content-length: 10\r\n\
1788 \r\n\
1789 "
1790 )
1791 .decode,
1792 DecodedLength::new(10)
1793 );
1794
1795 // multiple content-lengths with different values is an error
1796 parse_err(
1797 "\
1798 POST / HTTP/1.1\r\n\
1799 content-length: 10\r\n\
1800 content-length: 11\r\n\
1801 \r\n\
1802 ",
1803 "multiple content-lengths",
1804 );
1805
1806 // content-length with prefix is not allowed
1807 parse_err(
1808 "\
1809 POST / HTTP/1.1\r\n\
1810 content-length: +10\r\n\
1811 \r\n\
1812 ",
1813 "prefixed content-length",
1814 );
1815
1816 // transfer-encoding that isn't chunked is an error
1817 parse_err(
1818 "\
1819 POST / HTTP/1.1\r\n\
1820 transfer-encoding: gzip\r\n\
1821 \r\n\
1822 ",
1823 "transfer-encoding but not chunked",
1824 );
1825
1826 parse_err(
1827 "\
1828 POST / HTTP/1.1\r\n\
1829 transfer-encoding: chunked, gzip\r\n\
1830 \r\n\
1831 ",
1832 "transfer-encoding doesn't end in chunked",
1833 );
1834
1835 parse_err(
1836 "\
1837 POST / HTTP/1.1\r\n\
1838 transfer-encoding: chunked\r\n\
1839 transfer-encoding: afterlol\r\n\
1840 \r\n\
1841 ",
1842 "transfer-encoding multiple lines doesn't end in chunked",
1843 );
1844
1845 // http/1.0
1846
1847 assert_eq!(
1848 parse(
1849 "\
1850 POST / HTTP/1.0\r\n\
1851 content-length: 10\r\n\
1852 \r\n\
1853 "
1854 )
1855 .decode,
1856 DecodedLength::new(10)
1857 );
1858
1859 // 1.0 doesn't understand chunked, so its an error
1860 parse_err(
1861 "\
1862 POST / HTTP/1.0\r\n\
1863 transfer-encoding: chunked\r\n\
1864 \r\n\
1865 ",
1866 "1.0 chunked",
1867 );
1868 }
1869
1870 #[test]
test_decoder_response()1871 fn test_decoder_response() {
1872 fn parse(s: &str) -> ParsedMessage<StatusCode> {
1873 parse_with_method(s, Method::GET)
1874 }
1875
1876 fn parse_ignores(s: &str) {
1877 let mut bytes = BytesMut::from(s);
1878 assert!(Client::parse(
1879 &mut bytes,
1880 ParseContext {
1881 cached_headers: &mut None,
1882 req_method: &mut Some(Method::GET),
1883 h1_parser_config: Default::default(),
1884 preserve_header_case: false,
1885 h09_responses: false,
1886 #[cfg(feature = "ffi")]
1887 on_informational: &mut None,
1888 #[cfg(feature = "ffi")]
1889 raw_headers: false,
1890 }
1891 )
1892 .expect("parse ok")
1893 .is_none())
1894 }
1895
1896 fn parse_with_method(s: &str, m: Method) -> ParsedMessage<StatusCode> {
1897 let mut bytes = BytesMut::from(s);
1898 Client::parse(
1899 &mut bytes,
1900 ParseContext {
1901 cached_headers: &mut None,
1902 req_method: &mut Some(m),
1903 h1_parser_config: Default::default(),
1904 preserve_header_case: false,
1905 h09_responses: false,
1906 #[cfg(feature = "ffi")]
1907 on_informational: &mut None,
1908 #[cfg(feature = "ffi")]
1909 raw_headers: false,
1910 },
1911 )
1912 .expect("parse ok")
1913 .expect("parse complete")
1914 }
1915
1916 fn parse_err(s: &str) -> crate::error::Parse {
1917 let mut bytes = BytesMut::from(s);
1918 Client::parse(
1919 &mut bytes,
1920 ParseContext {
1921 cached_headers: &mut None,
1922 req_method: &mut Some(Method::GET),
1923 h1_parser_config: Default::default(),
1924 preserve_header_case: false,
1925 h09_responses: false,
1926 #[cfg(feature = "ffi")]
1927 on_informational: &mut None,
1928 #[cfg(feature = "ffi")]
1929 raw_headers: false,
1930 },
1931 )
1932 .expect_err("parse should err")
1933 }
1934
1935 // no content-length or transfer-encoding means close-delimited
1936 assert_eq!(
1937 parse(
1938 "\
1939 HTTP/1.1 200 OK\r\n\
1940 \r\n\
1941 "
1942 )
1943 .decode,
1944 DecodedLength::CLOSE_DELIMITED
1945 );
1946
1947 // 204 and 304 never have a body
1948 assert_eq!(
1949 parse(
1950 "\
1951 HTTP/1.1 204 No Content\r\n\
1952 \r\n\
1953 "
1954 )
1955 .decode,
1956 DecodedLength::ZERO
1957 );
1958
1959 assert_eq!(
1960 parse(
1961 "\
1962 HTTP/1.1 304 Not Modified\r\n\
1963 \r\n\
1964 "
1965 )
1966 .decode,
1967 DecodedLength::ZERO
1968 );
1969
1970 // content-length
1971 assert_eq!(
1972 parse(
1973 "\
1974 HTTP/1.1 200 OK\r\n\
1975 content-length: 8\r\n\
1976 \r\n\
1977 "
1978 )
1979 .decode,
1980 DecodedLength::new(8)
1981 );
1982
1983 assert_eq!(
1984 parse(
1985 "\
1986 HTTP/1.1 200 OK\r\n\
1987 content-length: 8\r\n\
1988 content-length: 8\r\n\
1989 \r\n\
1990 "
1991 )
1992 .decode,
1993 DecodedLength::new(8)
1994 );
1995
1996 parse_err(
1997 "\
1998 HTTP/1.1 200 OK\r\n\
1999 content-length: 8\r\n\
2000 content-length: 9\r\n\
2001 \r\n\
2002 ",
2003 );
2004
2005 parse_err(
2006 "\
2007 HTTP/1.1 200 OK\r\n\
2008 content-length: +8\r\n\
2009 \r\n\
2010 ",
2011 );
2012
2013 // transfer-encoding: chunked
2014 assert_eq!(
2015 parse(
2016 "\
2017 HTTP/1.1 200 OK\r\n\
2018 transfer-encoding: chunked\r\n\
2019 \r\n\
2020 "
2021 )
2022 .decode,
2023 DecodedLength::CHUNKED
2024 );
2025
2026 // transfer-encoding not-chunked is close-delimited
2027 assert_eq!(
2028 parse(
2029 "\
2030 HTTP/1.1 200 OK\r\n\
2031 transfer-encoding: yolo\r\n\
2032 \r\n\
2033 "
2034 )
2035 .decode,
2036 DecodedLength::CLOSE_DELIMITED
2037 );
2038
2039 // transfer-encoding and content-length = chunked
2040 assert_eq!(
2041 parse(
2042 "\
2043 HTTP/1.1 200 OK\r\n\
2044 content-length: 10\r\n\
2045 transfer-encoding: chunked\r\n\
2046 \r\n\
2047 "
2048 )
2049 .decode,
2050 DecodedLength::CHUNKED
2051 );
2052
2053 // HEAD can have content-length, but not body
2054 assert_eq!(
2055 parse_with_method(
2056 "\
2057 HTTP/1.1 200 OK\r\n\
2058 content-length: 8\r\n\
2059 \r\n\
2060 ",
2061 Method::HEAD
2062 )
2063 .decode,
2064 DecodedLength::ZERO
2065 );
2066
2067 // CONNECT with 200 never has body
2068 {
2069 let msg = parse_with_method(
2070 "\
2071 HTTP/1.1 200 OK\r\n\
2072 \r\n\
2073 ",
2074 Method::CONNECT,
2075 );
2076 assert_eq!(msg.decode, DecodedLength::ZERO);
2077 assert!(!msg.keep_alive, "should be upgrade");
2078 assert!(msg.wants_upgrade, "should be upgrade");
2079 }
2080
2081 // CONNECT receiving non 200 can have a body
2082 assert_eq!(
2083 parse_with_method(
2084 "\
2085 HTTP/1.1 400 Bad Request\r\n\
2086 \r\n\
2087 ",
2088 Method::CONNECT
2089 )
2090 .decode,
2091 DecodedLength::CLOSE_DELIMITED
2092 );
2093
2094 // 1xx status codes
2095 parse_ignores(
2096 "\
2097 HTTP/1.1 100 Continue\r\n\
2098 \r\n\
2099 ",
2100 );
2101
2102 parse_ignores(
2103 "\
2104 HTTP/1.1 103 Early Hints\r\n\
2105 \r\n\
2106 ",
2107 );
2108
2109 // 101 upgrade not supported yet
2110 {
2111 let msg = parse(
2112 "\
2113 HTTP/1.1 101 Switching Protocols\r\n\
2114 \r\n\
2115 ",
2116 );
2117 assert_eq!(msg.decode, DecodedLength::ZERO);
2118 assert!(!msg.keep_alive, "should be last");
2119 assert!(msg.wants_upgrade, "should be upgrade");
2120 }
2121
2122 // http/1.0
2123 assert_eq!(
2124 parse(
2125 "\
2126 HTTP/1.0 200 OK\r\n\
2127 \r\n\
2128 "
2129 )
2130 .decode,
2131 DecodedLength::CLOSE_DELIMITED
2132 );
2133
2134 // 1.0 doesn't understand chunked
2135 parse_err(
2136 "\
2137 HTTP/1.0 200 OK\r\n\
2138 transfer-encoding: chunked\r\n\
2139 \r\n\
2140 ",
2141 );
2142
2143 // keep-alive
2144 assert!(
2145 parse(
2146 "\
2147 HTTP/1.1 200 OK\r\n\
2148 content-length: 0\r\n\
2149 \r\n\
2150 "
2151 )
2152 .keep_alive,
2153 "HTTP/1.1 keep-alive is default"
2154 );
2155
2156 assert!(
2157 !parse(
2158 "\
2159 HTTP/1.1 200 OK\r\n\
2160 content-length: 0\r\n\
2161 connection: foo, close, bar\r\n\
2162 \r\n\
2163 "
2164 )
2165 .keep_alive,
2166 "connection close is always close"
2167 );
2168
2169 assert!(
2170 !parse(
2171 "\
2172 HTTP/1.0 200 OK\r\n\
2173 content-length: 0\r\n\
2174 \r\n\
2175 "
2176 )
2177 .keep_alive,
2178 "HTTP/1.0 close is default"
2179 );
2180
2181 assert!(
2182 parse(
2183 "\
2184 HTTP/1.0 200 OK\r\n\
2185 content-length: 0\r\n\
2186 connection: foo, keep-alive, bar\r\n\
2187 \r\n\
2188 "
2189 )
2190 .keep_alive,
2191 "connection keep-alive is always keep-alive"
2192 );
2193 }
2194
2195 #[test]
test_client_request_encode_title_case()2196 fn test_client_request_encode_title_case() {
2197 use crate::proto::BodyLength;
2198 use http::header::HeaderValue;
2199
2200 let mut head = MessageHead::default();
2201 head.headers
2202 .insert("content-length", HeaderValue::from_static("10"));
2203 head.headers
2204 .insert("content-type", HeaderValue::from_static("application/json"));
2205 head.headers.insert("*-*", HeaderValue::from_static("o_o"));
2206
2207 let mut vec = Vec::new();
2208 Client::encode(
2209 Encode {
2210 head: &mut head,
2211 body: Some(BodyLength::Known(10)),
2212 keep_alive: true,
2213 req_method: &mut None,
2214 title_case_headers: true,
2215 },
2216 &mut vec,
2217 )
2218 .unwrap();
2219
2220 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());
2221 }
2222
2223 #[test]
test_client_request_encode_orig_case()2224 fn test_client_request_encode_orig_case() {
2225 use crate::proto::BodyLength;
2226 use http::header::{HeaderValue, CONTENT_LENGTH};
2227
2228 let mut head = MessageHead::default();
2229 head.headers
2230 .insert("content-length", HeaderValue::from_static("10"));
2231 head.headers
2232 .insert("content-type", HeaderValue::from_static("application/json"));
2233
2234 let mut orig_headers = HeaderCaseMap::default();
2235 orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2236 head.extensions.insert(orig_headers);
2237
2238 let mut vec = Vec::new();
2239 Client::encode(
2240 Encode {
2241 head: &mut head,
2242 body: Some(BodyLength::Known(10)),
2243 keep_alive: true,
2244 req_method: &mut None,
2245 title_case_headers: false,
2246 },
2247 &mut vec,
2248 )
2249 .unwrap();
2250
2251 assert_eq!(
2252 &*vec,
2253 b"GET / HTTP/1.1\r\nCONTENT-LENGTH: 10\r\ncontent-type: application/json\r\n\r\n"
2254 .as_ref(),
2255 );
2256 }
2257 #[test]
test_client_request_encode_orig_and_title_case()2258 fn test_client_request_encode_orig_and_title_case() {
2259 use crate::proto::BodyLength;
2260 use http::header::{HeaderValue, CONTENT_LENGTH};
2261
2262 let mut head = MessageHead::default();
2263 head.headers
2264 .insert("content-length", HeaderValue::from_static("10"));
2265 head.headers
2266 .insert("content-type", HeaderValue::from_static("application/json"));
2267
2268 let mut orig_headers = HeaderCaseMap::default();
2269 orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2270 head.extensions.insert(orig_headers);
2271
2272 let mut vec = Vec::new();
2273 Client::encode(
2274 Encode {
2275 head: &mut head,
2276 body: Some(BodyLength::Known(10)),
2277 keep_alive: true,
2278 req_method: &mut None,
2279 title_case_headers: true,
2280 },
2281 &mut vec,
2282 )
2283 .unwrap();
2284
2285 assert_eq!(
2286 &*vec,
2287 b"GET / HTTP/1.1\r\nCONTENT-LENGTH: 10\r\nContent-Type: application/json\r\n\r\n"
2288 .as_ref(),
2289 );
2290 }
2291
2292 #[test]
test_server_encode_connect_method()2293 fn test_server_encode_connect_method() {
2294 let mut head = MessageHead::default();
2295
2296 let mut vec = Vec::new();
2297 let encoder = Server::encode(
2298 Encode {
2299 head: &mut head,
2300 body: None,
2301 keep_alive: true,
2302 req_method: &mut Some(Method::CONNECT),
2303 title_case_headers: false,
2304 },
2305 &mut vec,
2306 )
2307 .unwrap();
2308
2309 assert!(encoder.is_last());
2310 }
2311
2312 #[test]
test_server_response_encode_title_case()2313 fn test_server_response_encode_title_case() {
2314 use crate::proto::BodyLength;
2315 use http::header::HeaderValue;
2316
2317 let mut head = MessageHead::default();
2318 head.headers
2319 .insert("content-length", HeaderValue::from_static("10"));
2320 head.headers
2321 .insert("content-type", HeaderValue::from_static("application/json"));
2322 head.headers
2323 .insert("weird--header", HeaderValue::from_static(""));
2324
2325 let mut vec = Vec::new();
2326 Server::encode(
2327 Encode {
2328 head: &mut head,
2329 body: Some(BodyLength::Known(10)),
2330 keep_alive: true,
2331 req_method: &mut None,
2332 title_case_headers: true,
2333 },
2334 &mut vec,
2335 )
2336 .unwrap();
2337
2338 let expected_response =
2339 b"HTTP/1.1 200 OK\r\nContent-Length: 10\r\nContent-Type: application/json\r\nWeird--Header: \r\n";
2340
2341 assert_eq!(&vec[..expected_response.len()], &expected_response[..]);
2342 }
2343
2344 #[test]
test_server_response_encode_orig_case()2345 fn test_server_response_encode_orig_case() {
2346 use crate::proto::BodyLength;
2347 use http::header::{HeaderValue, CONTENT_LENGTH};
2348
2349 let mut head = MessageHead::default();
2350 head.headers
2351 .insert("content-length", HeaderValue::from_static("10"));
2352 head.headers
2353 .insert("content-type", HeaderValue::from_static("application/json"));
2354
2355 let mut orig_headers = HeaderCaseMap::default();
2356 orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2357 head.extensions.insert(orig_headers);
2358
2359 let mut vec = Vec::new();
2360 Server::encode(
2361 Encode {
2362 head: &mut head,
2363 body: Some(BodyLength::Known(10)),
2364 keep_alive: true,
2365 req_method: &mut None,
2366 title_case_headers: false,
2367 },
2368 &mut vec,
2369 )
2370 .unwrap();
2371
2372 let expected_response =
2373 b"HTTP/1.1 200 OK\r\nCONTENT-LENGTH: 10\r\ncontent-type: application/json\r\ndate: ";
2374
2375 assert_eq!(&vec[..expected_response.len()], &expected_response[..]);
2376 }
2377
2378 #[test]
test_server_response_encode_orig_and_title_case()2379 fn test_server_response_encode_orig_and_title_case() {
2380 use crate::proto::BodyLength;
2381 use http::header::{HeaderValue, CONTENT_LENGTH};
2382
2383 let mut head = MessageHead::default();
2384 head.headers
2385 .insert("content-length", HeaderValue::from_static("10"));
2386 head.headers
2387 .insert("content-type", HeaderValue::from_static("application/json"));
2388
2389 let mut orig_headers = HeaderCaseMap::default();
2390 orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
2391 head.extensions.insert(orig_headers);
2392
2393 let mut vec = Vec::new();
2394 Server::encode(
2395 Encode {
2396 head: &mut head,
2397 body: Some(BodyLength::Known(10)),
2398 keep_alive: true,
2399 req_method: &mut None,
2400 title_case_headers: true,
2401 },
2402 &mut vec,
2403 )
2404 .unwrap();
2405
2406 let expected_response =
2407 b"HTTP/1.1 200 OK\r\nCONTENT-LENGTH: 10\r\nContent-Type: application/json\r\nDate: ";
2408
2409 assert_eq!(&vec[..expected_response.len()], &expected_response[..]);
2410 }
2411
2412 #[test]
parse_header_htabs()2413 fn parse_header_htabs() {
2414 let mut bytes = BytesMut::from("HTTP/1.1 200 OK\r\nserver: hello\tworld\r\n\r\n");
2415 let parsed = Client::parse(
2416 &mut bytes,
2417 ParseContext {
2418 cached_headers: &mut None,
2419 req_method: &mut Some(Method::GET),
2420 h1_parser_config: Default::default(),
2421 preserve_header_case: false,
2422 h09_responses: false,
2423 #[cfg(feature = "ffi")]
2424 on_informational: &mut None,
2425 #[cfg(feature = "ffi")]
2426 raw_headers: false,
2427 },
2428 )
2429 .expect("parse ok")
2430 .expect("parse complete");
2431
2432 assert_eq!(parsed.head.headers["server"], "hello\tworld");
2433 }
2434
2435 #[test]
test_write_headers_orig_case_empty_value()2436 fn test_write_headers_orig_case_empty_value() {
2437 let mut headers = HeaderMap::new();
2438 let name = http::header::HeaderName::from_static("x-empty");
2439 headers.insert(&name, "".parse().expect("parse empty"));
2440 let mut orig_cases = HeaderCaseMap::default();
2441 orig_cases.insert(name, Bytes::from_static(b"X-EmptY"));
2442
2443 let mut dst = Vec::new();
2444 super::write_headers_original_case(&headers, &orig_cases, &mut dst, false);
2445
2446 assert_eq!(
2447 dst, b"X-EmptY:\r\n",
2448 "there should be no space between the colon and CRLF"
2449 );
2450 }
2451
2452 #[test]
test_write_headers_orig_case_multiple_entries()2453 fn test_write_headers_orig_case_multiple_entries() {
2454 let mut headers = HeaderMap::new();
2455 let name = http::header::HeaderName::from_static("x-empty");
2456 headers.insert(&name, "a".parse().unwrap());
2457 headers.append(&name, "b".parse().unwrap());
2458
2459 let mut orig_cases = HeaderCaseMap::default();
2460 orig_cases.insert(name.clone(), Bytes::from_static(b"X-Empty"));
2461 orig_cases.append(name, Bytes::from_static(b"X-EMPTY"));
2462
2463 let mut dst = Vec::new();
2464 super::write_headers_original_case(&headers, &orig_cases, &mut dst, false);
2465
2466 assert_eq!(dst, b"X-Empty: a\r\nX-EMPTY: b\r\n");
2467 }
2468
2469 #[cfg(feature = "nightly")]
2470 use test::Bencher;
2471
2472 #[cfg(feature = "nightly")]
2473 #[bench]
bench_parse_incoming(b: &mut Bencher)2474 fn bench_parse_incoming(b: &mut Bencher) {
2475 let mut raw = BytesMut::from(
2476 &b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\
2477 I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\
2478 _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\
2479 foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \
2480 hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \
2481 utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\
2482 Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\
2483 Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\
2484 Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\
2485 Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\
2486 \r\nSec-Websocket-Extensions: It looks super important!\r\n\
2487 Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\
2488 \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\
2489 X-Content-Duration: None\r\nX-Content-Security-Policy: None\
2490 \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \
2491 Something important obviously\r\nX-Requested-With: Nothing\
2492 \r\n\r\n"[..],
2493 );
2494 let len = raw.len();
2495 let mut headers = Some(HeaderMap::new());
2496
2497 b.bytes = len as u64;
2498 b.iter(|| {
2499 let mut msg = Server::parse(
2500 &mut raw,
2501 ParseContext {
2502 cached_headers: &mut headers,
2503 req_method: &mut None,
2504 h1_parser_config: Default::default(),
2505 preserve_header_case: false,
2506 h09_responses: false,
2507 #[cfg(feature = "ffi")]
2508 on_informational: &mut None,
2509 #[cfg(feature = "ffi")]
2510 raw_headers: false,
2511 },
2512 )
2513 .unwrap()
2514 .unwrap();
2515 ::test::black_box(&msg);
2516 msg.head.headers.clear();
2517 headers = Some(msg.head.headers);
2518 restart(&mut raw, len);
2519 });
2520
2521 fn restart(b: &mut BytesMut, len: usize) {
2522 b.reserve(1);
2523 unsafe {
2524 b.set_len(len);
2525 }
2526 }
2527 }
2528
2529 #[cfg(feature = "nightly")]
2530 #[bench]
bench_parse_short(b: &mut Bencher)2531 fn bench_parse_short(b: &mut Bencher) {
2532 let s = &b"GET / HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"[..];
2533 let mut raw = BytesMut::from(s);
2534 let len = raw.len();
2535 let mut headers = Some(HeaderMap::new());
2536
2537 b.bytes = len as u64;
2538 b.iter(|| {
2539 let mut msg = Server::parse(
2540 &mut raw,
2541 ParseContext {
2542 cached_headers: &mut headers,
2543 req_method: &mut None,
2544 h1_parser_config: Default::default(),
2545 preserve_header_case: false,
2546 h09_responses: false,
2547 #[cfg(feature = "ffi")]
2548 on_informational: &mut None,
2549 #[cfg(feature = "ffi")]
2550 raw_headers: false,
2551 },
2552 )
2553 .unwrap()
2554 .unwrap();
2555 ::test::black_box(&msg);
2556 msg.head.headers.clear();
2557 headers = Some(msg.head.headers);
2558 restart(&mut raw, len);
2559 });
2560
2561 fn restart(b: &mut BytesMut, len: usize) {
2562 b.reserve(1);
2563 unsafe {
2564 b.set_len(len);
2565 }
2566 }
2567 }
2568
2569 #[cfg(feature = "nightly")]
2570 #[bench]
bench_server_encode_headers_preset(b: &mut Bencher)2571 fn bench_server_encode_headers_preset(b: &mut Bencher) {
2572 use crate::proto::BodyLength;
2573 use http::header::HeaderValue;
2574
2575 let len = 108;
2576 b.bytes = len as u64;
2577
2578 let mut head = MessageHead::default();
2579 let mut headers = HeaderMap::new();
2580 headers.insert("content-length", HeaderValue::from_static("10"));
2581 headers.insert("content-type", HeaderValue::from_static("application/json"));
2582
2583 b.iter(|| {
2584 let mut vec = Vec::new();
2585 head.headers = headers.clone();
2586 Server::encode(
2587 Encode {
2588 head: &mut head,
2589 body: Some(BodyLength::Known(10)),
2590 keep_alive: true,
2591 req_method: &mut Some(Method::GET),
2592 title_case_headers: false,
2593 },
2594 &mut vec,
2595 )
2596 .unwrap();
2597 assert_eq!(vec.len(), len);
2598 ::test::black_box(vec);
2599 })
2600 }
2601
2602 #[cfg(feature = "nightly")]
2603 #[bench]
bench_server_encode_no_headers(b: &mut Bencher)2604 fn bench_server_encode_no_headers(b: &mut Bencher) {
2605 use crate::proto::BodyLength;
2606
2607 let len = 76;
2608 b.bytes = len as u64;
2609
2610 let mut head = MessageHead::default();
2611 let mut vec = Vec::with_capacity(128);
2612
2613 b.iter(|| {
2614 Server::encode(
2615 Encode {
2616 head: &mut head,
2617 body: Some(BodyLength::Known(10)),
2618 keep_alive: true,
2619 req_method: &mut Some(Method::GET),
2620 title_case_headers: false,
2621 },
2622 &mut vec,
2623 )
2624 .unwrap();
2625 assert_eq!(vec.len(), len);
2626 ::test::black_box(&vec);
2627
2628 vec.clear();
2629 })
2630 }
2631 }
2632