1
1
use crate :: hashed_regex:: HashedRegex ;
2
2
use anyhow:: Error ;
3
3
use http:: header:: { HeaderName , HeaderValue } ;
4
+ use log:: Level ;
4
5
use reqwest:: Client ;
5
6
use serde_derive:: { Deserialize , Serialize } ;
6
7
use std:: {
7
- collections:: HashMap , convert:: TryFrom , str:: FromStr , time:: Duration ,
8
+ collections:: HashMap ,
9
+ convert:: TryFrom ,
10
+ fmt:: { self , Display , Formatter } ,
11
+ str:: FromStr ,
12
+ time:: Duration ,
8
13
} ;
9
14
10
15
/// The configuration options available with this backend.
@@ -40,11 +45,18 @@ pub struct Config {
40
45
pub struct HttpHeader {
41
46
pub name : HeaderName ,
42
47
pub value : String ,
48
+ }
49
+
50
+ impl HttpHeader {
51
+ pub ( crate ) fn interpolate ( & self ) -> Result < HeaderValue , Error > {
52
+ interpolate_env ( & self . value )
53
+ }
54
+ }
43
55
44
- // This is a separate field because interpolated env vars
45
- // may contain some secrets that should not be revealed
46
- // in logs, config, error messages and the like.
47
- pub ( crate ) interpolated_value : HeaderValue ,
56
+ impl Display for HttpHeader {
57
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt :: Result {
58
+ write ! ( f , "{}: {}" , self . name , self . value )
59
+ }
48
60
}
49
61
50
62
impl Config {
@@ -67,6 +79,44 @@ impl Config {
67
79
. insert ( http:: header:: USER_AGENT , self . user_agent . parse ( ) . unwrap ( ) ) ;
68
80
Client :: builder ( ) . default_headers ( headers) . build ( ) . unwrap ( )
69
81
}
82
+
83
+ pub ( crate ) fn interpolate_headers (
84
+ & self ,
85
+ warning_policy : WarningPolicy ,
86
+ ) -> Vec < ( HashedRegex , Vec < ( HeaderName , HeaderValue ) > ) > {
87
+ let mut all_headers = Vec :: new ( ) ;
88
+ let log_level = warning_policy. to_log_level ( ) ;
89
+
90
+ for ( pattern, headers) in & self . http_headers {
91
+ let mut interpolated = Vec :: new ( ) ;
92
+
93
+ for header in headers {
94
+ match header. interpolate ( ) {
95
+ Ok ( value) => {
96
+ interpolated. push ( ( header. name . clone ( ) , value) )
97
+ } ,
98
+ Err ( e) => {
99
+ // We don't want failed interpolation (i.e. due to a
100
+ // missing env variable) to abort the whole
101
+ // linkchecking, so emit a warning and keep going.
102
+ //
103
+ // If it was important, the user would notice a "broken"
104
+ // link and read back through the logs.
105
+ log:: log!(
106
+ log_level,
107
+ "Unable to interpolate \" {}\" because {}" ,
108
+ header,
109
+ e
110
+ ) ;
111
+ } ,
112
+ }
113
+ }
114
+
115
+ all_headers. push ( ( pattern. clone ( ) , interpolated) ) ;
116
+ }
117
+
118
+ all_headers
119
+ }
70
120
}
71
121
72
122
impl Default for Config {
@@ -91,16 +141,14 @@ impl FromStr for HttpHeader {
91
141
Some ( idx) => {
92
142
let name = s[ ..idx] . parse ( ) ?;
93
143
let value = s[ idx + 2 ..] . to_string ( ) ;
94
- let interpolated_value = interpolate_env ( & value) ?;
95
144
Ok ( HttpHeader {
96
145
name,
97
146
value,
98
- interpolated_value,
99
147
} )
100
148
} ,
101
149
102
150
None => Err ( Error :: msg ( format ! (
103
- "The `{}` HTTP header must contain `: ` but it doesn 't" ,
151
+ "The `{}` HTTP header must be in the form `key: value ` but it isn 't" ,
104
152
s
105
153
) ) ) ,
106
154
}
@@ -209,6 +257,16 @@ pub enum WarningPolicy {
209
257
Error ,
210
258
}
211
259
260
+ impl WarningPolicy {
261
+ pub ( crate ) fn to_log_level ( self ) -> Level {
262
+ match self {
263
+ WarningPolicy :: Error => Level :: Error ,
264
+ WarningPolicy :: Warn => Level :: Warn ,
265
+ WarningPolicy :: Ignore => Level :: Debug ,
266
+ }
267
+ }
268
+ }
269
+
212
270
impl Default for WarningPolicy {
213
271
fn default ( ) -> WarningPolicy { WarningPolicy :: Warn }
214
272
}
@@ -269,16 +327,14 @@ https = ["accept: html/text", "authorization: Basic $TOKEN"]
269
327
270
328
#[ test]
271
329
fn interpolation ( ) {
272
- std:: env:: set_var ( "TOKEN" , "QWxhZGRpbjpPcGVuU2VzYW1l " ) ;
273
- let should_be = HttpHeader {
330
+ std:: env:: set_var ( "TOKEN" , "abcdefg123456 " ) ;
331
+ let header = HttpHeader {
274
332
name : "Authorization" . parse ( ) . unwrap ( ) ,
275
333
value : "Basic $TOKEN" . into ( ) ,
276
- interpolated_value : "Basic QWxhZGRpbjpPcGVuU2VzYW1l"
277
- . parse ( )
278
- . unwrap ( ) ,
279
334
} ;
335
+ let should_be: HeaderValue = "Basic abcdefg123456" . parse ( ) . unwrap ( ) ;
280
336
281
- let got = HttpHeader :: try_from ( "Authorization: Basic $TOKEN" ) . unwrap ( ) ;
337
+ let got = header . interpolate ( ) . unwrap ( ) ;
282
338
283
339
assert_eq ! ( got, should_be) ;
284
340
}
0 commit comments