Skip to content

Commit 223494c

Browse files
panvaMylesBorins
authored andcommittedAug 31, 2021
buffer: add base64url encoding option
Backport parts of dae283d PR-URL: #36952 Backport-PR-URL: #39702 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent 298a16a commit 223494c

22 files changed

+399
-139
lines changed
 

Diff for: ‎doc/api/buffer.md

+13-3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ const buf7 = Buffer.from('tést', 'latin1');
5050
## Buffers and character encodings
5151
<!-- YAML
5252
changes:
53+
- version: REPLACEME
54+
pr-url: https://github.com/nodejs/node/pull/36952
55+
description: Introduced `base64url` encoding.
5356
- version: v6.4.0
5457
pr-url: https://github.com/nodejs/node/pull/7111
5558
description: Introduced `latin1` as an alias for `binary`.
@@ -106,6 +109,11 @@ string into a `Buffer` as decoding.
106109
specified in [RFC 4648, Section 5][]. Whitespace characters such as spaces,
107110
tabs, and new lines contained within the base64-encoded string are ignored.
108111

112+
* `'base64url'`: [base64url][] encoding as specified in
113+
[RFC 4648, Section 5][]. When creating a `Buffer` from a string, this
114+
encoding will also correctly accept regular base64-encoded strings. When
115+
encoding a `Buffer` to a string, this encoding will omit padding.
116+
109117
* `'hex'`: Encode each byte as two hexadecimal characters. Data truncation
110118
may occur when decoding strings that do exclusively contain valid hexadecimal
111119
characters. See below for an example.
@@ -469,9 +477,10 @@ Returns the byte length of a string when encoded using `encoding`.
469477
This is not the same as [`String.prototype.length`][], which does not account
470478
for the encoding that is used to convert the string into bytes.
471479

472-
For `'base64'` and `'hex'`, this function assumes valid input. For strings that
473-
contain non-base64/hex-encoded data (e.g. whitespace), the return value might be
474-
greater than the length of a `Buffer` created from the string.
480+
For `'base64'`, `'base64url'`, and `'hex'`, this function assumes valid input.
481+
For strings that contain non-base64/hex-encoded data (e.g. whitespace), the
482+
return value might be greater than the length of a `Buffer` created from the
483+
string.
475484

476485
```js
477486
const str = '\u00bd + \u00bc = \u00be';
@@ -3427,6 +3436,7 @@ introducing security vulnerabilities into an application.
34273436
[`buffer.kMaxLength`]: #buffer_buffer_kmaxlength
34283437
[`util.inspect()`]: util.md#util_util_inspect_object_options
34293438
[`v8::TypedArray::kMaxLength`]: https://v8.github.io/api/head/classv8_1_1TypedArray.html#a54a48f4373da0850663c4393d843b9b0
3439+
[base64url]: https://tools.ietf.org/html/rfc4648#section-5
34303440
[binary strings]: https://developer.mozilla.org/en-US/docs/Web/API/DOMString/Binary
34313441
[endianness]: https://en.wikipedia.org/wiki/Endianness
34323442
[iterator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

Diff for: ‎lib/buffer.js

+19
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,20 @@ const encodingOps = {
659659
encodingsMap.base64,
660660
dir)
661661
},
662+
base64url: {
663+
encoding: 'base64url',
664+
encodingVal: encodingsMap.base64url,
665+
byteLength: (string) => base64ByteLength(string, string.length),
666+
write: (buf, string, offset, len) =>
667+
buf.base64urlWrite(string, offset, len),
668+
slice: (buf, start, end) => buf.base64urlSlice(start, end),
669+
indexOf: (buf, val, byteOffset, dir) =>
670+
indexOfBuffer(buf,
671+
fromStringFast(val, encodingOps.base64url),
672+
byteOffset,
673+
encodingsMap.base64url,
674+
dir)
675+
},
662676
hex: {
663677
encoding: 'hex',
664678
encodingVal: encodingsMap.hex,
@@ -715,6 +729,11 @@ function getEncodingOps(encoding) {
715729
if (encoding === 'hex' || StringPrototypeToLowerCase(encoding) === 'hex')
716730
return encodingOps.hex;
717731
break;
732+
case 9:
733+
if (encoding === 'base64url' ||
734+
StringPrototypeToLowerCase(encoding) === 'base64url')
735+
return encodingOps.base64url;
736+
break;
718737
}
719738
}
720739

Diff for: ‎lib/internal/buffer.js

+4
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ const { validateNumber } = require('internal/validators');
1818
const {
1919
asciiSlice,
2020
base64Slice,
21+
base64urlSlice,
2122
latin1Slice,
2223
hexSlice,
2324
ucs2Slice,
2425
utf8Slice,
2526
asciiWrite,
2627
base64Write,
28+
base64urlWrite,
2729
latin1Write,
2830
hexWrite,
2931
ucs2Write,
@@ -1026,12 +1028,14 @@ function addBufferPrototypeMethods(proto) {
10261028

10271029
proto.asciiSlice = asciiSlice;
10281030
proto.base64Slice = base64Slice;
1031+
proto.base64urlSlice = base64urlSlice;
10291032
proto.latin1Slice = latin1Slice;
10301033
proto.hexSlice = hexSlice;
10311034
proto.ucs2Slice = ucs2Slice;
10321035
proto.utf8Slice = utf8Slice;
10331036
proto.asciiWrite = asciiWrite;
10341037
proto.base64Write = base64Write;
1038+
proto.base64urlWrite = base64urlWrite;
10351039
proto.latin1Write = latin1Write;
10361040
proto.hexWrite = hexWrite;
10371041
proto.ucs2Write = ucs2Write;

Diff for: ‎lib/internal/util.js

+5
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ function slowCases(enc) {
177177
`${enc}`.toLowerCase() === 'utf-16le')
178178
return 'utf16le';
179179
break;
180+
case 9:
181+
if (enc === 'base64url' || enc === 'BASE64URL' ||
182+
`${enc}`.toLowerCase() === 'base64url')
183+
return 'base64url';
184+
break;
180185
default:
181186
if (enc === '') return 'utf8';
182187
}

Diff for: ‎src/api/encoding.cc

+4
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,17 @@ enum encoding ParseEncoding(const char* encoding,
6868
} else if (encoding[1] == 'a') {
6969
if (strncmp(encoding + 2, "se64", 5) == 0)
7070
return BASE64;
71+
if (strncmp(encoding + 2, "se64url", 8) == 0)
72+
return BASE64URL;
7173
}
7274
if (StringEqualNoCase(encoding, "binary"))
7375
return LATIN1; // BINARY is a deprecated alias of LATIN1.
7476
if (StringEqualNoCase(encoding, "buffer"))
7577
return BUFFER;
7678
if (StringEqualNoCase(encoding, "base64"))
7779
return BASE64;
80+
if (StringEqualNoCase(encoding, "base64url"))
81+
return BASE64URL;
7882
break;
7983

8084
case 'a':

Diff for: ‎src/base64-inl.h

+11-9
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,13 @@ size_t base64_decode(char* const dst, const size_t dstlen,
123123
inline size_t base64_encode(const char* src,
124124
size_t slen,
125125
char* dst,
126-
size_t dlen) {
126+
size_t dlen,
127+
Base64Mode mode) {
127128
// We know how much we'll write, just make sure that there's space.
128-
CHECK(dlen >= base64_encoded_size(slen) &&
129+
CHECK(dlen >= base64_encoded_size(slen, mode) &&
129130
"not enough space provided for base64 encode");
130131

131-
dlen = base64_encoded_size(slen);
132+
dlen = base64_encoded_size(slen, mode);
132133

133134
unsigned a;
134135
unsigned b;
@@ -137,9 +138,7 @@ inline size_t base64_encode(const char* src,
137138
unsigned k;
138139
unsigned n;
139140

140-
static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
141-
"abcdefghijklmnopqrstuvwxyz"
142-
"0123456789+/";
141+
const char* table = base64_select_table(mode);
143142

144143
i = 0;
145144
k = 0;
@@ -164,16 +163,19 @@ inline size_t base64_encode(const char* src,
164163
a = src[i + 0] & 0xff;
165164
dst[k + 0] = table[a >> 2];
166165
dst[k + 1] = table[(a & 3) << 4];
167-
dst[k + 2] = '=';
168-
dst[k + 3] = '=';
166+
if (mode == Base64Mode::NORMAL) {
167+
dst[k + 2] = '=';
168+
dst[k + 3] = '=';
169+
}
169170
break;
170171
case 2:
171172
a = src[i + 0] & 0xff;
172173
b = src[i + 1] & 0xff;
173174
dst[k + 0] = table[a >> 2];
174175
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
175176
dst[k + 2] = table[(b & 0x0f) << 2];
176-
dst[k + 3] = '=';
177+
if (mode == Base64Mode::NORMAL)
178+
dst[k + 3] = '=';
177179
break;
178180
}
179181

Diff for: ‎src/base64.h

+31-3
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,40 @@
55

66
#include "util.h"
77

8+
#include <cmath>
89
#include <cstddef>
910
#include <cstdint>
1011

1112
namespace node {
1213
//// Base 64 ////
13-
static inline constexpr size_t base64_encoded_size(size_t size) {
14-
return ((size + 2) / 3 * 4);
14+
15+
enum class Base64Mode {
16+
NORMAL,
17+
URL
18+
};
19+
20+
static constexpr char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
21+
"abcdefghijklmnopqrstuvwxyz"
22+
"0123456789+/";
23+
24+
static constexpr char base64_table_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
25+
"abcdefghijklmnopqrstuvwxyz"
26+
"0123456789-_";
27+
28+
static inline const char* base64_select_table(Base64Mode mode) {
29+
switch (mode) {
30+
case Base64Mode::NORMAL: return base64_table;
31+
case Base64Mode::URL: return base64_table_url;
32+
default: UNREACHABLE();
33+
}
34+
}
35+
36+
static inline constexpr size_t base64_encoded_size(
37+
size_t size,
38+
Base64Mode mode = Base64Mode::NORMAL) {
39+
return mode == Base64Mode::NORMAL
40+
? ((size + 2) / 3 * 4)
41+
: std::ceil(static_cast<double>(size * 4) / 3);
1542
}
1643

1744
// Doesn't check for padding at the end. Can be 1-2 bytes over.
@@ -32,7 +59,8 @@ size_t base64_decode(char* const dst, const size_t dstlen,
3259
inline size_t base64_encode(const char* src,
3360
size_t slen,
3461
char* dst,
35-
size_t dlen);
62+
size_t dlen,
63+
Base64Mode mode = Base64Mode::NORMAL);
3664
} // namespace node
3765

3866

Diff for: ‎src/node.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,18 @@ inline void NODE_SET_PROTOTYPE_METHOD(v8::Local<v8::FunctionTemplate> recv,
664664
#define NODE_SET_PROTOTYPE_METHOD node::NODE_SET_PROTOTYPE_METHOD
665665

666666
// BINARY is a deprecated alias of LATIN1.
667-
enum encoding {ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER, LATIN1 = BINARY};
667+
// BASE64URL is not currently exposed to the JavaScript side.
668+
enum encoding {
669+
ASCII,
670+
UTF8,
671+
BASE64,
672+
UCS2,
673+
BINARY,
674+
HEX,
675+
BUFFER,
676+
BASE64URL,
677+
LATIN1 = BINARY
678+
};
668679

669680
NODE_EXTERN enum encoding ParseEncoding(
670681
v8::Isolate* isolate,

Diff for: ‎src/node_buffer.cc

+2
Original file line numberDiff line numberDiff line change
@@ -1163,13 +1163,15 @@ void Initialize(Local<Object> target,
11631163

11641164
env->SetMethodNoSideEffect(target, "asciiSlice", StringSlice<ASCII>);
11651165
env->SetMethodNoSideEffect(target, "base64Slice", StringSlice<BASE64>);
1166+
env->SetMethodNoSideEffect(target, "base64urlSlice", StringSlice<BASE64URL>);
11661167
env->SetMethodNoSideEffect(target, "latin1Slice", StringSlice<LATIN1>);
11671168
env->SetMethodNoSideEffect(target, "hexSlice", StringSlice<HEX>);
11681169
env->SetMethodNoSideEffect(target, "ucs2Slice", StringSlice<UCS2>);
11691170
env->SetMethodNoSideEffect(target, "utf8Slice", StringSlice<UTF8>);
11701171

11711172
env->SetMethod(target, "asciiWrite", StringWrite<ASCII>);
11721173
env->SetMethod(target, "base64Write", StringWrite<BASE64>);
1174+
env->SetMethod(target, "base64urlWrite", StringWrite<BASE64URL>);
11731175
env->SetMethod(target, "latin1Write", StringWrite<LATIN1>);
11741176
env->SetMethod(target, "hexWrite", StringWrite<HEX>);
11751177
env->SetMethod(target, "ucs2Write", StringWrite<UCS2>);

Diff for: ‎src/string_bytes.cc

+20
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ size_t StringBytes::Write(Isolate* isolate,
358358
break;
359359
}
360360

361+
case BASE64URL:
362+
// Fall through
361363
case BASE64:
362364
if (str->IsExternalOneByte()) {
363365
auto ext = str->GetExternalOneByteStringResource();
@@ -425,6 +427,8 @@ Maybe<size_t> StringBytes::StorageSize(Isolate* isolate,
425427
data_size = str->Length() * sizeof(uint16_t);
426428
break;
427429

430+
case BASE64URL:
431+
// Fall through
428432
case BASE64:
429433
data_size = base64_decoded_size_fast(str->Length());
430434
break;
@@ -466,6 +470,8 @@ Maybe<size_t> StringBytes::Size(Isolate* isolate,
466470
case UCS2:
467471
return Just(str->Length() * sizeof(uint16_t));
468472

473+
case BASE64URL:
474+
// Fall through
469475
case BASE64: {
470476
String::Value value(isolate, str);
471477
return Just(base64_decoded_size(*value, value.length()));
@@ -691,6 +697,20 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
691697
return ExternOneByteString::New(isolate, dst, dlen, error);
692698
}
693699

700+
case BASE64URL: {
701+
size_t dlen = base64_encoded_size(buflen, Base64Mode::URL);
702+
char* dst = node::UncheckedMalloc(dlen);
703+
if (dst == nullptr) {
704+
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
705+
return MaybeLocal<Value>();
706+
}
707+
708+
size_t written = base64_encode(buf, buflen, dst, dlen, Base64Mode::URL);
709+
CHECK_EQ(written, dlen);
710+
711+
return ExternOneByteString::New(isolate, dst, dlen, error);
712+
}
713+
694714
case HEX: {
695715
size_t dlen = buflen * 2;
696716
char* dst = node::UncheckedMalloc(dlen);

Diff for: ‎src/string_decoder.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ MaybeLocal<String> StringDecoder::DecodeData(Isolate* isolate,
6969

7070
size_t nread = *nread_ptr;
7171

72-
if (Encoding() == UTF8 || Encoding() == UCS2 || Encoding() == BASE64) {
72+
if (Encoding() == UTF8 ||
73+
Encoding() == UCS2 ||
74+
Encoding() == BASE64 ||
75+
Encoding() == BASE64URL) {
7376
// See if we want bytes to finish a character from the previous
7477
// chunk; if so, copy the new bytes to the missing bytes buffer
7578
// and create a small string from it that is to be prepended to the
@@ -197,7 +200,7 @@ MaybeLocal<String> StringDecoder::DecodeData(Isolate* isolate,
197200
state_[kBufferedBytes] = 2;
198201
state_[kMissingBytes] = 2;
199202
}
200-
} else if (Encoding() == BASE64) {
203+
} else if (Encoding() == BASE64 || Encoding() == BASE64URL) {
201204
state_[kBufferedBytes] = nread % 3;
202205
if (state_[kBufferedBytes] > 0)
203206
state_[kMissingBytes] = 3 - BufferedBytes();
@@ -310,6 +313,7 @@ void InitializeStringDecoder(Local<Object> target,
310313
ADD_TO_ENCODINGS_ARRAY(ASCII, "ascii");
311314
ADD_TO_ENCODINGS_ARRAY(UTF8, "utf8");
312315
ADD_TO_ENCODINGS_ARRAY(BASE64, "base64");
316+
ADD_TO_ENCODINGS_ARRAY(BASE64URL, "base64url");
313317
ADD_TO_ENCODINGS_ARRAY(UCS2, "utf16le");
314318
ADD_TO_ENCODINGS_ARRAY(HEX, "hex");
315319
ADD_TO_ENCODINGS_ARRAY(BUFFER, "buffer");

Diff for: ‎test/addons/parse-encoding/binding.cc

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace {
66
#define ENCODING_MAP(V) \
77
V(ASCII) \
88
V(BASE64) \
9+
V(BASE64URL) \
910
V(BUFFER) \
1011
V(HEX) \
1112
V(LATIN1) \

Diff for: ‎test/addons/parse-encoding/test.js

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ assert.strictEqual(parseEncoding(''), 'UNKNOWN');
88

99
assert.strictEqual(parseEncoding('ascii'), 'ASCII');
1010
assert.strictEqual(parseEncoding('base64'), 'BASE64');
11+
assert.strictEqual(parseEncoding('base64url'), 'BASE64URL');
1112
assert.strictEqual(parseEncoding('binary'), 'LATIN1');
1213
assert.strictEqual(parseEncoding('buffer'), 'BUFFER');
1314
assert.strictEqual(parseEncoding('hex'), 'HEX');

Diff for: ‎test/cctest/test_base64.cc

+15
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ TEST(Base64Test, Encode) {
4444
"IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==");
4545
}
4646

47+
TEST(Base64Test, EncodeURL) {
48+
auto test = [](const char* string, const char* base64_string) {
49+
const size_t len = strlen(base64_string);
50+
char* const buffer = new char[len + 1];
51+
buffer[len] = 0;
52+
base64_encode(string, strlen(string), buffer, len, node::Base64Mode::URL);
53+
EXPECT_STREQ(base64_string, buffer);
54+
delete[] buffer;
55+
};
56+
57+
test("\x68\xd9\x16\x25\x5c\x1e\x40\x92\x2d\xfb", "aNkWJVweQJIt-w");
58+
test("\xac\xc7\x93\xaa\x83\x6f\xc3\xe3\x3f\x75", "rMeTqoNvw-M_dQ");
59+
}
60+
4761
TEST(Base64Test, Decode) {
4862
auto test = [](const char* base64_string, const char* string) {
4963
const size_t len = strlen(string);
@@ -75,6 +89,7 @@ TEST(Base64Test, Decode) {
7589
test("YWJj ZGVm", "abcdef");
7690
test("Y W J j Z G V m", "abcdef");
7791
test("Y W\n JjZ \nG Vm", "abcdef");
92+
test("rMeTqoNvw-M_dQ", "\xac\xc7\x93\xaa\x83\x6f\xc3\xe3\x3f\x75");
7893

7994
const char* text =
8095
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "

Diff for: ‎test/parallel/test-buffer-alloc.js

+200-104
Large diffs are not rendered by default.

Diff for: ‎test/parallel/test-buffer-bytelength.js

+10
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,19 @@ assert.strictEqual(Buffer.byteLength('aGkk', 'base64'), 3);
9191
assert.strictEqual(
9292
Buffer.byteLength('bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw==', 'base64'), 25
9393
);
94+
// base64url
95+
assert.strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ', 'base64url'), 11);
96+
assert.strictEqual(Buffer.byteLength('aGVsbG8gd29ybGQ', 'BASE64URL'), 11);
97+
assert.strictEqual(Buffer.byteLength('bm9kZS5qcyByb2NrcyE', 'base64url'), 14);
98+
assert.strictEqual(Buffer.byteLength('aGkk', 'base64url'), 3);
99+
assert.strictEqual(
100+
Buffer.byteLength('bHNrZGZsa3NqZmtsc2xrZmFqc2RsZmtqcw', 'base64url'), 25
101+
);
94102
// special padding
95103
assert.strictEqual(Buffer.byteLength('aaa=', 'base64'), 2);
96104
assert.strictEqual(Buffer.byteLength('aaaa==', 'base64'), 3);
105+
assert.strictEqual(Buffer.byteLength('aaa=', 'base64url'), 2);
106+
assert.strictEqual(Buffer.byteLength('aaaa==', 'base64url'), 3);
97107

98108
assert.strictEqual(Buffer.byteLength('Il était tué'), 14);
99109
assert.strictEqual(Buffer.byteLength('Il était tué', 'utf8'), 14);

Diff for: ‎test/parallel/test-buffer-fill.js

+30-14
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,36 @@ assert.throws(() => {
131131
});
132132

133133
// BASE64
134-
testBufs('YWJj', 'ucs2');
135-
testBufs('yKJhYQ==', 'ucs2');
136-
testBufs('Yci0Ysi1Y8i2', 'ucs2');
137-
testBufs('YWJj', 4, 'ucs2');
138-
testBufs('YWJj', SIZE, 'ucs2');
139-
testBufs('yKJhYQ==', 2, 'ucs2');
140-
testBufs('yKJhYQ==', 8, 'ucs2');
141-
testBufs('Yci0Ysi1Y8i2', 4, 'ucs2');
142-
testBufs('Yci0Ysi1Y8i2', 12, 'ucs2');
143-
testBufs('YWJj', 4, 1, 'ucs2');
144-
testBufs('YWJj', 5, 1, 'ucs2');
145-
testBufs('yKJhYQ==', 8, 1, 'ucs2');
146-
testBufs('Yci0Ysi1Y8i2', 4, 1, 'ucs2');
147-
testBufs('Yci0Ysi1Y8i2', 12, 1, 'ucs2');
134+
testBufs('YWJj', 'base64');
135+
testBufs('yKJhYQ==', 'base64');
136+
testBufs('Yci0Ysi1Y8i2', 'base64');
137+
testBufs('YWJj', 4, 'base64');
138+
testBufs('YWJj', SIZE, 'base64');
139+
testBufs('yKJhYQ==', 2, 'base64');
140+
testBufs('yKJhYQ==', 8, 'base64');
141+
testBufs('Yci0Ysi1Y8i2', 4, 'base64');
142+
testBufs('Yci0Ysi1Y8i2', 12, 'base64');
143+
testBufs('YWJj', 4, 1, 'base64');
144+
testBufs('YWJj', 5, 1, 'base64');
145+
testBufs('yKJhYQ==', 8, 1, 'base64');
146+
testBufs('Yci0Ysi1Y8i2', 4, 1, 'base64');
147+
testBufs('Yci0Ysi1Y8i2', 12, 1, 'base64');
148+
149+
// BASE64URL
150+
testBufs('YWJj', 'base64url');
151+
testBufs('yKJhYQ', 'base64url');
152+
testBufs('Yci0Ysi1Y8i2', 'base64url');
153+
testBufs('YWJj', 4, 'base64url');
154+
testBufs('YWJj', SIZE, 'base64url');
155+
testBufs('yKJhYQ', 2, 'base64url');
156+
testBufs('yKJhYQ', 8, 'base64url');
157+
testBufs('Yci0Ysi1Y8i2', 4, 'base64url');
158+
testBufs('Yci0Ysi1Y8i2', 12, 'base64url');
159+
testBufs('YWJj', 4, 1, 'base64url');
160+
testBufs('YWJj', 5, 1, 'base64url');
161+
testBufs('yKJhYQ', 8, 1, 'base64url');
162+
testBufs('Yci0Ysi1Y8i2', 4, 1, 'base64url');
163+
testBufs('Yci0Ysi1Y8i2', 12, 1, 'base64url');
148164

149165
// Buffer
150166
function deepStrictEqualValues(buf, arr) {

Diff for: ‎test/parallel/test-buffer-isencoding.js

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const assert = require('assert');
1111
'latin1',
1212
'binary',
1313
'base64',
14+
'base64url',
1415
'ucs2',
1516
'ucs-2',
1617
'utf16le',

Diff for: ‎test/parallel/test-buffer-write.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const resultMap = new Map([
2323
['binary', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])],
2424
['utf16le', Buffer.from([102, 0, 111, 0, 111, 0, 0, 0, 0])],
2525
['base64', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])],
26+
['base64url', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])],
2627
['hex', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])]
2728
]);
2829

@@ -44,7 +45,7 @@ encodings
4445
});
4546

4647
// base64
47-
['base64', 'BASE64'].forEach((encoding) => {
48+
['base64', 'BASE64', 'base64url', 'BASE64URL'].forEach((encoding) => {
4849
const buf = Buffer.alloc(9);
4950
const len = Buffer.byteLength('Zm9v', encoding);
5051

Diff for: ‎test/parallel/test-internal-util-normalizeencoding.js

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ const tests = [
3333
['base64', 'base64'],
3434
['BASE64', 'base64'],
3535
['Base64', 'base64'],
36+
['base64url', 'base64url'],
37+
['BASE64url', 'base64url'],
38+
['Base64url', 'base64url'],
3639
['hex', 'hex'],
3740
['HEX', 'hex'],
3841
['ASCII', 'ascii'],

Diff for: ‎test/parallel/test-string-decoder-end.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
require('../common');
2828
const assert = require('assert');
2929
const SD = require('string_decoder').StringDecoder;
30-
const encodings = ['base64', 'hex', 'utf8', 'utf16le', 'ucs2'];
30+
const encodings = ['base64', 'base64url', 'hex', 'utf8', 'utf16le', 'ucs2'];
3131

3232
const bufs = [ '☃💩', 'asdf' ].map((b) => Buffer.from(b));
3333

@@ -79,6 +79,13 @@ testEnd('base64', Buffer.of(0x61, 0x61), Buffer.of(0x61), 'YWE=YQ==');
7979
testEnd('base64', Buffer.of(0x61, 0x61, 0x61), Buffer.of(), 'YWFh');
8080
testEnd('base64', Buffer.of(0x61, 0x61, 0x61), Buffer.of(0x61), 'YWFhYQ==');
8181

82+
testEnd('base64url', Buffer.of(0x61), Buffer.of(), 'YQ');
83+
testEnd('base64url', Buffer.of(0x61), Buffer.of(0x61), 'YQYQ');
84+
testEnd('base64url', Buffer.of(0x61, 0x61), Buffer.of(), 'YWE');
85+
testEnd('base64url', Buffer.of(0x61, 0x61), Buffer.of(0x61), 'YWEYQ');
86+
testEnd('base64url', Buffer.of(0x61, 0x61, 0x61), Buffer.of(), 'YWFh');
87+
testEnd('base64url', Buffer.of(0x61, 0x61, 0x61), Buffer.of(0x61), 'YWFhYQ');
88+
8289
function testEncoding(encoding) {
8390
bufs.forEach((buf) => {
8491
testBuf(encoding, buf);

Diff for: ‎test/parallel/test-string-decoder-fuzz.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function randBuf(maxLen) {
2020
}
2121

2222
const encodings = [
23-
'utf16le', 'utf8', 'ascii', 'hex', 'base64', 'latin1'
23+
'utf16le', 'utf8', 'ascii', 'hex', 'base64', 'latin1', 'base64url'
2424
];
2525

2626
function runSingleFuzzTest() {

0 commit comments

Comments
 (0)
Please sign in to comment.