UNPKG

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