@@ -2,7 +2,7 @@ use std::error::Error;
22use std:: fmt;
33use std:: sync:: Arc ;
44
5- use http:: { header:: HeaderValue , Uri } ;
5+ use http:: { header:: HeaderValue , HeaderMap , Uri } ;
66use hyper_util:: client:: proxy:: matcher;
77
88use crate :: into_url:: { IntoUrl , IntoUrlSealed } ;
@@ -67,6 +67,7 @@ pub struct NoProxy {
6767#[ derive( Clone ) ]
6868struct Extra {
6969 auth : Option < HeaderValue > ,
70+ misc : Option < HeaderMap > ,
7071}
7172
7273// ===== Internal =====
@@ -75,6 +76,7 @@ pub(crate) struct Matcher {
7576 inner : Matcher_ ,
7677 extra : Extra ,
7778 maybe_has_http_auth : bool ,
79+ maybe_has_http_custom_headers : bool ,
7880}
7981
8082enum Matcher_ {
@@ -100,6 +102,14 @@ impl ProxyScheme {
100102 _ => None,
101103 }
102104 }
105+
106+ fn maybe_http_custom_headers(&self) -> Option<&HeaderMap> {
107+ match self {
108+ ProxyScheme::Http { misc, .. } | ProxyScheme::Https { misc, .. } => misc.as_ref(),
109+ #[cfg(feature = "socks")]
110+ _ => None,
111+ }
112+ }
103113}
104114*/
105115
@@ -245,7 +255,10 @@ impl Proxy {
245255
246256 fn new ( intercept : Intercept ) -> Proxy {
247257 Proxy {
248- extra : Extra { auth : None } ,
258+ extra : Extra {
259+ auth : None ,
260+ misc : None ,
261+ } ,
249262 intercept,
250263 no_proxy : None ,
251264 }
@@ -297,6 +310,32 @@ impl Proxy {
297310 self
298311 }
299312
313+ /// Adds a Custom Headers to Proxy
314+ /// Adds custom headers to this Proxy
315+ ///
316+ /// # Example
317+ /// ```
318+ /// # extern crate reqwest;
319+ /// # use reqwest::header::*;
320+ /// # fn run() -> Result<(), Box<dyn std::error::Error>> {
321+ /// let mut headers = HeaderMap::new();
322+ /// headers.insert(USER_AGENT, "reqwest".parse().unwrap());
323+ /// let proxy = reqwest::Proxy::https("http://localhost:1234")?
324+ /// .headers(headers);
325+ /// # Ok(())
326+ /// # }
327+ /// # fn main() {}
328+ /// ```
329+ pub fn headers ( mut self , headers : HeaderMap ) -> Proxy {
330+ match self . intercept {
331+ Intercept :: All ( _) | Intercept :: Http ( _) | Intercept :: Https ( _) | Intercept :: Custom ( _) => {
332+ self . extra . misc = Some ( headers) ;
333+ }
334+ }
335+
336+ self
337+ }
338+
300339 /// Adds a `No Proxy` exclusion list to this Proxy
301340 ///
302341 /// # Example
@@ -323,10 +362,13 @@ impl Proxy {
323362 } = self ;
324363
325364 let maybe_has_http_auth;
365+ let maybe_has_http_custom_headers;
326366
327367 let inner = match intercept {
328368 Intercept :: All ( url) => {
329369 maybe_has_http_auth = cache_maybe_has_http_auth ( & url, & extra. auth ) ;
370+ maybe_has_http_custom_headers =
371+ cache_maybe_has_http_custom_headers ( & url, & extra. misc ) ;
330372 Matcher_ :: Util (
331373 matcher:: Matcher :: builder ( )
332374 . all ( String :: from ( url) )
@@ -336,6 +378,8 @@ impl Proxy {
336378 }
337379 Intercept :: Http ( url) => {
338380 maybe_has_http_auth = cache_maybe_has_http_auth ( & url, & extra. auth ) ;
381+ maybe_has_http_custom_headers =
382+ cache_maybe_has_http_custom_headers ( & url, & extra. misc ) ;
339383 Matcher_ :: Util (
340384 matcher:: Matcher :: builder ( )
341385 . http ( String :: from ( url) )
@@ -345,6 +389,8 @@ impl Proxy {
345389 }
346390 Intercept :: Https ( url) => {
347391 maybe_has_http_auth = cache_maybe_has_http_auth ( & url, & extra. auth ) ;
392+ maybe_has_http_custom_headers =
393+ cache_maybe_has_http_custom_headers ( & url, & extra. misc ) ;
348394 Matcher_ :: Util (
349395 matcher:: Matcher :: builder ( )
350396 . https ( String :: from ( url) )
@@ -354,6 +400,7 @@ impl Proxy {
354400 }
355401 Intercept :: Custom ( mut custom) => {
356402 maybe_has_http_auth = true ; // never know
403+ maybe_has_http_custom_headers = true ;
357404 custom. no_proxy = no_proxy;
358405 Matcher_ :: Custom ( custom)
359406 }
@@ -363,6 +410,7 @@ impl Proxy {
363410 inner,
364411 extra,
365412 maybe_has_http_auth,
413+ maybe_has_http_custom_headers,
366414 }
367415 }
368416
@@ -399,6 +447,10 @@ fn cache_maybe_has_http_auth(url: &Url, extra: &Option<HeaderValue>) -> bool {
399447 url. scheme ( ) == "http" && ( url. password ( ) . is_some ( ) || extra. is_some ( ) )
400448}
401449
450+ fn cache_maybe_has_http_custom_headers ( url : & Url , extra : & Option < HeaderMap > ) -> bool {
451+ url. scheme ( ) == "http" && extra. is_some ( )
452+ }
453+
402454impl fmt:: Debug for Proxy {
403455 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
404456 f. debug_tuple ( "Proxy" )
@@ -453,9 +505,13 @@ impl Matcher {
453505 pub ( crate ) fn system ( ) -> Self {
454506 Self {
455507 inner : Matcher_ :: Util ( matcher:: Matcher :: from_system ( ) ) ,
456- extra : Extra { auth : None } ,
508+ extra : Extra {
509+ auth : None ,
510+ misc : None ,
511+ } ,
457512 // maybe env vars have auth!
458513 maybe_has_http_auth : true ,
514+ maybe_has_http_custom_headers : true ,
459515 }
460516 }
461517
@@ -493,6 +549,20 @@ impl Matcher {
493549
494550 None
495551 }
552+
553+ pub ( crate ) fn maybe_has_http_custom_headers ( & self ) -> bool {
554+ self . maybe_has_http_custom_headers
555+ }
556+
557+ pub ( crate ) fn http_non_tunnel_custom_headers ( & self , dst : & Uri ) -> Option < HeaderMap > {
558+ if let Some ( proxy) = self . intercept ( dst) {
559+ if proxy. uri ( ) . scheme_str ( ) == Some ( "http" ) {
560+ return proxy. custom_headers ( ) . cloned ( ) ;
561+ }
562+ }
563+
564+ None
565+ }
496566}
497567
498568impl fmt:: Debug for Matcher {
@@ -516,6 +586,13 @@ impl Intercepted {
516586 self . inner . basic_auth ( )
517587 }
518588
589+ pub ( crate ) fn custom_headers ( & self ) -> Option < & HeaderMap > {
590+ if let Some ( ref val) = self . extra . misc {
591+ return Some ( val) ;
592+ }
593+ None
594+ }
595+
519596 #[ cfg( feature = "socks" ) ]
520597 pub ( crate ) fn raw_auth ( & self ) -> Option < ( & str , & str ) > {
521598 self . inner . raw_auth ( )
@@ -580,6 +657,25 @@ impl ProxyScheme {
580657 }
581658 }
582659
660+ fn set_custom_headers(&mut self, headers: HeaderMap) {
661+ match *self {
662+ ProxyScheme::Http { ref mut misc, .. } => {
663+ misc.get_or_insert_with(HeaderMap::new).extend(headers)
664+ }
665+ ProxyScheme::Https { ref mut misc, .. } => {
666+ misc.get_or_insert_with(HeaderMap::new).extend(headers)
667+ }
668+ #[cfg(feature = "socks")]
669+ ProxyScheme::Socks4 { .. } => {
670+ panic!("Socks4 is not supported for this method")
671+ }
672+ #[cfg(feature = "socks")]
673+ ProxyScheme::Socks5 { .. } => {
674+ panic!("Socks5 is not supported for this method")
675+ }
676+ }
677+ }
678+
583679 fn if_no_auth(mut self, update: &Option<HeaderValue>) -> Self {
584680 match self {
585681 ProxyScheme::Http { ref mut auth, .. } => {
0 commit comments