23 using v8::FunctionCallbackInfo;
24 using v8::HandleScope;
36 #define GET(env, obj, name) \ 37 obj->Get(env->context(), \ 38 OneByteString(env->isolate(), name)).ToLocalChecked() 40 #define GET_AND_SET(env, obj, name, data, flag) \ 42 Local<Value> val = GET(env, obj, #name); \ 43 if (val->IsString()) { \ 44 Utf8Value value(env->isolate(), val.As<String>()); \ 45 data->name = *value; \ 46 data->flags |= flag; \ 50 #define UTF8STRING(isolate, str) \ 51 String::NewFromUtf8(isolate, str.c_str(), v8::NewStringType::kNormal) \ 57 static const char kEOL = -1;
60 static const char16_t kUnicodeReplacementCharacter = 0xFFFD;
95 #define ERR_ARGS(XX) \ 100 #define XX(name) name, 106 #define XX(name) name, 111 #define CHAR_TEST(bits, name, expr) \ 112 template <typename T> \ 113 static inline bool name(const T ch) { \ 114 static_assert(sizeof(ch) >= (bits) / 8, \ 115 "Character must be wider than " #bits " bits"); \ 119 #define TWO_CHAR_STRING_TEST(bits, name, expr) \ 120 template <typename T> \ 121 static inline bool name(const T ch1, const T ch2) { \ 122 static_assert(sizeof(ch1) >= (bits) / 8, \ 123 "Character must be wider than " #bits " bits"); \ 126 template <typename T> \ 127 static inline bool name(const std::basic_string<T>& str) { \ 128 static_assert(sizeof(str[0]) >= (bits) / 8, \ 129 "Character must be wider than " #bits " bits"); \ 130 return str.length() >= 2 && name(str[0], str[1]); \ 134 CHAR_TEST(8, IsASCIITabOrNewline, (
ch ==
'\t' ||
ch ==
'\n' ||
ch ==
'\r'))
143 CHAR_TEST(8, IsASCIIHexDigit, (IsASCIIDigit(
ch) ||
144 (
ch >= 'A' &&
ch <= 'F') ||
145 (
ch >= '
a' &&
ch <= 'f')))
149 (
ch >= '
a' &&
ch <= 'z')))
155 template <typename T>
156 static inline T ASCIILowercase(T
ch) {
162 ch ==
'\0' ||
ch ==
'\t' ||
ch ==
'\n' ||
ch ==
'\r' ||
163 ch ==
' ' ||
ch ==
'#' ||
ch ==
'%' ||
ch ==
'/' ||
164 ch ==
':' ||
ch ==
'?' ||
ch ==
'@' ||
ch ==
'[' ||
165 ch ==
'\\' ||
ch ==
']')
176 CHAR_TEST(16, IsUnicodeTrail, (
ch & 0xFC00) == 0xDC00)
179 CHAR_TEST(16, IsUnicodeSurrogate, (
ch & 0xF800) == 0xD800)
182 CHAR_TEST(16, IsUnicodeSurrogateTrail, (
ch & 0x400) != 0)
185 #undef TWO_CHAR_STRING_TEST 187 static const char* hex[256] = {
188 "%00",
"%01",
"%02",
"%03",
"%04",
"%05",
"%06",
"%07",
189 "%08",
"%09",
"%0A",
"%0B",
"%0C",
"%0D",
"%0E",
"%0F",
190 "%10",
"%11",
"%12",
"%13",
"%14",
"%15",
"%16",
"%17",
191 "%18",
"%19",
"%1A",
"%1B",
"%1C",
"%1D",
"%1E",
"%1F",
192 "%20",
"%21",
"%22",
"%23",
"%24",
"%25",
"%26",
"%27",
193 "%28",
"%29",
"%2A",
"%2B",
"%2C",
"%2D",
"%2E",
"%2F",
194 "%30",
"%31",
"%32",
"%33",
"%34",
"%35",
"%36",
"%37",
195 "%38",
"%39",
"%3A",
"%3B",
"%3C",
"%3D",
"%3E",
"%3F",
196 "%40",
"%41",
"%42",
"%43",
"%44",
"%45",
"%46",
"%47",
197 "%48",
"%49",
"%4A",
"%4B",
"%4C",
"%4D",
"%4E",
"%4F",
198 "%50",
"%51",
"%52",
"%53",
"%54",
"%55",
"%56",
"%57",
199 "%58",
"%59",
"%5A",
"%5B",
"%5C",
"%5D",
"%5E",
"%5F",
200 "%60",
"%61",
"%62",
"%63",
"%64",
"%65",
"%66",
"%67",
201 "%68",
"%69",
"%6A",
"%6B",
"%6C",
"%6D",
"%6E",
"%6F",
202 "%70",
"%71",
"%72",
"%73",
"%74",
"%75",
"%76",
"%77",
203 "%78",
"%79",
"%7A",
"%7B",
"%7C",
"%7D",
"%7E",
"%7F",
204 "%80",
"%81",
"%82",
"%83",
"%84",
"%85",
"%86",
"%87",
205 "%88",
"%89",
"%8A",
"%8B",
"%8C",
"%8D",
"%8E",
"%8F",
206 "%90",
"%91",
"%92",
"%93",
"%94",
"%95",
"%96",
"%97",
207 "%98",
"%99",
"%9A",
"%9B",
"%9C",
"%9D",
"%9E",
"%9F",
208 "%A0",
"%A1",
"%A2",
"%A3",
"%A4",
"%A5",
"%A6",
"%A7",
209 "%A8",
"%A9",
"%AA",
"%AB",
"%AC",
"%AD",
"%AE",
"%AF",
210 "%B0",
"%B1",
"%B2",
"%B3",
"%B4",
"%B5",
"%B6",
"%B7",
211 "%B8",
"%B9",
"%BA",
"%BB",
"%BC",
"%BD",
"%BE",
"%BF",
212 "%C0",
"%C1",
"%C2",
"%C3",
"%C4",
"%C5",
"%C6",
"%C7",
213 "%C8",
"%C9",
"%CA",
"%CB",
"%CC",
"%CD",
"%CE",
"%CF",
214 "%D0",
"%D1",
"%D2",
"%D3",
"%D4",
"%D5",
"%D6",
"%D7",
215 "%D8",
"%D9",
"%DA",
"%DB",
"%DC",
"%DD",
"%DE",
"%DF",
216 "%E0",
"%E1",
"%E2",
"%E3",
"%E4",
"%E5",
"%E6",
"%E7",
217 "%E8",
"%E9",
"%EA",
"%EB",
"%EC",
"%ED",
"%EE",
"%EF",
218 "%F0",
"%F1",
"%F2",
"%F3",
"%F4",
"%F5",
"%F6",
"%F7",
219 "%F8",
"%F9",
"%FA",
"%FB",
"%FC",
"%FD",
"%FE",
"%FF" 222 static const uint8_t C0_CONTROL_ENCODE_SET[32] = {
224 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
226 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
228 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
230 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
232 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
234 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
236 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
238 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
240 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
242 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
244 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
246 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
248 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
250 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
252 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
254 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
256 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
258 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
260 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
262 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
264 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
266 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
268 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
270 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
272 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
274 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
276 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
278 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
280 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
282 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
284 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
286 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
289 static const uint8_t PATH_ENCODE_SET[32] = {
291 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
293 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
295 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
297 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
299 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
301 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
303 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
305 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x80,
307 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
309 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
311 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
313 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
315 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
317 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
319 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
321 0x00 | 0x00 | 0x00 | 0x08 | 0x00 | 0x20 | 0x00 | 0x80,
323 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
325 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
327 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
329 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
331 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
333 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
335 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
337 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
339 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
341 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
343 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
345 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
347 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
349 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
351 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
353 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
356 static const uint8_t USERINFO_ENCODE_SET[32] = {
358 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
360 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
362 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
364 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
366 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
368 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
370 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
372 0x00 | 0x00 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
374 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
376 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
378 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
380 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x40 | 0x00,
382 0x01 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
384 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
386 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
388 0x00 | 0x00 | 0x00 | 0x08 | 0x10 | 0x20 | 0x00 | 0x80,
390 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
392 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
394 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
396 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
398 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
400 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
402 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
404 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
406 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
408 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
410 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
412 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
414 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
416 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
418 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
420 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
423 static const uint8_t QUERY_ENCODE_SET[32] = {
425 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
427 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
429 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
431 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
433 0x01 | 0x00 | 0x04 | 0x08 | 0x00 | 0x00 | 0x00 | 0x00,
435 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
437 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
439 0x00 | 0x00 | 0x00 | 0x00 | 0x10 | 0x00 | 0x40 | 0x00,
441 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
443 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
445 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
447 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
449 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
451 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
453 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00,
455 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x80,
457 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
459 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
461 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
463 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
465 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
467 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
469 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
471 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
473 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
475 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
477 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
479 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
481 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
483 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
485 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80,
487 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80
490 static inline bool BitAt(
const uint8_t
a[],
const uint8_t i) {
491 return !!(a[i >> 3] & (1 << (i & 7)));
496 static inline void AppendOrEscape(std::string* str,
497 const unsigned char ch,
498 const uint8_t encode_set[]) {
499 if (BitAt(encode_set, ch))
505 template <
typename T>
506 static inline unsigned hex2bin(
const T ch) {
507 if (ch >=
'0' && ch <=
'9')
509 if (ch >=
'A' && ch <=
'F')
510 return 10 + (ch -
'A');
511 if (ch >=
'a' && ch <=
'f')
512 return 10 + (ch -
'a');
513 return static_cast<unsigned>(-1);
516 static inline void PercentDecode(
const char* input,
522 const char* pointer = input;
523 const char* end = input +
len;
524 size_t remaining = pointer - end - 1;
525 while (pointer < end) {
526 const char ch = pointer[0];
527 remaining = (end - pointer) + 1;
528 if (ch !=
'%' || remaining < 2 ||
530 (!IsASCIIHexDigit(pointer[1]) ||
531 !IsASCIIHexDigit(pointer[2])))) {
536 unsigned a = hex2bin(pointer[1]);
537 unsigned b = hex2bin(pointer[2]);
538 char c =
static_cast<char>(a * 16 + b);
545 #define SPECIALS(XX) \ 554 static inline bool IsSpecial(std::string scheme) {
555 #define XX(name, _) if (scheme == name) return true; 561 static inline int NormalizePort(std::string scheme,
int p) {
562 #define XX(name, port) if (scheme == name && p == port) return -1; 568 #if defined(NODE_HAVE_I18N_SUPPORT) 569 static inline bool ToUnicode(std::string* input, std::string* output) {
570 MaybeStackBuffer<char>
buf;
571 if (i18n::ToUnicode(&buf, input->c_str(), input->length()) < 0)
573 output->assign(*buf, buf.length());
577 static inline bool ToASCII(std::string* input, std::string* output) {
578 MaybeStackBuffer<char>
buf;
579 if (i18n::ToASCII(&buf, input->c_str(), input->length()) < 0)
581 output->assign(*buf, buf.length());
586 static inline bool ToUnicode(std::string* input, std::string* output) {
591 static inline bool ToASCII(std::string* input, std::string* output) {
601 for (
unsigned n = 0;
n < 8;
n++)
602 host->value.ipv6[
n] = 0;
603 uint16_t* piece_pointer = &host->value.ipv6[0];
604 uint16_t* last_piece = piece_pointer + 8;
605 uint16_t* compress_pointer =
nullptr;
606 const char* pointer = input;
607 const char* end = pointer + length;
608 unsigned value, len, swaps, numbers_seen;
609 char ch = pointer < end ? pointer[0] : kEOL;
611 if (length < 2 || pointer[1] !=
':')
614 ch = pointer < end ? pointer[0] : kEOL;
616 compress_pointer = piece_pointer;
619 if (piece_pointer > last_piece)
622 if (compress_pointer !=
nullptr)
625 ch = pointer < end ? pointer[0] : kEOL;
627 compress_pointer = piece_pointer;
632 while (len < 4 && IsASCIIHexDigit(ch)) {
633 value = value * 0x10 + hex2bin(ch);
635 ch = pointer < end ? pointer[0] : kEOL;
643 ch = pointer < end ? pointer[0] : kEOL;
644 if (piece_pointer > last_piece - 2)
649 if (numbers_seen > 0) {
650 if (ch ==
'.' && numbers_seen < 4) {
652 ch = pointer < end ? pointer[0] : kEOL;
657 if (!IsASCIIDigit(ch))
659 while (IsASCIIDigit(ch)) {
660 unsigned number = ch -
'0';
661 if (value == 0xffffffff) {
663 }
else if (value == 0) {
666 value = value * 10 + number;
671 ch = pointer < end ? pointer[0] : kEOL;
673 *piece_pointer = *piece_pointer * 0x100 + value;
675 if (numbers_seen == 2 || numbers_seen == 4)
678 if (numbers_seen != 4)
683 ch = pointer < end ? pointer[0] : kEOL;
692 *piece_pointer = value;
696 if (compress_pointer !=
nullptr) {
697 swaps = piece_pointer - compress_pointer;
698 piece_pointer = last_piece - 1;
699 while (piece_pointer != &host->value.ipv6[0] && swaps > 0) {
700 uint16_t temp = *piece_pointer;
701 uint16_t* swap_piece = compress_pointer + swaps - 1;
702 *piece_pointer = *swap_piece;
707 }
else if (compress_pointer ==
nullptr &&
708 piece_pointer != last_piece) {
717 static inline int64_t ParseNumber(
const char* start,
const char* end) {
719 if (end - start >= 2 && start[0] ==
'0' && (start[1] | 0x20) ==
'x') {
723 if (end - start == 0) {
725 }
else if (R == 10 && end - start > 1 && start[0] ==
'0') {
729 const char* p = start;
732 const char ch = p[0];
735 if (ch < '0' || ch >
'7')
739 if (!IsASCIIDigit(ch))
743 if (!IsASCIIHexDigit(ch))
749 return strtoll(start, NULL, R);
756 const char* pointer = input;
757 const char* mark = input;
758 const char* end = pointer + length;
762 int tooBigNumbers = 0;
766 while (pointer <= end) {
767 const char ch = pointer < end ? pointer[0] : kEOL;
768 const int remaining = end - pointer - 1;
769 if (ch ==
'.' || ch == kEOL) {
774 int64_t
n = ParseNumber(mark, pointer);
781 numbers[parts - 1] =
n;
783 if (ch ==
'.' && remaining == 0)
793 if (tooBigNumbers > 1 ||
794 (tooBigNumbers == 1 && numbers[parts - 1] <= 255) ||
795 numbers[parts - 1] >= pow(256, static_cast<double>(5 - parts))) {
801 val = numbers[parts - 1];
802 for (
int n = 0;
n < parts - 1;
n++) {
804 val += numbers[
n] * pow(256, b);
807 host->value.ipv4 = val;
818 output.reserve(length * 3);
819 for (
size_t i = 0; i < length; i++) {
820 const char ch = input[i];
821 if (ch !=
'%' && IsForbiddenHostCodePoint(ch)) {
825 AppendOrEscape(&output, ch, C0_CONTROL_ENCODE_SET);
829 host->value.opaque = output;
839 bool unicode =
false) {
841 const char* pointer = input;
847 if (pointer[0] ==
'[') {
848 if (pointer[length - 1] !=
']')
850 return ParseIPv6Host(host, ++pointer, length - 2);
854 return ParseOpaqueHost(host, input, length);
857 PercentDecode(input, length, &decoded);
860 if (!ToASCII(&decoded, &decoded))
864 for (
size_t n = 0;
n < decoded.size();
n++) {
865 const char ch = decoded[
n];
866 if (IsForbiddenHostCodePoint(ch)) {
872 type = ParseIPv4Host(host, decoded.c_str(), decoded.length());
877 if (unicode && !ToUnicode(&decoded, &decoded))
882 host->value.domain = decoded;
891 static inline uint16_t* FindLongestZeroSequence(uint16_t* values,
893 uint16_t* start = values;
894 uint16_t* end = start +
len;
895 uint16_t* result =
nullptr;
897 uint16_t* current =
nullptr;
898 unsigned counter = 0, longest = 1;
900 while (start < end) {
902 if (current ==
nullptr)
906 if (counter > longest) {
915 if (counter > longest)
920 static url_host_type WriteHost(url_host* host, std::string* dest) {
922 switch (host->type) {
924 *dest = host->value.domain;
928 uint32_t value = host->value.ipv4;
929 for (
int n = 0;
n < 4;
n++) {
932 snprintf(buffer,
sizeof(buf),
"%d", value % 256);
933 dest->insert(0, buf);
935 dest->insert(0, 1,
'.');
943 uint16_t* start = &host->value.ipv6[0];
944 uint16_t* compress_pointer =
945 FindLongestZeroSequence(start, 8);
946 bool ignore0 =
false;
947 for (
int n = 0;
n <= 7;
n++) {
948 uint16_t* piece = &host->value.ipv6[
n];
949 if (ignore0 && *piece == 0)
953 if (compress_pointer == piece) {
954 *dest +=
n == 0 ?
"::" :
":";
960 snprintf(buffer,
sizeof(buf),
"%x", *piece);
969 *dest = host->value.opaque;
977 static bool ParseHost(std::string* input,
980 bool unicode =
false) {
981 if (input->length() == 0) {
986 ParseHost(&host, input->c_str(), input->length(), is_special, unicode);
989 WriteHost(&host, output);
993 static inline void Copy(Environment* env,
995 std::vector<std::string>* vec) {
996 const int32_t len = ary->Length();
1000 for (int32_t
n = 0;
n <
len;
n++) {
1001 Local<Value> val = ary->Get(env->context(),
n).ToLocalChecked();
1002 if (val->IsString()) {
1003 Utf8Value value(env->isolate(), val.As<String>());
1004 vec->push_back(std::string(*value, value.length()));
1009 static inline Local<Array> Copy(Environment* env,
1010 const std::vector<std::string>& vec) {
1011 Isolate* isolate = env->isolate();
1012 Local<Array> ary =
Array::New(isolate, vec.size());
1013 for (
size_t n = 0;
n < vec.size();
n++)
1014 ary->Set(env->context(),
n,
UTF8STRING(isolate, vec[
n])).FromJust();
1018 static inline void HarvestBase(Environment* env,
1019 struct url_data* base,
1020 Local<Object> base_obj) {
1021 Local<Context> context = env->context();
1022 Local<Value> flags =
GET(env, base_obj,
"flags");
1023 if (flags->IsInt32())
1024 base->flags = flags->Int32Value(context).FromJust();
1026 Local<Value> scheme =
GET(env, base_obj,
"scheme");
1027 base->scheme = Utf8Value(env->isolate(), scheme).out();
1029 GET_AND_SET(env, base_obj, username, base, URL_FLAGS_HAS_USERNAME);
1030 GET_AND_SET(env, base_obj, password, base, URL_FLAGS_HAS_PASSWORD);
1031 GET_AND_SET(env, base_obj, host, base, URL_FLAGS_HAS_HOST);
1032 GET_AND_SET(env, base_obj, query, base, URL_FLAGS_HAS_QUERY);
1033 GET_AND_SET(env, base_obj, fragment, base, URL_FLAGS_HAS_FRAGMENT);
1034 Local<Value> port =
GET(env, base_obj,
"port");
1035 if (port->IsInt32())
1036 base->port = port->Int32Value(context).FromJust();
1037 Local<Value> path =
GET(env, base_obj,
"path");
1038 if (path->IsArray()) {
1039 base->flags |= URL_FLAGS_HAS_PATH;
1040 Copy(env, path.As<Array>(), &(base->path));
1044 static inline void HarvestContext(Environment* env,
1045 struct url_data* context,
1046 Local<Object> context_obj) {
1047 Local<Value> flags =
GET(env, context_obj,
"flags");
1048 if (flags->IsInt32()) {
1049 int32_t _flags = flags->Int32Value(env->context()).FromJust();
1050 if (_flags & URL_FLAGS_SPECIAL)
1051 context->flags |= URL_FLAGS_SPECIAL;
1052 if (_flags & URL_FLAGS_CANNOT_BE_BASE)
1053 context->flags |= URL_FLAGS_CANNOT_BE_BASE;
1054 if (_flags & URL_FLAGS_HAS_USERNAME)
1055 context->flags |= URL_FLAGS_HAS_USERNAME;
1056 if (_flags & URL_FLAGS_HAS_PASSWORD)
1057 context->flags |= URL_FLAGS_HAS_PASSWORD;
1058 if (_flags & URL_FLAGS_HAS_HOST)
1059 context->flags |= URL_FLAGS_HAS_HOST;
1061 Local<Value> scheme =
GET(env, context_obj,
"scheme");
1062 if (scheme->IsString()) {
1063 Utf8Value value(env->isolate(), scheme);
1064 context->scheme.assign(*value, value.length());
1066 Local<Value> port =
GET(env, context_obj,
"port");
1067 if (port->IsInt32())
1068 context->port = port->Int32Value(env->context()).FromJust();
1069 if (context->flags & URL_FLAGS_HAS_USERNAME) {
1070 Local<Value> username =
GET(env, context_obj,
"username");
1071 CHECK(username->IsString());
1072 Utf8Value value(env->isolate(), username);
1073 context->username.assign(*value, value.length());
1075 if (context->flags & URL_FLAGS_HAS_PASSWORD) {
1076 Local<Value> password =
GET(env, context_obj,
"password");
1077 CHECK(password->IsString());
1078 Utf8Value value(env->isolate(), password);
1079 context->password.assign(*value, value.length());
1081 Local<Value> host =
GET(env, context_obj,
"host");
1082 if (host->IsString()) {
1083 Utf8Value value(env->isolate(),
host);
1084 context->host.assign(*value, value.length());
1089 static inline bool IsSingleDotSegment(std::string str) {
1090 switch (str.size()) {
1094 return str[0] ==
'%' &&
1096 ASCIILowercase(str[2]) ==
'e';
1105 static inline bool IsDoubleDotSegment(std::string str) {
1106 switch (str.size()) {
1110 if (str[0] !=
'.' && str[0] !=
'%')
1112 return ((str[0] ==
'.' &&
1115 ASCIILowercase(str[3]) ==
'e') ||
1118 ASCIILowercase(str[2]) ==
'e' &&
1121 return (str[0] ==
'%' &&
1123 ASCIILowercase(str[2]) ==
'e' &&
1126 ASCIILowercase(str[5]) ==
'e');
1132 static inline void ShortenUrlPath(
struct url_data* url) {
1133 if (url->path.empty())
return;
1134 if (url->path.size() == 1 && url->scheme ==
"file:" &&
1135 IsNormalizedWindowsDriveLetter(url->path[0]))
return;
1136 url->path.pop_back();
1139 void URL::Parse(
const char* input,
1141 enum url_parse_state state_override,
1142 struct url_data* url,
1144 const struct url_data* base,
1146 const char* p = input;
1147 const char* end = input +
len;
1150 for (
const char* ptr = p; ptr < end; ptr++) {
1151 if (IsC0ControlOrSpace(*ptr))
1156 for (
const char* ptr = end - 1; ptr >=
p; ptr--) {
1157 if (IsC0ControlOrSpace(*ptr))
1165 std::string whitespace_stripped;
1166 whitespace_stripped.reserve(len);
1167 for (
const char* ptr = p; ptr < end; ptr++)
1168 if (!IsASCIITabOrNewline(*ptr))
1169 whitespace_stripped += *ptr;
1171 input = whitespace_stripped.c_str();
1172 len = whitespace_stripped.size();
1176 bool atflag =
false;
1177 bool sbflag =
false;
1181 url->scheme.reserve(len);
1182 url->username.reserve(len);
1183 url->password.reserve(len);
1184 url->host.reserve(len);
1185 url->path.reserve(len);
1186 url->query.reserve(len);
1187 url->fragment.reserve(len);
1188 buffer.reserve(len);
1191 const bool has_state_override = state_override != kUnknownState;
1192 enum url_parse_state state = has_state_override ? state_override :
1195 if (state < kSchemeStart || state > kFragment) {
1196 url->flags |= URL_FLAGS_INVALID_PARSE_STATE;
1201 const char ch = p < end ? p[0] : kEOL;
1202 const size_t remaining = end == p ? 0 : (end - p - 1);
1204 bool special = (url->flags & URL_FLAGS_SPECIAL);
1205 bool cannot_be_base;
1206 const bool special_back_slash = (special && ch ==
'\\');
1210 buffer += ASCIILowercase(ch);
1212 }
else if (!has_state_override) {
1216 url->flags |= URL_FLAGS_FAILED;
1221 if (IsASCIIAlphanumeric(ch) || ch ==
'+' || ch ==
'-' || ch ==
'.') {
1222 buffer += ASCIILowercase(ch);
1223 }
else if (ch ==
':' || (has_state_override && ch == kEOL)) {
1224 if (has_state_override && buffer.size() == 0) {
1225 url->flags |= URL_FLAGS_TERMINATED;
1230 bool new_is_special = IsSpecial(buffer);
1232 if (has_state_override) {
1233 if ((special != new_is_special) ||
1234 ((buffer ==
"file:") &&
1235 ((url->flags & URL_FLAGS_HAS_USERNAME) ||
1236 (url->flags & URL_FLAGS_HAS_PASSWORD) ||
1237 (url->port != -1)))) {
1238 url->flags |= URL_FLAGS_TERMINATED;
1246 url->scheme = buffer;
1247 url->port = NormalizePort(url->scheme, url->port);
1248 if (new_is_special) {
1249 url->flags |= URL_FLAGS_SPECIAL;
1252 url->flags &= ~URL_FLAGS_SPECIAL;
1256 if (has_state_override)
1258 if (url->scheme ==
"file:") {
1260 }
else if (special &&
1262 url->scheme == base->scheme) {
1263 state = kSpecialRelativeOrAuthority;
1264 }
else if (special) {
1265 state = kSpecialAuthoritySlashes;
1266 }
else if (p[1] ==
'/') {
1267 state = kPathOrAuthority;
1270 url->flags |= URL_FLAGS_CANNOT_BE_BASE;
1271 url->flags |= URL_FLAGS_HAS_PATH;
1272 url->path.push_back(
"");
1273 state = kCannotBeBase;
1275 }
else if (!has_state_override) {
1281 url->flags |= URL_FLAGS_FAILED;
1286 cannot_be_base = has_base && (base->flags & URL_FLAGS_CANNOT_BE_BASE);
1287 if (!has_base || (cannot_be_base && ch !=
'#')) {
1288 url->flags |= URL_FLAGS_FAILED;
1290 }
else if (cannot_be_base && ch ==
'#') {
1291 url->scheme = base->scheme;
1292 if (IsSpecial(url->scheme)) {
1293 url->flags |= URL_FLAGS_SPECIAL;
1296 url->flags &= ~URL_FLAGS_SPECIAL;
1299 if (base->flags & URL_FLAGS_HAS_PATH) {
1300 url->flags |= URL_FLAGS_HAS_PATH;
1301 url->path = base->path;
1303 if (base->flags & URL_FLAGS_HAS_QUERY) {
1304 url->flags |= URL_FLAGS_HAS_QUERY;
1305 url->query = base->query;
1307 if (base->flags & URL_FLAGS_HAS_FRAGMENT) {
1308 url->flags |= URL_FLAGS_HAS_FRAGMENT;
1309 url->fragment = base->fragment;
1311 url->flags |= URL_FLAGS_CANNOT_BE_BASE;
1313 }
else if (has_base &&
1314 base->scheme !=
"file:") {
1318 url->scheme =
"file:";
1319 url->flags |= URL_FLAGS_SPECIAL;
1325 case kSpecialRelativeOrAuthority:
1326 if (ch ==
'/' && p[1] ==
'/') {
1327 state = kSpecialAuthorityIgnoreSlashes;
1334 case kPathOrAuthority:
1343 url->scheme = base->scheme;
1344 if (IsSpecial(url->scheme)) {
1345 url->flags |= URL_FLAGS_SPECIAL;
1348 url->flags &= ~URL_FLAGS_SPECIAL;
1353 if (base->flags & URL_FLAGS_HAS_USERNAME) {
1354 url->flags |= URL_FLAGS_HAS_USERNAME;
1355 url->username = base->username;
1357 if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1358 url->flags |= URL_FLAGS_HAS_PASSWORD;
1359 url->password = base->password;
1361 if (base->flags & URL_FLAGS_HAS_HOST) {
1362 url->flags |= URL_FLAGS_HAS_HOST;
1363 url->host = base->host;
1365 if (base->flags & URL_FLAGS_HAS_QUERY) {
1366 url->flags |= URL_FLAGS_HAS_QUERY;
1367 url->query = base->query;
1369 if (base->flags & URL_FLAGS_HAS_PATH) {
1370 url->flags |= URL_FLAGS_HAS_PATH;
1371 url->path = base->path;
1373 url->port = base->port;
1376 state = kRelativeSlash;
1379 if (base->flags & URL_FLAGS_HAS_USERNAME) {
1380 url->flags |= URL_FLAGS_HAS_USERNAME;
1381 url->username = base->username;
1383 if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1384 url->flags |= URL_FLAGS_HAS_PASSWORD;
1385 url->password = base->password;
1387 if (base->flags & URL_FLAGS_HAS_HOST) {
1388 url->flags |= URL_FLAGS_HAS_HOST;
1389 url->host = base->host;
1391 if (base->flags & URL_FLAGS_HAS_PATH) {
1392 url->flags |= URL_FLAGS_HAS_PATH;
1393 url->path = base->path;
1395 url->port = base->port;
1399 if (base->flags & URL_FLAGS_HAS_USERNAME) {
1400 url->flags |= URL_FLAGS_HAS_USERNAME;
1401 url->username = base->username;
1403 if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1404 url->flags |= URL_FLAGS_HAS_PASSWORD;
1405 url->password = base->password;
1407 if (base->flags & URL_FLAGS_HAS_HOST) {
1408 url->flags |= URL_FLAGS_HAS_HOST;
1409 url->host = base->host;
1411 if (base->flags & URL_FLAGS_HAS_QUERY) {
1412 url->flags |= URL_FLAGS_HAS_QUERY;
1413 url->query = base->query;
1415 if (base->flags & URL_FLAGS_HAS_PATH) {
1416 url->flags |= URL_FLAGS_HAS_PATH;
1417 url->path = base->path;
1419 url->port = base->port;
1423 if (special_back_slash) {
1424 state = kRelativeSlash;
1426 if (base->flags & URL_FLAGS_HAS_USERNAME) {
1427 url->flags |= URL_FLAGS_HAS_USERNAME;
1428 url->username = base->username;
1430 if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1431 url->flags |= URL_FLAGS_HAS_PASSWORD;
1432 url->password = base->password;
1434 if (base->flags & URL_FLAGS_HAS_HOST) {
1435 url->flags |= URL_FLAGS_HAS_HOST;
1436 url->host = base->host;
1438 if (base->flags & URL_FLAGS_HAS_PATH) {
1439 url->flags |= URL_FLAGS_HAS_PATH;
1440 url->path = base->path;
1441 ShortenUrlPath(url);
1443 url->port = base->port;
1449 case kRelativeSlash:
1450 if (IsSpecial(url->scheme) && (ch ==
'/' || ch ==
'\\')) {
1451 state = kSpecialAuthorityIgnoreSlashes;
1452 }
else if (ch ==
'/') {
1455 if (base->flags & URL_FLAGS_HAS_USERNAME) {
1456 url->flags |= URL_FLAGS_HAS_USERNAME;
1457 url->username = base->username;
1459 if (base->flags & URL_FLAGS_HAS_PASSWORD) {
1460 url->flags |= URL_FLAGS_HAS_PASSWORD;
1461 url->password = base->password;
1463 if (base->flags & URL_FLAGS_HAS_HOST) {
1464 url->flags |= URL_FLAGS_HAS_HOST;
1465 url->host = base->host;
1467 url->port = base->port;
1472 case kSpecialAuthoritySlashes:
1473 state = kSpecialAuthorityIgnoreSlashes;
1474 if (ch ==
'/' && p[1] ==
'/') {
1480 case kSpecialAuthorityIgnoreSlashes:
1481 if (ch !=
'/' && ch !=
'\\') {
1489 buffer.reserve(buffer.size() + 3);
1490 buffer.insert(0,
"%40");
1493 const size_t blen = buffer.size();
1494 if (blen > 0 && buffer[0] !=
':') {
1495 url->flags |= URL_FLAGS_HAS_USERNAME;
1497 for (
size_t n = 0;
n < blen;
n++) {
1498 const char bch = buffer[
n];
1500 url->flags |= URL_FLAGS_HAS_PASSWORD;
1507 AppendOrEscape(&url->password, bch, USERINFO_ENCODE_SET);
1509 AppendOrEscape(&url->username, bch, USERINFO_ENCODE_SET);
1513 }
else if (ch == kEOL ||
1517 special_back_slash) {
1518 if (atflag && buffer.size() == 0) {
1519 url->flags |= URL_FLAGS_FAILED;
1522 p -= buffer.size() + 1;
1531 if (has_state_override && url->scheme ==
"file:") {
1534 }
else if (ch ==
':' && !sbflag) {
1535 if (buffer.size() == 0) {
1536 url->flags |= URL_FLAGS_FAILED;
1539 url->flags |= URL_FLAGS_HAS_HOST;
1540 if (!ParseHost(&buffer, &url->host, special)) {
1541 url->flags |= URL_FLAGS_FAILED;
1546 if (state_override == kHostname) {
1549 }
else if (ch == kEOL ||
1553 special_back_slash) {
1555 if (special && buffer.size() == 0) {
1556 url->flags |= URL_FLAGS_FAILED;
1559 if (has_state_override &&
1560 buffer.size() == 0 &&
1561 ((url->username.size() > 0 || url->password.size() > 0) ||
1563 url->flags |= URL_FLAGS_TERMINATED;
1566 url->flags |= URL_FLAGS_HAS_HOST;
1567 if (!ParseHost(&buffer, &url->host, special)) {
1568 url->flags |= URL_FLAGS_FAILED;
1573 if (has_state_override) {
1585 if (IsASCIIDigit(ch)) {
1587 }
else if (has_state_override ||
1592 special_back_slash) {
1593 if (buffer.size() > 0) {
1595 for (
size_t i = 0; i < buffer.size(); i++)
1596 port = port * 10 + buffer[i] -
'0';
1597 if (port < 0 || port > 0xffff) {
1602 if (state_override == kHost)
1605 url->flags |= URL_FLAGS_FAILED;
1608 url->port = NormalizePort(url->scheme, port);
1610 }
else if (has_state_override) {
1612 if (state_override == kHost)
1615 url->flags |= URL_FLAGS_TERMINATED;
1621 url->flags |= URL_FLAGS_FAILED;
1626 url->scheme =
"file:";
1627 if (ch ==
'/' || ch ==
'\\') {
1629 }
else if (has_base && base->scheme ==
"file:") {
1632 if (base->flags & URL_FLAGS_HAS_HOST) {
1633 url->flags |= URL_FLAGS_HAS_HOST;
1634 url->host = base->host;
1636 if (base->flags & URL_FLAGS_HAS_PATH) {
1637 url->flags |= URL_FLAGS_HAS_PATH;
1638 url->path = base->path;
1640 if (base->flags & URL_FLAGS_HAS_QUERY) {
1641 url->flags |= URL_FLAGS_HAS_QUERY;
1642 url->query = base->query;
1646 if (base->flags & URL_FLAGS_HAS_HOST) {
1647 url->flags |= URL_FLAGS_HAS_HOST;
1648 url->host = base->host;
1650 if (base->flags & URL_FLAGS_HAS_PATH) {
1651 url->flags |= URL_FLAGS_HAS_PATH;
1652 url->path = base->path;
1654 url->flags |= URL_FLAGS_HAS_QUERY;
1659 if (base->flags & URL_FLAGS_HAS_HOST) {
1660 url->flags |= URL_FLAGS_HAS_HOST;
1661 url->host = base->host;
1663 if (base->flags & URL_FLAGS_HAS_PATH) {
1664 url->flags |= URL_FLAGS_HAS_PATH;
1665 url->path = base->path;
1667 if (base->flags & URL_FLAGS_HAS_QUERY) {
1668 url->flags |= URL_FLAGS_HAS_QUERY;
1669 url->query = base->query;
1671 url->flags |= URL_FLAGS_HAS_FRAGMENT;
1672 url->fragment.clear();
1676 if ((remaining == 0 ||
1677 !IsWindowsDriveLetter(ch, p[1]) ||
1683 if (base->flags & URL_FLAGS_HAS_HOST) {
1684 url->flags |= URL_FLAGS_HAS_HOST;
1685 url->host = base->host;
1687 if (base->flags & URL_FLAGS_HAS_PATH) {
1688 url->flags |= URL_FLAGS_HAS_PATH;
1689 url->path = base->path;
1691 ShortenUrlPath(url);
1702 if (ch ==
'/' || ch ==
'\\') {
1706 base->scheme ==
"file:") {
1707 if (IsNormalizedWindowsDriveLetter(base->path[0])) {
1708 url->flags |= URL_FLAGS_HAS_PATH;
1709 url->path.push_back(base->path[0]);
1711 if (base->flags & URL_FLAGS_HAS_HOST) {
1712 url->flags |= URL_FLAGS_HAS_HOST;
1713 url->host = base->host;
1715 url->flags &= ~URL_FLAGS_HAS_HOST;
1730 if (!has_state_override &&
1731 buffer.size() == 2 &&
1732 IsWindowsDriveLetter(buffer)) {
1734 }
else if (buffer.size() == 0) {
1735 url->flags |= URL_FLAGS_HAS_HOST;
1737 if (has_state_override)
1742 if (!ParseHost(&buffer, &host, special)) {
1743 url->flags |= URL_FLAGS_FAILED;
1746 if (host ==
"localhost")
1748 url->flags |= URL_FLAGS_HAS_HOST;
1750 if (has_state_override)
1761 if (IsSpecial(url->scheme)) {
1763 if (ch !=
'/' && ch !=
'\\') {
1766 }
else if (!has_state_override && ch ==
'?') {
1767 url->flags |= URL_FLAGS_HAS_QUERY;
1770 }
else if (!has_state_override && ch ==
'#') {
1771 url->flags |= URL_FLAGS_HAS_FRAGMENT;
1772 url->fragment.clear();
1774 }
else if (ch != kEOL) {
1784 special_back_slash ||
1785 (!has_state_override && (ch ==
'?' || ch ==
'#'))) {
1786 if (IsDoubleDotSegment(buffer)) {
1787 ShortenUrlPath(url);
1788 if (ch !=
'/' && !special_back_slash) {
1789 url->flags |= URL_FLAGS_HAS_PATH;
1790 url->path.push_back(
"");
1792 }
else if (IsSingleDotSegment(buffer) &&
1793 ch !=
'/' && !special_back_slash) {
1794 url->flags |= URL_FLAGS_HAS_PATH;
1795 url->path.push_back(
"");
1796 }
else if (!IsSingleDotSegment(buffer)) {
1797 if (url->scheme ==
"file:" &&
1798 url->path.empty() &&
1799 buffer.size() == 2 &&
1800 IsWindowsDriveLetter(buffer)) {
1801 if ((url->flags & URL_FLAGS_HAS_HOST) &&
1802 !url->host.empty()) {
1804 url->flags |= URL_FLAGS_HAS_HOST;
1808 url->flags |= URL_FLAGS_HAS_PATH;
1809 std::string segment(buffer.c_str(), buffer.size());
1810 url->path.push_back(segment);
1813 if (url->scheme ==
"file:" &&
1817 while (url->path.size() > 1 && url->path[0].length() == 0) {
1818 url->path.erase(url->path.begin());
1822 url->flags |= URL_FLAGS_HAS_QUERY;
1824 }
else if (ch ==
'#') {
1828 AppendOrEscape(&buffer, ch, PATH_ENCODE_SET);
1840 if (url->path.size() == 0)
1841 url->path.push_back(
"");
1842 if (url->path.size() > 0 && ch != kEOL)
1843 AppendOrEscape(&url->path[0], ch, C0_CONTROL_ENCODE_SET);
1847 if (ch == kEOL || (!has_state_override && ch ==
'#')) {
1848 url->flags |= URL_FLAGS_HAS_QUERY;
1849 url->query = buffer;
1854 AppendOrEscape(&buffer, ch, QUERY_ENCODE_SET);
1860 url->flags |= URL_FLAGS_HAS_FRAGMENT;
1861 url->fragment = buffer;
1866 AppendOrEscape(&buffer, ch, C0_CONTROL_ENCODE_SET);
1870 url->flags |= URL_FLAGS_INVALID_PARSE_STATE;
1878 static inline void SetArgs(Environment* env,
1879 Local<Value> argv[],
1880 const struct url_data* url) {
1881 Isolate* isolate = env->isolate();
1882 argv[ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url->flags);
1883 argv[ARG_PROTOCOL] = OneByteString(isolate, url->scheme.c_str());
1884 if (url->flags & URL_FLAGS_HAS_USERNAME)
1885 argv[ARG_USERNAME] =
UTF8STRING(isolate, url->username);
1886 if (url->flags & URL_FLAGS_HAS_PASSWORD)
1887 argv[ARG_PASSWORD] =
UTF8STRING(isolate, url->password);
1888 if (url->flags & URL_FLAGS_HAS_HOST)
1889 argv[ARG_HOST] =
UTF8STRING(isolate, url->host);
1890 if (url->flags & URL_FLAGS_HAS_QUERY)
1891 argv[ARG_QUERY] =
UTF8STRING(isolate, url->query);
1892 if (url->flags & URL_FLAGS_HAS_FRAGMENT)
1893 argv[ARG_FRAGMENT] =
UTF8STRING(isolate, url->fragment);
1896 if (url->flags & URL_FLAGS_HAS_PATH)
1897 argv[ARG_PATH] = Copy(env, url->path);
1900 static void Parse(Environment* env,
1904 enum url_parse_state state_override,
1905 Local<Value> base_obj,
1906 Local<Value> context_obj,
1908 Local<Value> error_cb) {
1909 Isolate* isolate = env->isolate();
1910 Local<Context> context = env->context();
1911 HandleScope handle_scope(isolate);
1912 Context::Scope context_scope(context);
1914 const bool has_context = context_obj->IsObject();
1915 const bool has_base = base_obj->IsObject();
1917 struct url_data base;
1918 struct url_data url;
1920 HarvestContext(env, &url, context_obj.As<Object>());
1922 HarvestBase(env, &base, base_obj.As<Object>());
1924 URL::Parse(input, len, state_override, &url, has_context, &base, has_base);
1925 if ((url.flags & URL_FLAGS_INVALID_PARSE_STATE) ||
1926 ((state_override != kUnknownState) &&
1927 (url.flags & URL_FLAGS_TERMINATED)))
1931 const Local<Value> undef = Undefined(isolate);
1932 const Local<Value> null = Null(isolate);
1933 if (!(url.flags & URL_FLAGS_FAILED)) {
1934 Local<Value> argv[9] = {
1945 SetArgs(env, argv, &url);
1946 cb->Call(context, recv, arraysize(argv), argv).FromMaybe(Local<Value>());
1947 }
else if (error_cb->IsFunction()) {
1948 Local<Value> argv[2] = { undef, undef };
1949 argv[ERR_ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url.flags);
1950 argv[ERR_ARG_INPUT] =
1951 String::NewFromUtf8(env->isolate(),
1953 v8::NewStringType::kNormal).ToLocalChecked();
1954 error_cb.As<Function>()->Call(context, recv, arraysize(argv), argv)
1955 .FromMaybe(Local<Value>());
1959 static void Parse(
const FunctionCallbackInfo<Value>& args) {
1960 Environment* env = Environment::GetCurrent(args);
1961 CHECK_GE(args.Length(), 5);
1962 CHECK(args[0]->IsString());
1963 CHECK(args[2]->IsUndefined() ||
1964 args[2]->IsNull() ||
1965 args[2]->IsObject());
1966 CHECK(args[3]->IsUndefined() ||
1967 args[3]->IsNull() ||
1968 args[3]->IsObject());
1969 CHECK(args[4]->IsFunction());
1970 CHECK(args[5]->IsUndefined() || args[5]->IsFunction());
1972 Utf8Value input(env->isolate(), args[0]);
1973 enum url_parse_state state_override = kUnknownState;
1974 if (args[1]->IsNumber()) {
1975 state_override =
static_cast<enum url_parse_state
>(
1976 args[1]->Uint32Value(env->context()).FromJust());
1979 Parse(env, args.This(),
1980 *input, input.length(),
1984 args[4].As<Function>(),
1988 static void EncodeAuthSet(
const FunctionCallbackInfo<Value>& args) {
1989 Environment* env = Environment::GetCurrent(args);
1990 CHECK_GE(args.Length(), 1);
1991 CHECK(args[0]->IsString());
1992 Utf8Value value(env->isolate(), args[0]);
1994 const size_t len = value.length();
1995 output.reserve(len);
1996 for (
size_t n = 0;
n <
len;
n++) {
1997 const char ch = (*value)[
n];
1998 AppendOrEscape(&output, ch, USERINFO_ENCODE_SET);
2000 args.GetReturnValue().Set(
2001 String::NewFromUtf8(env->isolate(),
2003 v8::NewStringType::kNormal).ToLocalChecked());
2006 static void ToUSVString(
const FunctionCallbackInfo<Value>& args) {
2007 Environment* env = Environment::GetCurrent(args);
2008 CHECK_GE(args.Length(), 2);
2009 CHECK(args[0]->IsString());
2010 CHECK(args[1]->IsNumber());
2012 TwoByteValue value(env->isolate(), args[0]);
2013 const size_t n = value.length();
2015 const int64_t start = args[1]->IntegerValue(env->context()).FromJust();
2018 for (
size_t i = start; i <
n; i++) {
2020 if (!IsUnicodeSurrogate(c)) {
2022 }
else if (IsUnicodeSurrogateTrail(c) || i == n - 1) {
2023 value[i] = kUnicodeReplacementCharacter;
2026 if (IsUnicodeTrail(d)) {
2029 value[i] = kUnicodeReplacementCharacter;
2034 args.GetReturnValue().Set(
2035 String::NewFromTwoByte(env->isolate(),
2037 v8::NewStringType::kNormal,
2038 n).ToLocalChecked());
2041 static void DomainToASCII(
const FunctionCallbackInfo<Value>& args) {
2042 Environment* env = Environment::GetCurrent(args);
2043 CHECK_GE(args.Length(), 1);
2044 CHECK(args[0]->IsString());
2045 Utf8Value value(env->isolate(), args[0]);
2049 ParseHost(&host, *value, value.length(),
true);
2051 args.GetReturnValue().Set(FIXED_ONE_BYTE_STRING(env->isolate(),
""));
2055 WriteHost(&host, &out);
2056 args.GetReturnValue().Set(
2057 String::NewFromUtf8(env->isolate(),
2059 v8::NewStringType::kNormal).ToLocalChecked());
2062 static void DomainToUnicode(
const FunctionCallbackInfo<Value>& args) {
2063 Environment* env = Environment::GetCurrent(args);
2064 CHECK_GE(args.Length(), 1);
2065 CHECK(args[0]->IsString());
2066 Utf8Value value(env->isolate(), args[0]);
2070 ParseHost(&host, *value, value.length(),
true,
true);
2072 args.GetReturnValue().Set(FIXED_ONE_BYTE_STRING(env->isolate(),
""));
2076 WriteHost(&host, &out);
2077 args.GetReturnValue().Set(
2078 String::NewFromUtf8(env->isolate(),
2080 v8::NewStringType::kNormal).ToLocalChecked());
2083 std::string URL::ToFilePath() {
2089 const char* slash =
"\\";
2090 auto is_slash = [] (
char ch) {
2091 return ch ==
'/' || ch ==
'\\';
2094 const char* slash =
"/";
2095 auto is_slash = [] (
char ch) {
2098 if ((
context_.flags & URL_FLAGS_HAS_HOST) &&
2103 std::string decoded_path;
2104 for (std::string& part :
context_.path) {
2105 std::string decoded;
2106 PercentDecode(part.c_str(), part.length(), &decoded);
2107 for (
char& ch : decoded) {
2112 decoded_path += slash + decoded;
2123 if ((
context_.flags & URL_FLAGS_HAS_HOST) &&
2125 std::string unicode_host;
2126 if (!ToUnicode(&
context_.host, &unicode_host)) {
2129 return "\\\\" + unicode_host + decoded_path;
2132 if (decoded_path.length() < 3) {
2135 if (decoded_path[2] !=
':' ||
2140 return decoded_path.substr(1);
2142 return decoded_path;
2149 const Local<Value> URL::ToObject(Environment* env)
const {
2150 Isolate* isolate = env->isolate();
2151 Local<Context> context = env->context();
2152 Context::Scope context_scope(context);
2154 const Local<Value> undef = Undefined(isolate);
2155 const Local<Value> null = Null(isolate);
2157 if (
context_.flags & URL_FLAGS_FAILED)
2158 return Local<Value>();
2160 Local<Value> argv[9] = {
2173 TryCatch try_catch(isolate);
2179 MaybeLocal<Value> ret =
2180 env->url_constructor_function()
2181 ->Call(env->context(), undef, 9, argv);
2183 if (ret.IsEmpty()) {
2188 return ret.ToLocalChecked();
2191 static void SetURLConstructor(
const FunctionCallbackInfo<Value>& args) {
2192 Environment* env = Environment::GetCurrent(args);
2193 CHECK_EQ(args.Length(), 1);
2194 CHECK(args[0]->IsFunction());
2195 env->set_url_constructor_function(args[0].As<Function>());
2198 static void Init(Local<Object> target,
2199 Local<Value> unused,
2200 Local<Context> context,
2202 Environment* env = Environment::GetCurrent(context);
2203 env->SetMethod(target,
"parse", Parse);
2204 env->SetMethod(target,
"encodeAuth", EncodeAuthSet);
2205 env->SetMethod(target,
"toUSVString", ToUSVString);
2206 env->SetMethod(target,
"domainToASCII", DomainToASCII);
2207 env->SetMethod(target,
"domainToUnicode", DomainToUnicode);
2208 env->SetMethod(target,
"setURLConstructor", SetURLConstructor);
2210 #define XX(name, _) NODE_DEFINE_CONSTANT(target, name); 2214 #define XX(name) NODE_DEFINE_CONSTANT(target, name);
void ClearFatalExceptionHandlers(Environment *env)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
void FatalException(Isolate *isolate, Local< Value > error, Local< Message > message)
Persistent< Context > context_
#define GET_AND_SET(env, obj, name, data, flag)
#define UTF8STRING(isolate, str)
#define TWO_CHAR_STRING_TEST(bits, name, expr)
CHAR_TEST(8, IsASCIIHexDigit,(IsASCIIDigit(ch)||(ch >='A' &&ch<='F')||(ch >='a' &&ch<='f'))) CHAR_TEST(8
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
#define GET(env, obj, name)