1use std::{
2 cell::{Ref, RefCell, RefMut},
3 fmt, net,
4 rc::Rc,
5 str,
6};
7
8use actix_http::{Message, RequestHead};
9use actix_router::{Path, Url};
10use actix_utils::future::{ok, Ready};
11#[cfg(feature = "cookies")]
12use cookie::{Cookie, ParseError as CookieParseError};
13use smallvec::SmallVec;
14
15use crate::{
16 app_service::AppInitServiceState,
17 config::AppConfig,
18 dev::{Extensions, Payload},
19 error::UrlGenerationError,
20 http::{header::HeaderMap, Method, Uri, Version},
21 info::ConnectionInfo,
22 rmap::ResourceMap,
23 Error, FromRequest, HttpMessage,
24};
25
26#[cfg(feature = "cookies")]
27struct Cookies(Vec<Cookie<'static>>);
28
29#[derive(Clone)]
31pub struct HttpRequest {
32 pub(crate) inner: Rc<HttpRequestInner>,
37}
38
39pub(crate) struct HttpRequestInner {
40 pub(crate) head: Message<RequestHead>,
41 pub(crate) path: Path<Url>,
42 pub(crate) app_data: SmallVec<[Rc<Extensions>; 4]>,
43 pub(crate) conn_data: Option<Rc<Extensions>>,
44 pub(crate) extensions: Rc<RefCell<Extensions>>,
45 app_state: Rc<AppInitServiceState>,
46}
47
48impl HttpRequest {
49 #[inline]
50 pub(crate) fn new(
51 path: Path<Url>,
52 head: Message<RequestHead>,
53 app_state: Rc<AppInitServiceState>,
54 app_data: Rc<Extensions>,
55 conn_data: Option<Rc<Extensions>>,
56 extensions: Rc<RefCell<Extensions>>,
57 ) -> HttpRequest {
58 let mut data = SmallVec::<[Rc<Extensions>; 4]>::new();
59 data.push(app_data);
60
61 HttpRequest {
62 inner: Rc::new(HttpRequestInner {
63 head,
64 path,
65 app_state,
66 app_data: data,
67 conn_data,
68 extensions,
69 }),
70 }
71 }
72}
73
74impl HttpRequest {
75 #[inline]
77 pub fn head(&self) -> &RequestHead {
78 &self.inner.head
79 }
80
81 #[inline]
84 pub(crate) fn head_mut(&mut self) -> &mut RequestHead {
85 &mut Rc::get_mut(&mut self.inner).unwrap().head
86 }
87
88 #[inline]
90 pub fn uri(&self) -> &Uri {
91 &self.head().uri
92 }
93
94 pub fn full_url(&self) -> url::Url {
111 let info = self.connection_info();
112 let scheme = info.scheme();
113 let host = info.host();
114 let path_and_query = self
115 .uri()
116 .path_and_query()
117 .map(|paq| paq.as_str())
118 .unwrap_or("/");
119
120 url::Url::parse(&format!("{scheme}://{host}{path_and_query}")).unwrap()
121 }
122
123 #[inline]
125 pub fn method(&self) -> &Method {
126 &self.head().method
127 }
128
129 #[inline]
131 pub fn version(&self) -> Version {
132 self.head().version
133 }
134
135 #[inline]
136 pub fn headers(&self) -> &HeaderMap {
138 &self.head().headers
139 }
140
141 #[inline]
143 pub fn path(&self) -> &str {
144 self.head().uri.path()
145 }
146
147 #[inline]
151 pub fn query_string(&self) -> &str {
152 self.uri().query().unwrap_or_default()
153 }
154
155 #[inline]
167 pub fn match_info(&self) -> &Path<Url> {
168 &self.inner.path
169 }
170
171 #[inline]
176 pub(crate) fn match_info_mut(&mut self) -> &mut Path<Url> {
177 &mut Rc::get_mut(&mut self.inner).unwrap().path
178 }
179
180 #[inline]
187 pub fn match_pattern(&self) -> Option<String> {
188 self.resource_map().match_pattern(self.path())
189 }
190
191 #[inline]
195 pub fn match_name(&self) -> Option<&str> {
196 self.resource_map().match_name(self.path())
197 }
198
199 pub fn conn_data<T: 'static>(&self) -> Option<&T> {
207 self.inner
208 .conn_data
209 .as_deref()
210 .and_then(|container| container.get::<T>())
211 }
212
213 pub fn url_for<U, I>(&self, name: &str, elements: U) -> Result<url::Url, UrlGenerationError>
238 where
239 U: IntoIterator<Item = I>,
240 I: AsRef<str>,
241 {
242 self.resource_map().url_for(self, name, elements)
243 }
244
245 pub fn url_for_static(&self, name: &str) -> Result<url::Url, UrlGenerationError> {
250 const NO_PARAMS: [&str; 0] = [];
251 self.url_for(name, NO_PARAMS)
252 }
253
254 #[inline]
256 pub fn resource_map(&self) -> &ResourceMap {
257 self.app_state().rmap()
258 }
259
260 #[inline]
272 pub fn peer_addr(&self) -> Option<net::SocketAddr> {
273 self.head().peer_addr
274 }
275
276 #[inline]
283 pub fn connection_info(&self) -> Ref<'_, ConnectionInfo> {
284 if !self.extensions().contains::<ConnectionInfo>() {
285 let info = ConnectionInfo::new(self.head(), self.app_config());
286 self.extensions_mut().insert(info);
287 }
288
289 Ref::map(self.extensions(), |data| data.get().unwrap())
290 }
291
292 #[inline]
294 pub fn app_config(&self) -> &AppConfig {
295 self.app_state().config()
296 }
297
298 #[doc(alias = "state")]
326 pub fn app_data<T: 'static>(&self) -> Option<&T> {
327 for container in self.inner.app_data.iter().rev() {
328 if let Some(data) = container.get::<T>() {
329 return Some(data);
330 }
331 }
332
333 None
334 }
335
336 #[inline]
337 fn app_state(&self) -> &AppInitServiceState {
338 &self.inner.app_state
339 }
340
341 #[cfg(feature = "cookies")]
343 pub fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
344 use actix_http::header::COOKIE;
345
346 if self.extensions().get::<Cookies>().is_none() {
347 let mut cookies = Vec::new();
348 for hdr in self.headers().get_all(COOKIE) {
349 let s = str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?;
350 for cookie_str in s.split(';').map(|s| s.trim()) {
351 if !cookie_str.is_empty() {
352 cookies.push(Cookie::parse_encoded(cookie_str)?.into_owned());
353 }
354 }
355 }
356 self.extensions_mut().insert(Cookies(cookies));
357 }
358
359 Ok(Ref::map(self.extensions(), |ext| {
360 &ext.get::<Cookies>().unwrap().0
361 }))
362 }
363
364 #[cfg(feature = "cookies")]
366 pub fn cookie(&self, name: &str) -> Option<Cookie<'static>> {
367 if let Ok(cookies) = self.cookies() {
368 for cookie in cookies.iter() {
369 if cookie.name() == name {
370 return Some(cookie.to_owned());
371 }
372 }
373 }
374 None
375 }
376}
377
378impl HttpMessage for HttpRequest {
379 type Stream = ();
380
381 #[inline]
382 fn headers(&self) -> &HeaderMap {
383 &self.head().headers
384 }
385
386 #[inline]
387 fn extensions(&self) -> Ref<'_, Extensions> {
388 self.inner.extensions.borrow()
389 }
390
391 #[inline]
392 fn extensions_mut(&self) -> RefMut<'_, Extensions> {
393 self.inner.extensions.borrow_mut()
394 }
395
396 #[inline]
397 fn take_payload(&mut self) -> Payload<Self::Stream> {
398 Payload::None
399 }
400}
401
402impl Drop for HttpRequest {
403 fn drop(&mut self) {
404 if let Some(inner) = Rc::get_mut(&mut self.inner) {
408 if inner.app_state.pool().is_available() {
409 inner.app_data.truncate(1);
411
412 Rc::get_mut(&mut inner.extensions)
415 .unwrap()
416 .get_mut()
417 .clear();
418
419 inner.conn_data = None;
422
423 let req = Rc::clone(&self.inner);
425 self.app_state().pool().push(req);
426 }
427 }
428 }
429}
430
431impl FromRequest for HttpRequest {
449 type Error = Error;
450 type Future = Ready<Result<Self, Error>>;
451
452 #[inline]
453 fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
454 ok(req.clone())
455 }
456}
457
458impl fmt::Debug for HttpRequest {
459 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460 writeln!(
461 f,
462 "\nHttpRequest {:?} {}:{}",
463 self.inner.head.version,
464 self.inner.head.method,
465 self.path()
466 )?;
467
468 if !self.query_string().is_empty() {
469 writeln!(f, " query: ?{:?}", self.query_string())?;
470 }
471
472 if !self.match_info().is_empty() {
473 writeln!(f, " params: {:?}", self.match_info())?;
474 }
475
476 writeln!(f, " headers:")?;
477
478 for (key, val) in self.headers().iter() {
479 match key {
480 &crate::http::header::AUTHORIZATION
482 | &crate::http::header::PROXY_AUTHORIZATION
483 | &crate::http::header::COOKIE => writeln!(f, " {:?}: {:?}", key, "*redacted*")?,
484
485 _ => writeln!(f, " {:?}: {:?}", key, val)?,
486 }
487 }
488
489 Ok(())
490 }
491}
492
493pub(crate) struct HttpRequestPool {
504 inner: RefCell<Vec<Rc<HttpRequestInner>>>,
505 cap: usize,
506}
507
508impl Default for HttpRequestPool {
509 fn default() -> Self {
510 Self::with_capacity(128)
511 }
512}
513
514impl HttpRequestPool {
515 pub(crate) fn with_capacity(cap: usize) -> Self {
516 HttpRequestPool {
517 inner: RefCell::new(Vec::with_capacity(cap)),
518 cap,
519 }
520 }
521
522 #[inline]
524 pub(crate) fn pop(&self) -> Option<HttpRequest> {
525 self.inner
526 .borrow_mut()
527 .pop()
528 .map(|inner| HttpRequest { inner })
529 }
530
531 #[inline]
533 pub(crate) fn is_available(&self) -> bool {
534 self.inner.borrow_mut().len() < self.cap
535 }
536
537 #[inline]
539 pub(crate) fn push(&self, req: Rc<HttpRequestInner>) {
540 self.inner.borrow_mut().push(req);
541 }
542
543 pub(crate) fn clear(&self) {
545 self.inner.borrow_mut().clear()
546 }
547}
548
549#[cfg(test)]
550mod tests {
551 use bytes::Bytes;
552
553 use super::*;
554 use crate::{
555 dev::{ResourceDef, Service},
556 http::{header, StatusCode},
557 test::{self, call_service, init_service, read_body, TestRequest},
558 web, App, HttpResponse,
559 };
560
561 #[test]
562 fn test_debug() {
563 let req = TestRequest::default()
564 .insert_header(("content-type", "text/plain"))
565 .to_http_request();
566 let dbg = format!("{:?}", req);
567 assert!(dbg.contains("HttpRequest"));
568 }
569
570 #[test]
571 #[cfg(feature = "cookies")]
572 fn test_no_request_cookies() {
573 let req = TestRequest::default().to_http_request();
574 assert!(req.cookies().unwrap().is_empty());
575 }
576
577 #[test]
578 #[cfg(feature = "cookies")]
579 fn test_request_cookies() {
580 let req = TestRequest::default()
581 .append_header((header::COOKIE, "cookie1=value1"))
582 .append_header((header::COOKIE, "cookie2=value2"))
583 .to_http_request();
584 {
585 let cookies = req.cookies().unwrap();
586 assert_eq!(cookies.len(), 2);
587 assert_eq!(cookies[0].name(), "cookie1");
588 assert_eq!(cookies[0].value(), "value1");
589 assert_eq!(cookies[1].name(), "cookie2");
590 assert_eq!(cookies[1].value(), "value2");
591 }
592
593 let cookie = req.cookie("cookie1");
594 assert!(cookie.is_some());
595 let cookie = cookie.unwrap();
596 assert_eq!(cookie.name(), "cookie1");
597 assert_eq!(cookie.value(), "value1");
598
599 let cookie = req.cookie("cookie-unknown");
600 assert!(cookie.is_none());
601 }
602
603 #[test]
604 fn test_request_query() {
605 let req = TestRequest::with_uri("/?id=test").to_http_request();
606 assert_eq!(req.query_string(), "id=test");
607 }
608
609 #[test]
610 fn test_url_for() {
611 let mut res = ResourceDef::new("/user/{name}.{ext}");
612 res.set_name("index");
613
614 let mut rmap = ResourceMap::new(ResourceDef::prefix(""));
615 rmap.add(&mut res, None);
616 assert!(rmap.has_resource("/user/test.html"));
617 assert!(!rmap.has_resource("/test/unknown"));
618
619 let req = TestRequest::default()
620 .insert_header((header::HOST, "www.rust-lang.org"))
621 .rmap(rmap)
622 .to_http_request();
623
624 assert_eq!(
625 req.url_for("unknown", ["test"]),
626 Err(UrlGenerationError::ResourceNotFound)
627 );
628 assert_eq!(
629 req.url_for("index", ["test"]),
630 Err(UrlGenerationError::NotEnoughElements)
631 );
632 let url = req.url_for("index", ["test", "html"]);
633 assert_eq!(
634 url.ok().unwrap().as_str(),
635 "http://www.rust-lang.org/user/test.html"
636 );
637 }
638
639 #[test]
640 fn test_url_for_static() {
641 let mut rdef = ResourceDef::new("/index.html");
642 rdef.set_name("index");
643
644 let mut rmap = ResourceMap::new(ResourceDef::prefix(""));
645 rmap.add(&mut rdef, None);
646
647 assert!(rmap.has_resource("/index.html"));
648
649 let req = TestRequest::with_uri("/test")
650 .insert_header((header::HOST, "www.rust-lang.org"))
651 .rmap(rmap)
652 .to_http_request();
653 let url = req.url_for_static("index");
654 assert_eq!(
655 url.ok().unwrap().as_str(),
656 "http://www.rust-lang.org/index.html"
657 );
658 }
659
660 #[test]
661 fn test_match_name() {
662 let mut rdef = ResourceDef::new("/index.html");
663 rdef.set_name("index");
664
665 let mut rmap = ResourceMap::new(ResourceDef::prefix(""));
666 rmap.add(&mut rdef, None);
667
668 assert!(rmap.has_resource("/index.html"));
669
670 let req = TestRequest::default()
671 .uri("/index.html")
672 .rmap(rmap)
673 .to_http_request();
674
675 assert_eq!(req.match_name(), Some("index"));
676 }
677
678 #[test]
679 fn test_url_for_external() {
680 let mut rdef = ResourceDef::new("https://youtube.com/watch/{video_id}");
681
682 rdef.set_name("youtube");
683
684 let mut rmap = ResourceMap::new(ResourceDef::prefix(""));
685 rmap.add(&mut rdef, None);
686
687 let req = TestRequest::default().rmap(rmap).to_http_request();
688 let url = req.url_for("youtube", ["oHg5SJYRHA0"]);
689 assert_eq!(
690 url.ok().unwrap().as_str(),
691 "https://youtube.com/watch/oHg5SJYRHA0"
692 );
693 }
694
695 #[actix_rt::test]
696 async fn test_drop_http_request_pool() {
697 let srv = init_service(
698 App::new().service(web::resource("/").to(|req: HttpRequest| {
699 HttpResponse::Ok()
700 .insert_header(("pool_cap", req.app_state().pool().cap))
701 .finish()
702 })),
703 )
704 .await;
705
706 let req = TestRequest::default().to_request();
707 let resp = call_service(&srv, req).await;
708
709 drop(srv);
710
711 assert_eq!(resp.headers().get("pool_cap").unwrap(), "128");
712 }
713
714 #[actix_rt::test]
715 async fn test_data() {
716 let srv = init_service(App::new().app_data(10usize).service(web::resource("/").to(
717 |req: HttpRequest| {
718 if req.app_data::<usize>().is_some() {
719 HttpResponse::Ok()
720 } else {
721 HttpResponse::BadRequest()
722 }
723 },
724 )))
725 .await;
726
727 let req = TestRequest::default().to_request();
728 let resp = call_service(&srv, req).await;
729 assert_eq!(resp.status(), StatusCode::OK);
730
731 let srv = init_service(App::new().app_data(10u32).service(web::resource("/").to(
732 |req: HttpRequest| {
733 if req.app_data::<usize>().is_some() {
734 HttpResponse::Ok()
735 } else {
736 HttpResponse::BadRequest()
737 }
738 },
739 )))
740 .await;
741
742 let req = TestRequest::default().to_request();
743 let resp = call_service(&srv, req).await;
744 assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
745 }
746
747 #[actix_rt::test]
748 async fn test_cascading_data() {
749 #[allow(dead_code)]
750 fn echo_usize(req: HttpRequest) -> HttpResponse {
751 let num = req.app_data::<usize>().unwrap();
752 HttpResponse::Ok().body(num.to_string())
753 }
754
755 let srv = init_service(
756 App::new()
757 .app_data(88usize)
758 .service(web::resource("/").route(web::get().to(echo_usize)))
759 .service(
760 web::resource("/one")
761 .app_data(1u32)
762 .route(web::get().to(echo_usize)),
763 ),
764 )
765 .await;
766
767 let req = TestRequest::get().uri("/").to_request();
768 let resp = srv.call(req).await.unwrap();
769 let body = read_body(resp).await;
770 assert_eq!(body, Bytes::from_static(b"88"));
771
772 let req = TestRequest::get().uri("/one").to_request();
773 let resp = srv.call(req).await.unwrap();
774 let body = read_body(resp).await;
775 assert_eq!(body, Bytes::from_static(b"88"));
776 }
777
778 #[actix_rt::test]
779 async fn test_overwrite_data() {
780 #[allow(dead_code)]
781 fn echo_usize(req: HttpRequest) -> HttpResponse {
782 let num = req.app_data::<usize>().unwrap();
783 HttpResponse::Ok().body(num.to_string())
784 }
785
786 let srv = init_service(
787 App::new()
788 .app_data(88usize)
789 .service(web::resource("/").route(web::get().to(echo_usize)))
790 .service(
791 web::resource("/one")
792 .app_data(1usize)
793 .route(web::get().to(echo_usize)),
794 ),
795 )
796 .await;
797
798 let req = TestRequest::get().uri("/").to_request();
799 let resp = srv.call(req).await.unwrap();
800 let body = read_body(resp).await;
801 assert_eq!(body, Bytes::from_static(b"88"));
802
803 let req = TestRequest::get().uri("/one").to_request();
804 let resp = srv.call(req).await.unwrap();
805 let body = read_body(resp).await;
806 assert_eq!(body, Bytes::from_static(b"1"));
807 }
808
809 #[actix_rt::test]
810 async fn test_app_data_dropped() {
811 struct Tracker {
812 pub dropped: bool,
813 }
814 struct Foo {
815 tracker: Rc<RefCell<Tracker>>,
816 }
817 impl Drop for Foo {
818 fn drop(&mut self) {
819 self.tracker.borrow_mut().dropped = true;
820 }
821 }
822
823 let tracker = Rc::new(RefCell::new(Tracker { dropped: false }));
824 {
825 let tracker2 = Rc::clone(&tracker);
826 let srv = init_service(App::new().service(web::resource("/").to(
827 move |req: HttpRequest| {
828 req.extensions_mut().insert(Foo {
829 tracker: Rc::clone(&tracker2),
830 });
831 HttpResponse::Ok()
832 },
833 )))
834 .await;
835
836 let req = TestRequest::default().to_request();
837 let resp = call_service(&srv, req).await;
838 assert_eq!(resp.status(), StatusCode::OK);
839 }
840
841 assert!(tracker.borrow().dropped);
842 }
843
844 #[actix_rt::test]
845 async fn extract_path_pattern() {
846 let srv = init_service(
847 App::new().service(
848 web::scope("/user/{id}")
849 .service(web::resource("/profile").route(web::get().to(
850 move |req: HttpRequest| {
851 assert_eq!(req.match_pattern(), Some("/user/{id}/profile".to_owned()));
852
853 HttpResponse::Ok().finish()
854 },
855 )))
856 .default_service(web::to(move |req: HttpRequest| {
857 assert!(req.match_pattern().is_none());
858 HttpResponse::Ok().finish()
859 })),
860 ),
861 )
862 .await;
863
864 let req = TestRequest::get().uri("/user/22/profile").to_request();
865 let res = call_service(&srv, req).await;
866 assert_eq!(res.status(), StatusCode::OK);
867
868 let req = TestRequest::get().uri("/user/22/not-exist").to_request();
869 let res = call_service(&srv, req).await;
870 assert_eq!(res.status(), StatusCode::OK);
871 }
872
873 #[actix_rt::test]
874 async fn extract_path_pattern_complex() {
875 let srv = init_service(
876 App::new()
877 .service(web::scope("/user").service(web::scope("/{id}").service(
878 web::resource("").to(move |req: HttpRequest| {
879 assert_eq!(req.match_pattern(), Some("/user/{id}".to_owned()));
880
881 HttpResponse::Ok().finish()
882 }),
883 )))
884 .service(web::resource("/").to(move |req: HttpRequest| {
885 assert_eq!(req.match_pattern(), Some("/".to_owned()));
886
887 HttpResponse::Ok().finish()
888 }))
889 .default_service(web::to(move |req: HttpRequest| {
890 assert!(req.match_pattern().is_none());
891 HttpResponse::Ok().finish()
892 })),
893 )
894 .await;
895
896 let req = TestRequest::get().uri("/user/test").to_request();
897 let res = call_service(&srv, req).await;
898 assert_eq!(res.status(), StatusCode::OK);
899
900 let req = TestRequest::get().uri("/").to_request();
901 let res = call_service(&srv, req).await;
902 assert_eq!(res.status(), StatusCode::OK);
903
904 let req = TestRequest::get().uri("/not-exist").to_request();
905 let res = call_service(&srv, req).await;
906 assert_eq!(res.status(), StatusCode::OK);
907 }
908
909 #[actix_rt::test]
910 async fn url_for_closest_named_resource() {
911 let srv = test::init_service(
913 App::new()
914 .service(
915 web::scope("/foo")
916 .service(web::resource("/nested").name("nested").route(web::get().to(
917 |req: HttpRequest| {
918 HttpResponse::Ok()
919 .body(format!("{}", req.url_for_static("nested").unwrap()))
920 },
921 )))
922 .service(web::scope("/baz").service(web::resource("deep")))
923 .service(web::resource("{foo_param}")),
924 )
925 .service(web::scope("/bar").service(
926 web::resource("/nested").name("nested").route(web::get().to(
927 |req: HttpRequest| {
928 HttpResponse::Ok()
929 .body(format!("{}", req.url_for_static("nested").unwrap()))
930 },
931 )),
932 )),
933 )
934 .await;
935
936 let foo_resp =
937 test::call_service(&srv, TestRequest::with_uri("/foo/nested").to_request()).await;
938 assert_eq!(foo_resp.status(), StatusCode::OK);
939 let body = read_body(foo_resp).await;
940 assert_eq!(body, "http://localhost:8080/bar/nested");
945
946 let bar_resp =
947 test::call_service(&srv, TestRequest::with_uri("/bar/nested").to_request()).await;
948 assert_eq!(bar_resp.status(), StatusCode::OK);
949 let body = read_body(bar_resp).await;
950 assert_eq!(body, "http://localhost:8080/bar/nested");
951 }
952
953 #[test]
954 fn authorization_header_hidden_in_debug() {
955 let authorization_header = "Basic bXkgdXNlcm5hbWU6bXkgcGFzc3dvcmQK";
956 let req = TestRequest::get()
957 .insert_header((crate::http::header::AUTHORIZATION, authorization_header))
958 .to_http_request();
959
960 assert!(!format!("{:?}", req).contains(authorization_header));
961 }
962
963 #[test]
964 fn proxy_authorization_header_hidden_in_debug() {
965 let proxy_authorization_header = "secret value";
966 let req = TestRequest::get()
967 .insert_header((
968 crate::http::header::PROXY_AUTHORIZATION,
969 proxy_authorization_header,
970 ))
971 .to_http_request();
972
973 assert!(!format!("{:?}", req).contains(proxy_authorization_header));
974 }
975
976 #[test]
977 fn cookie_header_hidden_in_debug() {
978 let cookie_header = "secret";
979 let req = TestRequest::get()
980 .insert_header((crate::http::header::COOKIE, cookie_header))
981 .to_http_request();
982
983 assert!(!format!("{:?}", req).contains(cookie_header));
984 }
985
986 #[test]
987 fn other_header_visible_in_debug() {
988 let location_header = "192.0.0.1";
989 let req = TestRequest::get()
990 .insert_header((crate::http::header::LOCATION, location_header))
991 .to_http_request();
992
993 assert!(format!("{:?}", req).contains(location_header));
994 }
995
996 #[test]
997 fn check_full_url() {
998 let req = TestRequest::with_uri("/api?id=4&name=foo").to_http_request();
999 assert_eq!(
1000 req.full_url().as_str(),
1001 "http://localhost:8080/api?id=4&name=foo",
1002 );
1003
1004 let req = TestRequest::with_uri("https://example.com/api?id=4&name=foo").to_http_request();
1005 assert_eq!(
1006 req.full_url().as_str(),
1007 "https://example.com/api?id=4&name=foo",
1008 );
1009
1010 let req = TestRequest::with_uri("http://10.1.2.3:8443/api?id=4&name=foo")
1011 .insert_header(("host", "example.com"))
1012 .to_http_request();
1013 assert_eq!(
1014 req.full_url().as_str(),
1015 "http://example.com/api?id=4&name=foo",
1016 );
1017 }
1018}