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