| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 | 
							- // Copyright Joyent, Inc. and other Node contributors.
 
- //
 
- // Permission is hereby granted, free of charge, to any person obtaining a
 
- // copy of this software and associated documentation files (the
 
- // "Software"), to deal in the Software without restriction, including
 
- // without limitation the rights to use, copy, modify, merge, publish,
 
- // distribute, sublicense, and/or sell copies of the Software, and to permit
 
- // persons to whom the Software is furnished to do so, subject to the
 
- // following conditions:
 
- //
 
- // The above copyright notice and this permission notice shall be included
 
- // in all copies or substantial portions of the Software.
 
- //
 
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
- // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 
- // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 
- // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 
- // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 
- // USE OR OTHER DEALINGS IN THE SOFTWARE.
 
- 'use strict';
 
- //
 
- // Changes from joyent/node:
 
- //
 
- // 1. No leading slash in paths,
 
- //    e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/`
 
- //
 
- // 2. Backslashes are not replaced with slashes,
 
- //    so `http:\\example.org\` is treated like a relative path
 
- //
 
- // 3. Trailing colon is treated like a part of the path,
 
- //    i.e. in `http://example.org:foo` pathname is `:foo`
 
- //
 
- // 4. Nothing is URL-encoded in the resulting object,
 
- //    (in joyent/node some chars in auth and paths are encoded)
 
- //
 
- // 5. `url.parse()` does not have `parseQueryString` argument
 
- //
 
- // 6. Removed extraneous result properties: `host`, `path`, `query`, etc.,
 
- //    which can be constructed using other parts of the url.
 
- //
 
- function Url() {
 
-   this.protocol = null;
 
-   this.slashes = null;
 
-   this.auth = null;
 
-   this.port = null;
 
-   this.hostname = null;
 
-   this.hash = null;
 
-   this.search = null;
 
-   this.pathname = null;
 
- }
 
- // Reference: RFC 3986, RFC 1808, RFC 2396
 
- // define these here so at least they only have to be
 
- // compiled once on the first module load.
 
- var protocolPattern = /^([a-z0-9.+-]+:)/i,
 
-     portPattern = /:[0-9]*$/,
 
-     // Special case for a simple path URL
 
-     simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
 
-     // RFC 2396: characters reserved for delimiting URLs.
 
-     // We actually just auto-escape these.
 
-     delims = [ '<', '>', '"', '`', ' ', '\r', '\n', '\t' ],
 
-     // RFC 2396: characters not allowed for various reasons.
 
-     unwise = [ '{', '}', '|', '\\', '^', '`' ].concat(delims),
 
-     // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
 
-     autoEscape = [ '\'' ].concat(unwise),
 
-     // Characters that are never ever allowed in a hostname.
 
-     // Note that any invalid chars are also handled, but these
 
-     // are the ones that are *expected* to be seen, so we fast-path
 
-     // them.
 
-     nonHostChars = [ '%', '/', '?', ';', '#' ].concat(autoEscape),
 
-     hostEndingChars = [ '/', '?', '#' ],
 
-     hostnameMaxLen = 255,
 
-     hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
 
-     hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
 
-     // protocols that can allow "unsafe" and "unwise" chars.
 
-     /* eslint-disable no-script-url */
 
-     // protocols that never have a hostname.
 
-     hostlessProtocol = {
 
-       'javascript': true,
 
-       'javascript:': true
 
-     },
 
-     // protocols that always contain a // bit.
 
-     slashedProtocol = {
 
-       'http': true,
 
-       'https': true,
 
-       'ftp': true,
 
-       'gopher': true,
 
-       'file': true,
 
-       'http:': true,
 
-       'https:': true,
 
-       'ftp:': true,
 
-       'gopher:': true,
 
-       'file:': true
 
-     };
 
-     /* eslint-enable no-script-url */
 
- function urlParse(url, slashesDenoteHost) {
 
-   if (url && url instanceof Url) { return url; }
 
-   var u = new Url();
 
-   u.parse(url, slashesDenoteHost);
 
-   return u;
 
- }
 
- Url.prototype.parse = function(url, slashesDenoteHost) {
 
-   var i, l, lowerProto, hec, slashes,
 
-       rest = url;
 
-   // trim before proceeding.
 
-   // This is to support parse stuff like "  http://foo.com  \n"
 
-   rest = rest.trim();
 
-   if (!slashesDenoteHost && url.split('#').length === 1) {
 
-     // Try fast path regexp
 
-     var simplePath = simplePathPattern.exec(rest);
 
-     if (simplePath) {
 
-       this.pathname = simplePath[1];
 
-       if (simplePath[2]) {
 
-         this.search = simplePath[2];
 
-       }
 
-       return this;
 
-     }
 
-   }
 
-   var proto = protocolPattern.exec(rest);
 
-   if (proto) {
 
-     proto = proto[0];
 
-     lowerProto = proto.toLowerCase();
 
-     this.protocol = proto;
 
-     rest = rest.substr(proto.length);
 
-   }
 
-   // figure out if it's got a host
 
-   // user@server is *always* interpreted as a hostname, and url
 
-   // resolution will treat //foo/bar as host=foo,path=bar because that's
 
-   // how the browser resolves relative URLs.
 
-   if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
 
-     slashes = rest.substr(0, 2) === '//';
 
-     if (slashes && !(proto && hostlessProtocol[proto])) {
 
-       rest = rest.substr(2);
 
-       this.slashes = true;
 
-     }
 
-   }
 
-   if (!hostlessProtocol[proto] &&
 
-       (slashes || (proto && !slashedProtocol[proto]))) {
 
-     // there's a hostname.
 
-     // the first instance of /, ?, ;, or # ends the host.
 
-     //
 
-     // If there is an @ in the hostname, then non-host chars *are* allowed
 
-     // to the left of the last @ sign, unless some host-ending character
 
-     // comes *before* the @-sign.
 
-     // URLs are obnoxious.
 
-     //
 
-     // ex:
 
-     // http://a@b@c/ => user:a@b host:c
 
-     // http://a@b?@c => user:a host:c path:/?@c
 
-     // v0.12 TODO(isaacs): This is not quite how Chrome does things.
 
-     // Review our test case against browsers more comprehensively.
 
-     // find the first instance of any hostEndingChars
 
-     var hostEnd = -1;
 
-     for (i = 0; i < hostEndingChars.length; i++) {
 
-       hec = rest.indexOf(hostEndingChars[i]);
 
-       if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
 
-         hostEnd = hec;
 
-       }
 
-     }
 
-     // at this point, either we have an explicit point where the
 
-     // auth portion cannot go past, or the last @ char is the decider.
 
-     var auth, atSign;
 
-     if (hostEnd === -1) {
 
-       // atSign can be anywhere.
 
-       atSign = rest.lastIndexOf('@');
 
-     } else {
 
-       // atSign must be in auth portion.
 
-       // http://a@b/c@d => host:b auth:a path:/c@d
 
-       atSign = rest.lastIndexOf('@', hostEnd);
 
-     }
 
-     // Now we have a portion which is definitely the auth.
 
-     // Pull that off.
 
-     if (atSign !== -1) {
 
-       auth = rest.slice(0, atSign);
 
-       rest = rest.slice(atSign + 1);
 
-       this.auth = auth;
 
-     }
 
-     // the host is the remaining to the left of the first non-host char
 
-     hostEnd = -1;
 
-     for (i = 0; i < nonHostChars.length; i++) {
 
-       hec = rest.indexOf(nonHostChars[i]);
 
-       if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
 
-         hostEnd = hec;
 
-       }
 
-     }
 
-     // if we still have not hit it, then the entire thing is a host.
 
-     if (hostEnd === -1) {
 
-       hostEnd = rest.length;
 
-     }
 
-     if (rest[hostEnd - 1] === ':') { hostEnd--; }
 
-     var host = rest.slice(0, hostEnd);
 
-     rest = rest.slice(hostEnd);
 
-     // pull out port.
 
-     this.parseHost(host);
 
-     // we've indicated that there is a hostname,
 
-     // so even if it's empty, it has to be present.
 
-     this.hostname = this.hostname || '';
 
-     // if hostname begins with [ and ends with ]
 
-     // assume that it's an IPv6 address.
 
-     var ipv6Hostname = this.hostname[0] === '[' &&
 
-         this.hostname[this.hostname.length - 1] === ']';
 
-     // validate a little.
 
-     if (!ipv6Hostname) {
 
-       var hostparts = this.hostname.split(/\./);
 
-       for (i = 0, l = hostparts.length; i < l; i++) {
 
-         var part = hostparts[i];
 
-         if (!part) { continue; }
 
-         if (!part.match(hostnamePartPattern)) {
 
-           var newpart = '';
 
-           for (var j = 0, k = part.length; j < k; j++) {
 
-             if (part.charCodeAt(j) > 127) {
 
-               // we replace non-ASCII char with a temporary placeholder
 
-               // we need this to make sure size of hostname is not
 
-               // broken by replacing non-ASCII by nothing
 
-               newpart += 'x';
 
-             } else {
 
-               newpart += part[j];
 
-             }
 
-           }
 
-           // we test again with ASCII char only
 
-           if (!newpart.match(hostnamePartPattern)) {
 
-             var validParts = hostparts.slice(0, i);
 
-             var notHost = hostparts.slice(i + 1);
 
-             var bit = part.match(hostnamePartStart);
 
-             if (bit) {
 
-               validParts.push(bit[1]);
 
-               notHost.unshift(bit[2]);
 
-             }
 
-             if (notHost.length) {
 
-               rest = notHost.join('.') + rest;
 
-             }
 
-             this.hostname = validParts.join('.');
 
-             break;
 
-           }
 
-         }
 
-       }
 
-     }
 
-     if (this.hostname.length > hostnameMaxLen) {
 
-       this.hostname = '';
 
-     }
 
-     // strip [ and ] from the hostname
 
-     // the host field still retains them, though
 
-     if (ipv6Hostname) {
 
-       this.hostname = this.hostname.substr(1, this.hostname.length - 2);
 
-     }
 
-   }
 
-   // chop off from the tail first.
 
-   var hash = rest.indexOf('#');
 
-   if (hash !== -1) {
 
-     // got a fragment string.
 
-     this.hash = rest.substr(hash);
 
-     rest = rest.slice(0, hash);
 
-   }
 
-   var qm = rest.indexOf('?');
 
-   if (qm !== -1) {
 
-     this.search = rest.substr(qm);
 
-     rest = rest.slice(0, qm);
 
-   }
 
-   if (rest) { this.pathname = rest; }
 
-   if (slashedProtocol[lowerProto] &&
 
-       this.hostname && !this.pathname) {
 
-     this.pathname = '';
 
-   }
 
-   return this;
 
- };
 
- Url.prototype.parseHost = function(host) {
 
-   var port = portPattern.exec(host);
 
-   if (port) {
 
-     port = port[0];
 
-     if (port !== ':') {
 
-       this.port = port.substr(1);
 
-     }
 
-     host = host.substr(0, host.length - port.length);
 
-   }
 
-   if (host) { this.hostname = host; }
 
- };
 
- module.exports = urlParse;
 
 
  |