Skip to content

Commit 7d784cd

Browse files
cole-hsbihel
andauthored
Make authorization schemes case and whitespace insensitive (hyperium#153)
* Make authorization schemes case and whitespace insensitive According to RFC7235[1]: > It uses a case- > insensitive token as a means to identify the authentication scheme, > followed by additional information necessary for achieving > authentication via that scheme. [1]: https://datatracker.ietf.org/doc/html/rfc7235#section-2.1 * Use eq_ignore_ascii_case() for Authorization schemes This is effectively the same as comparing the result of `to_ascii_lowercase()`, with the benefit of avoiding "allocating and copying temporaries" (according to the Rust `std` docs[1]). [1]: https://doc.rust-lang.org/std/primitive.slice.html#method.eq_ignore_ascii_case --------- Co-authored-by: Simon Bihel <[email protected]>
1 parent 4400aa9 commit 7d784cd

File tree

1 file changed

+33
-5
lines changed

1 file changed

+33
-5
lines changed

src/common/authorization.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ impl<C: Credentials> ::Header for Authorization<C> {
8282
.next()
8383
.and_then(|val| {
8484
let slice = val.as_bytes();
85-
if slice.starts_with(C::SCHEME.as_bytes())
86-
&& slice.len() > C::SCHEME.len()
85+
if slice.len() > C::SCHEME.len()
8786
&& slice[C::SCHEME.len()] == b' '
87+
&& slice[..C::SCHEME.len()].eq_ignore_ascii_case(C::SCHEME.as_bytes())
8888
{
8989
C::decode(val).map(Authorization)
9090
} else {
@@ -151,7 +151,7 @@ impl Credentials for Basic {
151151

152152
fn decode(value: &HeaderValue) -> Option<Self> {
153153
debug_assert!(
154-
value.as_bytes().starts_with(b"Basic "),
154+
value.as_bytes()[..Self::SCHEME.len()].eq_ignore_ascii_case(Self::SCHEME.as_bytes()),
155155
"HeaderValue to decode should start with \"Basic ..\", received = {:?}",
156156
value,
157157
);
@@ -186,7 +186,7 @@ pub struct Bearer(HeaderValueString);
186186
impl Bearer {
187187
/// View the token part as a `&str`.
188188
pub fn token(&self) -> &str {
189-
&self.0.as_str()["Bearer ".len()..]
189+
self.0.as_str()["Bearer ".len()..].trim_start()
190190
}
191191
}
192192

@@ -195,7 +195,7 @@ impl Credentials for Bearer {
195195

196196
fn decode(value: &HeaderValue) -> Option<Self> {
197197
debug_assert!(
198-
value.as_bytes().starts_with(b"Bearer "),
198+
value.as_bytes()[..Self::SCHEME.len()].eq_ignore_ascii_case(Self::SCHEME.as_bytes()),
199199
"HeaderValue to decode should start with \"Bearer ..\", received = {:?}",
200200
value,
201201
);
@@ -252,6 +252,22 @@ mod tests {
252252
assert_eq!(auth.0.password(), "open sesame");
253253
}
254254

255+
#[test]
256+
fn basic_decode_case_insensitive() {
257+
let auth: Authorization<Basic> =
258+
test_decode(&["basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
259+
assert_eq!(auth.0.username(), "Aladdin");
260+
assert_eq!(auth.0.password(), "open sesame");
261+
}
262+
263+
#[test]
264+
fn basic_decode_extra_whitespaces() {
265+
let auth: Authorization<Basic> =
266+
test_decode(&["Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
267+
assert_eq!(auth.0.username(), "Aladdin");
268+
assert_eq!(auth.0.password(), "open sesame");
269+
}
270+
255271
#[test]
256272
fn basic_decode_no_password() {
257273
let auth: Authorization<Basic> = test_decode(&["Basic QWxhZGRpbjo="]).unwrap();
@@ -273,6 +289,18 @@ mod tests {
273289
let auth: Authorization<Bearer> = test_decode(&["Bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
274290
assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
275291
}
292+
293+
#[test]
294+
fn bearer_decode_case_insensitive() {
295+
let auth: Authorization<Bearer> = test_decode(&["bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
296+
assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
297+
}
298+
299+
#[test]
300+
fn bearer_decode_extra_whitespaces() {
301+
let auth: Authorization<Bearer> = test_decode(&["Bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
302+
assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
303+
}
276304
}
277305

278306
//bench_header!(raw, Authorization<String>, { vec![b"foo bar baz".to_vec()] });

0 commit comments

Comments
 (0)