undici 7.15.0 → 7.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -2
- package/docs/docs/api/Agent.md +1 -0
- package/docs/docs/api/Client.md +1 -0
- package/docs/docs/api/DiagnosticsChannel.md +57 -0
- package/docs/docs/api/Dispatcher.md +86 -0
- package/docs/docs/api/Errors.md +0 -1
- package/docs/docs/api/RoundRobinPool.md +145 -0
- package/docs/docs/api/WebSocket.md +21 -0
- package/docs/docs/best-practices/crawling.md +58 -0
- package/index-fetch.js +2 -2
- package/index.js +8 -9
- package/lib/api/api-request.js +22 -8
- package/lib/api/api-upgrade.js +2 -1
- package/lib/api/readable.js +7 -5
- package/lib/core/connect.js +4 -1
- package/lib/core/diagnostics.js +28 -1
- package/lib/core/errors.js +217 -13
- package/lib/core/request.js +5 -1
- package/lib/core/symbols.js +3 -0
- package/lib/core/util.js +61 -41
- package/lib/dispatcher/agent.js +19 -7
- package/lib/dispatcher/balanced-pool.js +10 -0
- package/lib/dispatcher/client-h1.js +18 -23
- package/lib/dispatcher/client-h2.js +166 -26
- package/lib/dispatcher/client.js +64 -59
- package/lib/dispatcher/dispatcher-base.js +20 -16
- package/lib/dispatcher/env-http-proxy-agent.js +12 -16
- package/lib/dispatcher/fixed-queue.js +15 -39
- package/lib/dispatcher/h2c-client.js +7 -78
- package/lib/dispatcher/pool-base.js +60 -43
- package/lib/dispatcher/pool.js +2 -2
- package/lib/dispatcher/proxy-agent.js +27 -11
- package/lib/dispatcher/round-robin-pool.js +137 -0
- package/lib/encoding/index.js +33 -0
- package/lib/global.js +19 -1
- package/lib/handler/cache-handler.js +84 -27
- package/lib/handler/deduplication-handler.js +216 -0
- package/lib/handler/retry-handler.js +0 -2
- package/lib/interceptor/cache.js +94 -15
- package/lib/interceptor/decompress.js +2 -1
- package/lib/interceptor/deduplicate.js +109 -0
- package/lib/interceptor/dns.js +55 -13
- package/lib/mock/mock-agent.js +4 -4
- package/lib/mock/mock-errors.js +10 -0
- package/lib/mock/mock-utils.js +13 -12
- package/lib/mock/snapshot-agent.js +11 -5
- package/lib/mock/snapshot-recorder.js +12 -4
- package/lib/mock/snapshot-utils.js +4 -4
- package/lib/util/cache.js +29 -1
- package/lib/util/date.js +534 -140
- package/lib/util/runtime-features.js +124 -0
- package/lib/web/cookies/index.js +1 -1
- package/lib/web/cookies/parse.js +1 -1
- package/lib/web/eventsource/eventsource-stream.js +2 -2
- package/lib/web/eventsource/eventsource.js +34 -29
- package/lib/web/eventsource/util.js +1 -9
- package/lib/web/fetch/body.js +45 -61
- package/lib/web/fetch/data-url.js +12 -160
- package/lib/web/fetch/formdata-parser.js +204 -127
- package/lib/web/fetch/index.js +21 -19
- package/lib/web/fetch/request.js +6 -0
- package/lib/web/fetch/response.js +4 -7
- package/lib/web/fetch/util.js +10 -79
- package/lib/web/infra/index.js +229 -0
- package/lib/web/subresource-integrity/subresource-integrity.js +6 -5
- package/lib/web/webidl/index.js +207 -44
- package/lib/web/websocket/connection.js +33 -22
- package/lib/web/websocket/events.js +1 -1
- package/lib/web/websocket/frame.js +9 -15
- package/lib/web/websocket/stream/websocketerror.js +22 -1
- package/lib/web/websocket/stream/websocketstream.js +17 -8
- package/lib/web/websocket/util.js +2 -1
- package/lib/web/websocket/websocket.js +32 -42
- package/package.json +9 -7
- package/types/agent.d.ts +2 -1
- package/types/api.d.ts +2 -2
- package/types/balanced-pool.d.ts +2 -1
- package/types/cache-interceptor.d.ts +1 -0
- package/types/client.d.ts +1 -1
- package/types/connector.d.ts +2 -2
- package/types/diagnostics-channel.d.ts +2 -2
- package/types/dispatcher.d.ts +12 -12
- package/types/errors.d.ts +5 -15
- package/types/fetch.d.ts +4 -4
- package/types/formdata.d.ts +1 -1
- package/types/h2c-client.d.ts +1 -1
- package/types/index.d.ts +9 -1
- package/types/interceptors.d.ts +36 -2
- package/types/pool.d.ts +1 -1
- package/types/readable.d.ts +2 -2
- package/types/round-robin-pool.d.ts +41 -0
- package/types/webidl.d.ts +82 -21
- package/types/websocket.d.ts +9 -9
package/lib/util/date.js
CHANGED
|
@@ -1,32 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const IMF_DAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
|
|
4
|
-
const IMF_SPACES = [4, 7, 11, 16, 25]
|
|
5
|
-
const IMF_MONTHS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
|
|
6
|
-
const IMF_COLONS = [19, 22]
|
|
7
|
-
|
|
8
|
-
const ASCTIME_SPACES = [3, 7, 10, 19]
|
|
9
|
-
|
|
10
|
-
const RFC850_DAYS = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
|
|
11
|
-
|
|
12
3
|
/**
|
|
13
4
|
* @see https://www.rfc-editor.org/rfc/rfc9110.html#name-date-time-formats
|
|
14
5
|
*
|
|
15
6
|
* @param {string} date
|
|
16
|
-
* @param {Date} [now]
|
|
17
7
|
* @returns {Date | undefined}
|
|
18
8
|
*/
|
|
19
|
-
function parseHttpDate (date
|
|
9
|
+
function parseHttpDate (date) {
|
|
20
10
|
// Sun, 06 Nov 1994 08:49:37 GMT ; IMF-fixdate
|
|
21
11
|
// Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
|
|
22
12
|
// Sunday, 06-Nov-94 08:49:37 GMT ; obsolete RFC 850 format
|
|
23
13
|
|
|
24
|
-
date = date.toLowerCase()
|
|
25
|
-
|
|
26
14
|
switch (date[3]) {
|
|
27
15
|
case ',': return parseImfDate(date)
|
|
28
16
|
case ' ': return parseAscTimeDate(date)
|
|
29
|
-
default: return parseRfc850Date(date
|
|
17
|
+
default: return parseRfc850Date(date)
|
|
30
18
|
}
|
|
31
19
|
}
|
|
32
20
|
|
|
@@ -37,69 +25,207 @@ function parseHttpDate (date, now) {
|
|
|
37
25
|
* @returns {Date | undefined}
|
|
38
26
|
*/
|
|
39
27
|
function parseImfDate (date) {
|
|
40
|
-
if (
|
|
28
|
+
if (
|
|
29
|
+
date.length !== 29 ||
|
|
30
|
+
date[4] !== ' ' ||
|
|
31
|
+
date[7] !== ' ' ||
|
|
32
|
+
date[11] !== ' ' ||
|
|
33
|
+
date[16] !== ' ' ||
|
|
34
|
+
date[19] !== ':' ||
|
|
35
|
+
date[22] !== ':' ||
|
|
36
|
+
date[25] !== ' ' ||
|
|
37
|
+
date[26] !== 'G' ||
|
|
38
|
+
date[27] !== 'M' ||
|
|
39
|
+
date[28] !== 'T'
|
|
40
|
+
) {
|
|
41
41
|
return undefined
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
let weekday = -1
|
|
45
|
+
if (date[0] === 'S' && date[1] === 'u' && date[2] === 'n') { // Sunday
|
|
46
|
+
weekday = 0
|
|
47
|
+
} else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n') { // Monday
|
|
48
|
+
weekday = 1
|
|
49
|
+
} else if (date[0] === 'T' && date[1] === 'u' && date[2] === 'e') { // Tuesday
|
|
50
|
+
weekday = 2
|
|
51
|
+
} else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd') { // Wednesday
|
|
52
|
+
weekday = 3
|
|
53
|
+
} else if (date[0] === 'T' && date[1] === 'h' && date[2] === 'u') { // Thursday
|
|
54
|
+
weekday = 4
|
|
55
|
+
} else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i') { // Friday
|
|
56
|
+
weekday = 5
|
|
57
|
+
} else if (date[0] === 'S' && date[1] === 'a' && date[2] === 't') { // Saturday
|
|
58
|
+
weekday = 6
|
|
59
|
+
} else {
|
|
60
|
+
return undefined // Not a valid day of the week
|
|
47
61
|
}
|
|
48
62
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
63
|
+
let day = 0
|
|
64
|
+
if (date[5] === '0') {
|
|
65
|
+
// Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
|
|
66
|
+
const code = date.charCodeAt(6)
|
|
67
|
+
if (code < 49 || code > 57) {
|
|
68
|
+
return undefined // Not a digit
|
|
52
69
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
return undefined
|
|
70
|
+
day = code - 48 // Convert ASCII code to number
|
|
71
|
+
} else {
|
|
72
|
+
const code1 = date.charCodeAt(5)
|
|
73
|
+
if (code1 < 49 || code1 > 51) {
|
|
74
|
+
return undefined // Not a digit between 1 and 3
|
|
75
|
+
}
|
|
76
|
+
const code2 = date.charCodeAt(6)
|
|
77
|
+
if (code2 < 48 || code2 > 57) {
|
|
78
|
+
return undefined // Not a digit
|
|
58
79
|
}
|
|
80
|
+
day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
59
81
|
}
|
|
60
82
|
|
|
61
|
-
|
|
62
|
-
if (
|
|
83
|
+
let monthIdx = -1
|
|
84
|
+
if (
|
|
85
|
+
(date[8] === 'J' && date[9] === 'a' && date[10] === 'n')
|
|
86
|
+
) {
|
|
87
|
+
monthIdx = 0 // Jan
|
|
88
|
+
} else if (
|
|
89
|
+
(date[8] === 'F' && date[9] === 'e' && date[10] === 'b')
|
|
90
|
+
) {
|
|
91
|
+
monthIdx = 1 // Feb
|
|
92
|
+
} else if (
|
|
93
|
+
(date[8] === 'M' && date[9] === 'a')
|
|
94
|
+
) {
|
|
95
|
+
if (date[10] === 'r') {
|
|
96
|
+
monthIdx = 2 // Mar
|
|
97
|
+
} else if (date[10] === 'y') {
|
|
98
|
+
monthIdx = 4 // May
|
|
99
|
+
} else {
|
|
100
|
+
return undefined // Invalid month
|
|
101
|
+
}
|
|
102
|
+
} else if (
|
|
103
|
+
(date[8] === 'J')
|
|
104
|
+
) {
|
|
105
|
+
if (date[9] === 'a' && date[10] === 'n') {
|
|
106
|
+
monthIdx = 0 // Jan
|
|
107
|
+
} else if (date[9] === 'u') {
|
|
108
|
+
if (date[10] === 'n') {
|
|
109
|
+
monthIdx = 5 // Jun
|
|
110
|
+
} else if (date[10] === 'l') {
|
|
111
|
+
monthIdx = 6 // Jul
|
|
112
|
+
} else {
|
|
113
|
+
return undefined // Invalid month
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
return undefined // Invalid month
|
|
117
|
+
}
|
|
118
|
+
} else if (
|
|
119
|
+
(date[8] === 'A')
|
|
120
|
+
) {
|
|
121
|
+
if (date[9] === 'p' && date[10] === 'r') {
|
|
122
|
+
monthIdx = 3 // Apr
|
|
123
|
+
} else if (date[9] === 'u' && date[10] === 'g') {
|
|
124
|
+
monthIdx = 7 // Aug
|
|
125
|
+
} else {
|
|
126
|
+
return undefined // Invalid month
|
|
127
|
+
}
|
|
128
|
+
} else if (
|
|
129
|
+
(date[8] === 'S' && date[9] === 'e' && date[10] === 'p')
|
|
130
|
+
) {
|
|
131
|
+
monthIdx = 8 // Sep
|
|
132
|
+
} else if (
|
|
133
|
+
(date[8] === 'O' && date[9] === 'c' && date[10] === 't')
|
|
134
|
+
) {
|
|
135
|
+
monthIdx = 9 // Oct
|
|
136
|
+
} else if (
|
|
137
|
+
(date[8] === 'N' && date[9] === 'o' && date[10] === 'v')
|
|
138
|
+
) {
|
|
139
|
+
monthIdx = 10 // Nov
|
|
140
|
+
} else if (
|
|
141
|
+
(date[8] === 'D' && date[9] === 'e' && date[10] === 'c')
|
|
142
|
+
) {
|
|
143
|
+
monthIdx = 11 // Dec
|
|
144
|
+
} else {
|
|
145
|
+
// Not a valid month
|
|
63
146
|
return undefined
|
|
64
147
|
}
|
|
65
148
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// Not a number, 0, or it's less than 10 and didn't start with a 0
|
|
70
|
-
return undefined
|
|
149
|
+
const yearDigit1 = date.charCodeAt(12)
|
|
150
|
+
if (yearDigit1 < 48 || yearDigit1 > 57) {
|
|
151
|
+
return undefined // Not a digit
|
|
71
152
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (monthIdx === -1) {
|
|
76
|
-
return undefined
|
|
153
|
+
const yearDigit2 = date.charCodeAt(13)
|
|
154
|
+
if (yearDigit2 < 48 || yearDigit2 > 57) {
|
|
155
|
+
return undefined // Not a digit
|
|
77
156
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
157
|
+
const yearDigit3 = date.charCodeAt(14)
|
|
158
|
+
if (yearDigit3 < 48 || yearDigit3 > 57) {
|
|
159
|
+
return undefined // Not a digit
|
|
160
|
+
}
|
|
161
|
+
const yearDigit4 = date.charCodeAt(15)
|
|
162
|
+
if (yearDigit4 < 48 || yearDigit4 > 57) {
|
|
163
|
+
return undefined // Not a digit
|
|
82
164
|
}
|
|
165
|
+
const year = (yearDigit1 - 48) * 1000 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48)
|
|
83
166
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
167
|
+
let hour = 0
|
|
168
|
+
if (date[17] === '0') {
|
|
169
|
+
const code = date.charCodeAt(18)
|
|
170
|
+
if (code < 48 || code > 57) {
|
|
171
|
+
return undefined // Not a digit
|
|
172
|
+
}
|
|
173
|
+
hour = code - 48 // Convert ASCII code to number
|
|
174
|
+
} else {
|
|
175
|
+
const code1 = date.charCodeAt(17)
|
|
176
|
+
if (code1 < 48 || code1 > 50) {
|
|
177
|
+
return undefined // Not a digit between 0 and 2
|
|
178
|
+
}
|
|
179
|
+
const code2 = date.charCodeAt(18)
|
|
180
|
+
if (code2 < 48 || code2 > 57) {
|
|
181
|
+
return undefined // Not a digit
|
|
182
|
+
}
|
|
183
|
+
if (code1 === 50 && code2 > 51) {
|
|
184
|
+
return undefined // Hour cannot be greater than 23
|
|
185
|
+
}
|
|
186
|
+
hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
88
187
|
}
|
|
89
188
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
189
|
+
let minute = 0
|
|
190
|
+
if (date[20] === '0') {
|
|
191
|
+
const code = date.charCodeAt(21)
|
|
192
|
+
if (code < 48 || code > 57) {
|
|
193
|
+
return undefined // Not a digit
|
|
194
|
+
}
|
|
195
|
+
minute = code - 48 // Convert ASCII code to number
|
|
196
|
+
} else {
|
|
197
|
+
const code1 = date.charCodeAt(20)
|
|
198
|
+
if (code1 < 48 || code1 > 53) {
|
|
199
|
+
return undefined // Not a digit between 0 and 5
|
|
200
|
+
}
|
|
201
|
+
const code2 = date.charCodeAt(21)
|
|
202
|
+
if (code2 < 48 || code2 > 57) {
|
|
203
|
+
return undefined // Not a digit
|
|
204
|
+
}
|
|
205
|
+
minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
94
206
|
}
|
|
95
207
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
208
|
+
let second = 0
|
|
209
|
+
if (date[23] === '0') {
|
|
210
|
+
const code = date.charCodeAt(24)
|
|
211
|
+
if (code < 48 || code > 57) {
|
|
212
|
+
return undefined // Not a digit
|
|
213
|
+
}
|
|
214
|
+
second = code - 48 // Convert ASCII code to number
|
|
215
|
+
} else {
|
|
216
|
+
const code1 = date.charCodeAt(23)
|
|
217
|
+
if (code1 < 48 || code1 > 53) {
|
|
218
|
+
return undefined // Not a digit between 0 and 5
|
|
219
|
+
}
|
|
220
|
+
const code2 = date.charCodeAt(24)
|
|
221
|
+
if (code2 < 48 || code2 > 57) {
|
|
222
|
+
return undefined // Not a digit
|
|
223
|
+
}
|
|
224
|
+
second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
100
225
|
}
|
|
101
226
|
|
|
102
|
-
|
|
227
|
+
const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
|
|
228
|
+
return result.getUTCDay() === weekday ? result : undefined
|
|
103
229
|
}
|
|
104
230
|
|
|
105
231
|
/**
|
|
@@ -111,147 +237,415 @@ function parseImfDate (date) {
|
|
|
111
237
|
function parseAscTimeDate (date) {
|
|
112
238
|
// This is assumed to be in UTC
|
|
113
239
|
|
|
114
|
-
if (
|
|
240
|
+
if (
|
|
241
|
+
date.length !== 24 ||
|
|
242
|
+
date[7] !== ' ' ||
|
|
243
|
+
date[10] !== ' ' ||
|
|
244
|
+
date[19] !== ' '
|
|
245
|
+
) {
|
|
115
246
|
return undefined
|
|
116
247
|
}
|
|
117
248
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
249
|
+
let weekday = -1
|
|
250
|
+
if (date[0] === 'S' && date[1] === 'u' && date[2] === 'n') { // Sunday
|
|
251
|
+
weekday = 0
|
|
252
|
+
} else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n') { // Monday
|
|
253
|
+
weekday = 1
|
|
254
|
+
} else if (date[0] === 'T' && date[1] === 'u' && date[2] === 'e') { // Tuesday
|
|
255
|
+
weekday = 2
|
|
256
|
+
} else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd') { // Wednesday
|
|
257
|
+
weekday = 3
|
|
258
|
+
} else if (date[0] === 'T' && date[1] === 'h' && date[2] === 'u') { // Thursday
|
|
259
|
+
weekday = 4
|
|
260
|
+
} else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i') { // Friday
|
|
261
|
+
weekday = 5
|
|
262
|
+
} else if (date[0] === 'S' && date[1] === 'a' && date[2] === 't') { // Saturday
|
|
263
|
+
weekday = 6
|
|
264
|
+
} else {
|
|
265
|
+
return undefined // Not a valid day of the week
|
|
122
266
|
}
|
|
123
267
|
|
|
124
|
-
|
|
125
|
-
if (
|
|
268
|
+
let monthIdx = -1
|
|
269
|
+
if (
|
|
270
|
+
(date[4] === 'J' && date[5] === 'a' && date[6] === 'n')
|
|
271
|
+
) {
|
|
272
|
+
monthIdx = 0 // Jan
|
|
273
|
+
} else if (
|
|
274
|
+
(date[4] === 'F' && date[5] === 'e' && date[6] === 'b')
|
|
275
|
+
) {
|
|
276
|
+
monthIdx = 1 // Feb
|
|
277
|
+
} else if (
|
|
278
|
+
(date[4] === 'M' && date[5] === 'a')
|
|
279
|
+
) {
|
|
280
|
+
if (date[6] === 'r') {
|
|
281
|
+
monthIdx = 2 // Mar
|
|
282
|
+
} else if (date[6] === 'y') {
|
|
283
|
+
monthIdx = 4 // May
|
|
284
|
+
} else {
|
|
285
|
+
return undefined // Invalid month
|
|
286
|
+
}
|
|
287
|
+
} else if (
|
|
288
|
+
(date[4] === 'J')
|
|
289
|
+
) {
|
|
290
|
+
if (date[5] === 'a' && date[6] === 'n') {
|
|
291
|
+
monthIdx = 0 // Jan
|
|
292
|
+
} else if (date[5] === 'u') {
|
|
293
|
+
if (date[6] === 'n') {
|
|
294
|
+
monthIdx = 5 // Jun
|
|
295
|
+
} else if (date[6] === 'l') {
|
|
296
|
+
monthIdx = 6 // Jul
|
|
297
|
+
} else {
|
|
298
|
+
return undefined // Invalid month
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
return undefined // Invalid month
|
|
302
|
+
}
|
|
303
|
+
} else if (
|
|
304
|
+
(date[4] === 'A')
|
|
305
|
+
) {
|
|
306
|
+
if (date[5] === 'p' && date[6] === 'r') {
|
|
307
|
+
monthIdx = 3 // Apr
|
|
308
|
+
} else if (date[5] === 'u' && date[6] === 'g') {
|
|
309
|
+
monthIdx = 7 // Aug
|
|
310
|
+
} else {
|
|
311
|
+
return undefined // Invalid month
|
|
312
|
+
}
|
|
313
|
+
} else if (
|
|
314
|
+
(date[4] === 'S' && date[5] === 'e' && date[6] === 'p')
|
|
315
|
+
) {
|
|
316
|
+
monthIdx = 8 // Sep
|
|
317
|
+
} else if (
|
|
318
|
+
(date[4] === 'O' && date[5] === 'c' && date[6] === 't')
|
|
319
|
+
) {
|
|
320
|
+
monthIdx = 9 // Oct
|
|
321
|
+
} else if (
|
|
322
|
+
(date[4] === 'N' && date[5] === 'o' && date[6] === 'v')
|
|
323
|
+
) {
|
|
324
|
+
monthIdx = 10 // Nov
|
|
325
|
+
} else if (
|
|
326
|
+
(date[4] === 'D' && date[5] === 'e' && date[6] === 'c')
|
|
327
|
+
) {
|
|
328
|
+
monthIdx = 11 // Dec
|
|
329
|
+
} else {
|
|
330
|
+
// Not a valid month
|
|
126
331
|
return undefined
|
|
127
332
|
}
|
|
128
333
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
334
|
+
let day = 0
|
|
335
|
+
if (date[8] === ' ') {
|
|
336
|
+
// Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
|
|
337
|
+
const code = date.charCodeAt(9)
|
|
338
|
+
if (code < 49 || code > 57) {
|
|
339
|
+
return undefined // Not a digit
|
|
340
|
+
}
|
|
341
|
+
day = code - 48 // Convert ASCII code to number
|
|
342
|
+
} else {
|
|
343
|
+
const code1 = date.charCodeAt(8)
|
|
344
|
+
if (code1 < 49 || code1 > 51) {
|
|
345
|
+
return undefined // Not a digit between 1 and 3
|
|
346
|
+
}
|
|
347
|
+
const code2 = date.charCodeAt(9)
|
|
348
|
+
if (code2 < 48 || code2 > 57) {
|
|
349
|
+
return undefined // Not a digit
|
|
350
|
+
}
|
|
351
|
+
day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
133
352
|
}
|
|
134
353
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
354
|
+
let hour = 0
|
|
355
|
+
if (date[11] === '0') {
|
|
356
|
+
const code = date.charCodeAt(12)
|
|
357
|
+
if (code < 48 || code > 57) {
|
|
358
|
+
return undefined // Not a digit
|
|
359
|
+
}
|
|
360
|
+
hour = code - 48 // Convert ASCII code to number
|
|
361
|
+
} else {
|
|
362
|
+
const code1 = date.charCodeAt(11)
|
|
363
|
+
if (code1 < 48 || code1 > 50) {
|
|
364
|
+
return undefined // Not a digit between 0 and 2
|
|
365
|
+
}
|
|
366
|
+
const code2 = date.charCodeAt(12)
|
|
367
|
+
if (code2 < 48 || code2 > 57) {
|
|
368
|
+
return undefined // Not a digit
|
|
369
|
+
}
|
|
370
|
+
if (code1 === 50 && code2 > 51) {
|
|
371
|
+
return undefined // Hour cannot be greater than 23
|
|
372
|
+
}
|
|
373
|
+
hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
139
374
|
}
|
|
140
375
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
376
|
+
let minute = 0
|
|
377
|
+
if (date[14] === '0') {
|
|
378
|
+
const code = date.charCodeAt(15)
|
|
379
|
+
if (code < 48 || code > 57) {
|
|
380
|
+
return undefined // Not a digit
|
|
381
|
+
}
|
|
382
|
+
minute = code - 48 // Convert ASCII code to number
|
|
383
|
+
} else {
|
|
384
|
+
const code1 = date.charCodeAt(14)
|
|
385
|
+
if (code1 < 48 || code1 > 53) {
|
|
386
|
+
return undefined // Not a digit between 0 and 5
|
|
387
|
+
}
|
|
388
|
+
const code2 = date.charCodeAt(15)
|
|
389
|
+
if (code2 < 48 || code2 > 57) {
|
|
390
|
+
return undefined // Not a digit
|
|
391
|
+
}
|
|
392
|
+
minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
145
393
|
}
|
|
146
394
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
395
|
+
let second = 0
|
|
396
|
+
if (date[17] === '0') {
|
|
397
|
+
const code = date.charCodeAt(18)
|
|
398
|
+
if (code < 48 || code > 57) {
|
|
399
|
+
return undefined // Not a digit
|
|
400
|
+
}
|
|
401
|
+
second = code - 48 // Convert ASCII code to number
|
|
402
|
+
} else {
|
|
403
|
+
const code1 = date.charCodeAt(17)
|
|
404
|
+
if (code1 < 48 || code1 > 53) {
|
|
405
|
+
return undefined // Not a digit between 0 and 5
|
|
406
|
+
}
|
|
407
|
+
const code2 = date.charCodeAt(18)
|
|
408
|
+
if (code2 < 48 || code2 > 57) {
|
|
409
|
+
return undefined // Not a digit
|
|
410
|
+
}
|
|
411
|
+
second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
151
412
|
}
|
|
152
413
|
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return undefined
|
|
414
|
+
const yearDigit1 = date.charCodeAt(20)
|
|
415
|
+
if (yearDigit1 < 48 || yearDigit1 > 57) {
|
|
416
|
+
return undefined // Not a digit
|
|
157
417
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return undefined
|
|
418
|
+
const yearDigit2 = date.charCodeAt(21)
|
|
419
|
+
if (yearDigit2 < 48 || yearDigit2 > 57) {
|
|
420
|
+
return undefined // Not a digit
|
|
162
421
|
}
|
|
422
|
+
const yearDigit3 = date.charCodeAt(22)
|
|
423
|
+
if (yearDigit3 < 48 || yearDigit3 > 57) {
|
|
424
|
+
return undefined // Not a digit
|
|
425
|
+
}
|
|
426
|
+
const yearDigit4 = date.charCodeAt(23)
|
|
427
|
+
if (yearDigit4 < 48 || yearDigit4 > 57) {
|
|
428
|
+
return undefined // Not a digit
|
|
429
|
+
}
|
|
430
|
+
const year = (yearDigit1 - 48) * 1000 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48)
|
|
163
431
|
|
|
164
|
-
|
|
432
|
+
const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
|
|
433
|
+
return result.getUTCDay() === weekday ? result : undefined
|
|
165
434
|
}
|
|
166
435
|
|
|
167
436
|
/**
|
|
168
437
|
* @see https://httpwg.org/specs/rfc9110.html#obsolete.date.formats
|
|
169
438
|
*
|
|
170
439
|
* @param {string} date
|
|
171
|
-
* @param {Date} [now]
|
|
172
440
|
* @returns {Date | undefined}
|
|
173
441
|
*/
|
|
174
|
-
function parseRfc850Date (date
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
442
|
+
function parseRfc850Date (date) {
|
|
443
|
+
let commaIndex = -1
|
|
444
|
+
|
|
445
|
+
let weekday = -1
|
|
446
|
+
if (date[0] === 'S') {
|
|
447
|
+
if (date[1] === 'u' && date[2] === 'n' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
|
|
448
|
+
weekday = 0 // Sunday
|
|
449
|
+
commaIndex = 6
|
|
450
|
+
} else if (date[1] === 'a' && date[2] === 't' && date[3] === 'u' && date[4] === 'r' && date[5] === 'd' && date[6] === 'a' && date[7] === 'y') {
|
|
451
|
+
weekday = 6 // Saturday
|
|
452
|
+
commaIndex = 8
|
|
453
|
+
}
|
|
454
|
+
} else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
|
|
455
|
+
weekday = 1 // Monday
|
|
456
|
+
commaIndex = 6
|
|
457
|
+
} else if (date[0] === 'T') {
|
|
458
|
+
if (date[1] === 'u' && date[2] === 'e' && date[3] === 's' && date[4] === 'd' && date[5] === 'a' && date[6] === 'y') {
|
|
459
|
+
weekday = 2 // Tuesday
|
|
460
|
+
commaIndex = 7
|
|
461
|
+
} else if (date[1] === 'h' && date[2] === 'u' && date[3] === 'r' && date[4] === 's' && date[5] === 'd' && date[6] === 'a' && date[7] === 'y') {
|
|
462
|
+
weekday = 4 // Thursday
|
|
463
|
+
commaIndex = 8
|
|
464
|
+
}
|
|
465
|
+
} else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd' && date[3] === 'n' && date[4] === 'e' && date[5] === 's' && date[6] === 'd' && date[7] === 'a' && date[8] === 'y') {
|
|
466
|
+
weekday = 3 // Wednesday
|
|
467
|
+
commaIndex = 9
|
|
468
|
+
} else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
|
|
469
|
+
weekday = 5 // Friday
|
|
470
|
+
commaIndex = 6
|
|
471
|
+
} else {
|
|
472
|
+
// Not a valid day name
|
|
191
473
|
return undefined
|
|
192
474
|
}
|
|
193
475
|
|
|
194
476
|
if (
|
|
477
|
+
date[commaIndex] !== ',' ||
|
|
478
|
+
(date.length - commaIndex - 1) !== 23 ||
|
|
195
479
|
date[commaIndex + 1] !== ' ' ||
|
|
196
480
|
date[commaIndex + 4] !== '-' ||
|
|
197
481
|
date[commaIndex + 8] !== '-' ||
|
|
198
482
|
date[commaIndex + 11] !== ' ' ||
|
|
199
483
|
date[commaIndex + 14] !== ':' ||
|
|
200
484
|
date[commaIndex + 17] !== ':' ||
|
|
201
|
-
date[commaIndex + 20] !== ' '
|
|
485
|
+
date[commaIndex + 20] !== ' ' ||
|
|
486
|
+
date[commaIndex + 21] !== 'G' ||
|
|
487
|
+
date[commaIndex + 22] !== 'M' ||
|
|
488
|
+
date[commaIndex + 23] !== 'T'
|
|
202
489
|
) {
|
|
203
490
|
return undefined
|
|
204
491
|
}
|
|
205
492
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
493
|
+
let day = 0
|
|
494
|
+
if (date[commaIndex + 2] === '0') {
|
|
495
|
+
// Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
|
|
496
|
+
const code = date.charCodeAt(commaIndex + 3)
|
|
497
|
+
if (code < 49 || code > 57) {
|
|
498
|
+
return undefined // Not a digit
|
|
499
|
+
}
|
|
500
|
+
day = code - 48 // Convert ASCII code to number
|
|
501
|
+
} else {
|
|
502
|
+
const code1 = date.charCodeAt(commaIndex + 2)
|
|
503
|
+
if (code1 < 49 || code1 > 51) {
|
|
504
|
+
return undefined // Not a digit between 1 and 3
|
|
505
|
+
}
|
|
506
|
+
const code2 = date.charCodeAt(commaIndex + 3)
|
|
507
|
+
if (code2 < 48 || code2 > 57) {
|
|
508
|
+
return undefined // Not a digit
|
|
509
|
+
}
|
|
510
|
+
day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
211
511
|
}
|
|
212
512
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
513
|
+
let monthIdx = -1
|
|
514
|
+
if (
|
|
515
|
+
(date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'n')
|
|
516
|
+
) {
|
|
517
|
+
monthIdx = 0 // Jan
|
|
518
|
+
} else if (
|
|
519
|
+
(date[commaIndex + 5] === 'F' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'b')
|
|
520
|
+
) {
|
|
521
|
+
monthIdx = 1 // Feb
|
|
522
|
+
} else if (
|
|
523
|
+
(date[commaIndex + 5] === 'M' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'r')
|
|
524
|
+
) {
|
|
525
|
+
monthIdx = 2 // Mar
|
|
526
|
+
} else if (
|
|
527
|
+
(date[commaIndex + 5] === 'A' && date[commaIndex + 6] === 'p' && date[commaIndex + 7] === 'r')
|
|
528
|
+
) {
|
|
529
|
+
monthIdx = 3 // Apr
|
|
530
|
+
} else if (
|
|
531
|
+
(date[commaIndex + 5] === 'M' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'y')
|
|
532
|
+
) {
|
|
533
|
+
monthIdx = 4 // May
|
|
534
|
+
} else if (
|
|
535
|
+
(date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'n')
|
|
536
|
+
) {
|
|
537
|
+
monthIdx = 5 // Jun
|
|
538
|
+
} else if (
|
|
539
|
+
(date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'l')
|
|
540
|
+
) {
|
|
541
|
+
monthIdx = 6 // Jul
|
|
542
|
+
} else if (
|
|
543
|
+
(date[commaIndex + 5] === 'A' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'g')
|
|
544
|
+
) {
|
|
545
|
+
monthIdx = 7 // Aug
|
|
546
|
+
} else if (
|
|
547
|
+
(date[commaIndex + 5] === 'S' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'p')
|
|
548
|
+
) {
|
|
549
|
+
monthIdx = 8 // Sep
|
|
550
|
+
} else if (
|
|
551
|
+
(date[commaIndex + 5] === 'O' && date[commaIndex + 6] === 'c' && date[commaIndex + 7] === 't')
|
|
552
|
+
) {
|
|
553
|
+
monthIdx = 9 // Oct
|
|
554
|
+
} else if (
|
|
555
|
+
(date[commaIndex + 5] === 'N' && date[commaIndex + 6] === 'o' && date[commaIndex + 7] === 'v')
|
|
556
|
+
) {
|
|
557
|
+
monthIdx = 10 // Nov
|
|
558
|
+
} else if (
|
|
559
|
+
(date[commaIndex + 5] === 'D' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'c')
|
|
560
|
+
) {
|
|
561
|
+
monthIdx = 11 // Dec
|
|
562
|
+
} else {
|
|
563
|
+
// Not a valid month
|
|
216
564
|
return undefined
|
|
217
565
|
}
|
|
218
566
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
567
|
+
const yearDigit1 = date.charCodeAt(commaIndex + 9)
|
|
568
|
+
if (yearDigit1 < 48 || yearDigit1 > 57) {
|
|
569
|
+
return undefined // Not a digit
|
|
570
|
+
}
|
|
571
|
+
const yearDigit2 = date.charCodeAt(commaIndex + 10)
|
|
572
|
+
if (yearDigit2 < 48 || yearDigit2 > 57) {
|
|
573
|
+
return undefined // Not a digit
|
|
223
574
|
}
|
|
224
575
|
|
|
225
|
-
|
|
226
|
-
const currentDecade = currentYear % 100
|
|
227
|
-
const currentCentury = Math.floor(currentYear / 100)
|
|
576
|
+
let year = (yearDigit1 - 48) * 10 + (yearDigit2 - 48) // Convert ASCII codes to number
|
|
228
577
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
578
|
+
// RFC 6265 states that the year is in the range 1970-2069.
|
|
579
|
+
// @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.1
|
|
580
|
+
//
|
|
581
|
+
// 3. If the year-value is greater than or equal to 70 and less than or
|
|
582
|
+
// equal to 99, increment the year-value by 1900.
|
|
583
|
+
// 4. If the year-value is greater than or equal to 0 and less than or
|
|
584
|
+
// equal to 69, increment the year-value by 2000.
|
|
585
|
+
year += year < 70 ? 2000 : 1900
|
|
235
586
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
587
|
+
let hour = 0
|
|
588
|
+
if (date[commaIndex + 12] === '0') {
|
|
589
|
+
const code = date.charCodeAt(commaIndex + 13)
|
|
590
|
+
if (code < 48 || code > 57) {
|
|
591
|
+
return undefined // Not a digit
|
|
592
|
+
}
|
|
593
|
+
hour = code - 48 // Convert ASCII code to number
|
|
594
|
+
} else {
|
|
595
|
+
const code1 = date.charCodeAt(commaIndex + 12)
|
|
596
|
+
if (code1 < 48 || code1 > 50) {
|
|
597
|
+
return undefined // Not a digit between 0 and 2
|
|
598
|
+
}
|
|
599
|
+
const code2 = date.charCodeAt(commaIndex + 13)
|
|
600
|
+
if (code2 < 48 || code2 > 57) {
|
|
601
|
+
return undefined // Not a digit
|
|
602
|
+
}
|
|
603
|
+
if (code1 === 50 && code2 > 51) {
|
|
604
|
+
return undefined // Hour cannot be greater than 23
|
|
605
|
+
}
|
|
606
|
+
hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
240
607
|
}
|
|
241
608
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
609
|
+
let minute = 0
|
|
610
|
+
if (date[commaIndex + 15] === '0') {
|
|
611
|
+
const code = date.charCodeAt(commaIndex + 16)
|
|
612
|
+
if (code < 48 || code > 57) {
|
|
613
|
+
return undefined // Not a digit
|
|
614
|
+
}
|
|
615
|
+
minute = code - 48 // Convert ASCII code to number
|
|
616
|
+
} else {
|
|
617
|
+
const code1 = date.charCodeAt(commaIndex + 15)
|
|
618
|
+
if (code1 < 48 || code1 > 53) {
|
|
619
|
+
return undefined // Not a digit between 0 and 5
|
|
620
|
+
}
|
|
621
|
+
const code2 = date.charCodeAt(commaIndex + 16)
|
|
622
|
+
if (code2 < 48 || code2 > 57) {
|
|
623
|
+
return undefined // Not a digit
|
|
624
|
+
}
|
|
625
|
+
minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
246
626
|
}
|
|
247
627
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
628
|
+
let second = 0
|
|
629
|
+
if (date[commaIndex + 18] === '0') {
|
|
630
|
+
const code = date.charCodeAt(commaIndex + 19)
|
|
631
|
+
if (code < 48 || code > 57) {
|
|
632
|
+
return undefined // Not a digit
|
|
633
|
+
}
|
|
634
|
+
second = code - 48 // Convert ASCII code to number
|
|
635
|
+
} else {
|
|
636
|
+
const code1 = date.charCodeAt(commaIndex + 18)
|
|
637
|
+
if (code1 < 48 || code1 > 53) {
|
|
638
|
+
return undefined // Not a digit between 0 and 5
|
|
639
|
+
}
|
|
640
|
+
const code2 = date.charCodeAt(commaIndex + 19)
|
|
641
|
+
if (code2 < 48 || code2 > 57) {
|
|
642
|
+
return undefined // Not a digit
|
|
643
|
+
}
|
|
644
|
+
second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
|
|
252
645
|
}
|
|
253
646
|
|
|
254
|
-
|
|
647
|
+
const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
|
|
648
|
+
return result.getUTCDay() === weekday ? result : undefined
|
|
255
649
|
}
|
|
256
650
|
|
|
257
651
|
module.exports = {
|