Skip to content

Commit b4de5e5

Browse files
committed
Add a test to ensure we don't panic when the header is not given
1 parent e62f021 commit b4de5e5

File tree

5 files changed

+75
-47
lines changed

5 files changed

+75
-47
lines changed

src/config.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub struct Config {
1818
pub mirror: Replica,
1919
pub api_protocol: String,
2020
pub publish_rate_limit: PublishRateLimit,
21+
pub blocked_traffic: Vec<(String, Vec<String>)>,
2122
}
2223

2324
impl Default for Config {
@@ -135,6 +136,48 @@ impl Default for Config {
135136
mirror,
136137
api_protocol,
137138
publish_rate_limit: Default::default(),
139+
blocked_traffic: blocked_traffic(),
138140
}
139141
}
140142
}
143+
144+
fn blocked_traffic() -> Vec<(String, Vec<String>)> {
145+
let pattern_list = dotenv::var("BLOCKED_TRAFFIC").unwrap_or_default();
146+
parse_traffic_patterns(&pattern_list)
147+
.map(|(header, value_env_var)| {
148+
let value_list = dotenv::var(value_env_var).unwrap_or_default();
149+
let values = value_list.split(',').map(String::from).collect();
150+
(header.into(), values)
151+
})
152+
.collect()
153+
}
154+
155+
fn parse_traffic_patterns(patterns: &str) -> impl Iterator<Item = (&str, &str)> {
156+
patterns.split_terminator(',').map(|pattern| {
157+
if let Some(idx) = pattern.find('=') {
158+
(&pattern[..idx], &pattern[(idx + 1)..])
159+
} else {
160+
panic!(
161+
"BLOCKED_TRAFFIC must be in the form HEADER=VALUE_ENV_VAR, \
162+
got invalid pattern {}",
163+
pattern
164+
)
165+
}
166+
})
167+
}
168+
169+
#[test]
170+
fn parse_traffic_patterns_splits_on_comma_and_looks_for_equal_sign() {
171+
let pattern_string_1 = "Foo=BAR,Bar=BAZ";
172+
let pattern_string_2 = "Baz=QUX";
173+
let pattern_string_3 = "";
174+
175+
let patterns_1 = parse_traffic_patterns(pattern_string_1).collect::<Vec<_>>();
176+
assert_eq!(vec![("Foo", "BAR"), ("Bar", "BAZ")], patterns_1);
177+
178+
let patterns_2 = parse_traffic_patterns(pattern_string_2).collect::<Vec<_>>();
179+
assert_eq!(vec![("Baz", "QUX")], patterns_2);
180+
181+
let patterns_3 = parse_traffic_patterns(pattern_string_3).collect::<Vec<_>>();
182+
assert!(patterns_3.is_empty());
183+
}

src/middleware.rs

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ use crate::{App, Env};
3838

3939
pub fn build_middleware(app: Arc<App>, endpoints: R404) -> MiddlewareBuilder {
4040
let mut m = MiddlewareBuilder::new(endpoints);
41-
let env = app.config.env;
41+
let config = app.config.clone();
42+
let env = config.env;
4243

4344
if env != Env::Test {
4445
m.add(ensure_well_formed_500::EnsureWellFormed500);
@@ -69,7 +70,7 @@ pub fn build_middleware(app: Arc<App>, endpoints: R404) -> MiddlewareBuilder {
6970
));
7071

7172
if env == Env::Production {
72-
m.add(SecurityHeaders::new(&app.config.uploader));
73+
m.add(SecurityHeaders::new(&config.uploader));
7374
}
7475
m.add(AppMiddleware::new(app));
7576

@@ -87,7 +88,7 @@ pub fn build_middleware(app: Arc<App>, endpoints: R404) -> MiddlewareBuilder {
8788

8889
m.around(Head::default());
8990

90-
for (header, blocked_values) in blocked_traffic() {
91+
for (header, blocked_values) in config.blocked_traffic {
9192
m.around(block_traffic::BlockTraffic::new(header, blocked_values));
9293
}
9394

@@ -99,44 +100,3 @@ pub fn build_middleware(app: Arc<App>, endpoints: R404) -> MiddlewareBuilder {
99100

100101
m
101102
}
102-
103-
fn blocked_traffic() -> Vec<(String, Vec<String>)> {
104-
let pattern_list = env::var("BLOCKED_TRAFFIC").unwrap_or_default();
105-
parse_traffic_patterns(&pattern_list)
106-
.map(|(header, value_env_var)| {
107-
let value_list = env::var(value_env_var).unwrap_or_default();
108-
let values = value_list.split(',').map(String::from).collect();
109-
(header.into(), values)
110-
})
111-
.collect()
112-
}
113-
114-
fn parse_traffic_patterns(patterns: &str) -> impl Iterator<Item = (&str, &str)> {
115-
patterns.split_terminator(',').map(|pattern| {
116-
if let Some(idx) = pattern.find('=') {
117-
(&pattern[..idx], &pattern[(idx + 1)..])
118-
} else {
119-
panic!(
120-
"BLOCKED_TRAFFIC must be in the form HEADER=VALUE_ENV_VAR, \
121-
got invalid pattern {}",
122-
pattern
123-
)
124-
}
125-
})
126-
}
127-
128-
#[test]
129-
fn parse_traffic_patterns_splits_on_comma_and_looks_for_equal_sign() {
130-
let pattern_string_1 = "Foo=BAR,Bar=BAZ";
131-
let pattern_string_2 = "Baz=QUX";
132-
let pattern_string_3 = "";
133-
134-
let patterns_1 = parse_traffic_patterns(pattern_string_1).collect::<Vec<_>>();
135-
assert_eq!(vec![("Foo", "BAR"), ("Bar", "BAZ")], patterns_1);
136-
137-
let patterns_2 = parse_traffic_patterns(pattern_string_2).collect::<Vec<_>>();
138-
assert_eq!(vec![("Baz", "QUX")], patterns_2);
139-
140-
let patterns_3 = parse_traffic_patterns(pattern_string_3).collect::<Vec<_>>();
141-
assert!(patterns_3.is_empty());
142-
}

src/tests/all.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ fn simple_config() -> Config {
148148
// sniff/record it, but everywhere else we use https
149149
api_protocol: String::from("http"),
150150
publish_rate_limit: Default::default(),
151+
blocked_traffic: Default::default(),
151152
}
152153
}
153154

src/tests/server.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,21 @@ fn user_agent_is_not_required_for_download() {
2626
let resp = anon.run::<()>(req);
2727
resp.assert_status(302);
2828
}
29+
30+
#[test]
31+
fn blocked_traffic_doesnt_panic_if_checked_header_is_not_present() {
32+
let (app, anon, user) = TestApp::init()
33+
.with_config(|config| {
34+
config.blocked_traffic = vec![("Never-Given".into(), vec!["1".into()])];
35+
})
36+
.with_user();
37+
38+
app.db(|conn| {
39+
CrateBuilder::new("dl_no_ua", user.as_model().id).expect_build(conn);
40+
});
41+
42+
let mut req = anon.request_builder(Method::Get, "/api/v1/crates/dl_no_ua/0.99.0/download");
43+
req.header("User-Agent", "");
44+
let resp = anon.run::<()>(req);
45+
resp.assert_status(302);
46+
}

src/tests/util.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,18 @@ impl TestAppBuilder {
268268
(app, anon, user, token)
269269
}
270270

271-
pub fn with_publish_rate_limit(mut self, rate: Duration, burst: i32) -> Self {
272-
self.config.publish_rate_limit.rate = rate;
273-
self.config.publish_rate_limit.burst = burst;
271+
pub fn with_config(mut self, f: impl FnOnce(&mut Config)) -> Self {
272+
f(&mut self.config);
274273
self
275274
}
276275

276+
pub fn with_publish_rate_limit(self, rate: Duration, burst: i32) -> Self {
277+
self.with_config(|config| {
278+
config.publish_rate_limit.rate = rate;
279+
config.publish_rate_limit.burst = burst;
280+
})
281+
}
282+
277283
pub fn with_git_index(mut self) -> Self {
278284
use crate::git;
279285

0 commit comments

Comments
 (0)