1 | 'use strict';
|
2 |
|
3 | require('../modules/es.string.iterator');
|
4 | var $ = require('../internals/export');
|
5 | var DESCRIPTORS = require('../internals/descriptors');
|
6 | var USE_NATIVE_URL = require('../internals/native-url');
|
7 | var global = require('../internals/global');
|
8 | var defineProperties = require('../internals/object-define-properties');
|
9 | var redefine = require('../internals/redefine');
|
10 | var anInstance = require('../internals/an-instance');
|
11 | var has = require('../internals/has');
|
12 | var assign = require('../internals/object-assign');
|
13 | var arrayFrom = require('../internals/array-from');
|
14 | var codeAt = require('../internals/string-multibyte').codeAt;
|
15 | var toASCII = require('../internals/punycode-to-ascii');
|
16 | var setToStringTag = require('../internals/set-to-string-tag');
|
17 | var URLSearchParamsModule = require('../modules/web.url-search-params');
|
18 | var InternalStateModule = require('../internals/internal-state');
|
19 |
|
20 | var NativeURL = global.URL;
|
21 | var URLSearchParams = URLSearchParamsModule.URLSearchParams;
|
22 | var getInternalSearchParamsState = URLSearchParamsModule.getState;
|
23 | var setInternalState = InternalStateModule.set;
|
24 | var getInternalURLState = InternalStateModule.getterFor('URL');
|
25 | var floor = Math.floor;
|
26 | var pow = Math.pow;
|
27 |
|
28 | var INVALID_AUTHORITY = 'Invalid authority';
|
29 | var INVALID_SCHEME = 'Invalid scheme';
|
30 | var INVALID_HOST = 'Invalid host';
|
31 | var INVALID_PORT = 'Invalid port';
|
32 |
|
33 | var ALPHA = /[A-Za-z]/;
|
34 | var ALPHANUMERIC = /[\d+\-.A-Za-z]/;
|
35 | var DIGIT = /\d/;
|
36 | var HEX_START = /^(0x|0X)/;
|
37 | var OCT = /^[0-7]+$/;
|
38 | var DEC = /^\d+$/;
|
39 | var HEX = /^[\dA-Fa-f]+$/;
|
40 |
|
41 | var FORBIDDEN_HOST_CODE_POINT = /[\u0000\u0009\u000A\u000D #%/:?@[\\]]/;
|
42 |
|
43 | var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\u0000\u0009\u000A\u000D #/:?@[\\]]/;
|
44 |
|
45 | var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g;
|
46 |
|
47 | var TAB_AND_NEW_LINE = /[\u0009\u000A\u000D]/g;
|
48 | var EOF;
|
49 |
|
50 | var parseHost = function (url, input) {
|
51 | var result, codePoints, index;
|
52 | if (input.charAt(0) == '[') {
|
53 | if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
|
54 | result = parseIPv6(input.slice(1, -1));
|
55 | if (!result) return INVALID_HOST;
|
56 | url.host = result;
|
57 |
|
58 | } else if (!isSpecial(url)) {
|
59 | if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
|
60 | result = '';
|
61 | codePoints = arrayFrom(input);
|
62 | for (index = 0; index < codePoints.length; index++) {
|
63 | result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
|
64 | }
|
65 | url.host = result;
|
66 | } else {
|
67 | input = toASCII(input);
|
68 | if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
|
69 | result = parseIPv4(input);
|
70 | if (result === null) return INVALID_HOST;
|
71 | url.host = result;
|
72 | }
|
73 | };
|
74 |
|
75 | var parseIPv4 = function (input) {
|
76 | var parts = input.split('.');
|
77 | var partsLength, numbers, index, part, radix, number, ipv4;
|
78 | if (parts.length && parts[parts.length - 1] == '') {
|
79 | parts.pop();
|
80 | }
|
81 | partsLength = parts.length;
|
82 | if (partsLength > 4) return input;
|
83 | numbers = [];
|
84 | for (index = 0; index < partsLength; index++) {
|
85 | part = parts[index];
|
86 | if (part == '') return input;
|
87 | radix = 10;
|
88 | if (part.length > 1 && part.charAt(0) == '0') {
|
89 | radix = HEX_START.test(part) ? 16 : 8;
|
90 | part = part.slice(radix == 8 ? 1 : 2);
|
91 | }
|
92 | if (part === '') {
|
93 | number = 0;
|
94 | } else {
|
95 | if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
|
96 | number = parseInt(part, radix);
|
97 | }
|
98 | numbers.push(number);
|
99 | }
|
100 | for (index = 0; index < partsLength; index++) {
|
101 | number = numbers[index];
|
102 | if (index == partsLength - 1) {
|
103 | if (number >= pow(256, 5 - partsLength)) return null;
|
104 | } else if (number > 255) return null;
|
105 | }
|
106 | ipv4 = numbers.pop();
|
107 | for (index = 0; index < numbers.length; index++) {
|
108 | ipv4 += numbers[index] * pow(256, 3 - index);
|
109 | }
|
110 | return ipv4;
|
111 | };
|
112 |
|
113 |
|
114 | var parseIPv6 = function (input) {
|
115 | var address = [0, 0, 0, 0, 0, 0, 0, 0];
|
116 | var pieceIndex = 0;
|
117 | var compress = null;
|
118 | var pointer = 0;
|
119 | var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
|
120 |
|
121 | var char = function () {
|
122 | return input.charAt(pointer);
|
123 | };
|
124 |
|
125 | if (char() == ':') {
|
126 | if (input.charAt(1) != ':') return;
|
127 | pointer += 2;
|
128 | pieceIndex++;
|
129 | compress = pieceIndex;
|
130 | }
|
131 | while (char()) {
|
132 | if (pieceIndex == 8) return;
|
133 | if (char() == ':') {
|
134 | if (compress !== null) return;
|
135 | pointer++;
|
136 | pieceIndex++;
|
137 | compress = pieceIndex;
|
138 | continue;
|
139 | }
|
140 | value = length = 0;
|
141 | while (length < 4 && HEX.test(char())) {
|
142 | value = value * 16 + parseInt(char(), 16);
|
143 | pointer++;
|
144 | length++;
|
145 | }
|
146 | if (char() == '.') {
|
147 | if (length == 0) return;
|
148 | pointer -= length;
|
149 | if (pieceIndex > 6) return;
|
150 | numbersSeen = 0;
|
151 | while (char()) {
|
152 | ipv4Piece = null;
|
153 | if (numbersSeen > 0) {
|
154 | if (char() == '.' && numbersSeen < 4) pointer++;
|
155 | else return;
|
156 | }
|
157 | if (!DIGIT.test(char())) return;
|
158 | while (DIGIT.test(char())) {
|
159 | number = parseInt(char(), 10);
|
160 | if (ipv4Piece === null) ipv4Piece = number;
|
161 | else if (ipv4Piece == 0) return;
|
162 | else ipv4Piece = ipv4Piece * 10 + number;
|
163 | if (ipv4Piece > 255) return;
|
164 | pointer++;
|
165 | }
|
166 | address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
|
167 | numbersSeen++;
|
168 | if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
|
169 | }
|
170 | if (numbersSeen != 4) return;
|
171 | break;
|
172 | } else if (char() == ':') {
|
173 | pointer++;
|
174 | if (!char()) return;
|
175 | } else if (char()) return;
|
176 | address[pieceIndex++] = value;
|
177 | }
|
178 | if (compress !== null) {
|
179 | swaps = pieceIndex - compress;
|
180 | pieceIndex = 7;
|
181 | while (pieceIndex != 0 && swaps > 0) {
|
182 | swap = address[pieceIndex];
|
183 | address[pieceIndex--] = address[compress + swaps - 1];
|
184 | address[compress + --swaps] = swap;
|
185 | }
|
186 | } else if (pieceIndex != 8) return;
|
187 | return address;
|
188 | };
|
189 |
|
190 | var findLongestZeroSequence = function (ipv6) {
|
191 | var maxIndex = null;
|
192 | var maxLength = 1;
|
193 | var currStart = null;
|
194 | var currLength = 0;
|
195 | var index = 0;
|
196 | for (; index < 8; index++) {
|
197 | if (ipv6[index] !== 0) {
|
198 | if (currLength > maxLength) {
|
199 | maxIndex = currStart;
|
200 | maxLength = currLength;
|
201 | }
|
202 | currStart = null;
|
203 | currLength = 0;
|
204 | } else {
|
205 | if (currStart === null) currStart = index;
|
206 | ++currLength;
|
207 | }
|
208 | }
|
209 | if (currLength > maxLength) {
|
210 | maxIndex = currStart;
|
211 | maxLength = currLength;
|
212 | }
|
213 | return maxIndex;
|
214 | };
|
215 |
|
216 | var serializeHost = function (host) {
|
217 | var result, index, compress, ignore0;
|
218 |
|
219 | if (typeof host == 'number') {
|
220 | result = [];
|
221 | for (index = 0; index < 4; index++) {
|
222 | result.unshift(host % 256);
|
223 | host = floor(host / 256);
|
224 | } return result.join('.');
|
225 |
|
226 | } else if (typeof host == 'object') {
|
227 | result = '';
|
228 | compress = findLongestZeroSequence(host);
|
229 | for (index = 0; index < 8; index++) {
|
230 | if (ignore0 && host[index] === 0) continue;
|
231 | if (ignore0) ignore0 = false;
|
232 | if (compress === index) {
|
233 | result += index ? ':' : '::';
|
234 | ignore0 = true;
|
235 | } else {
|
236 | result += host[index].toString(16);
|
237 | if (index < 7) result += ':';
|
238 | }
|
239 | }
|
240 | return '[' + result + ']';
|
241 | } return host;
|
242 | };
|
243 |
|
244 | var C0ControlPercentEncodeSet = {};
|
245 | var fragmentPercentEncodeSet = assign({}, C0ControlPercentEncodeSet, {
|
246 | ' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
|
247 | });
|
248 | var pathPercentEncodeSet = assign({}, fragmentPercentEncodeSet, {
|
249 | '#': 1, '?': 1, '{': 1, '}': 1
|
250 | });
|
251 | var userinfoPercentEncodeSet = assign({}, pathPercentEncodeSet, {
|
252 | '/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
|
253 | });
|
254 |
|
255 | var percentEncode = function (char, set) {
|
256 | var code = codeAt(char, 0);
|
257 | return code > 0x20 && code < 0x7F && !has(set, char) ? char : encodeURIComponent(char);
|
258 | };
|
259 |
|
260 | var specialSchemes = {
|
261 | ftp: 21,
|
262 | file: null,
|
263 | http: 80,
|
264 | https: 443,
|
265 | ws: 80,
|
266 | wss: 443
|
267 | };
|
268 |
|
269 | var isSpecial = function (url) {
|
270 | return has(specialSchemes, url.scheme);
|
271 | };
|
272 |
|
273 | var includesCredentials = function (url) {
|
274 | return url.username != '' || url.password != '';
|
275 | };
|
276 |
|
277 | var cannotHaveUsernamePasswordPort = function (url) {
|
278 | return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
|
279 | };
|
280 |
|
281 | var isWindowsDriveLetter = function (string, normalized) {
|
282 | var second;
|
283 | return string.length == 2 && ALPHA.test(string.charAt(0))
|
284 | && ((second = string.charAt(1)) == ':' || (!normalized && second == '|'));
|
285 | };
|
286 |
|
287 | var startsWithWindowsDriveLetter = function (string) {
|
288 | var third;
|
289 | return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (
|
290 | string.length == 2 ||
|
291 | ((third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#')
|
292 | );
|
293 | };
|
294 |
|
295 | var shortenURLsPath = function (url) {
|
296 | var path = url.path;
|
297 | var pathSize = path.length;
|
298 | if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
|
299 | path.pop();
|
300 | }
|
301 | };
|
302 |
|
303 | var isSingleDot = function (segment) {
|
304 | return segment === '.' || segment.toLowerCase() === '%2e';
|
305 | };
|
306 |
|
307 | var isDoubleDot = function (segment) {
|
308 | segment = segment.toLowerCase();
|
309 | return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
|
310 | };
|
311 |
|
312 |
|
313 | var SCHEME_START = {};
|
314 | var SCHEME = {};
|
315 | var NO_SCHEME = {};
|
316 | var SPECIAL_RELATIVE_OR_AUTHORITY = {};
|
317 | var PATH_OR_AUTHORITY = {};
|
318 | var RELATIVE = {};
|
319 | var RELATIVE_SLASH = {};
|
320 | var SPECIAL_AUTHORITY_SLASHES = {};
|
321 | var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
|
322 | var AUTHORITY = {};
|
323 | var HOST = {};
|
324 | var HOSTNAME = {};
|
325 | var PORT = {};
|
326 | var FILE = {};
|
327 | var FILE_SLASH = {};
|
328 | var FILE_HOST = {};
|
329 | var PATH_START = {};
|
330 | var PATH = {};
|
331 | var CANNOT_BE_A_BASE_URL_PATH = {};
|
332 | var QUERY = {};
|
333 | var FRAGMENT = {};
|
334 |
|
335 |
|
336 | var parseURL = function (url, input, stateOverride, base) {
|
337 | var state = stateOverride || SCHEME_START;
|
338 | var pointer = 0;
|
339 | var buffer = '';
|
340 | var seenAt = false;
|
341 | var seenBracket = false;
|
342 | var seenPasswordToken = false;
|
343 | var codePoints, char, bufferCodePoints, failure;
|
344 |
|
345 | if (!stateOverride) {
|
346 | url.scheme = '';
|
347 | url.username = '';
|
348 | url.password = '';
|
349 | url.host = null;
|
350 | url.port = null;
|
351 | url.path = [];
|
352 | url.query = null;
|
353 | url.fragment = null;
|
354 | url.cannotBeABaseURL = false;
|
355 | input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
|
356 | }
|
357 |
|
358 | input = input.replace(TAB_AND_NEW_LINE, '');
|
359 |
|
360 | codePoints = arrayFrom(input);
|
361 |
|
362 | while (pointer <= codePoints.length) {
|
363 | char = codePoints[pointer];
|
364 | switch (state) {
|
365 | case SCHEME_START:
|
366 | if (char && ALPHA.test(char)) {
|
367 | buffer += char.toLowerCase();
|
368 | state = SCHEME;
|
369 | } else if (!stateOverride) {
|
370 | state = NO_SCHEME;
|
371 | continue;
|
372 | } else return INVALID_SCHEME;
|
373 | break;
|
374 |
|
375 | case SCHEME:
|
376 | if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
|
377 | buffer += char.toLowerCase();
|
378 | } else if (char == ':') {
|
379 | if (stateOverride && (
|
380 | (isSpecial(url) != has(specialSchemes, buffer)) ||
|
381 | (buffer == 'file' && (includesCredentials(url) || url.port !== null)) ||
|
382 | (url.scheme == 'file' && !url.host)
|
383 | )) return;
|
384 | url.scheme = buffer;
|
385 | if (stateOverride) {
|
386 | if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
|
387 | return;
|
388 | }
|
389 | buffer = '';
|
390 | if (url.scheme == 'file') {
|
391 | state = FILE;
|
392 | } else if (isSpecial(url) && base && base.scheme == url.scheme) {
|
393 | state = SPECIAL_RELATIVE_OR_AUTHORITY;
|
394 | } else if (isSpecial(url)) {
|
395 | state = SPECIAL_AUTHORITY_SLASHES;
|
396 | } else if (codePoints[pointer + 1] == '/') {
|
397 | state = PATH_OR_AUTHORITY;
|
398 | pointer++;
|
399 | } else {
|
400 | url.cannotBeABaseURL = true;
|
401 | url.path.push('');
|
402 | state = CANNOT_BE_A_BASE_URL_PATH;
|
403 | }
|
404 | } else if (!stateOverride) {
|
405 | buffer = '';
|
406 | state = NO_SCHEME;
|
407 | pointer = 0;
|
408 | continue;
|
409 | } else return INVALID_SCHEME;
|
410 | break;
|
411 |
|
412 | case NO_SCHEME:
|
413 | if (!base || (base.cannotBeABaseURL && char != '#')) return INVALID_SCHEME;
|
414 | if (base.cannotBeABaseURL && char == '#') {
|
415 | url.scheme = base.scheme;
|
416 | url.path = base.path.slice();
|
417 | url.query = base.query;
|
418 | url.fragment = '';
|
419 | url.cannotBeABaseURL = true;
|
420 | state = FRAGMENT;
|
421 | break;
|
422 | }
|
423 | state = base.scheme == 'file' ? FILE : RELATIVE;
|
424 | continue;
|
425 |
|
426 | case SPECIAL_RELATIVE_OR_AUTHORITY:
|
427 | if (char == '/' && codePoints[pointer + 1] == '/') {
|
428 | state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
|
429 | pointer++;
|
430 | } else {
|
431 | state = RELATIVE;
|
432 | continue;
|
433 | } break;
|
434 |
|
435 | case PATH_OR_AUTHORITY:
|
436 | if (char == '/') {
|
437 | state = AUTHORITY;
|
438 | break;
|
439 | } else {
|
440 | state = PATH;
|
441 | continue;
|
442 | }
|
443 |
|
444 | case RELATIVE:
|
445 | url.scheme = base.scheme;
|
446 | if (char == EOF) {
|
447 | url.username = base.username;
|
448 | url.password = base.password;
|
449 | url.host = base.host;
|
450 | url.port = base.port;
|
451 | url.path = base.path.slice();
|
452 | url.query = base.query;
|
453 | } else if (char == '/' || (char == '\\' && isSpecial(url))) {
|
454 | state = RELATIVE_SLASH;
|
455 | } else if (char == '?') {
|
456 | url.username = base.username;
|
457 | url.password = base.password;
|
458 | url.host = base.host;
|
459 | url.port = base.port;
|
460 | url.path = base.path.slice();
|
461 | url.query = '';
|
462 | state = QUERY;
|
463 | } else if (char == '#') {
|
464 | url.username = base.username;
|
465 | url.password = base.password;
|
466 | url.host = base.host;
|
467 | url.port = base.port;
|
468 | url.path = base.path.slice();
|
469 | url.query = base.query;
|
470 | url.fragment = '';
|
471 | state = FRAGMENT;
|
472 | } else {
|
473 | url.username = base.username;
|
474 | url.password = base.password;
|
475 | url.host = base.host;
|
476 | url.port = base.port;
|
477 | url.path = base.path.slice();
|
478 | url.path.pop();
|
479 | state = PATH;
|
480 | continue;
|
481 | } break;
|
482 |
|
483 | case RELATIVE_SLASH:
|
484 | if (isSpecial(url) && (char == '/' || char == '\\')) {
|
485 | state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
|
486 | } else if (char == '/') {
|
487 | state = AUTHORITY;
|
488 | } else {
|
489 | url.username = base.username;
|
490 | url.password = base.password;
|
491 | url.host = base.host;
|
492 | url.port = base.port;
|
493 | state = PATH;
|
494 | continue;
|
495 | } break;
|
496 |
|
497 | case SPECIAL_AUTHORITY_SLASHES:
|
498 | state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
|
499 | if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
|
500 | pointer++;
|
501 | break;
|
502 |
|
503 | case SPECIAL_AUTHORITY_IGNORE_SLASHES:
|
504 | if (char != '/' && char != '\\') {
|
505 | state = AUTHORITY;
|
506 | continue;
|
507 | } break;
|
508 |
|
509 | case AUTHORITY:
|
510 | if (char == '@') {
|
511 | if (seenAt) buffer = '%40' + buffer;
|
512 | seenAt = true;
|
513 | bufferCodePoints = arrayFrom(buffer);
|
514 | for (var i = 0; i < bufferCodePoints.length; i++) {
|
515 | var codePoint = bufferCodePoints[i];
|
516 | if (codePoint == ':' && !seenPasswordToken) {
|
517 | seenPasswordToken = true;
|
518 | continue;
|
519 | }
|
520 | var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
|
521 | if (seenPasswordToken) url.password += encodedCodePoints;
|
522 | else url.username += encodedCodePoints;
|
523 | }
|
524 | buffer = '';
|
525 | } else if (
|
526 | char == EOF || char == '/' || char == '?' || char == '#' ||
|
527 | (char == '\\' && isSpecial(url))
|
528 | ) {
|
529 | if (seenAt && buffer == '') return INVALID_AUTHORITY;
|
530 | pointer -= arrayFrom(buffer).length + 1;
|
531 | buffer = '';
|
532 | state = HOST;
|
533 | } else buffer += char;
|
534 | break;
|
535 |
|
536 | case HOST:
|
537 | case HOSTNAME:
|
538 | if (stateOverride && url.scheme == 'file') {
|
539 | state = FILE_HOST;
|
540 | continue;
|
541 | } else if (char == ':' && !seenBracket) {
|
542 | if (buffer == '') return INVALID_HOST;
|
543 | failure = parseHost(url, buffer);
|
544 | if (failure) return failure;
|
545 | buffer = '';
|
546 | state = PORT;
|
547 | if (stateOverride == HOSTNAME) return;
|
548 | } else if (
|
549 | char == EOF || char == '/' || char == '?' || char == '#' ||
|
550 | (char == '\\' && isSpecial(url))
|
551 | ) {
|
552 | if (isSpecial(url) && buffer == '') return INVALID_HOST;
|
553 | if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
|
554 | failure = parseHost(url, buffer);
|
555 | if (failure) return failure;
|
556 | buffer = '';
|
557 | state = PATH_START;
|
558 | if (stateOverride) return;
|
559 | continue;
|
560 | } else {
|
561 | if (char == '[') seenBracket = true;
|
562 | else if (char == ']') seenBracket = false;
|
563 | buffer += char;
|
564 | } break;
|
565 |
|
566 | case PORT:
|
567 | if (DIGIT.test(char)) {
|
568 | buffer += char;
|
569 | } else if (
|
570 | char == EOF || char == '/' || char == '?' || char == '#' ||
|
571 | (char == '\\' && isSpecial(url)) ||
|
572 | stateOverride
|
573 | ) {
|
574 | if (buffer != '') {
|
575 | var port = parseInt(buffer, 10);
|
576 | if (port > 0xFFFF) return INVALID_PORT;
|
577 | url.port = (isSpecial(url) && port === specialSchemes[url.scheme]) ? null : port;
|
578 | buffer = '';
|
579 | }
|
580 | if (stateOverride) return;
|
581 | state = PATH_START;
|
582 | continue;
|
583 | } else return INVALID_PORT;
|
584 | break;
|
585 |
|
586 | case FILE:
|
587 | url.scheme = 'file';
|
588 | if (char == '/' || char == '\\') state = FILE_SLASH;
|
589 | else if (base && base.scheme == 'file') {
|
590 | if (char == EOF) {
|
591 | url.host = base.host;
|
592 | url.path = base.path.slice();
|
593 | url.query = base.query;
|
594 | } else if (char == '?') {
|
595 | url.host = base.host;
|
596 | url.path = base.path.slice();
|
597 | url.query = '';
|
598 | state = QUERY;
|
599 | } else if (char == '#') {
|
600 | url.host = base.host;
|
601 | url.path = base.path.slice();
|
602 | url.query = base.query;
|
603 | url.fragment = '';
|
604 | state = FRAGMENT;
|
605 | } else {
|
606 | if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
|
607 | url.host = base.host;
|
608 | url.path = base.path.slice();
|
609 | shortenURLsPath(url);
|
610 | }
|
611 | state = PATH;
|
612 | continue;
|
613 | }
|
614 | } else {
|
615 | state = PATH;
|
616 | continue;
|
617 | } break;
|
618 |
|
619 | case FILE_SLASH:
|
620 | if (char == '/' || char == '\\') {
|
621 | state = FILE_HOST;
|
622 | break;
|
623 | }
|
624 | if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
|
625 | if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);
|
626 | else url.host = base.host;
|
627 | }
|
628 | state = PATH;
|
629 | continue;
|
630 |
|
631 | case FILE_HOST:
|
632 | if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
|
633 | if (!stateOverride && isWindowsDriveLetter(buffer)) {
|
634 | state = PATH;
|
635 | } else if (buffer == '') {
|
636 | url.host = '';
|
637 | if (stateOverride) return;
|
638 | state = PATH_START;
|
639 | } else {
|
640 | failure = parseHost(url, buffer);
|
641 | if (failure) return failure;
|
642 | if (url.host == 'localhost') url.host = '';
|
643 | if (stateOverride) return;
|
644 | buffer = '';
|
645 | state = PATH_START;
|
646 | } continue;
|
647 | } else buffer += char;
|
648 | break;
|
649 |
|
650 | case PATH_START:
|
651 | if (isSpecial(url)) {
|
652 | state = PATH;
|
653 | if (char != '/' && char != '\\') continue;
|
654 | } else if (!stateOverride && char == '?') {
|
655 | url.query = '';
|
656 | state = QUERY;
|
657 | } else if (!stateOverride && char == '#') {
|
658 | url.fragment = '';
|
659 | state = FRAGMENT;
|
660 | } else if (char != EOF) {
|
661 | state = PATH;
|
662 | if (char != '/') continue;
|
663 | } break;
|
664 |
|
665 | case PATH:
|
666 | if (
|
667 | char == EOF || char == '/' ||
|
668 | (char == '\\' && isSpecial(url)) ||
|
669 | (!stateOverride && (char == '?' || char == '#'))
|
670 | ) {
|
671 | if (isDoubleDot(buffer)) {
|
672 | shortenURLsPath(url);
|
673 | if (char != '/' && !(char == '\\' && isSpecial(url))) {
|
674 | url.path.push('');
|
675 | }
|
676 | } else if (isSingleDot(buffer)) {
|
677 | if (char != '/' && !(char == '\\' && isSpecial(url))) {
|
678 | url.path.push('');
|
679 | }
|
680 | } else {
|
681 | if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
|
682 | if (url.host) url.host = '';
|
683 | buffer = buffer.charAt(0) + ':';
|
684 | }
|
685 | url.path.push(buffer);
|
686 | }
|
687 | buffer = '';
|
688 | if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
|
689 | while (url.path.length > 1 && url.path[0] === '') {
|
690 | url.path.shift();
|
691 | }
|
692 | }
|
693 | if (char == '?') {
|
694 | url.query = '';
|
695 | state = QUERY;
|
696 | } else if (char == '#') {
|
697 | url.fragment = '';
|
698 | state = FRAGMENT;
|
699 | }
|
700 | } else {
|
701 | buffer += percentEncode(char, pathPercentEncodeSet);
|
702 | } break;
|
703 |
|
704 | case CANNOT_BE_A_BASE_URL_PATH:
|
705 | if (char == '?') {
|
706 | url.query = '';
|
707 | state = QUERY;
|
708 | } else if (char == '#') {
|
709 | url.fragment = '';
|
710 | state = FRAGMENT;
|
711 | } else if (char != EOF) {
|
712 | url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
|
713 | } break;
|
714 |
|
715 | case QUERY:
|
716 | if (!stateOverride && char == '#') {
|
717 | url.fragment = '';
|
718 | state = FRAGMENT;
|
719 | } else if (char != EOF) {
|
720 | if (char == "'" && isSpecial(url)) url.query += '%27';
|
721 | else if (char == '#') url.query += '%23';
|
722 | else url.query += percentEncode(char, C0ControlPercentEncodeSet);
|
723 | } break;
|
724 |
|
725 | case FRAGMENT:
|
726 | if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
|
727 | break;
|
728 | }
|
729 |
|
730 | pointer++;
|
731 | }
|
732 | };
|
733 |
|
734 |
|
735 |
|
736 | var URLConstructor = function URL(url /* , base */) {
|
737 | var that = anInstance(this, URLConstructor, 'URL');
|
738 | var base = arguments.length > 1 ? arguments[1] : undefined;
|
739 | var urlString = String(url);
|
740 | var state = setInternalState(that, { type: 'URL' });
|
741 | var baseState, failure;
|
742 | if (base !== undefined) {
|
743 | if (base instanceof URLConstructor) baseState = getInternalURLState(base);
|
744 | else {
|
745 | failure = parseURL(baseState = {}, String(base));
|
746 | if (failure) throw TypeError(failure);
|
747 | }
|
748 | }
|
749 | failure = parseURL(state, urlString, null, baseState);
|
750 | if (failure) throw TypeError(failure);
|
751 | var searchParams = state.searchParams = new URLSearchParams();
|
752 | var searchParamsState = getInternalSearchParamsState(searchParams);
|
753 | searchParamsState.updateSearchParams(state.query);
|
754 | searchParamsState.updateURL = function () {
|
755 | state.query = String(searchParams) || null;
|
756 | };
|
757 | if (!DESCRIPTORS) {
|
758 | that.href = serializeURL.call(that);
|
759 | that.origin = getOrigin.call(that);
|
760 | that.protocol = getProtocol.call(that);
|
761 | that.username = getUsername.call(that);
|
762 | that.password = getPassword.call(that);
|
763 | that.host = getHost.call(that);
|
764 | that.hostname = getHostname.call(that);
|
765 | that.port = getPort.call(that);
|
766 | that.pathname = getPathname.call(that);
|
767 | that.search = getSearch.call(that);
|
768 | that.searchParams = getSearchParams.call(that);
|
769 | that.hash = getHash.call(that);
|
770 | }
|
771 | };
|
772 |
|
773 | var URLPrototype = URLConstructor.prototype;
|
774 |
|
775 | var serializeURL = function () {
|
776 | var url = getInternalURLState(this);
|
777 | var scheme = url.scheme;
|
778 | var username = url.username;
|
779 | var password = url.password;
|
780 | var host = url.host;
|
781 | var port = url.port;
|
782 | var path = url.path;
|
783 | var query = url.query;
|
784 | var fragment = url.fragment;
|
785 | var output = scheme + ':';
|
786 | if (host !== null) {
|
787 | output += '//';
|
788 | if (includesCredentials(url)) {
|
789 | output += username + (password ? ':' + password : '') + '@';
|
790 | }
|
791 | output += serializeHost(host);
|
792 | if (port !== null) output += ':' + port;
|
793 | } else if (scheme == 'file') output += '//';
|
794 | output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
|
795 | if (query !== null) output += '?' + query;
|
796 | if (fragment !== null) output += '#' + fragment;
|
797 | return output;
|
798 | };
|
799 |
|
800 | var getOrigin = function () {
|
801 | var url = getInternalURLState(this);
|
802 | var scheme = url.scheme;
|
803 | var port = url.port;
|
804 | if (scheme == 'blob') try {
|
805 | return new URL(scheme.path[0]).origin;
|
806 | } catch (error) {
|
807 | return 'null';
|
808 | }
|
809 | if (scheme == 'file' || !isSpecial(url)) return 'null';
|
810 | return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
|
811 | };
|
812 |
|
813 | var getProtocol = function () {
|
814 | return getInternalURLState(this).scheme + ':';
|
815 | };
|
816 |
|
817 | var getUsername = function () {
|
818 | return getInternalURLState(this).username;
|
819 | };
|
820 |
|
821 | var getPassword = function () {
|
822 | return getInternalURLState(this).password;
|
823 | };
|
824 |
|
825 | var getHost = function () {
|
826 | var url = getInternalURLState(this);
|
827 | var host = url.host;
|
828 | var port = url.port;
|
829 | return host === null ? ''
|
830 | : port === null ? serializeHost(host)
|
831 | : serializeHost(host) + ':' + port;
|
832 | };
|
833 |
|
834 | var getHostname = function () {
|
835 | var host = getInternalURLState(this).host;
|
836 | return host === null ? '' : serializeHost(host);
|
837 | };
|
838 |
|
839 | var getPort = function () {
|
840 | var port = getInternalURLState(this).port;
|
841 | return port === null ? '' : String(port);
|
842 | };
|
843 |
|
844 | var getPathname = function () {
|
845 | var url = getInternalURLState(this);
|
846 | var path = url.path;
|
847 | return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
|
848 | };
|
849 |
|
850 | var getSearch = function () {
|
851 | var query = getInternalURLState(this).query;
|
852 | return query ? '?' + query : '';
|
853 | };
|
854 |
|
855 | var getSearchParams = function () {
|
856 | return getInternalURLState(this).searchParams;
|
857 | };
|
858 |
|
859 | var getHash = function () {
|
860 | var fragment = getInternalURLState(this).fragment;
|
861 | return fragment ? '#' + fragment : '';
|
862 | };
|
863 |
|
864 | var accessorDescriptor = function (getter, setter) {
|
865 | return { get: getter, set: setter, configurable: true, enumerable: true };
|
866 | };
|
867 |
|
868 | if (DESCRIPTORS) {
|
869 | defineProperties(URLPrototype, {
|
870 |
|
871 |
|
872 | href: accessorDescriptor(serializeURL, function (href) {
|
873 | var url = getInternalURLState(this);
|
874 | var urlString = String(href);
|
875 | var failure = parseURL(url, urlString);
|
876 | if (failure) throw TypeError(failure);
|
877 | getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
|
878 | }),
|
879 |
|
880 |
|
881 | origin: accessorDescriptor(getOrigin),
|
882 |
|
883 |
|
884 | protocol: accessorDescriptor(getProtocol, function (protocol) {
|
885 | var url = getInternalURLState(this);
|
886 | parseURL(url, String(protocol) + ':', SCHEME_START);
|
887 | }),
|
888 |
|
889 |
|
890 | username: accessorDescriptor(getUsername, function (username) {
|
891 | var url = getInternalURLState(this);
|
892 | var codePoints = arrayFrom(String(username));
|
893 | if (cannotHaveUsernamePasswordPort(url)) return;
|
894 | url.username = '';
|
895 | for (var i = 0; i < codePoints.length; i++) {
|
896 | url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
|
897 | }
|
898 | }),
|
899 |
|
900 |
|
901 | password: accessorDescriptor(getPassword, function (password) {
|
902 | var url = getInternalURLState(this);
|
903 | var codePoints = arrayFrom(String(password));
|
904 | if (cannotHaveUsernamePasswordPort(url)) return;
|
905 | url.password = '';
|
906 | for (var i = 0; i < codePoints.length; i++) {
|
907 | url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
|
908 | }
|
909 | }),
|
910 |
|
911 |
|
912 | host: accessorDescriptor(getHost, function (host) {
|
913 | var url = getInternalURLState(this);
|
914 | if (url.cannotBeABaseURL) return;
|
915 | parseURL(url, String(host), HOST);
|
916 | }),
|
917 |
|
918 |
|
919 | hostname: accessorDescriptor(getHostname, function (hostname) {
|
920 | var url = getInternalURLState(this);
|
921 | if (url.cannotBeABaseURL) return;
|
922 | parseURL(url, String(hostname), HOSTNAME);
|
923 | }),
|
924 |
|
925 |
|
926 | port: accessorDescriptor(getPort, function (port) {
|
927 | var url = getInternalURLState(this);
|
928 | if (cannotHaveUsernamePasswordPort(url)) return;
|
929 | port = String(port);
|
930 | if (port == '') url.port = null;
|
931 | else parseURL(url, port, PORT);
|
932 | }),
|
933 |
|
934 |
|
935 | pathname: accessorDescriptor(getPathname, function (pathname) {
|
936 | var url = getInternalURLState(this);
|
937 | if (url.cannotBeABaseURL) return;
|
938 | url.path = [];
|
939 | parseURL(url, pathname + '', PATH_START);
|
940 | }),
|
941 |
|
942 |
|
943 | search: accessorDescriptor(getSearch, function (search) {
|
944 | var url = getInternalURLState(this);
|
945 | search = String(search);
|
946 | if (search == '') {
|
947 | url.query = null;
|
948 | } else {
|
949 | if ('?' == search.charAt(0)) search = search.slice(1);
|
950 | url.query = '';
|
951 | parseURL(url, search, QUERY);
|
952 | }
|
953 | getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
|
954 | }),
|
955 |
|
956 |
|
957 | searchParams: accessorDescriptor(getSearchParams),
|
958 |
|
959 |
|
960 | hash: accessorDescriptor(getHash, function (hash) {
|
961 | var url = getInternalURLState(this);
|
962 | hash = String(hash);
|
963 | if (hash == '') {
|
964 | url.fragment = null;
|
965 | return;
|
966 | }
|
967 | if ('#' == hash.charAt(0)) hash = hash.slice(1);
|
968 | url.fragment = '';
|
969 | parseURL(url, hash, FRAGMENT);
|
970 | })
|
971 | });
|
972 | }
|
973 |
|
974 |
|
975 |
|
976 | redefine(URLPrototype, 'toJSON', function toJSON() {
|
977 | return serializeURL.call(this);
|
978 | }, { enumerable: true });
|
979 |
|
980 |
|
981 |
|
982 | redefine(URLPrototype, 'toString', function toString() {
|
983 | return serializeURL.call(this);
|
984 | }, { enumerable: true });
|
985 |
|
986 | if (NativeURL) {
|
987 | var nativeCreateObjectURL = NativeURL.createObjectURL;
|
988 | var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
|
989 |
|
990 |
|
991 |
|
992 | if (nativeCreateObjectURL) redefine(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
|
993 | return nativeCreateObjectURL.apply(NativeURL, arguments);
|
994 | });
|
995 |
|
996 |
|
997 |
|
998 | if (nativeRevokeObjectURL) redefine(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
|
999 | return nativeRevokeObjectURL.apply(NativeURL, arguments);
|
1000 | });
|
1001 | }
|
1002 |
|
1003 | setToStringTag(URLConstructor, 'URL');
|
1004 |
|
1005 | $({ global: true, forced: !USE_NATIVE_URL, sham: !DESCRIPTORS }, {
|
1006 | URL: URLConstructor
|
1007 | });
|