source: trip-planner-front/node_modules/url/url.js@ b738035

Last change on this file since b738035 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 22.8 KB
RevLine 
[6a3a178]1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23
24var punycode = require('punycode');
25var util = require('./util');
26
27exports.parse = urlParse;
28exports.resolve = urlResolve;
29exports.resolveObject = urlResolveObject;
30exports.format = urlFormat;
31
32exports.Url = Url;
33
34function Url() {
35 this.protocol = null;
36 this.slashes = null;
37 this.auth = null;
38 this.host = null;
39 this.port = null;
40 this.hostname = null;
41 this.hash = null;
42 this.search = null;
43 this.query = null;
44 this.pathname = null;
45 this.path = null;
46 this.href = null;
47}
48
49// Reference: RFC 3986, RFC 1808, RFC 2396
50
51// define these here so at least they only have to be
52// compiled once on the first module load.
53var protocolPattern = /^([a-z0-9.+-]+:)/i,
54 portPattern = /:[0-9]*$/,
55
56 // Special case for a simple path URL
57 simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
58
59 // RFC 2396: characters reserved for delimiting URLs.
60 // We actually just auto-escape these.
61 delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
62
63 // RFC 2396: characters not allowed for various reasons.
64 unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
65
66 // Allowed by RFCs, but cause of XSS attacks. Always escape these.
67 autoEscape = ['\''].concat(unwise),
68 // Characters that are never ever allowed in a hostname.
69 // Note that any invalid chars are also handled, but these
70 // are the ones that are *expected* to be seen, so we fast-path
71 // them.
72 nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
73 hostEndingChars = ['/', '?', '#'],
74 hostnameMaxLen = 255,
75 hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
76 hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
77 // protocols that can allow "unsafe" and "unwise" chars.
78 unsafeProtocol = {
79 'javascript': true,
80 'javascript:': true
81 },
82 // protocols that never have a hostname.
83 hostlessProtocol = {
84 'javascript': true,
85 'javascript:': true
86 },
87 // protocols that always contain a // bit.
88 slashedProtocol = {
89 'http': true,
90 'https': true,
91 'ftp': true,
92 'gopher': true,
93 'file': true,
94 'http:': true,
95 'https:': true,
96 'ftp:': true,
97 'gopher:': true,
98 'file:': true
99 },
100 querystring = require('querystring');
101
102function urlParse(url, parseQueryString, slashesDenoteHost) {
103 if (url && util.isObject(url) && url instanceof Url) return url;
104
105 var u = new Url;
106 u.parse(url, parseQueryString, slashesDenoteHost);
107 return u;
108}
109
110Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
111 if (!util.isString(url)) {
112 throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
113 }
114
115 // Copy chrome, IE, opera backslash-handling behavior.
116 // Back slashes before the query string get converted to forward slashes
117 // See: https://code.google.com/p/chromium/issues/detail?id=25916
118 var queryIndex = url.indexOf('?'),
119 splitter =
120 (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',
121 uSplit = url.split(splitter),
122 slashRegex = /\\/g;
123 uSplit[0] = uSplit[0].replace(slashRegex, '/');
124 url = uSplit.join(splitter);
125
126 var rest = url;
127
128 // trim before proceeding.
129 // This is to support parse stuff like " http://foo.com \n"
130 rest = rest.trim();
131
132 if (!slashesDenoteHost && url.split('#').length === 1) {
133 // Try fast path regexp
134 var simplePath = simplePathPattern.exec(rest);
135 if (simplePath) {
136 this.path = rest;
137 this.href = rest;
138 this.pathname = simplePath[1];
139 if (simplePath[2]) {
140 this.search = simplePath[2];
141 if (parseQueryString) {
142 this.query = querystring.parse(this.search.substr(1));
143 } else {
144 this.query = this.search.substr(1);
145 }
146 } else if (parseQueryString) {
147 this.search = '';
148 this.query = {};
149 }
150 return this;
151 }
152 }
153
154 var proto = protocolPattern.exec(rest);
155 if (proto) {
156 proto = proto[0];
157 var lowerProto = proto.toLowerCase();
158 this.protocol = lowerProto;
159 rest = rest.substr(proto.length);
160 }
161
162 // figure out if it's got a host
163 // user@server is *always* interpreted as a hostname, and url
164 // resolution will treat //foo/bar as host=foo,path=bar because that's
165 // how the browser resolves relative URLs.
166 if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
167 var slashes = rest.substr(0, 2) === '//';
168 if (slashes && !(proto && hostlessProtocol[proto])) {
169 rest = rest.substr(2);
170 this.slashes = true;
171 }
172 }
173
174 if (!hostlessProtocol[proto] &&
175 (slashes || (proto && !slashedProtocol[proto]))) {
176
177 // there's a hostname.
178 // the first instance of /, ?, ;, or # ends the host.
179 //
180 // If there is an @ in the hostname, then non-host chars *are* allowed
181 // to the left of the last @ sign, unless some host-ending character
182 // comes *before* the @-sign.
183 // URLs are obnoxious.
184 //
185 // ex:
186 // http://a@b@c/ => user:a@b host:c
187 // http://a@b?@c => user:a host:c path:/?@c
188
189 // v0.12 TODO(isaacs): This is not quite how Chrome does things.
190 // Review our test case against browsers more comprehensively.
191
192 // find the first instance of any hostEndingChars
193 var hostEnd = -1;
194 for (var i = 0; i < hostEndingChars.length; i++) {
195 var hec = rest.indexOf(hostEndingChars[i]);
196 if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
197 hostEnd = hec;
198 }
199
200 // at this point, either we have an explicit point where the
201 // auth portion cannot go past, or the last @ char is the decider.
202 var auth, atSign;
203 if (hostEnd === -1) {
204 // atSign can be anywhere.
205 atSign = rest.lastIndexOf('@');
206 } else {
207 // atSign must be in auth portion.
208 // http://a@b/c@d => host:b auth:a path:/c@d
209 atSign = rest.lastIndexOf('@', hostEnd);
210 }
211
212 // Now we have a portion which is definitely the auth.
213 // Pull that off.
214 if (atSign !== -1) {
215 auth = rest.slice(0, atSign);
216 rest = rest.slice(atSign + 1);
217 this.auth = decodeURIComponent(auth);
218 }
219
220 // the host is the remaining to the left of the first non-host char
221 hostEnd = -1;
222 for (var i = 0; i < nonHostChars.length; i++) {
223 var hec = rest.indexOf(nonHostChars[i]);
224 if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
225 hostEnd = hec;
226 }
227 // if we still have not hit it, then the entire thing is a host.
228 if (hostEnd === -1)
229 hostEnd = rest.length;
230
231 this.host = rest.slice(0, hostEnd);
232 rest = rest.slice(hostEnd);
233
234 // pull out port.
235 this.parseHost();
236
237 // we've indicated that there is a hostname,
238 // so even if it's empty, it has to be present.
239 this.hostname = this.hostname || '';
240
241 // if hostname begins with [ and ends with ]
242 // assume that it's an IPv6 address.
243 var ipv6Hostname = this.hostname[0] === '[' &&
244 this.hostname[this.hostname.length - 1] === ']';
245
246 // validate a little.
247 if (!ipv6Hostname) {
248 var hostparts = this.hostname.split(/\./);
249 for (var i = 0, l = hostparts.length; i < l; i++) {
250 var part = hostparts[i];
251 if (!part) continue;
252 if (!part.match(hostnamePartPattern)) {
253 var newpart = '';
254 for (var j = 0, k = part.length; j < k; j++) {
255 if (part.charCodeAt(j) > 127) {
256 // we replace non-ASCII char with a temporary placeholder
257 // we need this to make sure size of hostname is not
258 // broken by replacing non-ASCII by nothing
259 newpart += 'x';
260 } else {
261 newpart += part[j];
262 }
263 }
264 // we test again with ASCII char only
265 if (!newpart.match(hostnamePartPattern)) {
266 var validParts = hostparts.slice(0, i);
267 var notHost = hostparts.slice(i + 1);
268 var bit = part.match(hostnamePartStart);
269 if (bit) {
270 validParts.push(bit[1]);
271 notHost.unshift(bit[2]);
272 }
273 if (notHost.length) {
274 rest = '/' + notHost.join('.') + rest;
275 }
276 this.hostname = validParts.join('.');
277 break;
278 }
279 }
280 }
281 }
282
283 if (this.hostname.length > hostnameMaxLen) {
284 this.hostname = '';
285 } else {
286 // hostnames are always lower case.
287 this.hostname = this.hostname.toLowerCase();
288 }
289
290 if (!ipv6Hostname) {
291 // IDNA Support: Returns a punycoded representation of "domain".
292 // It only converts parts of the domain name that
293 // have non-ASCII characters, i.e. it doesn't matter if
294 // you call it with a domain that already is ASCII-only.
295 this.hostname = punycode.toASCII(this.hostname);
296 }
297
298 var p = this.port ? ':' + this.port : '';
299 var h = this.hostname || '';
300 this.host = h + p;
301 this.href += this.host;
302
303 // strip [ and ] from the hostname
304 // the host field still retains them, though
305 if (ipv6Hostname) {
306 this.hostname = this.hostname.substr(1, this.hostname.length - 2);
307 if (rest[0] !== '/') {
308 rest = '/' + rest;
309 }
310 }
311 }
312
313 // now rest is set to the post-host stuff.
314 // chop off any delim chars.
315 if (!unsafeProtocol[lowerProto]) {
316
317 // First, make 100% sure that any "autoEscape" chars get
318 // escaped, even if encodeURIComponent doesn't think they
319 // need to be.
320 for (var i = 0, l = autoEscape.length; i < l; i++) {
321 var ae = autoEscape[i];
322 if (rest.indexOf(ae) === -1)
323 continue;
324 var esc = encodeURIComponent(ae);
325 if (esc === ae) {
326 esc = escape(ae);
327 }
328 rest = rest.split(ae).join(esc);
329 }
330 }
331
332
333 // chop off from the tail first.
334 var hash = rest.indexOf('#');
335 if (hash !== -1) {
336 // got a fragment string.
337 this.hash = rest.substr(hash);
338 rest = rest.slice(0, hash);
339 }
340 var qm = rest.indexOf('?');
341 if (qm !== -1) {
342 this.search = rest.substr(qm);
343 this.query = rest.substr(qm + 1);
344 if (parseQueryString) {
345 this.query = querystring.parse(this.query);
346 }
347 rest = rest.slice(0, qm);
348 } else if (parseQueryString) {
349 // no query string, but parseQueryString still requested
350 this.search = '';
351 this.query = {};
352 }
353 if (rest) this.pathname = rest;
354 if (slashedProtocol[lowerProto] &&
355 this.hostname && !this.pathname) {
356 this.pathname = '/';
357 }
358
359 //to support http.request
360 if (this.pathname || this.search) {
361 var p = this.pathname || '';
362 var s = this.search || '';
363 this.path = p + s;
364 }
365
366 // finally, reconstruct the href based on what has been validated.
367 this.href = this.format();
368 return this;
369};
370
371// format a parsed object into a url string
372function urlFormat(obj) {
373 // ensure it's an object, and not a string url.
374 // If it's an obj, this is a no-op.
375 // this way, you can call url_format() on strings
376 // to clean up potentially wonky urls.
377 if (util.isString(obj)) obj = urlParse(obj);
378 if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
379 return obj.format();
380}
381
382Url.prototype.format = function() {
383 var auth = this.auth || '';
384 if (auth) {
385 auth = encodeURIComponent(auth);
386 auth = auth.replace(/%3A/i, ':');
387 auth += '@';
388 }
389
390 var protocol = this.protocol || '',
391 pathname = this.pathname || '',
392 hash = this.hash || '',
393 host = false,
394 query = '';
395
396 if (this.host) {
397 host = auth + this.host;
398 } else if (this.hostname) {
399 host = auth + (this.hostname.indexOf(':') === -1 ?
400 this.hostname :
401 '[' + this.hostname + ']');
402 if (this.port) {
403 host += ':' + this.port;
404 }
405 }
406
407 if (this.query &&
408 util.isObject(this.query) &&
409 Object.keys(this.query).length) {
410 query = querystring.stringify(this.query);
411 }
412
413 var search = this.search || (query && ('?' + query)) || '';
414
415 if (protocol && protocol.substr(-1) !== ':') protocol += ':';
416
417 // only the slashedProtocols get the //. Not mailto:, xmpp:, etc.
418 // unless they had them to begin with.
419 if (this.slashes ||
420 (!protocol || slashedProtocol[protocol]) && host !== false) {
421 host = '//' + (host || '');
422 if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
423 } else if (!host) {
424 host = '';
425 }
426
427 if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
428 if (search && search.charAt(0) !== '?') search = '?' + search;
429
430 pathname = pathname.replace(/[?#]/g, function(match) {
431 return encodeURIComponent(match);
432 });
433 search = search.replace('#', '%23');
434
435 return protocol + host + pathname + search + hash;
436};
437
438function urlResolve(source, relative) {
439 return urlParse(source, false, true).resolve(relative);
440}
441
442Url.prototype.resolve = function(relative) {
443 return this.resolveObject(urlParse(relative, false, true)).format();
444};
445
446function urlResolveObject(source, relative) {
447 if (!source) return relative;
448 return urlParse(source, false, true).resolveObject(relative);
449}
450
451Url.prototype.resolveObject = function(relative) {
452 if (util.isString(relative)) {
453 var rel = new Url();
454 rel.parse(relative, false, true);
455 relative = rel;
456 }
457
458 var result = new Url();
459 var tkeys = Object.keys(this);
460 for (var tk = 0; tk < tkeys.length; tk++) {
461 var tkey = tkeys[tk];
462 result[tkey] = this[tkey];
463 }
464
465 // hash is always overridden, no matter what.
466 // even href="" will remove it.
467 result.hash = relative.hash;
468
469 // if the relative url is empty, then there's nothing left to do here.
470 if (relative.href === '') {
471 result.href = result.format();
472 return result;
473 }
474
475 // hrefs like //foo/bar always cut to the protocol.
476 if (relative.slashes && !relative.protocol) {
477 // take everything except the protocol from relative
478 var rkeys = Object.keys(relative);
479 for (var rk = 0; rk < rkeys.length; rk++) {
480 var rkey = rkeys[rk];
481 if (rkey !== 'protocol')
482 result[rkey] = relative[rkey];
483 }
484
485 //urlParse appends trailing / to urls like http://www.example.com
486 if (slashedProtocol[result.protocol] &&
487 result.hostname && !result.pathname) {
488 result.path = result.pathname = '/';
489 }
490
491 result.href = result.format();
492 return result;
493 }
494
495 if (relative.protocol && relative.protocol !== result.protocol) {
496 // if it's a known url protocol, then changing
497 // the protocol does weird things
498 // first, if it's not file:, then we MUST have a host,
499 // and if there was a path
500 // to begin with, then we MUST have a path.
501 // if it is file:, then the host is dropped,
502 // because that's known to be hostless.
503 // anything else is assumed to be absolute.
504 if (!slashedProtocol[relative.protocol]) {
505 var keys = Object.keys(relative);
506 for (var v = 0; v < keys.length; v++) {
507 var k = keys[v];
508 result[k] = relative[k];
509 }
510 result.href = result.format();
511 return result;
512 }
513
514 result.protocol = relative.protocol;
515 if (!relative.host && !hostlessProtocol[relative.protocol]) {
516 var relPath = (relative.pathname || '').split('/');
517 while (relPath.length && !(relative.host = relPath.shift()));
518 if (!relative.host) relative.host = '';
519 if (!relative.hostname) relative.hostname = '';
520 if (relPath[0] !== '') relPath.unshift('');
521 if (relPath.length < 2) relPath.unshift('');
522 result.pathname = relPath.join('/');
523 } else {
524 result.pathname = relative.pathname;
525 }
526 result.search = relative.search;
527 result.query = relative.query;
528 result.host = relative.host || '';
529 result.auth = relative.auth;
530 result.hostname = relative.hostname || relative.host;
531 result.port = relative.port;
532 // to support http.request
533 if (result.pathname || result.search) {
534 var p = result.pathname || '';
535 var s = result.search || '';
536 result.path = p + s;
537 }
538 result.slashes = result.slashes || relative.slashes;
539 result.href = result.format();
540 return result;
541 }
542
543 var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
544 isRelAbs = (
545 relative.host ||
546 relative.pathname && relative.pathname.charAt(0) === '/'
547 ),
548 mustEndAbs = (isRelAbs || isSourceAbs ||
549 (result.host && relative.pathname)),
550 removeAllDots = mustEndAbs,
551 srcPath = result.pathname && result.pathname.split('/') || [],
552 relPath = relative.pathname && relative.pathname.split('/') || [],
553 psychotic = result.protocol && !slashedProtocol[result.protocol];
554
555 // if the url is a non-slashed url, then relative
556 // links like ../.. should be able
557 // to crawl up to the hostname, as well. This is strange.
558 // result.protocol has already been set by now.
559 // Later on, put the first path part into the host field.
560 if (psychotic) {
561 result.hostname = '';
562 result.port = null;
563 if (result.host) {
564 if (srcPath[0] === '') srcPath[0] = result.host;
565 else srcPath.unshift(result.host);
566 }
567 result.host = '';
568 if (relative.protocol) {
569 relative.hostname = null;
570 relative.port = null;
571 if (relative.host) {
572 if (relPath[0] === '') relPath[0] = relative.host;
573 else relPath.unshift(relative.host);
574 }
575 relative.host = null;
576 }
577 mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
578 }
579
580 if (isRelAbs) {
581 // it's absolute.
582 result.host = (relative.host || relative.host === '') ?
583 relative.host : result.host;
584 result.hostname = (relative.hostname || relative.hostname === '') ?
585 relative.hostname : result.hostname;
586 result.search = relative.search;
587 result.query = relative.query;
588 srcPath = relPath;
589 // fall through to the dot-handling below.
590 } else if (relPath.length) {
591 // it's relative
592 // throw away the existing file, and take the new path instead.
593 if (!srcPath) srcPath = [];
594 srcPath.pop();
595 srcPath = srcPath.concat(relPath);
596 result.search = relative.search;
597 result.query = relative.query;
598 } else if (!util.isNullOrUndefined(relative.search)) {
599 // just pull out the search.
600 // like href='?foo'.
601 // Put this after the other two cases because it simplifies the booleans
602 if (psychotic) {
603 result.hostname = result.host = srcPath.shift();
604 //occationaly the auth can get stuck only in host
605 //this especially happens in cases like
606 //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
607 var authInHost = result.host && result.host.indexOf('@') > 0 ?
608 result.host.split('@') : false;
609 if (authInHost) {
610 result.auth = authInHost.shift();
611 result.host = result.hostname = authInHost.shift();
612 }
613 }
614 result.search = relative.search;
615 result.query = relative.query;
616 //to support http.request
617 if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
618 result.path = (result.pathname ? result.pathname : '') +
619 (result.search ? result.search : '');
620 }
621 result.href = result.format();
622 return result;
623 }
624
625 if (!srcPath.length) {
626 // no path at all. easy.
627 // we've already handled the other stuff above.
628 result.pathname = null;
629 //to support http.request
630 if (result.search) {
631 result.path = '/' + result.search;
632 } else {
633 result.path = null;
634 }
635 result.href = result.format();
636 return result;
637 }
638
639 // if a url ENDs in . or .., then it must get a trailing slash.
640 // however, if it ends in anything else non-slashy,
641 // then it must NOT get a trailing slash.
642 var last = srcPath.slice(-1)[0];
643 var hasTrailingSlash = (
644 (result.host || relative.host || srcPath.length > 1) &&
645 (last === '.' || last === '..') || last === '');
646
647 // strip single dots, resolve double dots to parent dir
648 // if the path tries to go above the root, `up` ends up > 0
649 var up = 0;
650 for (var i = srcPath.length; i >= 0; i--) {
651 last = srcPath[i];
652 if (last === '.') {
653 srcPath.splice(i, 1);
654 } else if (last === '..') {
655 srcPath.splice(i, 1);
656 up++;
657 } else if (up) {
658 srcPath.splice(i, 1);
659 up--;
660 }
661 }
662
663 // if the path is allowed to go above the root, restore leading ..s
664 if (!mustEndAbs && !removeAllDots) {
665 for (; up--; up) {
666 srcPath.unshift('..');
667 }
668 }
669
670 if (mustEndAbs && srcPath[0] !== '' &&
671 (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
672 srcPath.unshift('');
673 }
674
675 if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
676 srcPath.push('');
677 }
678
679 var isAbsolute = srcPath[0] === '' ||
680 (srcPath[0] && srcPath[0].charAt(0) === '/');
681
682 // put the host back
683 if (psychotic) {
684 result.hostname = result.host = isAbsolute ? '' :
685 srcPath.length ? srcPath.shift() : '';
686 //occationaly the auth can get stuck only in host
687 //this especially happens in cases like
688 //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
689 var authInHost = result.host && result.host.indexOf('@') > 0 ?
690 result.host.split('@') : false;
691 if (authInHost) {
692 result.auth = authInHost.shift();
693 result.host = result.hostname = authInHost.shift();
694 }
695 }
696
697 mustEndAbs = mustEndAbs || (result.host && srcPath.length);
698
699 if (mustEndAbs && !isAbsolute) {
700 srcPath.unshift('');
701 }
702
703 if (!srcPath.length) {
704 result.pathname = null;
705 result.path = null;
706 } else {
707 result.pathname = srcPath.join('/');
708 }
709
710 //to support request.http
711 if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
712 result.path = (result.pathname ? result.pathname : '') +
713 (result.search ? result.search : '');
714 }
715 result.auth = relative.auth || result.auth;
716 result.slashes = result.slashes || relative.slashes;
717 result.href = result.format();
718 return result;
719};
720
721Url.prototype.parseHost = function() {
722 var host = this.host;
723 var port = portPattern.exec(host);
724 if (port) {
725 port = port[0];
726 if (port !== ':') {
727 this.port = port.substr(1);
728 }
729 host = host.substr(0, host.length - port.length);
730 }
731 if (host) this.hostname = host;
732};
Note: See TracBrowser for help on using the repository browser.