summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock17
-rw-r--r--Cargo.toml4
-rw-r--r--ext/web/Cargo.toml2
-rw-r--r--ext/web/lib.rs69
4 files changed, 39 insertions, 53 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0910acd14..07449b7a2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -243,6 +243,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
+name = "base64-simd"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "278c7ba87265587c4823cf1b2fdf57834151540b2e509574adb03627f8c7f22d"
+dependencies = [
+ "simd-abstraction",
+]
+
+[[package]]
name = "base64ct"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1202,7 +1211,7 @@ name = "deno_web"
version = "0.89.0"
dependencies = [
"async-trait",
- "base64 0.13.0",
+ "base64-simd",
"deno_bench_util",
"deno_core",
"deno_url",
@@ -3894,6 +3903,12 @@ dependencies = [
]
[[package]]
+name = "simd-abstraction"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2880f3f7b392823ee65bbcc681961cd8e698c6a30e91ab9b4eef1f9c6c226d8"
+
+[[package]]
name = "siphasher"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 12a8b2cce..071947c01 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -110,6 +110,8 @@ opt-level = 3
opt-level = 3
[profile.bench.package.zstd-sys]
opt-level = 3
+[profile.bench.package.base64-simd]
+opt-level = 3
# NB: the `bench` and `release` profiles must remain EXACTLY the same.
[profile.release.package.rand]
@@ -174,3 +176,5 @@ opt-level = 3
opt-level = 3
[profile.release.package.zstd-sys]
opt-level = 3
+[profile.release.package.base64-simd]
+opt-level = 3
diff --git a/ext/web/Cargo.toml b/ext/web/Cargo.toml
index ada3faab6..e321f4fb6 100644
--- a/ext/web/Cargo.toml
+++ b/ext/web/Cargo.toml
@@ -15,7 +15,7 @@ path = "lib.rs"
[dependencies]
async-trait = "0.1.51"
-base64 = "0.13.0"
+base64-simd = "0.6.2"
deno_core = { version = "0.140.0", path = "../../core" }
encoding_rs = "0.8.31"
flate2 = "1"
diff --git a/ext/web/lib.rs b/ext/web/lib.rs
index b21ea3812..9bc7c1cce 100644
--- a/ext/web/lib.rs
+++ b/ext/web/lib.rs
@@ -124,74 +124,41 @@ pub fn init<P: TimersPermission + 'static>(
#[op]
fn op_base64_decode(input: String) -> Result<ZeroCopyBuf, AnyError> {
- let mut input = input.into_bytes();
- input.retain(|c| !c.is_ascii_whitespace());
- Ok(b64_decode(&input)?.into())
+ Ok(forgiving_base64_decode(input.into_bytes())?.into())
}
#[op]
-fn op_base64_atob(mut s: ByteString) -> Result<ByteString, AnyError> {
- s.retain(|c| !c.is_ascii_whitespace());
-
- // If padding is expected, fail if not 4-byte aligned
- if s.len() % 4 != 0 && (s.ends_with(b"==") || s.ends_with(b"=")) {
- return Err(
- DomExceptionInvalidCharacterError::new("Failed to decode base64.").into(),
- );
- }
-
- Ok(b64_decode(&s)?.into())
+fn op_base64_atob(s: ByteString) -> Result<ByteString, AnyError> {
+ Ok(forgiving_base64_decode(s.into())?.into())
}
-fn b64_decode(input: &[u8]) -> Result<Vec<u8>, AnyError> {
- // "If the length of input divides by 4 leaving no remainder, then:
- // if input ends with one or two U+003D EQUALS SIGN (=) characters,
- // remove them from input."
- let input = match input.len() % 4 == 0 {
- true if input.ends_with(b"==") => &input[..input.len() - 2],
- true if input.ends_with(b"=") => &input[..input.len() - 1],
- _ => input,
- };
+/// See <https://infra.spec.whatwg.org/#forgiving-base64>
+fn forgiving_base64_decode(mut input: Vec<u8>) -> Result<Vec<u8>, AnyError> {
+ let error: _ =
+ || DomExceptionInvalidCharacterError::new("Failed to decode base64");
- // "If the length of input divides by 4 leaving a remainder of 1,
- // throw an InvalidCharacterError exception and abort these steps."
- if input.len() % 4 == 1 {
- return Err(
- DomExceptionInvalidCharacterError::new("Failed to decode base64.").into(),
- );
- }
-
- let cfg = base64::Config::new(base64::CharacterSet::Standard, true)
- .decode_allow_trailing_bits(true);
- let out = base64::decode_config(input, cfg).map_err(|err| match err {
- base64::DecodeError::InvalidByte(_, _) => {
- DomExceptionInvalidCharacterError::new(
- "Failed to decode base64: invalid character",
- )
- }
- _ => DomExceptionInvalidCharacterError::new(&format!(
- "Failed to decode base64: {:?}",
- err
- )),
- })?;
+ let decoded = base64_simd::Base64::forgiving_decode_inplace(&mut input)
+ .map_err(|_| error())?;
- Ok(out)
+ let decoded_len = decoded.len();
+ input.truncate(decoded_len);
+ Ok(input)
}
#[op]
fn op_base64_encode(s: ZeroCopyBuf) -> String {
- b64_encode(&s)
+ forgiving_base64_encode(s.as_ref())
}
#[op]
fn op_base64_btoa(s: ByteString) -> String {
- b64_encode(s)
+ forgiving_base64_encode(s.as_ref())
}
-fn b64_encode(s: impl AsRef<[u8]>) -> String {
- let cfg = base64::Config::new(base64::CharacterSet::Standard, true)
- .decode_allow_trailing_bits(true);
- base64::encode_config(s.as_ref(), cfg)
+/// See <https://infra.spec.whatwg.org/#forgiving-base64>
+fn forgiving_base64_encode(s: &[u8]) -> String {
+ let base64 = base64_simd::Base64::STANDARD;
+ base64.encode_to_boxed_str(s).into_string()
}
#[derive(Deserialize)]