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