diff --git a/actix-web-httpauth/Cargo.toml b/actix-web-httpauth/Cargo.toml index 513f5d727..befdce661 100644 --- a/actix-web-httpauth/Cargo.toml +++ b/actix-web-httpauth/Cargo.toml @@ -21,7 +21,7 @@ path = "src/lib.rs" actix-utils = "3" actix-web = { version = "4.1", default_features = false } -base64 = "0.20" +base64 = "0.21" futures-core = "0.3.7" futures-util = { version = "0.3.7", default-features = false, features = ["std"] } log = "0.4" diff --git a/actix-web-httpauth/src/headers/authorization/scheme/basic.rs b/actix-web-httpauth/src/headers/authorization/scheme/basic.rs index da7a94f8b..4e5cbc676 100644 --- a/actix-web-httpauth/src/headers/authorization/scheme/basic.rs +++ b/actix-web-httpauth/src/headers/authorization/scheme/basic.rs @@ -4,6 +4,7 @@ use actix_web::{ http::header::{HeaderValue, InvalidHeaderValue, TryIntoHeaderValue}, web::{BufMut, BytesMut}, }; +use base64::{prelude::BASE64_STANDARD, Engine}; use crate::headers::authorization::{errors::ParseError, Scheme}; @@ -58,7 +59,7 @@ impl Scheme for Basic { _ => return Err(ParseError::MissingScheme), } - let decoded = base64::decode(parts.next().ok_or(ParseError::Invalid)?)?; + let decoded = BASE64_STANDARD.decode(parts.next().ok_or(ParseError::Invalid)?)?; let mut credentials = str::from_utf8(&decoded)?.splitn(2, ':'); let user_id = credentials @@ -97,11 +98,13 @@ impl TryIntoHeaderValue for Basic { type Error = InvalidHeaderValue; fn try_into_value(self) -> Result { - let mut credentials = BytesMut::with_capacity( - self.user_id.len() - + 1 // ':' - + self.password.as_ref().map_or(0, |pwd| pwd.len()), - ); + let credential_length = + self.user_id.len() + 1 + self.password.as_ref().map_or(0, |pwd| pwd.len()); + // The length of BASE64 encoded bytes is `4 * credential_length.div_ceil(3)` + // TODO: Use credential_length.div_ceil(3) when `int_roundings` becomes stable + // https://github.com/rust-lang/rust/issues/88581 + let mut value = String::with_capacity(6 + 4 * (credential_length + 2) / 3); + let mut credentials = BytesMut::with_capacity(credential_length); credentials.extend_from_slice(self.user_id.as_bytes()); credentials.put_u8(b':'); @@ -109,14 +112,10 @@ impl TryIntoHeaderValue for Basic { credentials.extend_from_slice(password.as_bytes()); } - // TODO: It would be nice not to allocate new `String` here but write - // directly to `value` - let encoded = base64::encode(&credentials); - let mut value = BytesMut::with_capacity(6 + encoded.len()); - value.put(&b"Basic "[..]); - value.put(encoded.as_bytes()); + value.push_str("Basic "); + BASE64_STANDARD.encode_string(&credentials, &mut value); - HeaderValue::from_maybe_shared(value.freeze()) + HeaderValue::from_maybe_shared(value) } }