diff --git a/AK/Base64.cpp b/AK/Base64.cpp index 5737ba668b3..0485bd736cb 100644 --- a/AK/Base64.cpp +++ b/AK/Base64.cpp @@ -17,38 +17,70 @@ size_t size_required_to_decode_base64(StringView input) return simdutf::maximal_binary_length_from_base64(input.characters_without_null_termination(), input.length()); } -static ErrorOr decode_base64_into_impl(StringView input, ByteBuffer& output, simdutf::base64_options options) +static constexpr simdutf::last_chunk_handling_options to_simdutf_last_chunk_handling(LastChunkHandling last_chunk_handling) { - size_t output_length = output.size(); + switch (last_chunk_handling) { + case LastChunkHandling::Loose: + return simdutf::last_chunk_handling_options::loose; + case LastChunkHandling::Strict: + return simdutf::last_chunk_handling_options::strict; + case LastChunkHandling::StopBeforePartial: + return simdutf::last_chunk_handling_options::stop_before_partial; + } + + VERIFY_NOT_REACHED(); +} + +static ErrorOr decode_base64_into_impl(StringView input, ByteBuffer& output, LastChunkHandling last_chunk_handling, simdutf::base64_options options) +{ + static constexpr auto decode_up_to_bad_character = true; + auto output_length = output.size(); auto result = simdutf::base64_to_binary_safe( input.characters_without_null_termination(), input.length(), reinterpret_cast(output.data()), output_length, - options); + options, + to_simdutf_last_chunk_handling(last_chunk_handling), + decode_up_to_bad_character); - if (result.error != simdutf::SUCCESS && result.error != simdutf::OUTPUT_BUFFER_TOO_SMALL) { + if (result.error == simdutf::BASE64_INPUT_REMAINDER && last_chunk_handling == LastChunkHandling::StopBeforePartial) { + result.error = simdutf::SUCCESS; + } else if (result.error != simdutf::SUCCESS && result.error != simdutf::OUTPUT_BUFFER_TOO_SMALL) { output.resize((result.count / 4) * 3); - return InvalidBase64 { - .error = Error::from_string_literal("Invalid base64-encoded data"), - .valid_input_bytes = result.count, - }; + auto error = [&]() { + switch (result.error) { + case simdutf::BASE64_EXTRA_BITS: + return Error::from_string_literal("Extra bits found at end of chunk"); + case simdutf::BASE64_INPUT_REMAINDER: + return Error::from_string_literal("Invalid trailing data"); + case simdutf::INVALID_BASE64_CHARACTER: + return Error::from_string_literal("Invalid base64 character"); + default: + return Error::from_string_literal("Invalid base64-encoded data"); + } + }(); + + return InvalidBase64 { .error = move(error), .valid_input_bytes = result.count }; } VERIFY(output_length <= output.size()); output.resize(output_length); + if (last_chunk_handling == LastChunkHandling::StopBeforePartial) + return input.length() - (input.length() % 4); + return result.error == simdutf::SUCCESS ? input.length() : result.count; } -static ErrorOr decode_base64_impl(StringView input, simdutf::base64_options options) +static ErrorOr decode_base64_impl(StringView input, LastChunkHandling last_chunk_handling, simdutf::base64_options options) { ByteBuffer output; TRY(output.try_resize(size_required_to_decode_base64(input))); - if (auto result = decode_base64_into_impl(input, output, options); result.is_error()) + if (auto result = decode_base64_into_impl(input, output, last_chunk_handling, options); result.is_error()) return result.release_error().error; return output; @@ -68,24 +100,24 @@ static ErrorOr encode_base64_impl(StringView input, simdutf::base64_opti return String::from_utf8_without_validation(output); } -ErrorOr decode_base64(StringView input) +ErrorOr decode_base64(StringView input, LastChunkHandling last_chunk_handling) { - return decode_base64_impl(input, simdutf::base64_default); + return decode_base64_impl(input, last_chunk_handling, simdutf::base64_default); } -ErrorOr decode_base64url(StringView input) +ErrorOr decode_base64url(StringView input, LastChunkHandling last_chunk_handling) { - return decode_base64_impl(input, simdutf::base64_url); + return decode_base64_impl(input, last_chunk_handling, simdutf::base64_url); } -ErrorOr decode_base64_into(StringView input, ByteBuffer& output) +ErrorOr decode_base64_into(StringView input, ByteBuffer& output, LastChunkHandling last_chunk_handling) { - return decode_base64_into_impl(input, output, simdutf::base64_default); + return decode_base64_into_impl(input, output, last_chunk_handling, simdutf::base64_default); } -ErrorOr decode_base64url_into(StringView input, ByteBuffer& output) +ErrorOr decode_base64url_into(StringView input, ByteBuffer& output, LastChunkHandling last_chunk_handling) { - return decode_base64_into_impl(input, output, simdutf::base64_url); + return decode_base64_into_impl(input, output, last_chunk_handling, simdutf::base64_url); } ErrorOr encode_base64(ReadonlyBytes input, OmitPadding omit_padding) diff --git a/AK/Base64.h b/AK/Base64.h index 0c92b968500..3c988e8390d 100644 --- a/AK/Base64.h +++ b/AK/Base64.h @@ -15,8 +15,14 @@ namespace AK { size_t size_required_to_decode_base64(StringView); -ErrorOr decode_base64(StringView); -ErrorOr decode_base64url(StringView); +enum class LastChunkHandling { + Loose, + Strict, + StopBeforePartial, +}; + +ErrorOr decode_base64(StringView, LastChunkHandling = LastChunkHandling::Loose); +ErrorOr decode_base64url(StringView, LastChunkHandling = LastChunkHandling::Loose); struct InvalidBase64 { Error error; @@ -25,8 +31,8 @@ struct InvalidBase64 { // On success, these return the number of input bytes that were decoded. This might be less than the // string length if the output buffer was not large enough. -ErrorOr decode_base64_into(StringView, ByteBuffer&); -ErrorOr decode_base64url_into(StringView, ByteBuffer&); +ErrorOr decode_base64_into(StringView, ByteBuffer&, LastChunkHandling = LastChunkHandling::Loose); +ErrorOr decode_base64url_into(StringView, ByteBuffer&, LastChunkHandling = LastChunkHandling::Loose); enum class OmitPadding { No, diff --git a/Libraries/LibJS/Runtime/Uint8Array.cpp b/Libraries/LibJS/Runtime/Uint8Array.cpp index 299434451ee..bf8ef87cbbb 100644 --- a/Libraries/LibJS/Runtime/Uint8Array.cpp +++ b/Libraries/LibJS/Runtime/Uint8Array.cpp @@ -4,7 +4,6 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include #include #include #include @@ -55,23 +54,23 @@ static ThrowCompletionOr parse_alphabet(VM& vm, Object& options) return vm.throw_completion(ErrorType::OptionIsNotValidValue, alphabet, "alphabet"sv); } -static ThrowCompletionOr parse_last_chunk_handling(VM& vm, Object& options) +static ThrowCompletionOr parse_last_chunk_handling(VM& vm, Object& options) { // Let lastChunkHandling be ? Get(opts, "lastChunkHandling"). auto last_chunk_handling = TRY(options.get(vm.names.lastChunkHandling)); // If lastChunkHandling is undefined, set lastChunkHandling to "loose". if (last_chunk_handling.is_undefined()) - return LastChunkHandling::Loose; + return AK::LastChunkHandling::Loose; // If lastChunkHandling is not one of "loose", "strict", or "stop-before-partial", throw a TypeError exception. if (last_chunk_handling.is_string()) { if (last_chunk_handling.as_string().utf8_string_view() == "loose"sv) - return LastChunkHandling::Loose; + return AK::LastChunkHandling::Loose; if (last_chunk_handling.as_string().utf8_string_view() == "strict"sv) - return LastChunkHandling::Strict; + return AK::LastChunkHandling::Strict; if (last_chunk_handling.as_string().utf8_string_view() == "stop-before-partial"sv) - return LastChunkHandling::StopBeforePartial; + return AK::LastChunkHandling::StopBeforePartial; } return vm.throw_completion(ErrorType::OptionIsNotValidValue, last_chunk_handling, "lastChunkHandling"sv); @@ -451,337 +450,23 @@ void set_uint8_array_bytes(TypedArrayBase& into, ReadonlyBytes bytes) } } -// 10.1 SkipAsciiWhitespace ( string, index ), https://tc39.es/proposal-arraybuffer-base64/spec/#sec-skipasciiwhitespace -static size_t skip_ascii_whitespace(StringView string, size_t index) -{ - // 1. Let length be the length of string. - auto length = string.length(); - - // 2. Repeat, while index < length, - while (index < length) { - // a. Let char be the code unit at index index of string. - auto ch = string[index]; - - // b. If char is neither 0x0009 (TAB), 0x000A (LF), 0x000C (FF), 0x000D (CR), nor 0x0020 (SPACE), then - if (ch != '\t' && ch != '\n' && ch != '\f' && ch != '\r' && ch != ' ') { - // i. Return index. - return index; - } - - // c. Set index to index + 1. - ++index; - } - - // 3. Return index. - return index; -} - -// 10.2 DecodeBase64Chunk ( chunk [ , throwOnExtraBits ] ), https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 -static ThrowCompletionOr decode_base64_chunk(VM& vm, StringBuilder& chunk, Optional throw_on_extra_bits = {}) -{ - // 1. Let chunkLength be the length of chunk. - auto chunk_length = chunk.length(); - - // 2. If chunkLength is 2, then - if (chunk_length == 2) { - // a. Set chunk to the string-concatenation of chunk and "AA". - chunk.append("AA"sv); - } - // 3. Else if chunkLength is 3, then - else if (chunk_length == 3) { - // a. Set chunk to the string-concatenation of chunk and "A". - chunk.append("A"sv); - } - // 4. Else, - else { - // a. Assert: chunkLength is 4. - VERIFY(chunk_length == 4); - } - - // 5. Let byteSequence be the unique sequence of 3 bytes resulting from decoding chunk as base64 (such that applying - // the base64 encoding specified in section 4 of RFC 4648 to byteSequence would produce chunk). - // 6. Let bytes be a List whose elements are the elements of byteSequence, in order. - auto bytes = MUST(decode_base64(chunk.string_view())); - - // 7. If chunkLength is 2, then - if (chunk_length == 2) { - // a. Assert: throwOnExtraBits is present. - VERIFY(throw_on_extra_bits.has_value()); - - // b. If throwOnExtraBits is true and bytes[1] ≠ 0, then - if (*throw_on_extra_bits && bytes[1] != 0) { - // i. Throw a SyntaxError exception. - return vm.throw_completion("Extra bits found at end of chunk"sv); - } - - // c. Return « bytes[0] ». - return MUST(bytes.slice(0, 1)); - } - - // 8. Else if chunkLength is 3, then - if (chunk_length == 3) { - // a. Assert: throwOnExtraBits is present. - VERIFY(throw_on_extra_bits.has_value()); - - // b. If throwOnExtraBits is true and bytes[2] ≠ 0, then - if (*throw_on_extra_bits && bytes[2] != 0) { - // i. Throw a SyntaxError exception. - return vm.throw_completion("Extra bits found at end of chunk"sv); - } - - // c. Return « bytes[0], bytes[1] ». - return MUST(bytes.slice(0, 2)); - } - - // 9. Else, - // a. Return bytes. - return bytes; -} - // 10.3 FromBase64 ( string, alphabet, lastChunkHandling [ , maxLength ] ), https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64 -DecodeResult from_base64(VM& vm, StringView string, Alphabet alphabet, LastChunkHandling last_chunk_handling, Optional max_length) +DecodeResult from_base64(VM& vm, StringView string, Alphabet alphabet, AK::LastChunkHandling last_chunk_handling, Optional max_length) { - // FIXME: We can only use simdutf when the last-chunk-handling parameter is "loose". Upstream is planning to implement - // the remaining options. When that is complete, we should be able to remove the slow implementation below. See: - // https://github.com/simdutf/simdutf/issues/440 - if (last_chunk_handling == LastChunkHandling::Loose) { - auto output = MUST(ByteBuffer::create_uninitialized(max_length.value_or_lazy_evaluated([&]() { - return AK::size_required_to_decode_base64(string); - }))); + auto output = MUST(ByteBuffer::create_uninitialized(max_length.value_or_lazy_evaluated([&]() { + return AK::size_required_to_decode_base64(string); + }))); - auto result = alphabet == Alphabet::Base64 - ? AK::decode_base64_into(string, output) - : AK::decode_base64url_into(string, output); + auto result = alphabet == Alphabet::Base64 + ? AK::decode_base64_into(string, output, last_chunk_handling) + : AK::decode_base64url_into(string, output, last_chunk_handling); - if (result.is_error()) { - auto error = vm.throw_completion(result.error().error.string_literal()); - return { .read = result.error().valid_input_bytes, .bytes = move(output), .error = move(error) }; - } - - return { .read = result.value(), .bytes = move(output), .error = {} }; + if (result.is_error()) { + auto error = vm.throw_completion(result.error().error.string_literal()); + return { .read = result.error().valid_input_bytes, .bytes = move(output), .error = move(error) }; } - // 1. If maxLength is not present, then - if (!max_length.has_value()) { - // a. Let maxLength be 2**53 - 1. - max_length = MAX_ARRAY_LIKE_INDEX; - - // b. NOTE: Because the input is a string, the length of strings is limited to 2**53 - 1 characters, and the - // output requires no more bytes than the input has characters, this limit can never be reached. However, it - // is editorially convenient to use a finite value here. - } - - // 2. NOTE: The order of validation and decoding in the algorithm below is not observable. Implementations are - // encouraged to perform them in whatever order is most efficient, possibly interleaving validation with decoding, - // as long as the behaviour is observably equivalent. - - // 3. If maxLength is 0, then - if (max_length == 0uz) { - // a. Return the Record { [[Read]]: 0, [[Bytes]]: « », [[Error]]: none }. - return { .read = 0, .bytes = {}, .error = {} }; - } - - // 4. Let read be 0. - size_t read = 0; - - // 5. Let bytes be « ». - ByteBuffer bytes; - - // 6. Let chunk be the empty String. - StringBuilder chunk; - - // 7. Let chunkLength be 0. - size_t chunk_length = 0; - - // 8. Let index be 0. - size_t index = 0; - - // 9. Let length be the length of string. - auto length = string.length(); - - // 10. Repeat, - while (true) { - // a. Set index to SkipAsciiWhitespace(string, index). - index = skip_ascii_whitespace(string, index); - - // b. If index = length, then - if (index == length) { - // i. If chunkLength > 0, then - if (chunk_length > 0) { - // 1. If lastChunkHandling is "stop-before-partial", then - if (last_chunk_handling == LastChunkHandling::StopBeforePartial) { - // a. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: none }. - return { .read = read, .bytes = move(bytes), .error = {} }; - } - // 2. Else if lastChunkHandling is "loose", then - else if (last_chunk_handling == LastChunkHandling::Loose) { - VERIFY_NOT_REACHED(); - } - // 3. Else, - else { - // a. Assert: lastChunkHandling is "strict". - VERIFY(last_chunk_handling == LastChunkHandling::Strict); - - // b. Let error be a new SyntaxError exception. - auto error = vm.throw_completion("Invalid trailing data"sv); - - // c. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: error }. - return { .read = read, .bytes = move(bytes), .error = move(error) }; - } - } - - // ii. Return the Record { [[Read]]: length, [[Bytes]]: bytes, [[Error]]: none }. - return { .read = length, .bytes = move(bytes), .error = {} }; - } - - // c. Let char be the substring of string from index to index + 1. - auto ch = string[index]; - - // d. Set index to index + 1. - ++index; - - // e. If char is "=", then - if (ch == '=') { - // i. If chunkLength < 2, then - if (chunk_length < 2) { - // 1. Let error be a new SyntaxError exception. - auto error = vm.throw_completion("Unexpected padding character"sv); - - // 2. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: error }. - return { .read = read, .bytes = move(bytes), .error = move(error) }; - } - - // ii. Set index to SkipAsciiWhitespace(string, index). - index = skip_ascii_whitespace(string, index); - - // iii. If chunkLength = 2, then - if (chunk_length == 2) { - // 1. If index = length, then - if (index == length) { - // a. If lastChunkHandling is "stop-before-partial", then - if (last_chunk_handling == LastChunkHandling::StopBeforePartial) { - // i. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: none }. - return { .read = read, .bytes = move(bytes), .error = {} }; - } - - // b. Let error be a new SyntaxError exception. - auto error = vm.throw_completion("Incomplete number of padding characters"sv); - - // c. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: error }. - return { .read = read, .bytes = move(bytes), .error = move(error) }; - } - - // 2. Set char to the substring of string from index to index + 1. - ch = string[index]; - - // 3. If char is "=", then - if (ch == '=') { - // a. Set index to SkipAsciiWhitespace(string, index + 1). - index = skip_ascii_whitespace(string, index + 1); - } - } - - // iv. If index < length, then - if (index < length) { - // 1. Let error be a new SyntaxError exception. - auto error = vm.throw_completion("Unexpected padding character"sv); - - // 2. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: error }. - return { .read = read, .bytes = move(bytes), .error = move(error) }; - } - - // v. If lastChunkHandling is "strict", let throwOnExtraBits be true. - // vi. Else, let throwOnExtraBits be false. - auto throw_on_extra_bits = last_chunk_handling == LastChunkHandling::Strict; - - // vii. Let decodeResult be Completion(DecodeBase64Chunk(chunk, throwOnExtraBits)). - auto decode_result = decode_base64_chunk(vm, chunk, throw_on_extra_bits); - - // viii. If decodeResult is an abrupt completion, then - if (decode_result.is_error()) { - // 1. Let error be decodeResult.[[Value]]. - auto error = decode_result.release_error(); - - // 2. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: error }. - return { .read = read, .bytes = move(bytes), .error = move(error) }; - } - - // ix. Set bytes to the list-concatenation of bytes and ! decodeResult. - bytes.append(decode_result.release_value()); - - // x. Return the Record { [[Read]]: length, [[Bytes]]: bytes, [[Error]]: none }. - return { .read = length, .bytes = move(bytes), .error = {} }; - } - - // f. If alphabet is "base64url", then - if (alphabet == Alphabet::Base64URL) { - // i. If char is either "+" or "/", then - if (ch == '+' || ch == '/') { - // 1. Let error be a new SyntaxError exception. - auto error = vm.throw_completion(MUST(String::formatted("Invalid character '{}'", ch))); - - // 2. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: error }. - return { .read = read, .bytes = move(bytes), .error = move(error) }; - } - // ii. Else if char is "-", then - else if (ch == '-') { - // 1. Set char to "+". - ch = '+'; - } - // iii. Else if char is "_", then - else if (ch == '_') { - // 1. Set char to "/". - ch = '/'; - } - } - - // g. If the sole code unit of char is not an element of the standard base64 alphabet, then - static constexpr auto standard_base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"sv; - - if (!standard_base64_alphabet.contains(ch)) { - // i. Let error be a new SyntaxError exception. - auto error = vm.throw_completion(MUST(String::formatted("Invalid character '{}'", ch))); - - // ii. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: error }. - return { .read = read, .bytes = move(bytes), .error = move(error) }; - } - - // h. Let remaining be maxLength - the length of bytes. - auto remaining = *max_length - bytes.size(); - - // i. If remaining = 1 and chunkLength = 2, or if remaining = 2 and chunkLength = 3, then - if ((remaining == 1 && chunk_length == 2) || (remaining == 2 && chunk_length == 3)) { - // i. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: none }. - return { .read = read, .bytes = move(bytes), .error = {} }; - } - - // j. Set chunk to the string-concatenation of chunk and char. - chunk.append(ch); - - // k. Set chunkLength to the length of chunk. - chunk_length = chunk.length(); - - // l. If chunkLength = 4, then - if (chunk_length == 4) { - // i. Set bytes to the list-concatenation of bytes and ! DecodeBase64Chunk(chunk). - bytes.append(MUST(decode_base64_chunk(vm, chunk))); - - // ii. Set chunk to the empty String. - chunk.clear(); - - // iii. Set chunkLength to 0. - chunk_length = 0; - - // iv. Set read to index. - read = index; - - // v. If the length of bytes = maxLength, then - if (bytes.size() == max_length) { - // 1. Return the Record { [[Read]]: read, [[Bytes]]: bytes, [[Error]]: none }. - return { .read = read, .bytes = move(bytes), .error = {} }; - } - } - } + return { .read = result.value(), .bytes = move(output), .error = {} }; } // 10.4 FromHex ( string [ , maxLength ] ), https://tc39.es/proposal-arraybuffer-base64/spec/#sec-fromhex diff --git a/Libraries/LibJS/Runtime/Uint8Array.h b/Libraries/LibJS/Runtime/Uint8Array.h index c78255b5ff3..59d7ee846df 100644 --- a/Libraries/LibJS/Runtime/Uint8Array.h +++ b/Libraries/LibJS/Runtime/Uint8Array.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -41,12 +42,6 @@ enum class Alphabet { Base64URL, }; -enum class LastChunkHandling { - Loose, - Strict, - StopBeforePartial, -}; - struct DecodeResult { size_t read { 0 }; // [[Read]] ByteBuffer bytes; // [[Bytes]] @@ -56,7 +51,7 @@ struct DecodeResult { ThrowCompletionOr> validate_uint8_array(VM&); ThrowCompletionOr get_uint8_array_bytes(VM&, TypedArrayBase const&); void set_uint8_array_bytes(TypedArrayBase&, ReadonlyBytes); -DecodeResult from_base64(VM&, StringView string, Alphabet alphabet, LastChunkHandling last_chunk_handling, Optional max_length = {}); +DecodeResult from_base64(VM&, StringView string, Alphabet alphabet, AK::LastChunkHandling last_chunk_handling, Optional max_length = {}); DecodeResult from_hex(VM&, StringView string, Optional max_length = {}); } diff --git a/Libraries/LibJS/Tests/builtins/TypedArray/Uint8Array.fromBase64.js b/Libraries/LibJS/Tests/builtins/TypedArray/Uint8Array.fromBase64.js index b7df4acf0eb..8ca3aa1cbae 100644 --- a/Libraries/LibJS/Tests/builtins/TypedArray/Uint8Array.fromBase64.js +++ b/Libraries/LibJS/Tests/builtins/TypedArray/Uint8Array.fromBase64.js @@ -40,25 +40,25 @@ describe("errors", () => { test("invalid padding", () => { expect(() => { Uint8Array.fromBase64("Zm9v=", { lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Unexpected padding character"); + }).toThrowWithMessage(SyntaxError, "Invalid trailing data"); expect(() => { Uint8Array.fromBase64("Zm9vaa=", { lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Incomplete number of padding characters"); + }).toThrowWithMessage(SyntaxError, "Invalid trailing data"); expect(() => { Uint8Array.fromBase64("Zm9vaa=a", { lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Unexpected padding character"); + }).toThrowWithMessage(SyntaxError, "Invalid base64 character"); }); test("invalid alphabet", () => { expect(() => { Uint8Array.fromBase64("-", { lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Invalid character '-'"); + }).toThrowWithMessage(SyntaxError, "Invalid base64 character"); expect(() => { Uint8Array.fromBase64("+", { alphabet: "base64url", lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Invalid character '+'"); + }).toThrowWithMessage(SyntaxError, "Invalid base64 character"); }); test("overlong chunk", () => { diff --git a/Libraries/LibJS/Tests/builtins/TypedArray/Uint8Array.prototype.setFromBase64.js b/Libraries/LibJS/Tests/builtins/TypedArray/Uint8Array.prototype.setFromBase64.js index 214b29e960c..da5136a4f53 100644 --- a/Libraries/LibJS/Tests/builtins/TypedArray/Uint8Array.prototype.setFromBase64.js +++ b/Libraries/LibJS/Tests/builtins/TypedArray/Uint8Array.prototype.setFromBase64.js @@ -79,28 +79,28 @@ describe("errors", () => { test("invalid padding", () => { expect(() => { new Uint8Array(10).setFromBase64("Zm9v=", { lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Unexpected padding character"); + }).toThrowWithMessage(SyntaxError, "Invalid trailing data"); expect(() => { new Uint8Array(10).setFromBase64("Zm9vaa=", { lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Incomplete number of padding characters"); + }).toThrowWithMessage(SyntaxError, "Invalid trailing data"); expect(() => { new Uint8Array(10).setFromBase64("Zm9vaa=a", { lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Unexpected padding character"); + }).toThrowWithMessage(SyntaxError, "Invalid base64 character"); }); test("invalid alphabet", () => { expect(() => { new Uint8Array(10).setFromBase64("-", { lastChunkHandling: "strict" }); - }).toThrowWithMessage(SyntaxError, "Invalid character '-'"); + }).toThrowWithMessage(SyntaxError, "Invalid base64 character"); expect(() => { new Uint8Array(10).setFromBase64("+", { alphabet: "base64url", lastChunkHandling: "strict", }); - }).toThrowWithMessage(SyntaxError, "Invalid character '+'"); + }).toThrowWithMessage(SyntaxError, "Invalid base64 character"); }); test("overlong chunk", () => {