Skip to content

Commit 370be21

Browse files
authored
Merge branch 'main' into no-wasm-simd
2 parents 24d33ab + 5b46db3 commit 370be21

File tree

15 files changed

+306
-259
lines changed

15 files changed

+306
-259
lines changed

.github/workflows/nodejs.yml

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ jobs:
134134
NODE_V8_COVERAGE: ${{ inputs.codecov == true && './coverage/tmp' || '' }}
135135
UNDICI_NO_WASM_SIMD: ${{ inputs['no-wasm-simd'] }}
136136

137+
- name: Test infra
138+
run: npm run test:infra
139+
id: test-infra
140+
env:
141+
CI: true
142+
NODE_V8_COVERAGE: ${{ inputs.codecov == true && './coverage/tmp' || '' }}
143+
137144
- name: Test subresource-integrity
138145
run: npm run test:subresource-integrity
139146
id: test-subresource-integrity
@@ -166,14 +173,6 @@ jobs:
166173
NODE_V8_COVERAGE: ${{ inputs.codecov == true && './coverage/tmp' || '' }}
167174
UNDICI_NO_WASM_SIMD: ${{ inputs['no-wasm-simd'] }}
168175

169-
- name: Test h2
170-
run: npm run test:h2
171-
id: test-h2
172-
env:
173-
CI: true
174-
NODE_V8_COVERAGE: ${{ inputs.codecov == true && './coverage/tmp' || '' }}
175-
UNDICI_NO_WASM_SIMD: ${{ inputs['no-wasm-simd'] }}
176-
177176
- name: Test jest
178177
run: npm run test:jest
179178
id: test-jest

lib/encoding/index.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict'
2+
3+
const textDecoder = new TextDecoder()
4+
5+
/**
6+
* @see https://encoding.spec.whatwg.org/#utf-8-decode
7+
* @param {Uint8Array} buffer
8+
*/
9+
function utf8DecodeBytes (buffer) {
10+
if (buffer.length === 0) {
11+
return ''
12+
}
13+
14+
// 1. Let buffer be the result of peeking three bytes from
15+
// ioQueue, converted to a byte sequence.
16+
17+
// 2. If buffer is 0xEF 0xBB 0xBF, then read three
18+
// bytes from ioQueue. (Do nothing with those bytes.)
19+
if (buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
20+
buffer = buffer.subarray(3)
21+
}
22+
23+
// 3. Process a queue with an instance of UTF-8’s
24+
// decoder, ioQueue, output, and "replacement".
25+
const output = textDecoder.decode(buffer)
26+
27+
// 4. Return output.
28+
return output
29+
}
30+
31+
module.exports = {
32+
utf8DecodeBytes
33+
}

lib/web/cookies/parse.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use strict'
22

3+
const { collectASequenceOfCodePointsFast } = require('../infra')
34
const { maxNameValuePairSize, maxAttributeValueSize } = require('./constants')
45
const { isCTLExcludingHtab } = require('./util')
5-
const { collectASequenceOfCodePointsFast } = require('../fetch/data-url')
66
const assert = require('node:assert')
77
const { unescape: qsUnescape } = require('node:querystring')
88

lib/web/fetch/body.js

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ const {
55
ReadableStreamFrom,
66
readableStreamClose,
77
fullyReadBody,
8-
extractMimeType,
9-
utf8DecodeBytes
8+
extractMimeType
109
} = require('./util')
1110
const { FormData, setFormDataState } = require('./formdata')
1211
const { webidl } = require('../webidl')
@@ -16,6 +15,8 @@ const { isArrayBuffer } = require('node:util/types')
1615
const { serializeAMimeType } = require('./data-url')
1716
const { multipartFormDataParser } = require('./formdata-parser')
1817
const { createDeferredPromise } = require('../../util/promise')
18+
const { parseJSONFromBytes } = require('../infra')
19+
const { utf8DecodeBytes } = require('../../encoding')
1920

2021
let random
2122

@@ -496,14 +497,6 @@ function bodyUnusable (object) {
496497
return body != null && (body.stream.locked || util.isDisturbed(body.stream))
497498
}
498499

499-
/**
500-
* @see https://infra.spec.whatwg.org/#parse-json-bytes-to-a-javascript-value
501-
* @param {Uint8Array} bytes
502-
*/
503-
function parseJSONFromBytes (bytes) {
504-
return JSON.parse(utf8DecodeBytes(bytes))
505-
}
506-
507500
/**
508501
* @see https://fetch.spec.whatwg.org/#concept-body-mime-type
509502
* @param {any} requestOrResponse internal state

lib/web/fetch/data-url.js

Lines changed: 2 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22

33
const assert = require('node:assert')
4+
const { forgivingBase64, collectASequenceOfCodePoints, collectASequenceOfCodePointsFast, isomorphicDecode, removeASCIIWhitespace, removeChars } = require('../infra')
45

56
const encoder = new TextEncoder()
67

@@ -9,7 +10,6 @@ const encoder = new TextEncoder()
910
*/
1011
const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+\-.^_|~A-Za-z0-9]+$/
1112
const HTTP_WHITESPACE_REGEX = /[\u000A\u000D\u0009\u0020]/ // eslint-disable-line
12-
const ASCII_WHITESPACE_REPLACE_REGEX = /[\u0009\u000A\u000C\u000D\u0020]/g // eslint-disable-line
1313
/**
1414
* @see https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
1515
*/
@@ -136,49 +136,6 @@ function URLSerializer (url, excludeFragment = false) {
136136
return serialized
137137
}
138138

139-
// https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points
140-
/**
141-
* @param {(char: string) => boolean} condition
142-
* @param {string} input
143-
* @param {{ position: number }} position
144-
*/
145-
function collectASequenceOfCodePoints (condition, input, position) {
146-
// 1. Let result be the empty string.
147-
let result = ''
148-
149-
// 2. While position doesn’t point past the end of input and the
150-
// code point at position within input meets the condition condition:
151-
while (position.position < input.length && condition(input[position.position])) {
152-
// 1. Append that code point to the end of result.
153-
result += input[position.position]
154-
155-
// 2. Advance position by 1.
156-
position.position++
157-
}
158-
159-
// 3. Return result.
160-
return result
161-
}
162-
163-
/**
164-
* A faster collectASequenceOfCodePoints that only works when comparing a single character.
165-
* @param {string} char
166-
* @param {string} input
167-
* @param {{ position: number }} position
168-
*/
169-
function collectASequenceOfCodePointsFast (char, input, position) {
170-
const idx = input.indexOf(char, position.position)
171-
const start = position.position
172-
173-
if (idx === -1) {
174-
position.position = input.length
175-
return input.slice(start)
176-
}
177-
178-
position.position = idx
179-
return input.slice(start, position.position)
180-
}
181-
182139
// https://url.spec.whatwg.org/#string-percent-decode
183140
/** @param {string} input */
184141
function stringPercentDecode (input) {
@@ -427,45 +384,6 @@ function parseMIMEType (input) {
427384
return mimeType
428385
}
429386

430-
// https://infra.spec.whatwg.org/#forgiving-base64-decode
431-
/** @param {string} data */
432-
function forgivingBase64 (data) {
433-
// 1. Remove all ASCII whitespace from data.
434-
data = data.replace(ASCII_WHITESPACE_REPLACE_REGEX, '')
435-
436-
let dataLength = data.length
437-
// 2. If data’s code point length divides by 4 leaving
438-
// no remainder, then:
439-
if (dataLength % 4 === 0) {
440-
// 1. If data ends with one or two U+003D (=) code points,
441-
// then remove them from data.
442-
if (data.charCodeAt(dataLength - 1) === 0x003D) {
443-
--dataLength
444-
if (data.charCodeAt(dataLength - 1) === 0x003D) {
445-
--dataLength
446-
}
447-
}
448-
}
449-
450-
// 3. If data’s code point length divides by 4 leaving
451-
// a remainder of 1, then return failure.
452-
if (dataLength % 4 === 1) {
453-
return 'failure'
454-
}
455-
456-
// 4. If data contains a code point that is not one of
457-
// U+002B (+)
458-
// U+002F (/)
459-
// ASCII alphanumeric
460-
// then return failure.
461-
if (/[^+/0-9A-Za-z]/.test(data.length === dataLength ? data : data.substring(0, dataLength))) {
462-
return 'failure'
463-
}
464-
465-
const buffer = Buffer.from(data, 'base64')
466-
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength)
467-
}
468-
469387
// https://fetch.spec.whatwg.org/#collect-an-http-quoted-string
470388
// tests: https://fetch.spec.whatwg.org/#example-http-quoted-string
471389
/**
@@ -608,71 +526,6 @@ function removeHTTPWhitespace (str, leading = true, trailing = true) {
608526
return removeChars(str, leading, trailing, isHTTPWhiteSpace)
609527
}
610528

611-
/**
612-
* @see https://infra.spec.whatwg.org/#ascii-whitespace
613-
* @param {number} char
614-
*/
615-
function isASCIIWhitespace (char) {
616-
// "\r\n\t\f "
617-
return char === 0x00d || char === 0x00a || char === 0x009 || char === 0x00c || char === 0x020
618-
}
619-
620-
/**
621-
* @see https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace
622-
* @param {string} str
623-
* @param {boolean} [leading=true]
624-
* @param {boolean} [trailing=true]
625-
*/
626-
function removeASCIIWhitespace (str, leading = true, trailing = true) {
627-
return removeChars(str, leading, trailing, isASCIIWhitespace)
628-
}
629-
630-
/**
631-
* @param {string} str
632-
* @param {boolean} leading
633-
* @param {boolean} trailing
634-
* @param {(charCode: number) => boolean} predicate
635-
* @returns
636-
*/
637-
function removeChars (str, leading, trailing, predicate) {
638-
let lead = 0
639-
let trail = str.length - 1
640-
641-
if (leading) {
642-
while (lead < str.length && predicate(str.charCodeAt(lead))) lead++
643-
}
644-
645-
if (trailing) {
646-
while (trail > 0 && predicate(str.charCodeAt(trail))) trail--
647-
}
648-
649-
return lead === 0 && trail === str.length - 1 ? str : str.slice(lead, trail + 1)
650-
}
651-
652-
/**
653-
* @see https://infra.spec.whatwg.org/#isomorphic-decode
654-
* @param {Uint8Array} input
655-
* @returns {string}
656-
*/
657-
function isomorphicDecode (input) {
658-
// 1. To isomorphic decode a byte sequence input, return a string whose code point
659-
// length is equal to input’s length and whose code points have the same values
660-
// as the values of input’s bytes, in the same order.
661-
const length = input.length
662-
if ((2 << 15) - 1 > length) {
663-
return String.fromCharCode.apply(null, input)
664-
}
665-
let result = ''; let i = 0
666-
let addition = (2 << 15) - 1
667-
while (i < length) {
668-
if (i + addition > length) {
669-
addition = length - i
670-
}
671-
result += String.fromCharCode.apply(null, input.subarray(i, i += addition))
672-
}
673-
return result
674-
}
675-
676529
/**
677530
* @see https://mimesniff.spec.whatwg.org/#minimize-a-supported-mime-type
678531
* @param {Exclude<ReturnType<typeof parseMIMEType>, 'failure'>} mimeType
@@ -730,15 +583,11 @@ function minimizeSupportedMimeType (mimeType) {
730583
module.exports = {
731584
dataURLProcessor,
732585
URLSerializer,
733-
collectASequenceOfCodePoints,
734-
collectASequenceOfCodePointsFast,
735586
stringPercentDecode,
736587
parseMIMEType,
737588
collectAnHTTPQuotedString,
738589
serializeAMimeType,
739-
removeChars,
740590
removeHTTPWhitespace,
741591
minimizeSupportedMimeType,
742-
HTTP_TOKEN_CODEPOINTS,
743-
isomorphicDecode
592+
HTTP_TOKEN_CODEPOINTS
744593
}

lib/web/fetch/formdata-parser.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
'use strict'
22

33
const { bufferToLowerCasedHeaderName } = require('../../core/util')
4-
const { utf8DecodeBytes } = require('./util')
5-
const { HTTP_TOKEN_CODEPOINTS, isomorphicDecode } = require('./data-url')
4+
const { HTTP_TOKEN_CODEPOINTS } = require('./data-url')
65
const { makeEntry } = require('./formdata')
76
const { webidl } = require('../webidl')
87
const assert = require('node:assert')
8+
const { isomorphicDecode } = require('../infra')
9+
const { utf8DecodeBytes } = require('../../encoding')
910

1011
const formDataNameBuffer = Buffer.from('form-data; name="')
1112
const filenameBuffer = Buffer.from('filename')

lib/web/fetch/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ const {
3535
isErrorLike,
3636
fullyReadBody,
3737
readableStreamClose,
38-
isomorphicEncode,
3938
urlIsLocal,
4039
urlIsHttpHttpsScheme,
4140
urlHasHttpsScheme,
@@ -63,6 +62,7 @@ const { webidl } = require('../webidl')
6362
const { STATUS_CODES } = require('node:http')
6463
const { bytesMatch } = require('../subresource-integrity/subresource-integrity')
6564
const { createDeferredPromise } = require('../../util/promise')
65+
const { isomorphicEncode } = require('../infra')
6666

6767
const hasZstd = typeof zlib.createZstdDecompress === 'function'
6868

lib/web/fetch/response.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ const {
99
isValidReasonPhrase,
1010
isCancelled,
1111
isAborted,
12-
serializeJavascriptValueToJSONString,
1312
isErrorLike,
14-
isomorphicEncode,
1513
environmentSettingsObject: relevantRealm
1614
} = require('./util')
1715
const {
@@ -22,6 +20,7 @@ const { webidl } = require('../webidl')
2220
const { URLSerializer } = require('./data-url')
2321
const { kConstruct } = require('../../core/symbols')
2422
const assert = require('node:assert')
23+
const { isomorphicEncode, serializeJavascriptValueToJSONString } = require('../infra')
2524

2625
const textEncoder = new TextEncoder('utf-8')
2726

0 commit comments

Comments
 (0)