1#![allow(clippy::new_without_default)]
24
25use bytes::BufMut;
26use http::header::{AsHeaderName, HeaderName, HeaderValue};
27use http::request::Builder as ReqBuilder;
28use http::request::Parts as ReqParts;
29use http::response::Builder as RespBuilder;
30use http::response::Parts as RespParts;
31use http::uri::Uri;
32use pingora_error::{ErrorType::*, OrErr, Result};
33use std::ops::{Deref, DerefMut};
34
35pub use http::method::Method;
36pub use http::status::StatusCode;
37pub use http::version::Version;
38pub use http::HeaderMap as HMap;
39
40mod case_header_name;
41use case_header_name::CaseHeaderName;
42pub use case_header_name::IntoCaseHeaderName;
43
44pub mod prelude {
45 pub use crate::RequestHeader;
46 pub use crate::ResponseHeader;
47}
48
49type CaseMap = HMap<CaseHeaderName>;
59
60pub enum HeaderNameVariant<'a> {
61 Case(&'a CaseHeaderName),
62 Titled(&'a str),
63}
64
65#[derive(Debug)]
73pub struct RequestHeader {
74 base: ReqParts,
75 header_name_map: Option<CaseMap>,
76 raw_path_fallback: Vec<u8>, send_end_stream: bool,
80}
81
82impl AsRef<ReqParts> for RequestHeader {
83 fn as_ref(&self) -> &ReqParts {
84 &self.base
85 }
86}
87
88impl Deref for RequestHeader {
89 type Target = ReqParts;
90
91 fn deref(&self) -> &Self::Target {
92 &self.base
93 }
94}
95
96impl DerefMut for RequestHeader {
97 fn deref_mut(&mut self) -> &mut Self::Target {
98 &mut self.base
99 }
100}
101
102impl RequestHeader {
103 fn new_no_case(size_hint: Option<usize>) -> Self {
104 let mut base = ReqBuilder::new().body(()).unwrap().into_parts().0;
105 base.headers.reserve(http_header_map_upper_bound(size_hint));
106 RequestHeader {
107 base,
108 header_name_map: None,
109 raw_path_fallback: vec![],
110 send_end_stream: true,
111 }
112 }
113
114 pub fn build(
118 method: impl TryInto<Method>,
119 path: &[u8],
120 size_hint: Option<usize>,
121 ) -> Result<Self> {
122 let mut req = Self::build_no_case(method, path, size_hint)?;
123 req.header_name_map = Some(CaseMap::with_capacity(http_header_map_upper_bound(
124 size_hint,
125 )));
126 Ok(req)
127 }
128
129 pub fn build_no_case(
135 method: impl TryInto<Method>,
136 path: &[u8],
137 size_hint: Option<usize>,
138 ) -> Result<Self> {
139 let mut req = Self::new_no_case(size_hint);
140 req.base.method = method
141 .try_into()
142 .explain_err(InvalidHTTPHeader, |_| "invalid method")?;
143 req.set_raw_path(path)?;
144 Ok(req)
145 }
146
147 pub fn append_header(
152 &mut self,
153 name: impl IntoCaseHeaderName,
154 value: impl TryInto<HeaderValue>,
155 ) -> Result<bool> {
156 let header_value = value
157 .try_into()
158 .explain_err(InvalidHTTPHeader, |_| "invalid value while append")?;
159 append_header_value(
160 self.header_name_map.as_mut(),
161 &mut self.base.headers,
162 name,
163 header_value,
164 )
165 }
166
167 pub fn insert_header(
172 &mut self,
173 name: impl IntoCaseHeaderName,
174 value: impl TryInto<HeaderValue>,
175 ) -> Result<()> {
176 let header_value = value
177 .try_into()
178 .explain_err(InvalidHTTPHeader, |_| "invalid value while insert")?;
179 insert_header_value(
180 self.header_name_map.as_mut(),
181 &mut self.base.headers,
182 name,
183 header_value,
184 )
185 }
186
187 pub fn remove_header<'a, N: ?Sized>(&mut self, name: &'a N) -> Option<HeaderValue>
189 where
190 &'a N: 'a + AsHeaderName,
191 {
192 remove_header(self.header_name_map.as_mut(), &mut self.base.headers, name)
193 }
194
195 pub fn header_to_h1_wire(&self, buf: &mut impl BufMut) {
199 header_to_h1_wire(self.header_name_map.as_ref(), &self.base.headers, buf)
200 }
201
202 pub fn case_header_iter(&self) -> impl Iterator<Item = (&CaseHeaderName, &HeaderValue)> + '_ {
207 case_header_iter(self.header_name_map.as_ref(), &self.base.headers)
208 }
209
210 pub fn has_case(&self) -> bool {
212 self.header_name_map.is_some()
213 }
214
215 pub fn map<F: FnMut(HeaderNameVariant, &HeaderValue) -> Result<()>>(
216 &self,
217 mut f: F,
218 ) -> Result<()> {
219 let key_map = self.header_name_map.as_ref();
220 let value_map = &self.base.headers;
221
222 if let Some(key_map) = key_map {
223 let iter = key_map.iter().zip(value_map.iter());
224 for ((header, case_header), (header2, val)) in iter {
225 if header != header2 {
226 panic!("header iter mismatch {}, {}", header, header2)
228 }
229 f(HeaderNameVariant::Case(case_header), val)?;
230 }
231 } else {
232 for (header, value) in value_map {
233 let titled_header =
234 case_header_name::titled_header_name_str(header).unwrap_or(header.as_str());
235 f(HeaderNameVariant::Titled(titled_header), value)?;
236 }
237 }
238
239 Ok(())
240 }
241
242 pub fn set_method(&mut self, method: Method) {
244 self.base.method = method;
245 }
246
247 pub fn set_uri(&mut self, uri: http::Uri) {
249 self.base.uri = uri;
250 self.raw_path_fallback = vec![];
252 }
253
254 pub fn set_raw_path(&mut self, path: &[u8]) -> Result<()> {
260 if let Ok(p) = std::str::from_utf8(path) {
261 let uri = Uri::builder()
262 .path_and_query(p)
263 .build()
264 .explain_err(InvalidHTTPHeader, |_| format!("invalid uri {}", p))?;
265 self.base.uri = uri;
266 } else {
268 let lossy_str = String::from_utf8_lossy(path);
270 let uri = Uri::builder()
271 .path_and_query(lossy_str.as_ref())
272 .build()
273 .explain_err(InvalidHTTPHeader, |_| format!("invalid uri {}", lossy_str))?;
274 self.base.uri = uri;
275 self.raw_path_fallback = path.to_vec();
276 }
277 Ok(())
278 }
279
280 pub fn set_send_end_stream(&mut self, send_end_stream: bool) {
282 self.send_end_stream = send_end_stream;
283 }
284
285 pub fn send_end_stream(&self) -> Option<bool> {
288 if self.base.version != Version::HTTP_2 {
289 return None;
290 }
291 Some(self.send_end_stream)
292 }
293
294 pub fn raw_path(&self) -> &[u8] {
298 if !self.raw_path_fallback.is_empty() {
299 &self.raw_path_fallback
300 } else {
301 self.base
303 .uri
304 .path_and_query()
305 .as_ref()
306 .unwrap()
307 .as_str()
308 .as_bytes()
309 }
310 }
311
312 pub fn uri_file_extension(&self) -> Option<&str> {
314 let (_, ext) = self
316 .uri
317 .path_and_query()
318 .and_then(|pq| pq.path().rsplit_once('.'))?;
319 Some(ext)
320 }
321
322 pub fn set_version(&mut self, version: Version) {
324 self.base.version = version;
325 }
326
327 pub fn as_owned_parts(&self) -> ReqParts {
329 clone_req_parts(&self.base)
330 }
331}
332
333impl Clone for RequestHeader {
334 fn clone(&self) -> Self {
335 Self {
336 base: self.as_owned_parts(),
337 header_name_map: self.header_name_map.clone(),
338 raw_path_fallback: self.raw_path_fallback.clone(),
339 send_end_stream: self.send_end_stream,
340 }
341 }
342}
343
344impl From<ReqParts> for RequestHeader {
346 fn from(parts: ReqParts) -> RequestHeader {
347 Self {
348 base: parts,
349 header_name_map: None,
350 raw_path_fallback: vec![],
352 send_end_stream: true,
353 }
354 }
355}
356
357impl From<RequestHeader> for ReqParts {
358 fn from(resp: RequestHeader) -> ReqParts {
359 resp.base
360 }
361}
362
363#[derive(Debug)]
369pub struct ResponseHeader {
370 base: RespParts,
371 header_name_map: Option<CaseMap>,
373 reason_phrase: Option<String>,
375}
376
377impl AsRef<RespParts> for ResponseHeader {
378 fn as_ref(&self) -> &RespParts {
379 &self.base
380 }
381}
382
383impl Deref for ResponseHeader {
384 type Target = RespParts;
385
386 fn deref(&self) -> &Self::Target {
387 &self.base
388 }
389}
390
391impl DerefMut for ResponseHeader {
392 fn deref_mut(&mut self) -> &mut Self::Target {
393 &mut self.base
394 }
395}
396
397impl Clone for ResponseHeader {
398 fn clone(&self) -> Self {
399 Self {
400 base: self.as_owned_parts(),
401 header_name_map: self.header_name_map.clone(),
402 reason_phrase: self.reason_phrase.clone(),
403 }
404 }
405}
406
407impl From<RespParts> for ResponseHeader {
409 fn from(parts: RespParts) -> ResponseHeader {
410 Self {
411 base: parts,
412 header_name_map: None,
413 reason_phrase: None,
414 }
415 }
416}
417
418impl From<ResponseHeader> for RespParts {
419 fn from(resp: ResponseHeader) -> RespParts {
420 resp.base
421 }
422}
423
424impl From<Box<ResponseHeader>> for Box<RespParts> {
425 fn from(resp: Box<ResponseHeader>) -> Box<RespParts> {
426 Box::new(resp.base)
427 }
428}
429
430impl ResponseHeader {
431 fn new(size_hint: Option<usize>) -> Self {
432 let mut resp_header = Self::new_no_case(size_hint);
433 resp_header.header_name_map = Some(CaseMap::with_capacity(http_header_map_upper_bound(
434 size_hint,
435 )));
436 resp_header
437 }
438
439 fn new_no_case(size_hint: Option<usize>) -> Self {
440 let mut base = RespBuilder::new().body(()).unwrap().into_parts().0;
441 base.headers.reserve(http_header_map_upper_bound(size_hint));
442 ResponseHeader {
443 base,
444 header_name_map: None,
445 reason_phrase: None,
446 }
447 }
448
449 pub fn build(code: impl TryInto<StatusCode>, size_hint: Option<usize>) -> Result<Self> {
451 let mut resp = Self::new(size_hint);
452 resp.base.status = code
453 .try_into()
454 .explain_err(InvalidHTTPHeader, |_| "invalid status")?;
455 Ok(resp)
456 }
457
458 pub fn build_no_case(code: impl TryInto<StatusCode>, size_hint: Option<usize>) -> Result<Self> {
464 let mut resp = Self::new_no_case(size_hint);
465 resp.base.status = code
466 .try_into()
467 .explain_err(InvalidHTTPHeader, |_| "invalid status")?;
468 Ok(resp)
469 }
470
471 pub fn append_header(
476 &mut self,
477 name: impl IntoCaseHeaderName,
478 value: impl TryInto<HeaderValue>,
479 ) -> Result<bool> {
480 let header_value = value
481 .try_into()
482 .explain_err(InvalidHTTPHeader, |_| "invalid value while append")?;
483 append_header_value(
484 self.header_name_map.as_mut(),
485 &mut self.base.headers,
486 name,
487 header_value,
488 )
489 }
490
491 pub fn insert_header(
496 &mut self,
497 name: impl IntoCaseHeaderName,
498 value: impl TryInto<HeaderValue>,
499 ) -> Result<()> {
500 let header_value = value
501 .try_into()
502 .explain_err(InvalidHTTPHeader, |_| "invalid value while insert")?;
503 insert_header_value(
504 self.header_name_map.as_mut(),
505 &mut self.base.headers,
506 name,
507 header_value,
508 )
509 }
510
511 pub fn remove_header<'a, N: ?Sized>(&mut self, name: &'a N) -> Option<HeaderValue>
513 where
514 &'a N: 'a + AsHeaderName,
515 {
516 remove_header(self.header_name_map.as_mut(), &mut self.base.headers, name)
517 }
518
519 pub fn header_to_h1_wire(&self, buf: &mut impl BufMut) {
523 header_to_h1_wire(self.header_name_map.as_ref(), &self.base.headers, buf)
524 }
525
526 pub fn case_header_iter(&self) -> impl Iterator<Item = (&CaseHeaderName, &HeaderValue)> + '_ {
531 case_header_iter(self.header_name_map.as_ref(), &self.base.headers)
532 }
533
534 pub fn has_case(&self) -> bool {
536 self.header_name_map.is_some()
537 }
538
539 pub fn map<F: FnMut(HeaderNameVariant, &HeaderValue) -> Result<()>>(
540 &self,
541 mut f: F,
542 ) -> Result<()> {
543 let key_map = self.header_name_map.as_ref();
544 let value_map = &self.base.headers;
545
546 if let Some(key_map) = key_map {
547 let iter = key_map.iter().zip(value_map.iter());
548 for ((header, case_header), (header2, val)) in iter {
549 if header != header2 {
550 panic!("header iter mismatch {}, {}", header, header2)
552 }
553 f(HeaderNameVariant::Case(case_header), val)?;
554 }
555 } else {
556 for (header, value) in value_map {
557 let titled_header =
558 case_header_name::titled_header_name_str(header).unwrap_or(header.as_str());
559 f(HeaderNameVariant::Titled(titled_header), value)?;
560 }
561 }
562
563 Ok(())
564 }
565
566 pub fn set_status(&mut self, status: impl TryInto<StatusCode>) -> Result<()> {
568 self.base.status = status
569 .try_into()
570 .explain_err(InvalidHTTPHeader, |_| "invalid status")?;
571 Ok(())
572 }
573
574 pub fn set_version(&mut self, version: Version) {
576 self.base.version = version
577 }
578
579 pub fn set_reason_phrase(&mut self, reason_phrase: Option<&str>) -> Result<()> {
581 if reason_phrase == self.base.status.canonical_reason() {
583 self.reason_phrase = None;
584 return Ok(());
585 }
586
587 self.reason_phrase = reason_phrase.map(str::to_string);
589 Ok(())
590 }
591
592 pub fn get_reason_phrase(&self) -> Option<&str> {
595 self.reason_phrase
596 .as_deref()
597 .or_else(|| self.base.status.canonical_reason())
598 }
599
600 pub fn as_owned_parts(&self) -> RespParts {
602 clone_resp_parts(&self.base)
603 }
604
605 pub fn set_content_length(&mut self, len: usize) -> Result<()> {
607 self.insert_header(http::header::CONTENT_LENGTH, len)
608 }
609}
610
611fn clone_req_parts(me: &ReqParts) -> ReqParts {
612 let mut parts = ReqBuilder::new()
613 .method(me.method.clone())
614 .uri(me.uri.clone())
615 .version(me.version)
616 .body(())
617 .unwrap()
618 .into_parts()
619 .0;
620 parts.headers = me.headers.clone();
621 parts.extensions = me.extensions.clone();
622 parts
623}
624
625fn clone_resp_parts(me: &RespParts) -> RespParts {
626 let mut parts = RespBuilder::new()
627 .status(me.status)
628 .version(me.version)
629 .body(())
630 .unwrap()
631 .into_parts()
632 .0;
633 parts.headers = me.headers.clone();
634 parts.extensions = me.extensions.clone();
635 parts
636}
637
638fn http_header_map_upper_bound(size_hint: Option<usize>) -> usize {
643 const PINGORA_MAX_HEADER_COUNT: usize = 4096;
651 const INIT_HEADER_SIZE: usize = 8;
652
653 std::cmp::min(
656 size_hint.unwrap_or(INIT_HEADER_SIZE),
657 PINGORA_MAX_HEADER_COUNT,
658 )
659}
660
661#[inline]
662fn append_header_value<T>(
663 name_map: Option<&mut CaseMap>,
664 value_map: &mut HMap<T>,
665 name: impl IntoCaseHeaderName,
666 value: T,
667) -> Result<bool> {
668 let case_header_name = name.into_case_header_name();
669 let header_name: HeaderName = case_header_name
670 .as_slice()
671 .try_into()
672 .or_err(InvalidHTTPHeader, "invalid header name")?;
673 if let Some(name_map) = name_map {
675 name_map.append(header_name.clone(), case_header_name);
676 }
677
678 Ok(value_map.append(header_name, value))
679}
680
681#[inline]
682fn insert_header_value<T>(
683 name_map: Option<&mut CaseMap>,
684 value_map: &mut HMap<T>,
685 name: impl IntoCaseHeaderName,
686 value: T,
687) -> Result<()> {
688 let case_header_name = name.into_case_header_name();
689 let header_name: HeaderName = case_header_name
690 .as_slice()
691 .try_into()
692 .or_err(InvalidHTTPHeader, "invalid header name")?;
693 if let Some(name_map) = name_map {
694 name_map.insert(header_name.clone(), case_header_name);
696 }
697 value_map.insert(header_name, value);
698 Ok(())
699}
700
701#[inline]
703fn remove_header<'a, T, N: ?Sized>(
704 name_map: Option<&mut CaseMap>,
705 value_map: &mut HMap<T>,
706 name: &'a N,
707) -> Option<T>
708where
709 &'a N: 'a + AsHeaderName,
710{
711 let removed = value_map.remove(name);
712 if removed.is_some() {
713 if let Some(name_map) = name_map {
714 name_map.remove(name);
715 }
716 }
717 removed
718}
719
720#[inline]
721fn header_to_h1_wire(key_map: Option<&CaseMap>, value_map: &HMap, buf: &mut impl BufMut) {
722 const CRLF: &[u8; 2] = b"\r\n";
723 const HEADER_KV_DELIMITER: &[u8; 2] = b": ";
724
725 if let Some(key_map) = key_map {
726 case_header_iter(key_map.into(), value_map).for_each(|(case_header, val)| {
727 buf.put_slice(case_header.as_slice());
728 buf.put_slice(HEADER_KV_DELIMITER);
729 buf.put_slice(val.as_ref());
730 buf.put_slice(CRLF);
731 });
732 } else {
733 for (header, value) in value_map {
734 let titled_header =
735 case_header_name::titled_header_name_str(header).unwrap_or(header.as_str());
736 buf.put_slice(titled_header.as_bytes());
737 buf.put_slice(HEADER_KV_DELIMITER);
738 buf.put_slice(value.as_ref());
739 buf.put_slice(CRLF);
740 }
741 }
742}
743
744#[inline]
745fn case_header_iter<'a>(
746 name_map: Option<&'a CaseMap>,
747 value_map: &'a HMap,
748) -> impl Iterator<Item = (&'a CaseHeaderName, &'a HeaderValue)> + 'a {
749 name_map.into_iter().flat_map(|name_map| {
750 name_map
751 .iter()
752 .zip(value_map.iter())
753 .map(|((h1, name), (h2, value))| {
754 assert_eq!(h1, h2, "header iter mismatch {}, {}", h1, h2);
756 (name, value)
757 })
758 })
759}
760
761#[cfg(test)]
762mod tests {
763 use super::*;
764
765 #[test]
766 fn header_map_upper_bound() {
767 assert_eq!(8, http_header_map_upper_bound(None));
768 assert_eq!(16, http_header_map_upper_bound(Some(16)));
769 assert_eq!(4096, http_header_map_upper_bound(Some(7777)));
770 }
771
772 #[test]
773 fn test_single_header() {
774 let mut req = RequestHeader::build("GET", b"\\", None).unwrap();
775 req.insert_header("foo", "bar").unwrap();
776 req.insert_header("FoO", "Bar").unwrap();
777 let mut buf: Vec<u8> = vec![];
778 req.header_to_h1_wire(&mut buf);
779 assert_eq!(buf, b"FoO: Bar\r\n");
780 req.case_header_iter().enumerate().for_each(|(i, (k, v))| {
781 let name = String::from_utf8_lossy(k.as_slice()).into_owned();
782 let value = String::from_utf8_lossy(v.as_ref()).into_owned();
783 match i + 1 {
784 1 => {
785 assert_eq!(name, "FoO");
786 assert_eq!(value, "Bar");
787 }
788 _ => panic!("too many headers"),
789 }
790 });
791
792 let mut resp = ResponseHeader::new(None);
793 resp.insert_header("foo", "bar").unwrap();
794 resp.insert_header("FoO", "Bar").unwrap();
795 let mut buf: Vec<u8> = vec![];
796 resp.header_to_h1_wire(&mut buf);
797 assert_eq!(buf, b"FoO: Bar\r\n");
798 resp.case_header_iter().enumerate().for_each(|(i, (k, v))| {
799 let name = String::from_utf8_lossy(k.as_slice()).into_owned();
800 let value = String::from_utf8_lossy(v.as_ref()).into_owned();
801 match i + 1 {
802 1 => {
803 assert_eq!(name, "FoO");
804 assert_eq!(value, "Bar");
805 }
806 _ => panic!("too many headers"),
807 }
808 });
809 }
810
811 #[test]
812 fn test_single_header_no_case() {
813 let mut req = RequestHeader::new_no_case(None);
814 req.insert_header("foo", "bar").unwrap();
815 req.insert_header("FoO", "Bar").unwrap();
816 let mut buf: Vec<u8> = vec![];
817 req.header_to_h1_wire(&mut buf);
818 assert_eq!(buf, b"foo: Bar\r\n");
819 req.case_header_iter().for_each(|(_, _)| {
820 unreachable!("request has no case");
821 });
822
823 let mut resp = ResponseHeader::new_no_case(None);
824 resp.insert_header("foo", "bar").unwrap();
825 resp.insert_header("FoO", "Bar").unwrap();
826 let mut buf: Vec<u8> = vec![];
827 resp.header_to_h1_wire(&mut buf);
828 assert_eq!(buf, b"foo: Bar\r\n");
829 resp.case_header_iter().for_each(|(_, _)| {
830 unreachable!("response has no case");
831 });
832 }
833
834 #[test]
835 fn test_multiple_header() {
836 let mut req = RequestHeader::build("GET", b"\\", None).unwrap();
837 req.append_header("FoO", "Bar").unwrap();
838 req.append_header("fOO", "bar").unwrap();
839 req.append_header("BAZ", "baR").unwrap();
840 req.append_header(http::header::CONTENT_LENGTH, "0")
841 .unwrap();
842 req.append_header("a", "b").unwrap();
843 req.remove_header("a");
844 let mut buf: Vec<u8> = vec![];
845 req.header_to_h1_wire(&mut buf);
846 assert_eq!(
847 buf,
848 b"FoO: Bar\r\nfOO: bar\r\nBAZ: baR\r\nContent-Length: 0\r\n"
849 );
850 req.case_header_iter().enumerate().for_each(|(i, (k, v))| {
851 let name = String::from_utf8_lossy(k.as_slice()).into_owned();
852 let value = String::from_utf8_lossy(v.as_ref()).into_owned();
853 match i + 1 {
854 1 => {
855 assert_eq!(name, "FoO");
856 assert_eq!(value, "Bar");
857 }
858 2 => {
859 assert_eq!(name, "fOO");
860 assert_eq!(value, "bar");
861 }
862 3 => {
863 assert_eq!(name, "BAZ");
864 assert_eq!(value, "baR");
865 }
866 4 => {
867 assert_eq!(name, "Content-Length");
868 assert_eq!(value, "0");
869 }
870 _ => panic!("too many headers"),
871 }
872 });
873
874 let mut resp = ResponseHeader::new(None);
875 resp.append_header("FoO", "Bar").unwrap();
876 resp.append_header("fOO", "bar").unwrap();
877 resp.append_header("BAZ", "baR").unwrap();
878 resp.append_header(http::header::CONTENT_LENGTH, "0")
879 .unwrap();
880 resp.append_header("a", "b").unwrap();
881 resp.remove_header("a");
882 let mut buf: Vec<u8> = vec![];
883 resp.header_to_h1_wire(&mut buf);
884 assert_eq!(
885 buf,
886 b"FoO: Bar\r\nfOO: bar\r\nBAZ: baR\r\nContent-Length: 0\r\n"
887 );
888 resp.case_header_iter().enumerate().for_each(|(i, (k, v))| {
889 let name = String::from_utf8_lossy(k.as_slice()).into_owned();
890 let value = String::from_utf8_lossy(v.as_ref()).into_owned();
891 match i + 1 {
892 1 => {
893 assert_eq!(name, "FoO");
894 assert_eq!(value, "Bar");
895 }
896 2 => {
897 assert_eq!(name, "fOO");
898 assert_eq!(value, "bar");
899 }
900 3 => {
901 assert_eq!(name, "BAZ");
902 assert_eq!(value, "baR");
903 }
904 4 => {
905 assert_eq!(name, "Content-Length");
906 assert_eq!(value, "0");
907 }
908 _ => panic!("too many headers"),
909 }
910 });
911 }
912
913 #[cfg(feature = "patched_http1")]
914 #[test]
915 fn test_invalid_path() {
916 let raw_path = b"Hello\xF0\x90\x80World";
917 let req = RequestHeader::build("GET", &raw_path[..], None).unwrap();
918 assert_eq!("Hello�World", req.uri.path_and_query().unwrap());
919 assert_eq!(raw_path, req.raw_path());
920 }
921
922 #[cfg(feature = "patched_http1")]
923 #[test]
924 fn test_override_invalid_path() {
925 let raw_path = b"Hello\xF0\x90\x80World";
926 let mut req = RequestHeader::build("GET", &raw_path[..], None).unwrap();
927 assert_eq!("Hello�World", req.uri.path_and_query().unwrap());
928 assert_eq!(raw_path, req.raw_path());
929
930 let new_path = "/HelloWorld";
931 req.set_uri(Uri::builder().path_and_query(new_path).build().unwrap());
932 assert_eq!(new_path, req.uri.path_and_query().unwrap());
933 assert_eq!(new_path.as_bytes(), req.raw_path());
934 }
935
936 #[test]
937 fn test_reason_phrase() {
938 let mut resp = ResponseHeader::new(None);
939 let reason = resp.get_reason_phrase().unwrap();
940 assert_eq!(reason, "OK");
941
942 resp.set_reason_phrase(Some("FooBar")).unwrap();
943 let reason = resp.get_reason_phrase().unwrap();
944 assert_eq!(reason, "FooBar");
945
946 resp.set_reason_phrase(Some("OK")).unwrap();
947 let reason = resp.get_reason_phrase().unwrap();
948 assert_eq!(reason, "OK");
949
950 resp.set_reason_phrase(None).unwrap();
951 let reason = resp.get_reason_phrase().unwrap();
952 assert_eq!(reason, "OK");
953 }
954
955 #[test]
956 fn set_test_send_end_stream() {
957 let mut req = RequestHeader::build("GET", b"/", None).unwrap();
958 req.set_send_end_stream(true);
959
960 assert!(req.send_end_stream().is_none());
962
963 let mut req = RequestHeader::build("GET", b"/", None).unwrap();
964 req.set_version(Version::HTTP_2);
965
966 assert!(req.send_end_stream().unwrap());
968
969 req.set_send_end_stream(false);
970 assert!(!req.send_end_stream().unwrap());
972 }
973
974 #[test]
975 fn set_test_set_content_length() {
976 let mut resp = ResponseHeader::new(None);
977 resp.set_content_length(10).unwrap();
978
979 assert_eq!(
980 b"10",
981 resp.headers
982 .get(http::header::CONTENT_LENGTH)
983 .map(|d| d.as_bytes())
984 .unwrap()
985 );
986 }
987}