summaryrefslogtreecommitdiff
path: root/node_modules/mdurl
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/mdurl')
-rw-r--r--node_modules/mdurl/CHANGELOG.md16
-rw-r--r--node_modules/mdurl/LICENSE45
-rw-r--r--node_modules/mdurl/README.md102
-rw-r--r--node_modules/mdurl/decode.js122
-rw-r--r--node_modules/mdurl/encode.js98
-rw-r--r--node_modules/mdurl/format.js25
-rw-r--r--node_modules/mdurl/index.js7
-rw-r--r--node_modules/mdurl/package.json16
-rw-r--r--node_modules/mdurl/parse.js312
9 files changed, 743 insertions, 0 deletions
diff --git a/node_modules/mdurl/CHANGELOG.md b/node_modules/mdurl/CHANGELOG.md
new file mode 100644
index 0000000..ed33c78
--- /dev/null
+++ b/node_modules/mdurl/CHANGELOG.md
@@ -0,0 +1,16 @@
+1.0.1 / 2015-09-15
+------------------
+
+- Fixed closure compiler compatibility (#1).
+
+
+1.0.0 / 2015-03-04
+------------------
+
+- Added `.decode()`, `.parse()`, `.format()`.
+
+
+0.0.1 / 2015-03-02
+------------------
+
+- First release.
diff --git a/node_modules/mdurl/LICENSE b/node_modules/mdurl/LICENSE
new file mode 100644
index 0000000..3b2c7bf
--- /dev/null
+++ b/node_modules/mdurl/LICENSE
@@ -0,0 +1,45 @@
+Copyright (c) 2015 Vitaly Puzrin, Alex Kocharin.
+
+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.
+
+--------------------------------------------------------------------------------
+
+.parse() is based on Joyent's node.js `url` code:
+
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+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.
diff --git a/node_modules/mdurl/README.md b/node_modules/mdurl/README.md
new file mode 100644
index 0000000..72aebef
--- /dev/null
+++ b/node_modules/mdurl/README.md
@@ -0,0 +1,102 @@
+# mdurl
+
+[![Build Status](https://img.shields.io/travis/markdown-it/mdurl/master.svg?style=flat)](https://travis-ci.org/markdown-it/mdurl)
+[![NPM version](https://img.shields.io/npm/v/mdurl.svg?style=flat)](https://www.npmjs.org/package/mdurl)
+
+> URL utilities for [markdown-it](https://github.com/markdown-it/markdown-it) parser.
+
+
+## API
+
+### .encode(str [, exclude, keepEncoded]) -> String
+
+Percent-encode a string, avoiding double encoding. Don't touch `/a-zA-Z0-9/` +
+excluded chars + `/%[a-fA-F0-9]{2}/` (if not disabled). Broken surrorates are
+replaced with `U+FFFD`.
+
+Params:
+
+- __str__ - input string.
+- __exclude__ - optional, `;/?:@&=+$,-_.!~*'()#`. Additional chars to keep intact
+ (except `/a-zA-Z0-9/`).
+- __keepEncoded__ - optional, `true`. By default it skips already encoded sequences
+ (`/%[a-fA-F0-9]{2}/`). If set to `false`, `%` will be encoded.
+
+
+### encode.defaultChars, encode.componentChars
+
+You can use these constants as second argument to `encode` function.
+
+ - `encode.defaultChars` is the same exclude set as in the standard `encodeURI()` function
+ - `encode.componentChars` is the same exclude set as in the `encodeURIComponent()` function
+
+For example, `encode('something', encode.componentChars, true)` is roughly the equivalent of
+the `encodeURIComponent()` function (except `encode()` doesn't throw).
+
+
+### .decode(str [, exclude]) -> String
+
+Decode percent-encoded string. Invalid percent-encoded sequences (e.g. `%2G`)
+are left as is. Invalid UTF-8 characters are replaced with `U+FFFD`.
+
+
+Params:
+
+- __str__ - input string.
+- __exclude__ - set of characters to leave encoded, optional, `;/?:@&=+$,#`.
+
+
+### decode.defaultChars, decode.componentChars
+
+You can use these constants as second argument to `decode` function.
+
+ - `decode.defaultChars` is the same exclude set as in the standard `decodeURI()` function
+ - `decode.componentChars` is the same exclude set as in the `decodeURIComponent()` function
+
+For example, `decode('something', decode.defaultChars)` has the same behavior as
+`decodeURI('something')` on a correctly encoded input.
+
+
+### .parse(url, slashesDenoteHost) -> urlObs
+
+Parse url string. Similar to node's [url.parse](http://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost), but without any
+normalizations and query string parse.
+
+ - __url__ - input url (string)
+ - __slashesDenoteHost__ - if url starts with `//`, expect a hostname after it. Optional, `false`.
+
+Result (hash):
+
+- protocol
+- slashes
+- auth
+- port
+- hostname
+- hash
+- search
+- pathname
+
+Difference with node's `url`:
+
+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.
+
+
+### .format(urlObject)
+
+Format an object previously obtained with `.parse()` function. Similar to node's
+[url.format](http://nodejs.org/api/url.html#url_url_format_urlobj).
+
+
+## License
+
+[MIT](https://github.com/markdown-it/mdurl/blob/master/LICENSE)
diff --git a/node_modules/mdurl/decode.js b/node_modules/mdurl/decode.js
new file mode 100644
index 0000000..189d7b9
--- /dev/null
+++ b/node_modules/mdurl/decode.js
@@ -0,0 +1,122 @@
+
+'use strict';
+
+
+/* eslint-disable no-bitwise */
+
+var decodeCache = {};
+
+function getDecodeCache(exclude) {
+ var i, ch, cache = decodeCache[exclude];
+ if (cache) { return cache; }
+
+ cache = decodeCache[exclude] = [];
+
+ for (i = 0; i < 128; i++) {
+ ch = String.fromCharCode(i);
+ cache.push(ch);
+ }
+
+ for (i = 0; i < exclude.length; i++) {
+ ch = exclude.charCodeAt(i);
+ cache[ch] = '%' + ('0' + ch.toString(16).toUpperCase()).slice(-2);
+ }
+
+ return cache;
+}
+
+
+// Decode percent-encoded string.
+//
+function decode(string, exclude) {
+ var cache;
+
+ if (typeof exclude !== 'string') {
+ exclude = decode.defaultChars;
+ }
+
+ cache = getDecodeCache(exclude);
+
+ return string.replace(/(%[a-f0-9]{2})+/gi, function(seq) {
+ var i, l, b1, b2, b3, b4, chr,
+ result = '';
+
+ for (i = 0, l = seq.length; i < l; i += 3) {
+ b1 = parseInt(seq.slice(i + 1, i + 3), 16);
+
+ if (b1 < 0x80) {
+ result += cache[b1];
+ continue;
+ }
+
+ if ((b1 & 0xE0) === 0xC0 && (i + 3 < l)) {
+ // 110xxxxx 10xxxxxx
+ b2 = parseInt(seq.slice(i + 4, i + 6), 16);
+
+ if ((b2 & 0xC0) === 0x80) {
+ chr = ((b1 << 6) & 0x7C0) | (b2 & 0x3F);
+
+ if (chr < 0x80) {
+ result += '\ufffd\ufffd';
+ } else {
+ result += String.fromCharCode(chr);
+ }
+
+ i += 3;
+ continue;
+ }
+ }
+
+ if ((b1 & 0xF0) === 0xE0 && (i + 6 < l)) {
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ b2 = parseInt(seq.slice(i + 4, i + 6), 16);
+ b3 = parseInt(seq.slice(i + 7, i + 9), 16);
+
+ if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
+ chr = ((b1 << 12) & 0xF000) | ((b2 << 6) & 0xFC0) | (b3 & 0x3F);
+
+ if (chr < 0x800 || (chr >= 0xD800 && chr <= 0xDFFF)) {
+ result += '\ufffd\ufffd\ufffd';
+ } else {
+ result += String.fromCharCode(chr);
+ }
+
+ i += 6;
+ continue;
+ }
+ }
+
+ if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) {
+ // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx
+ b2 = parseInt(seq.slice(i + 4, i + 6), 16);
+ b3 = parseInt(seq.slice(i + 7, i + 9), 16);
+ b4 = parseInt(seq.slice(i + 10, i + 12), 16);
+
+ if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) {
+ chr = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F);
+
+ if (chr < 0x10000 || chr > 0x10FFFF) {
+ result += '\ufffd\ufffd\ufffd\ufffd';
+ } else {
+ chr -= 0x10000;
+ result += String.fromCharCode(0xD800 + (chr >> 10), 0xDC00 + (chr & 0x3FF));
+ }
+
+ i += 9;
+ continue;
+ }
+ }
+
+ result += '\ufffd';
+ }
+
+ return result;
+ });
+}
+
+
+decode.defaultChars = ';/?:@&=+$,#';
+decode.componentChars = '';
+
+
+module.exports = decode;
diff --git a/node_modules/mdurl/encode.js b/node_modules/mdurl/encode.js
new file mode 100644
index 0000000..6dff4f9
--- /dev/null
+++ b/node_modules/mdurl/encode.js
@@ -0,0 +1,98 @@
+
+'use strict';
+
+
+var encodeCache = {};
+
+
+// Create a lookup array where anything but characters in `chars` string
+// and alphanumeric chars is percent-encoded.
+//
+function getEncodeCache(exclude) {
+ var i, ch, cache = encodeCache[exclude];
+ if (cache) { return cache; }
+
+ cache = encodeCache[exclude] = [];
+
+ for (i = 0; i < 128; i++) {
+ ch = String.fromCharCode(i);
+
+ if (/^[0-9a-z]$/i.test(ch)) {
+ // always allow unencoded alphanumeric characters
+ cache.push(ch);
+ } else {
+ cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2));
+ }
+ }
+
+ for (i = 0; i < exclude.length; i++) {
+ cache[exclude.charCodeAt(i)] = exclude[i];
+ }
+
+ return cache;
+}
+
+
+// Encode unsafe characters with percent-encoding, skipping already
+// encoded sequences.
+//
+// - string - string to encode
+// - exclude - list of characters to ignore (in addition to a-zA-Z0-9)
+// - keepEscaped - don't encode '%' in a correct escape sequence (default: true)
+//
+function encode(string, exclude, keepEscaped) {
+ var i, l, code, nextCode, cache,
+ result = '';
+
+ if (typeof exclude !== 'string') {
+ // encode(string, keepEscaped)
+ keepEscaped = exclude;
+ exclude = encode.defaultChars;
+ }
+
+ if (typeof keepEscaped === 'undefined') {
+ keepEscaped = true;
+ }
+
+ cache = getEncodeCache(exclude);
+
+ for (i = 0, l = string.length; i < l; i++) {
+ code = string.charCodeAt(i);
+
+ if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {
+ if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {
+ result += string.slice(i, i + 3);
+ i += 2;
+ continue;
+ }
+ }
+
+ if (code < 128) {
+ result += cache[code];
+ continue;
+ }
+
+ if (code >= 0xD800 && code <= 0xDFFF) {
+ if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {
+ nextCode = string.charCodeAt(i + 1);
+ if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {
+ result += encodeURIComponent(string[i] + string[i + 1]);
+ i++;
+ continue;
+ }
+ }
+ result += '%EF%BF%BD';
+ continue;
+ }
+
+ result += encodeURIComponent(string[i]);
+ }
+
+ return result;
+}
+
+encode.defaultChars = ";/?:@&=+$,-_.!~*'()#";
+encode.componentChars = "-_.!~*'()";
+
+
+module.exports = encode;
diff --git a/node_modules/mdurl/format.js b/node_modules/mdurl/format.js
new file mode 100644
index 0000000..c4eb9f4
--- /dev/null
+++ b/node_modules/mdurl/format.js
@@ -0,0 +1,25 @@
+
+'use strict';
+
+
+module.exports = function format(url) {
+ var result = '';
+
+ result += url.protocol || '';
+ result += url.slashes ? '//' : '';
+ result += url.auth ? url.auth + '@' : '';
+
+ if (url.hostname && url.hostname.indexOf(':') !== -1) {
+ // ipv6 address
+ result += '[' + url.hostname + ']';
+ } else {
+ result += url.hostname || '';
+ }
+
+ result += url.port ? ':' + url.port : '';
+ result += url.pathname || '';
+ result += url.search || '';
+ result += url.hash || '';
+
+ return result;
+};
diff --git a/node_modules/mdurl/index.js b/node_modules/mdurl/index.js
new file mode 100644
index 0000000..194abff
--- /dev/null
+++ b/node_modules/mdurl/index.js
@@ -0,0 +1,7 @@
+'use strict';
+
+
+module.exports.encode = require('./encode');
+module.exports.decode = require('./decode');
+module.exports.format = require('./format');
+module.exports.parse = require('./parse');
diff --git a/node_modules/mdurl/package.json b/node_modules/mdurl/package.json
new file mode 100644
index 0000000..017d740
--- /dev/null
+++ b/node_modules/mdurl/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "mdurl",
+ "version": "1.0.1",
+ "description": "URL utilities for markdown-it",
+ "repository": "markdown-it/mdurl",
+ "license": "MIT",
+ "scripts": {
+ "test": "make test"
+ },
+ "devDependencies": {
+ "mocha": "*",
+ "eslint": "0.13.0",
+ "eslint-plugin-nodeca": "^1.0.0",
+ "istanbul": "*"
+ }
+}
diff --git a/node_modules/mdurl/parse.js b/node_modules/mdurl/parse.js
new file mode 100644
index 0000000..6c33ac1
--- /dev/null
+++ b/node_modules/mdurl/parse.js
@@ -0,0 +1,312 @@
+// 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;