8
8
9
9
'use strict'
10
10
11
- const base64 = require ( 'base64-js' )
12
11
const ieee754 = require ( 'ieee754' )
13
12
const customInspectSymbol =
14
13
( typeof Symbol === 'function' && typeof Symbol [ 'for' ] === 'function' ) // eslint-disable-line dot-notation
@@ -38,10 +37,54 @@ exports.constants = {
38
37
MAX_STRING_LENGTH : K_STRING_MAX_LENGTH
39
38
}
40
39
41
- exports . Blob = global . Blob
42
- exports . File = global . File
43
- exports . atob = global . atob
44
- exports . btoa = global . btoa
40
+ exports . Blob = typeof Blob !== 'undefined' ? Blob : undefined
41
+ exports . File = typeof File !== 'undefined' ? File : undefined
42
+ exports . atob = typeof atob !== 'undefined' ? atob : undefined
43
+ exports . btoa = typeof btoa !== 'undefined' ? btoa : undefined
44
+
45
+ /**
46
+ * The `atob` and `btoa` functions are unoptimized in node.js[1][2].
47
+ * As a result of this, we call out to Buffer directly when running
48
+ * inside of node.js. Unfortunately, detecting node.js is tricky:
49
+ *
50
+ * We can't check `process.browser` because it will cause browserify
51
+ * to pull in the entire `process` module.
52
+ *
53
+ * Instead, we check for a global `Buffer` object with `asciiSlice`
54
+ * defined on the prototype. This undocumented method has been
55
+ * defined on the node.js Buffer prototype since the _very_ early
56
+ * days of node.js (as early as 0.4.0) and is still defined to this
57
+ * day (but is not defined on _our_ Buffer prototype).
58
+ *
59
+ * Because our `Buffer` constructor is hoisted, we can't check for
60
+ * `typeof Buffer === 'function'`. Instead, we need to access `global`.
61
+ *
62
+ * Unfortunately, we can't assume `global` exists as there may be a
63
+ * non-browserify bundler which supports CJS but not a full node.js
64
+ * environment which includes `global`.
65
+ *
66
+ * As an added bonus, this hack also accounts for nodes prior to
67
+ * v16.0.0 (when `atob` and `btoa` were first exposed globally).
68
+ *
69
+ * [1] https://github.com/feross/buffer/issues/339
70
+ * [2] https://github.com/nodejs/node/pull/38433
71
+ */
72
+ let _atob = exports . atob
73
+ let _btoa = exports . btoa
74
+
75
+ if ( typeof global !== 'undefined' && global && global . Math === Math &&
76
+ typeof global . Buffer === 'function' && global . Buffer . prototype &&
77
+ typeof global . Buffer . prototype . asciiSlice === 'function' ) {
78
+ const NodeBuffer = global . Buffer
79
+
80
+ _atob = function atob ( str ) {
81
+ return NodeBuffer . from ( str , 'base64' ) . toString ( 'binary' )
82
+ }
83
+
84
+ _btoa = function btoa ( str ) {
85
+ return NodeBuffer . from ( str , 'binary' ) . toString ( 'base64' )
86
+ }
87
+ }
45
88
46
89
/**
47
90
* If `Buffer.TYPED_ARRAY_SUPPORT`:
@@ -398,6 +441,7 @@ Buffer.isEncoding = function isEncoding (encoding) {
398
441
case 'latin1' :
399
442
case 'binary' :
400
443
case 'base64' :
444
+ case 'base64url' :
401
445
case 'ucs2' :
402
446
case 'ucs-2' :
403
447
case 'utf16le' :
@@ -489,7 +533,8 @@ function byteLength (string, encoding) {
489
533
case 'hex' :
490
534
return len >>> 1
491
535
case 'base64' :
492
- return base64ToBytes ( string ) . length
536
+ case 'base64url' :
537
+ return base64ByteLength ( string , len )
493
538
default :
494
539
if ( loweredCase ) {
495
540
return mustMatch ? - 1 : utf8ByteLength ( string ) // assume utf8
@@ -557,6 +602,9 @@ function slowToString (encoding, start, end) {
557
602
case 'base64' :
558
603
return base64Slice ( this , start , end )
559
604
605
+ case 'base64url' :
606
+ return base64UrlSlice ( this , start , end )
607
+
560
608
case 'ucs2' :
561
609
case 'ucs-2' :
562
610
case 'utf16le' :
@@ -1020,7 +1068,14 @@ function asciiWrite (buf, string, offset, length) {
1020
1068
}
1021
1069
1022
1070
function base64Write ( buf , string , offset , length ) {
1023
- return blitBuffer ( base64ToBytes ( string ) , buf , offset , length )
1071
+ try {
1072
+ // Parse optimistically as base64.
1073
+ string = _atob ( string )
1074
+ } catch ( e ) {
1075
+ // Fall back to full preprocessing.
1076
+ string = _atob ( base64clean ( string ) )
1077
+ }
1078
+ return asciiWrite ( buf , string , offset , length )
1024
1079
}
1025
1080
1026
1081
function ucs2Write ( buf , string , offset , length ) {
@@ -1096,6 +1151,7 @@ Buffer.prototype.write = function write (string, offset, length, encoding) {
1096
1151
return asciiWrite ( this , string , offset , length )
1097
1152
1098
1153
case 'base64' :
1154
+ case 'base64url' :
1099
1155
// Warning: maxLength not taken into account in base64Write
1100
1156
return base64Write ( this , string , offset , length )
1101
1157
@@ -1121,11 +1177,11 @@ Buffer.prototype.toJSON = function toJSON () {
1121
1177
}
1122
1178
1123
1179
function base64Slice ( buf , start , end ) {
1124
- if ( start === 0 && end === buf . length ) {
1125
- return base64 . fromByteArray ( buf )
1126
- } else {
1127
- return base64 . fromByteArray ( buf . slice ( start , end ) )
1128
- }
1180
+ return _btoa ( latin1Slice ( buf , start , end ) )
1181
+ }
1182
+
1183
+ function base64UrlSlice ( buf , start , end ) {
1184
+ return base64convert ( base64Slice ( buf , start , end ) )
1129
1185
}
1130
1186
1131
1187
function utf8Slice ( buf , start , end ) {
@@ -2109,23 +2165,62 @@ function boundsError (value, length, type) {
2109
2165
// ================
2110
2166
2111
2167
const INVALID_BASE64_RE = / [ ^ + / 0 - 9 A - Z a - z - _ ] / g
2168
+ const BASE64URL_62 = / - / g
2169
+ const BASE64URL_63 = / _ / g
2112
2170
2113
2171
function base64clean ( str ) {
2114
- // Node takes equal signs as end of the Base64 encoding
2115
- str = str . split ( '=' ) [ 0 ]
2116
- // Node strips out invalid characters like \n and \t from the string, base64-js does not
2117
- str = str . trim ( ) . replace ( INVALID_BASE64_RE , '' )
2172
+ // Node takes equal signs as end of the encoding
2173
+ const index = str . indexOf ( '=' )
2174
+
2175
+ if ( index >= 0 ) {
2176
+ str = str . slice ( 0 , index )
2177
+ }
2178
+
2179
+ // Node strips out invalid characters, atob does not
2180
+ str = str . replace ( INVALID_BASE64_RE , '' )
2181
+
2118
2182
// Node converts strings with length < 2 to ''
2119
2183
if ( str . length < 2 ) return ''
2120
- // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
2121
- while ( str . length % 4 !== 0 ) {
2122
- str = str + '='
2184
+
2185
+ // Node handles base64-url, atob does not
2186
+ str = str . replace ( BASE64URL_62 , '+' )
2187
+ str = str . replace ( BASE64URL_63 , '/' )
2188
+
2189
+ // Node allows for non-padded strings, atob _may_ not
2190
+ while ( str . length & 3 ) {
2191
+ str += '='
2192
+ }
2193
+
2194
+ return str
2195
+ }
2196
+
2197
+ const BASE64_62 = / \+ / g
2198
+ const BASE64_63 = / \/ / g
2199
+
2200
+ function base64convert ( str ) {
2201
+ // Convert base64 to base64-url.
2202
+ let len = str . length
2203
+
2204
+ if ( len > 0 && str [ len - 1 ] === '=' ) len --
2205
+ if ( len > 0 && str [ len - 1 ] === '=' ) len --
2206
+
2207
+ if ( len !== str . length ) {
2208
+ str = str . slice ( 0 , len )
2123
2209
}
2210
+
2211
+ str = str . replace ( BASE64_62 , '-' )
2212
+ str = str . replace ( BASE64_63 , '_' )
2213
+
2124
2214
return str
2125
2215
}
2126
2216
2127
- function base64ToBytes ( str ) {
2128
- return base64 . toByteArray ( base64clean ( str ) )
2217
+ function base64ByteLength ( str , bytes ) {
2218
+ // Handle padding
2219
+ if ( bytes > 0 && str . charCodeAt ( bytes - 1 ) === 0x3d ) bytes --
2220
+ if ( bytes > 1 && str . charCodeAt ( bytes - 1 ) === 0x3d ) bytes --
2221
+
2222
+ // Base64 ratio: 3/4
2223
+ return ( bytes * 3 ) >>> 2
2129
2224
}
2130
2225
2131
2226
function writeInvalid ( buf , pos ) {
@@ -2136,15 +2231,6 @@ function writeInvalid (buf, pos) {
2136
2231
return pos
2137
2232
}
2138
2233
2139
- function blitBuffer ( src , dst , offset , length ) {
2140
- let i
2141
- for ( i = 0 ; i < length ; ++ i ) {
2142
- if ( ( i + offset >= dst . length ) || ( i >= src . length ) ) break
2143
- dst [ i + offset ] = src [ i ]
2144
- }
2145
- return i
2146
- }
2147
-
2148
2234
// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
2149
2235
// the `instanceof` check but they should be treated as of that type.
2150
2236
// See: https://github.com/feross/buffer/issues/166
0 commit comments