pax_global_header00006660000000000000000000000064125676272200014523gustar00rootroot0000000000000052 comment=7f82d6b09acba099163fede09b4226b4e55a5377 node-url-0.11.0/000077500000000000000000000000001256762722000133275ustar00rootroot00000000000000node-url-0.11.0/.gitignore000066400000000000000000000000571256762722000153210ustar00rootroot00000000000000node_modules .DS_Store npm-debug.log .jshintrc node-url-0.11.0/.npmignore000066400000000000000000000000141256762722000153210ustar00rootroot00000000000000test-url.js node-url-0.11.0/.travis.yml000066400000000000000000000006471256762722000154470ustar00rootroot00000000000000language: node_js node_js: - "0.10" env: global: - secure: OgPRLCzHFh5WbjHEKlghHFW1oOreSF2JVUr3CMaFDi03ngTS2WONSw8mRn8SA6FTldiGGBx1n8orDzUw6cdkB7+tkU3G5B0M0V3vl823NaUFKgxsCM3UGDYfJb3yfAG5cj72rVZoX/ABd1fVuG4vBIlDLxsSlKQFMzUCFoyttr8= - secure: AiZP8GHbyx83ZBhOvOxxtpNcgNHoP+vo5G1a1OYU78EHCgHg8NRyHKyCdrBnPvw6mV2BI/8frZaXAEicsHMtHMofBYn7nibNlaajBPI8AkHtYfNSc+zO+71Kwv7VOTOKKnkMEIkqhHlc6njFoH3QaBNHsgNlzzplPxaIt8vdUVk= node-url-0.11.0/.zuul.yml000066400000000000000000000004661256762722000151350ustar00rootroot00000000000000ui: mocha-tdd browsers: - name: chrome version: latest - name: firefox version: 24..latest - name: safari version: latest - name: ie version: 9..latest - name: iphone version: oldest..latest - name: ipad version: oldest..latest - name: android version: oldest..latest node-url-0.11.0/LICENSE000066400000000000000000000021131256762722000143310ustar00rootroot00000000000000The MIT License (MIT) 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. node-url-0.11.0/README.md000066400000000000000000000070241256762722000146110ustar00rootroot00000000000000# node-url [![Build Status](https://travis-ci.org/defunctzombie/node-url.svg?branch=master)](https://travis-ci.org/defunctzombie/node-url) This module has utilities for URL resolution and parsing meant to have feature parity with node.js core [url](http://nodejs.org/api/url.html) module. ```js var url = require('url'); ``` ## api Parsed URL objects have some or all of the following fields, depending on whether or not they exist in the URL string. Any parts that are not in the URL string will not be in the parsed object. Examples are shown for the URL `'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'` * `href`: The full URL that was originally parsed. Both the protocol and host are lowercased. Example: `'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'` * `protocol`: The request protocol, lowercased. Example: `'http:'` * `host`: The full lowercased host portion of the URL, including port information. Example: `'host.com:8080'` * `auth`: The authentication information portion of a URL. Example: `'user:pass'` * `hostname`: Just the lowercased hostname portion of the host. Example: `'host.com'` * `port`: The port number portion of the host. Example: `'8080'` * `pathname`: The path section of the URL, that comes after the host and before the query, including the initial slash if present. Example: `'/p/a/t/h'` * `search`: The 'query string' portion of the URL, including the leading question mark. Example: `'?query=string'` * `path`: Concatenation of `pathname` and `search`. Example: `'/p/a/t/h?query=string'` * `query`: Either the 'params' portion of the query string, or a querystring-parsed object. Example: `'query=string'` or `{'query':'string'}` * `hash`: The 'fragment' portion of the URL including the pound-sign. Example: `'#hash'` The following methods are provided by the URL module: ### url.parse(urlStr, [parseQueryString], [slashesDenoteHost]) Take a URL string, and return an object. Pass `true` as the second argument to also parse the query string using the `querystring` module. Defaults to `false`. Pass `true` as the third argument to treat `//foo/bar` as `{ host: 'foo', pathname: '/bar' }` rather than `{ pathname: '//foo/bar' }`. Defaults to `false`. ### url.format(urlObj) Take a parsed URL object, and return a formatted URL string. * `href` will be ignored. * `protocol` is treated the same with or without the trailing `:` (colon). * The protocols `http`, `https`, `ftp`, `gopher`, `file` will be postfixed with `://` (colon-slash-slash). * All other protocols `mailto`, `xmpp`, `aim`, `sftp`, `foo`, etc will be postfixed with `:` (colon) * `auth` will be used if present. * `hostname` will only be used if `host` is absent. * `port` will only be used if `host` is absent. * `host` will be used in place of `hostname` and `port` * `pathname` is treated the same with or without the leading `/` (slash) * `search` will be used in place of `query` * `query` (object; see `querystring`) will only be used if `search` is absent. * `search` is treated the same with or without the leading `?` (question mark) * `hash` is treated the same with or without the leading `#` (pound sign, anchor) ### url.resolve(from, to) Take a base URL, and a href URL, and resolve them as a browser would for an anchor tag. Examples: url.resolve('/one/two/three', 'four') // '/one/two/four' url.resolve('http://example.com/', '/one') // 'http://example.com/one' url.resolve('http://example.com/one', '/two') // 'http://example.com/two' node-url-0.11.0/package.json000066400000000000000000000010601256762722000156120ustar00rootroot00000000000000{ "name": "url", "description": "The core `url` packaged standalone for use with Browserify.", "version": "0.11.0", "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" }, "main": "./url.js", "devDependencies": { "assert": "1.1.1", "mocha": "1.18.2", "zuul": "3.3.0" }, "scripts": { "test": "mocha --ui qunit test.js && zuul -- test.js", "test-local": "zuul --local -- test.js" }, "repository": { "type": "git", "url": "https://github.com/defunctzombie/node-url.git" }, "license": "MIT" } node-url-0.11.0/test.js000066400000000000000000001341341256762722000146520ustar00rootroot00000000000000// 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. var assert = require('assert'); var url = require('./url'); // URLs to parse, and expected data // { url : parsed } var parseTests = { '//some_path' : { 'href': '//some_path', 'pathname': '//some_path', 'path': '//some_path' }, 'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h': { protocol: 'http:', slashes: true, host: 'evil-phisher', hostname: 'evil-phisher', pathname: '/foo.html', path: '/foo.html', hash: '#h%5Ca%5Cs%5Ch', href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch' }, 'http:\\\\evil-phisher\\foo.html?json="\\"foo\\""#h\\a\\s\\h': { protocol: 'http:', slashes: true, host: 'evil-phisher', hostname: 'evil-phisher', pathname: '/foo.html', search: '?json=%22%5C%22foo%5C%22%22', query: 'json=%22%5C%22foo%5C%22%22', path: '/foo.html?json=%22%5C%22foo%5C%22%22', hash: '#h%5Ca%5Cs%5Ch', href: 'http://evil-phisher/foo.html?json=%22%5C%22foo%5C%22%22#h%5Ca%5Cs%5Ch' }, 'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h?blarg': { protocol: 'http:', slashes: true, host: 'evil-phisher', hostname: 'evil-phisher', pathname: '/foo.html', path: '/foo.html', hash: '#h%5Ca%5Cs%5Ch?blarg', href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch?blarg' }, 'http:\\\\evil-phisher\\foo.html': { protocol: 'http:', slashes: true, host: 'evil-phisher', hostname: 'evil-phisher', pathname: '/foo.html', path: '/foo.html', href: 'http://evil-phisher/foo.html' }, 'HTTP://www.example.com/' : { 'href': 'http://www.example.com/', 'protocol': 'http:', 'slashes': true, 'host': 'www.example.com', 'hostname': 'www.example.com', 'pathname': '/', 'path': '/' }, 'HTTP://www.example.com' : { 'href': 'http://www.example.com/', 'protocol': 'http:', 'slashes': true, 'host': 'www.example.com', 'hostname': 'www.example.com', 'pathname': '/', 'path': '/' }, 'http://www.ExAmPlE.com/' : { 'href': 'http://www.example.com/', 'protocol': 'http:', 'slashes': true, 'host': 'www.example.com', 'hostname': 'www.example.com', 'pathname': '/', 'path': '/' }, 'http://user:pw@www.ExAmPlE.com/' : { 'href': 'http://user:pw@www.example.com/', 'protocol': 'http:', 'slashes': true, 'auth': 'user:pw', 'host': 'www.example.com', 'hostname': 'www.example.com', 'pathname': '/', 'path': '/' }, 'http://USER:PW@www.ExAmPlE.com/' : { 'href': 'http://USER:PW@www.example.com/', 'protocol': 'http:', 'slashes': true, 'auth': 'USER:PW', 'host': 'www.example.com', 'hostname': 'www.example.com', 'pathname': '/', 'path': '/' }, 'http://user@www.example.com/' : { 'href': 'http://user@www.example.com/', 'protocol': 'http:', 'slashes': true, 'auth': 'user', 'host': 'www.example.com', 'hostname': 'www.example.com', 'pathname': '/', 'path': '/' }, 'http://user%3Apw@www.example.com/' : { 'href': 'http://user:pw@www.example.com/', 'protocol': 'http:', 'slashes': true, 'auth': 'user:pw', 'host': 'www.example.com', 'hostname': 'www.example.com', 'pathname': '/', 'path': '/' }, 'http://x.com/path?that\'s#all, folks' : { 'href': 'http://x.com/path?that%27s#all,%20folks', 'protocol': 'http:', 'slashes': true, 'host': 'x.com', 'hostname': 'x.com', 'search': '?that%27s', 'query': 'that%27s', 'pathname': '/path', 'hash': '#all,%20folks', 'path': '/path?that%27s' }, 'HTTP://X.COM/Y' : { 'href': 'http://x.com/Y', 'protocol': 'http:', 'slashes': true, 'host': 'x.com', 'hostname': 'x.com', 'pathname': '/Y', 'path': '/Y' }, // + not an invalid host character // per https://url.spec.whatwg.org/#host-parsing 'http://x.y.com+a/b/c' : { 'href': 'http://x.y.com+a/b/c', 'protocol': 'http:', 'slashes': true, 'host': 'x.y.com+a', 'hostname': 'x.y.com+a', 'pathname': '/b/c', 'path': '/b/c' }, // an unexpected invalid char in the hostname. 'HtTp://x.y.cOm;a/b/c?d=e#f gi' : { 'href': 'http://x.y.com/;a/b/c?d=e#f%20g%3Ch%3Ei', 'protocol': 'http:', 'slashes': true, 'host': 'x.y.com', 'hostname': 'x.y.com', 'pathname': ';a/b/c', 'search': '?d=e', 'query': 'd=e', 'hash': '#f%20g%3Ch%3Ei', 'path': ';a/b/c?d=e' }, // make sure that we don't accidentally lcast the path parts. 'HtTp://x.y.cOm;A/b/c?d=e#f gi' : { 'href': 'http://x.y.com/;A/b/c?d=e#f%20g%3Ch%3Ei', 'protocol': 'http:', 'slashes': true, 'host': 'x.y.com', 'hostname': 'x.y.com', 'pathname': ';A/b/c', 'search': '?d=e', 'query': 'd=e', 'hash': '#f%20g%3Ch%3Ei', 'path': ';A/b/c?d=e' }, 'http://x...y...#p': { 'href': 'http://x...y.../#p', 'protocol': 'http:', 'slashes': true, 'host': 'x...y...', 'hostname': 'x...y...', 'hash': '#p', 'pathname': '/', 'path': '/' }, 'http://x/p/"quoted"': { 'href': 'http://x/p/%22quoted%22', 'protocol': 'http:', 'slashes': true, 'host': 'x', 'hostname': 'x', 'pathname': '/p/%22quoted%22', 'path': '/p/%22quoted%22' }, ' Is a URL!': { 'href': '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!', 'pathname': '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!', 'path': '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!' }, 'http://www.narwhaljs.org/blog/categories?id=news' : { 'href': 'http://www.narwhaljs.org/blog/categories?id=news', 'protocol': 'http:', 'slashes': true, 'host': 'www.narwhaljs.org', 'hostname': 'www.narwhaljs.org', 'search': '?id=news', 'query': 'id=news', 'pathname': '/blog/categories', 'path': '/blog/categories?id=news' }, 'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=' : { 'href': 'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=', 'protocol': 'http:', 'slashes': true, 'host': 'mt0.google.com', 'hostname': 'mt0.google.com', 'pathname': '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=', 'path': '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=' }, 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=' : { 'href': 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api' + '&x=2&y=2&z=3&s=', 'protocol': 'http:', 'slashes': true, 'host': 'mt0.google.com', 'hostname': 'mt0.google.com', 'search': '???&hl=en&src=api&x=2&y=2&z=3&s=', 'query': '??&hl=en&src=api&x=2&y=2&z=3&s=', 'pathname': '/vt/lyrs=m@114', 'path': '/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=' }, 'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=': { 'href': 'http://user:pass@mt0.google.com/vt/lyrs=m@114???' + '&hl=en&src=api&x=2&y=2&z=3&s=', 'protocol': 'http:', 'slashes': true, 'host': 'mt0.google.com', 'auth': 'user:pass', 'hostname': 'mt0.google.com', 'search': '???&hl=en&src=api&x=2&y=2&z=3&s=', 'query': '??&hl=en&src=api&x=2&y=2&z=3&s=', 'pathname': '/vt/lyrs=m@114', 'path': '/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=' }, 'file:///etc/passwd' : { 'href': 'file:///etc/passwd', 'slashes': true, 'protocol': 'file:', 'pathname': '/etc/passwd', 'hostname': '', 'host': '', 'path': '/etc/passwd' }, 'file://localhost/etc/passwd' : { 'href': 'file://localhost/etc/passwd', 'protocol': 'file:', 'slashes': true, 'pathname': '/etc/passwd', 'hostname': 'localhost', 'host': 'localhost', 'path': '/etc/passwd' }, 'file://foo/etc/passwd' : { 'href': 'file://foo/etc/passwd', 'protocol': 'file:', 'slashes': true, 'pathname': '/etc/passwd', 'hostname': 'foo', 'host': 'foo', 'path': '/etc/passwd' }, 'file:///etc/node/' : { 'href': 'file:///etc/node/', 'slashes': true, 'protocol': 'file:', 'pathname': '/etc/node/', 'hostname': '', 'host': '', 'path': '/etc/node/' }, 'file://localhost/etc/node/' : { 'href': 'file://localhost/etc/node/', 'protocol': 'file:', 'slashes': true, 'pathname': '/etc/node/', 'hostname': 'localhost', 'host': 'localhost', 'path': '/etc/node/' }, 'file://foo/etc/node/' : { 'href': 'file://foo/etc/node/', 'protocol': 'file:', 'slashes': true, 'pathname': '/etc/node/', 'hostname': 'foo', 'host': 'foo', 'path': '/etc/node/' }, 'http:/baz/../foo/bar' : { 'href': 'http:/baz/../foo/bar', 'protocol': 'http:', 'pathname': '/baz/../foo/bar', 'path': '/baz/../foo/bar' }, 'http://user:pass@example.com:8000/foo/bar?baz=quux#frag' : { 'href': 'http://user:pass@example.com:8000/foo/bar?baz=quux#frag', 'protocol': 'http:', 'slashes': true, 'host': 'example.com:8000', 'auth': 'user:pass', 'port': '8000', 'hostname': 'example.com', 'hash': '#frag', 'search': '?baz=quux', 'query': 'baz=quux', 'pathname': '/foo/bar', 'path': '/foo/bar?baz=quux' }, '//user:pass@example.com:8000/foo/bar?baz=quux#frag' : { 'href': '//user:pass@example.com:8000/foo/bar?baz=quux#frag', 'slashes': true, 'host': 'example.com:8000', 'auth': 'user:pass', 'port': '8000', 'hostname': 'example.com', 'hash': '#frag', 'search': '?baz=quux', 'query': 'baz=quux', 'pathname': '/foo/bar', 'path': '/foo/bar?baz=quux' }, '/foo/bar?baz=quux#frag' : { 'href': '/foo/bar?baz=quux#frag', 'hash': '#frag', 'search': '?baz=quux', 'query': 'baz=quux', 'pathname': '/foo/bar', 'path': '/foo/bar?baz=quux' }, 'http:/foo/bar?baz=quux#frag' : { 'href': 'http:/foo/bar?baz=quux#frag', 'protocol': 'http:', 'hash': '#frag', 'search': '?baz=quux', 'query': 'baz=quux', 'pathname': '/foo/bar', 'path': '/foo/bar?baz=quux' }, 'mailto:foo@bar.com?subject=hello' : { 'href': 'mailto:foo@bar.com?subject=hello', 'protocol': 'mailto:', 'host': 'bar.com', 'auth' : 'foo', 'hostname' : 'bar.com', 'search': '?subject=hello', 'query': 'subject=hello', 'path': '?subject=hello' }, 'javascript:alert(\'hello\');' : { 'href': 'javascript:alert(\'hello\');', 'protocol': 'javascript:', 'pathname': 'alert(\'hello\');', 'path': 'alert(\'hello\');' }, 'xmpp:isaacschlueter@jabber.org' : { 'href': 'xmpp:isaacschlueter@jabber.org', 'protocol': 'xmpp:', 'host': 'jabber.org', 'auth': 'isaacschlueter', 'hostname': 'jabber.org' }, 'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar' : { 'href' : 'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar', 'protocol' : 'http:', 'slashes': true, 'host' : '127.0.0.1:8080', 'auth' : 'atpass:foo@bar', 'hostname' : '127.0.0.1', 'port' : '8080', 'pathname': '/path', 'search' : '?search=foo', 'query' : 'search=foo', 'hash' : '#bar', 'path': '/path?search=foo' }, 'svn+ssh://foo/bar': { 'href': 'svn+ssh://foo/bar', 'host': 'foo', 'hostname': 'foo', 'protocol': 'svn+ssh:', 'pathname': '/bar', 'path': '/bar', 'slashes': true }, 'dash-test://foo/bar': { 'href': 'dash-test://foo/bar', 'host': 'foo', 'hostname': 'foo', 'protocol': 'dash-test:', 'pathname': '/bar', 'path': '/bar', 'slashes': true }, 'dash-test:foo/bar': { 'href': 'dash-test:foo/bar', 'host': 'foo', 'hostname': 'foo', 'protocol': 'dash-test:', 'pathname': '/bar', 'path': '/bar' }, 'dot.test://foo/bar': { 'href': 'dot.test://foo/bar', 'host': 'foo', 'hostname': 'foo', 'protocol': 'dot.test:', 'pathname': '/bar', 'path': '/bar', 'slashes': true }, 'dot.test:foo/bar': { 'href': 'dot.test:foo/bar', 'host': 'foo', 'hostname': 'foo', 'protocol': 'dot.test:', 'pathname': '/bar', 'path': '/bar' }, // IDNA tests 'http://www.日本語.com/' : { 'href': 'http://www.xn--wgv71a119e.com/', 'protocol': 'http:', 'slashes': true, 'host': 'www.xn--wgv71a119e.com', 'hostname': 'www.xn--wgv71a119e.com', 'pathname': '/', 'path': '/' }, 'http://example.Bücher.com/' : { 'href': 'http://example.xn--bcher-kva.com/', 'protocol': 'http:', 'slashes': true, 'host': 'example.xn--bcher-kva.com', 'hostname': 'example.xn--bcher-kva.com', 'pathname': '/', 'path': '/' }, 'http://www.Äffchen.com/' : { 'href': 'http://www.xn--ffchen-9ta.com/', 'protocol': 'http:', 'slashes': true, 'host': 'www.xn--ffchen-9ta.com', 'hostname': 'www.xn--ffchen-9ta.com', 'pathname': '/', 'path': '/' }, 'http://www.Äffchen.cOm;A/b/c?d=e#f gi' : { 'href': 'http://www.xn--ffchen-9ta.com/;A/b/c?d=e#f%20g%3Ch%3Ei', 'protocol': 'http:', 'slashes': true, 'host': 'www.xn--ffchen-9ta.com', 'hostname': 'www.xn--ffchen-9ta.com', 'pathname': ';A/b/c', 'search': '?d=e', 'query': 'd=e', 'hash': '#f%20g%3Ch%3Ei', 'path': ';A/b/c?d=e' }, 'http://SÉLIER.COM/' : { 'href': 'http://xn--slier-bsa.com/', 'protocol': 'http:', 'slashes': true, 'host': 'xn--slier-bsa.com', 'hostname': 'xn--slier-bsa.com', 'pathname': '/', 'path': '/' }, 'http://ليهمابتكلموشعربي؟.ي؟/' : { 'href': 'http://xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f/', 'protocol': 'http:', 'slashes': true, 'host': 'xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f', 'hostname': 'xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f', 'pathname': '/', 'path': '/' }, 'http://➡.ws/➡' : { 'href': 'http://xn--hgi.ws/➡', 'protocol': 'http:', 'slashes': true, 'host': 'xn--hgi.ws', 'hostname': 'xn--hgi.ws', 'pathname': '/➡', 'path': '/➡' }, 'http://bucket_name.s3.amazonaws.com/image.jpg': { protocol: 'http:', 'slashes': true, slashes: true, host: 'bucket_name.s3.amazonaws.com', hostname: 'bucket_name.s3.amazonaws.com', pathname: '/image.jpg', href: 'http://bucket_name.s3.amazonaws.com/image.jpg', 'path': '/image.jpg' }, 'git+http://github.com/joyent/node.git': { protocol: 'git+http:', slashes: true, host: 'github.com', hostname: 'github.com', pathname: '/joyent/node.git', path: '/joyent/node.git', href: 'git+http://github.com/joyent/node.git' }, //if local1@domain1 is uses as a relative URL it may //be parse into auth@hostname, but here there is no //way to make it work in url.parse, I add the test to be explicit 'local1@domain1': { 'pathname': 'local1@domain1', 'path': 'local1@domain1', 'href': 'local1@domain1' }, //While this may seem counter-intuitive, a browser will parse // as a path. 'www.example.com' : { 'href': 'www.example.com', 'pathname': 'www.example.com', 'path': 'www.example.com' }, // ipv6 support '[fe80::1]': { 'href': '[fe80::1]', 'pathname': '[fe80::1]', 'path': '[fe80::1]' }, 'coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]': { 'protocol': 'coap:', 'slashes': true, 'host': '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]', 'hostname': 'fedc:ba98:7654:3210:fedc:ba98:7654:3210', 'href': 'coap://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]/', 'pathname': '/', 'path': '/' }, 'coap://[1080:0:0:0:8:800:200C:417A]:61616/': { 'protocol': 'coap:', 'slashes': true, 'host': '[1080:0:0:0:8:800:200c:417a]:61616', 'port': '61616', 'hostname': '1080:0:0:0:8:800:200c:417a', 'href': 'coap://[1080:0:0:0:8:800:200c:417a]:61616/', 'pathname': '/', 'path': '/' }, 'http://user:password@[3ffe:2a00:100:7031::1]:8080': { 'protocol': 'http:', 'slashes': true, 'auth': 'user:password', 'host': '[3ffe:2a00:100:7031::1]:8080', 'port': '8080', 'hostname': '3ffe:2a00:100:7031::1', 'href': 'http://user:password@[3ffe:2a00:100:7031::1]:8080/', 'pathname': '/', 'path': '/' }, 'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature': { 'protocol': 'coap:', 'slashes': true, 'auth': 'u:p', 'host': '[::192.9.5.5]:61616', 'port': '61616', 'hostname': '::192.9.5.5', 'href': 'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature', 'search': '?n=Temperature', 'query': 'n=Temperature', 'pathname': '/.well-known/r', 'path': '/.well-known/r?n=Temperature' }, // empty port 'http://example.com:': { 'protocol': 'http:', 'slashes': true, 'host': 'example.com', 'hostname': 'example.com', 'href': 'http://example.com/', 'pathname': '/', 'path': '/' }, 'http://example.com:/a/b.html': { 'protocol': 'http:', 'slashes': true, 'host': 'example.com', 'hostname': 'example.com', 'href': 'http://example.com/a/b.html', 'pathname': '/a/b.html', 'path': '/a/b.html' }, 'http://example.com:?a=b': { 'protocol': 'http:', 'slashes': true, 'host': 'example.com', 'hostname': 'example.com', 'href': 'http://example.com/?a=b', 'search': '?a=b', 'query': 'a=b', 'pathname': '/', 'path': '/?a=b' }, 'http://example.com:#abc': { 'protocol': 'http:', 'slashes': true, 'host': 'example.com', 'hostname': 'example.com', 'href': 'http://example.com/#abc', 'hash': '#abc', 'pathname': '/', 'path': '/' }, 'http://[fe80::1]:/a/b?a=b#abc': { 'protocol': 'http:', 'slashes': true, 'host': '[fe80::1]', 'hostname': 'fe80::1', 'href': 'http://[fe80::1]/a/b?a=b#abc', 'search': '?a=b', 'query': 'a=b', 'hash': '#abc', 'pathname': '/a/b', 'path': '/a/b?a=b' }, 'http://-lovemonsterz.tumblr.com/rss': { 'protocol': 'http:', 'slashes': true, 'host': '-lovemonsterz.tumblr.com', 'hostname': '-lovemonsterz.tumblr.com', 'href': 'http://-lovemonsterz.tumblr.com/rss', 'pathname': '/rss', 'path': '/rss', }, 'http://-lovemonsterz.tumblr.com:80/rss': { 'protocol': 'http:', 'slashes': true, 'port': '80', 'host': '-lovemonsterz.tumblr.com:80', 'hostname': '-lovemonsterz.tumblr.com', 'href': 'http://-lovemonsterz.tumblr.com:80/rss', 'pathname': '/rss', 'path': '/rss', }, 'http://user:pass@-lovemonsterz.tumblr.com/rss': { 'protocol': 'http:', 'slashes': true, 'auth': 'user:pass', 'host': '-lovemonsterz.tumblr.com', 'hostname': '-lovemonsterz.tumblr.com', 'href': 'http://user:pass@-lovemonsterz.tumblr.com/rss', 'pathname': '/rss', 'path': '/rss', }, 'http://user:pass@-lovemonsterz.tumblr.com:80/rss': { 'protocol': 'http:', 'slashes': true, 'auth': 'user:pass', 'port': '80', 'host': '-lovemonsterz.tumblr.com:80', 'hostname': '-lovemonsterz.tumblr.com', 'href': 'http://user:pass@-lovemonsterz.tumblr.com:80/rss', 'pathname': '/rss', 'path': '/rss', }, 'http://_jabber._tcp.google.com/test': { 'protocol': 'http:', 'slashes': true, 'host': '_jabber._tcp.google.com', 'hostname': '_jabber._tcp.google.com', 'href': 'http://_jabber._tcp.google.com/test', 'pathname': '/test', 'path': '/test', }, 'http://user:pass@_jabber._tcp.google.com/test': { 'protocol': 'http:', 'slashes': true, 'auth': 'user:pass', 'host': '_jabber._tcp.google.com', 'hostname': '_jabber._tcp.google.com', 'href': 'http://user:pass@_jabber._tcp.google.com/test', 'pathname': '/test', 'path': '/test', }, 'http://_jabber._tcp.google.com:80/test': { 'protocol': 'http:', 'slashes': true, 'port': '80', 'host': '_jabber._tcp.google.com:80', 'hostname': '_jabber._tcp.google.com', 'href': 'http://_jabber._tcp.google.com:80/test', 'pathname': '/test', 'path': '/test', }, 'http://user:pass@_jabber._tcp.google.com:80/test': { 'protocol': 'http:', 'slashes': true, 'auth': 'user:pass', 'port': '80', 'host': '_jabber._tcp.google.com:80', 'hostname': '_jabber._tcp.google.com', 'href': 'http://user:pass@_jabber._tcp.google.com:80/test', 'pathname': '/test', 'path': '/test', }, 'http://x:1/\' <>"`/{}|\\^~`/': { protocol: 'http:', slashes: true, host: 'x:1', port: '1', hostname: 'x', pathname: '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/', path: '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/', href: 'http://x:1/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/' }, 'http://a@b@c/': { protocol: 'http:', slashes: true, auth: 'a@b', host: 'c', hostname: 'c', href: 'http://a%40b@c/', path: '/', pathname: '/' }, 'http://a@b?@c': { protocol: 'http:', slashes: true, auth: 'a', host: 'b', hostname: 'b', href: 'http://a@b/?@c', path: '/?@c', pathname: '/', search: '?@c', query: '@c' }, 'http://a\r" \t\n<\'b:b@c\r\nd/e?f':{ protocol: 'http:', slashes: true, auth: 'a\r" \t\n<\'b:b', host: 'c', port: null, hostname: 'c', hash: null, search: '?f', query: 'f', pathname: '%0D%0Ad/e', path: '%0D%0Ad/e?f', href: 'http://a%0D%22%20%09%0A%3C\'b:b@c/%0D%0Ad/e?f' }, // git urls used by npm 'git+ssh://git@github.com:npm/npm': { protocol: 'git+ssh:', slashes: true, auth: 'git', host: 'github.com', port: null, hostname: 'github.com', hash: null, search: null, query: null, pathname: '/:npm/npm', path: '/:npm/npm', href: 'git+ssh://git@github.com/:npm/npm' } }; Object.keys(parseTests).forEach(function(u) { test('parse(' + u + ')', function() { var actual = url.parse(u), spaced = url.parse(' \t ' + u + '\n\t'); expected = parseTests[u]; Object.keys(actual).forEach(function (i) { if (expected[i] === undefined && actual[i] === null) { expected[i] = null; } }); assert.deepEqual(actual, expected); assert.deepEqual(spaced, expected); var expected = parseTests[u].href, actual = url.format(parseTests[u]); assert.equal(actual, expected, 'format(' + u + ') == ' + u + '\nactual:' + actual); }); }); var parseTestsWithQueryString = { '/foo/bar?baz=quux#frag' : { 'href': '/foo/bar?baz=quux#frag', 'hash': '#frag', 'search': '?baz=quux', 'query': { 'baz': 'quux' }, 'pathname': '/foo/bar', 'path': '/foo/bar?baz=quux' }, 'http://example.com' : { 'href': 'http://example.com/', 'protocol': 'http:', 'slashes': true, 'host': 'example.com', 'hostname': 'example.com', 'query': {}, 'search': '', 'pathname': '/', 'path': '/' }, '/example': { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: '', query: {}, pathname: '/example', path: '/example', href: '/example' }, '/example?query=value':{ protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: '?query=value', query: { query: 'value' }, pathname: '/example', path: '/example?query=value', href: '/example?query=value' } }; Object.keys(parseTestsWithQueryString).forEach(function(u) { test('parse(' + u + ')', function() { var actual = url.parse(u, true); var expected = parseTestsWithQueryString[u]; for (var i in actual) { if (actual[i] === null && expected[i] === undefined) { expected[i] = null; } } assert.deepEqual(actual, expected); }); }); // some extra formatting tests, just to verify // that it'll format slightly wonky content to a valid url. var formatTests = { 'http://example.com?' : { 'href': 'http://example.com/?', 'protocol': 'http:', 'slashes': true, 'host': 'example.com', 'hostname': 'example.com', 'search': '?', 'query': {}, 'pathname': '/' }, 'http://example.com?foo=bar#frag' : { 'href': 'http://example.com/?foo=bar#frag', 'protocol': 'http:', 'host': 'example.com', 'hostname': 'example.com', 'hash': '#frag', 'search': '?foo=bar', 'query': 'foo=bar', 'pathname': '/' }, 'http://example.com?foo=@bar#frag' : { 'href': 'http://example.com/?foo=@bar#frag', 'protocol': 'http:', 'host': 'example.com', 'hostname': 'example.com', 'hash': '#frag', 'search': '?foo=@bar', 'query': 'foo=@bar', 'pathname': '/' }, 'http://example.com?foo=/bar/#frag' : { 'href': 'http://example.com/?foo=/bar/#frag', 'protocol': 'http:', 'host': 'example.com', 'hostname': 'example.com', 'hash': '#frag', 'search': '?foo=/bar/', 'query': 'foo=/bar/', 'pathname': '/' }, 'http://example.com?foo=?bar/#frag' : { 'href': 'http://example.com/?foo=?bar/#frag', 'protocol': 'http:', 'host': 'example.com', 'hostname': 'example.com', 'hash': '#frag', 'search': '?foo=?bar/', 'query': 'foo=?bar/', 'pathname': '/' }, 'http://example.com#frag=?bar/#frag' : { 'href': 'http://example.com/#frag=?bar/#frag', 'protocol': 'http:', 'host': 'example.com', 'hostname': 'example.com', 'hash': '#frag=?bar/#frag', 'pathname': '/' }, 'http://google.com" onload="alert(42)/' : { 'href': 'http://google.com/%22%20onload=%22alert(42)/', 'protocol': 'http:', 'host': 'google.com', 'pathname': '/%22%20onload=%22alert(42)/' }, 'http://a.com/a/b/c?s#h' : { 'href': 'http://a.com/a/b/c?s#h', 'protocol': 'http', 'host': 'a.com', 'pathname': 'a/b/c', 'hash': 'h', 'search': 's' }, 'xmpp:isaacschlueter@jabber.org' : { 'href': 'xmpp:isaacschlueter@jabber.org', 'protocol': 'xmpp:', 'host': 'jabber.org', 'auth': 'isaacschlueter', 'hostname': 'jabber.org' }, 'http://atpass:foo%40bar@127.0.0.1/' : { 'href': 'http://atpass:foo%40bar@127.0.0.1/', 'auth': 'atpass:foo@bar', 'hostname': '127.0.0.1', 'protocol': 'http:', 'pathname': '/' }, 'http://atslash%2F%40:%2F%40@foo/' : { 'href': 'http://atslash%2F%40:%2F%40@foo/', 'auth': 'atslash/@:/@', 'hostname': 'foo', 'protocol': 'http:', 'pathname': '/' }, 'svn+ssh://foo/bar': { 'href': 'svn+ssh://foo/bar', 'hostname': 'foo', 'protocol': 'svn+ssh:', 'pathname': '/bar', 'slashes': true }, 'dash-test://foo/bar': { 'href': 'dash-test://foo/bar', 'hostname': 'foo', 'protocol': 'dash-test:', 'pathname': '/bar', 'slashes': true }, 'dash-test:foo/bar': { 'href': 'dash-test:foo/bar', 'hostname': 'foo', 'protocol': 'dash-test:', 'pathname': '/bar' }, 'dot.test://foo/bar': { 'href': 'dot.test://foo/bar', 'hostname': 'foo', 'protocol': 'dot.test:', 'pathname': '/bar', 'slashes': true }, 'dot.test:foo/bar': { 'href': 'dot.test:foo/bar', 'hostname': 'foo', 'protocol': 'dot.test:', 'pathname': '/bar' }, // ipv6 support 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature': { 'href': 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature', 'protocol': 'coap:', 'auth': 'u:p', 'hostname': '::1', 'port': '61616', 'pathname': '/.well-known/r', 'search': 'n=Temperature' }, 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton': { 'href': 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton', 'protocol': 'coap', 'host': '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616', 'pathname': '/s/stopButton' }, // encode context-specific delimiters in path and query, but do not touch // other non-delimiter chars like `%`. // // `#`,`?` in path '/path/to/%%23%3F+=&.txt?foo=theA1#bar' : { href : '/path/to/%%23%3F+=&.txt?foo=theA1#bar', pathname: '/path/to/%#?+=&.txt', query: { foo: 'theA1' }, hash: "#bar" }, // `#`,`?` in path + `#` in query '/path/to/%%23%3F+=&.txt?foo=the%231#bar' : { href : '/path/to/%%23%3F+=&.txt?foo=the%231#bar', pathname: '/path/to/%#?+=&.txt', query: { foo: 'the#1' }, hash: "#bar" }, // `?` and `#` in path and search 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag': { href: 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag', protocol: 'http:', hostname: 'ex.com', hash: '#frag', search: '?abc=the#1?&foo=bar', pathname: '/foo?100%m#r', }, // `?` and `#` in search only 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag': { href: 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag', protocol: 'http:', hostname: 'ex.com', hash: '#frag', search: '?abc=the#1?&foo=bar', pathname: '/fooA100%mBr', } }; Object.keys(formatTests).forEach(function(u) { test('format(' + u + ')', function() { var expect = formatTests[u].href; delete formatTests[u].href; var actual = url.format(u); var actualObj = url.format(formatTests[u]); assert.equal(actual, expect, 'wonky format(' + u + ') == ' + expect + '\nactual:' + actual); assert.equal(actualObj, expect, 'wonky format(' + JSON.stringify(formatTests[u]) + ') == ' + expect + '\nactual: ' + actualObj); }); }); /* [from, path, expected] */ var relativeTests = [ ['/foo/bar/baz', 'quux', '/foo/bar/quux'], ['/foo/bar/baz', 'quux/asdf', '/foo/bar/quux/asdf'], ['/foo/bar/baz', 'quux/baz', '/foo/bar/quux/baz'], ['/foo/bar/baz', '../quux/baz', '/foo/quux/baz'], ['/foo/bar/baz', '/bar', '/bar'], ['/foo/bar/baz/', 'quux', '/foo/bar/baz/quux'], ['/foo/bar/baz/', 'quux/baz', '/foo/bar/baz/quux/baz'], ['/foo/bar/baz', '../../../../../../../../quux/baz', '/quux/baz'], ['/foo/bar/baz', '../../../../../../../quux/baz', '/quux/baz'], ['/foo', '.', '/'], ['/foo', '..', '/'], ['/foo/', '.', '/foo/'], ['/foo/', '..', '/'], ['/foo/bar', '.', '/foo/'], ['/foo/bar', '..', '/'], ['/foo/bar/', '.', '/foo/bar/'], ['/foo/bar/', '..', '/foo/'], ['foo/bar', '../../../baz', '../../baz'], ['foo/bar/', '../../../baz', '../baz'], ['http://example.com/b//c//d;p?q#blarg', 'https:#hash2', 'https:///#hash2'], ['http://example.com/b//c//d;p?q#blarg', 'https:/p/a/t/h?s#hash2', 'https://p/a/t/h?s#hash2'], ['http://example.com/b//c//d;p?q#blarg', 'https://u:p@h.com/p/a/t/h?s#hash2', 'https://u:p@h.com/p/a/t/h?s#hash2'], ['http://example.com/b//c//d;p?q#blarg', 'https:/a/b/c/d', 'https://a/b/c/d'], ['http://example.com/b//c//d;p?q#blarg', 'http:#hash2', 'http://example.com/b//c//d;p?q#hash2'], ['http://example.com/b//c//d;p?q#blarg', 'http:/p/a/t/h?s#hash2', 'http://example.com/p/a/t/h?s#hash2'], ['http://example.com/b//c//d;p?q#blarg', 'http://u:p@h.com/p/a/t/h?s#hash2', 'http://u:p@h.com/p/a/t/h?s#hash2'], ['http://example.com/b//c//d;p?q#blarg', 'http:/a/b/c/d', 'http://example.com/a/b/c/d'], ['/foo/bar/baz', '/../etc/passwd', '/etc/passwd'] ]; relativeTests.forEach(function(relativeTest) { test('resolve(' + [relativeTest[0], relativeTest[1]] + ')', function() { var a = url.resolve(relativeTest[0], relativeTest[1]), e = relativeTest[2]; assert.equal(a, e, 'resolve(' + [relativeTest[0], relativeTest[1]] + ') == ' + e + '\n actual=' + a); }); }); // https://github.com/joyent/node/issues/568 [ undefined, null, true, false, 0.0, 0, [], {} ].forEach(function(val) { test('parse(' + val + ')', function() { assert.throws(function() { url.parse(val); }, TypeError); }); }); // // Tests below taken from Chiron // http://code.google.com/p/chironjs/source/browse/trunk/src/test/http/url.js // // Copyright (c) 2002-2008 Kris Kowal // used with permission under MIT License // // Changes marked with @isaacs var bases = [ 'http://a/b/c/d;p?q', 'http://a/b/c/d;p?q=1/2', 'http://a/b/c/d;p=1/2?q', 'fred:///s//a/b/c', 'http:///s//a/b/c' ]; //[to, from, result] var relativeTests2 = [ // http://lists.w3.org/Archives/Public/uri/2004Feb/0114.html ['../c', 'foo:a/b', 'foo:c'], ['foo:.', 'foo:a', 'foo:'], ['/foo/../../../bar', 'zz:abc', 'zz:/bar'], ['/foo/../bar', 'zz:abc', 'zz:/bar'], // @isaacs Disagree. Not how web browsers resolve this. ['foo/../../../bar', 'zz:abc', 'zz:bar'], // ['foo/../../../bar', 'zz:abc', 'zz:../../bar'], // @isaacs Added ['foo/../bar', 'zz:abc', 'zz:bar'], ['zz:.', 'zz:abc', 'zz:'], ['/.', bases[0], 'http://a/'], ['/.foo', bases[0], 'http://a/.foo'], ['.foo', bases[0], 'http://a/b/c/.foo'], // http://gbiv.com/protocols/uri/test/rel_examples1.html // examples from RFC 2396 ['g:h', bases[0], 'g:h'], ['g', bases[0], 'http://a/b/c/g'], ['./g', bases[0], 'http://a/b/c/g'], ['g/', bases[0], 'http://a/b/c/g/'], ['/g', bases[0], 'http://a/g'], ['//g', bases[0], 'http://g/'], // changed with RFC 2396bis //('?y', bases[0], 'http://a/b/c/d;p?y'], ['?y', bases[0], 'http://a/b/c/d;p?y'], ['g?y', bases[0], 'http://a/b/c/g?y'], // changed with RFC 2396bis //('#s', bases[0], CURRENT_DOC_URI + '#s'], ['#s', bases[0], 'http://a/b/c/d;p?q#s'], ['g#s', bases[0], 'http://a/b/c/g#s'], ['g?y#s', bases[0], 'http://a/b/c/g?y#s'], [';x', bases[0], 'http://a/b/c/;x'], ['g;x', bases[0], 'http://a/b/c/g;x'], ['g;x?y#s' , bases[0], 'http://a/b/c/g;x?y#s'], // changed with RFC 2396bis //('', bases[0], CURRENT_DOC_URI], ['', bases[0], 'http://a/b/c/d;p?q'], ['.', bases[0], 'http://a/b/c/'], ['./', bases[0], 'http://a/b/c/'], ['..', bases[0], 'http://a/b/'], ['../', bases[0], 'http://a/b/'], ['../g', bases[0], 'http://a/b/g'], ['../..', bases[0], 'http://a/'], ['../../', bases[0], 'http://a/'], ['../../g' , bases[0], 'http://a/g'], ['../../../g', bases[0], ('http://a/../g', 'http://a/g')], ['../../../../g', bases[0], ('http://a/../../g', 'http://a/g')], // changed with RFC 2396bis //('/./g', bases[0], 'http://a/./g'], ['/./g', bases[0], 'http://a/g'], // changed with RFC 2396bis //('/../g', bases[0], 'http://a/../g'], ['/../g', bases[0], 'http://a/g'], ['g.', bases[0], 'http://a/b/c/g.'], ['.g', bases[0], 'http://a/b/c/.g'], ['g..', bases[0], 'http://a/b/c/g..'], ['..g', bases[0], 'http://a/b/c/..g'], ['./../g', bases[0], 'http://a/b/g'], ['./g/.', bases[0], 'http://a/b/c/g/'], ['g/./h', bases[0], 'http://a/b/c/g/h'], ['g/../h', bases[0], 'http://a/b/c/h'], ['g;x=1/./y', bases[0], 'http://a/b/c/g;x=1/y'], ['g;x=1/../y', bases[0], 'http://a/b/c/y'], ['g?y/./x', bases[0], 'http://a/b/c/g?y/./x'], ['g?y/../x', bases[0], 'http://a/b/c/g?y/../x'], ['g#s/./x', bases[0], 'http://a/b/c/g#s/./x'], ['g#s/../x', bases[0], 'http://a/b/c/g#s/../x'], ['http:g', bases[0], ('http:g', 'http://a/b/c/g')], ['http:', bases[0], ('http:', bases[0])], // not sure where this one originated ['/a/b/c/./../../g', bases[0], 'http://a/a/g'], // http://gbiv.com/protocols/uri/test/rel_examples2.html // slashes in base URI's query args ['g', bases[1], 'http://a/b/c/g'], ['./g', bases[1], 'http://a/b/c/g'], ['g/', bases[1], 'http://a/b/c/g/'], ['/g', bases[1], 'http://a/g'], ['//g', bases[1], 'http://g/'], // changed in RFC 2396bis //('?y', bases[1], 'http://a/b/c/?y'], ['?y', bases[1], 'http://a/b/c/d;p?y'], ['g?y', bases[1], 'http://a/b/c/g?y'], ['g?y/./x' , bases[1], 'http://a/b/c/g?y/./x'], ['g?y/../x', bases[1], 'http://a/b/c/g?y/../x'], ['g#s', bases[1], 'http://a/b/c/g#s'], ['g#s/./x' , bases[1], 'http://a/b/c/g#s/./x'], ['g#s/../x', bases[1], 'http://a/b/c/g#s/../x'], ['./', bases[1], 'http://a/b/c/'], ['../', bases[1], 'http://a/b/'], ['../g', bases[1], 'http://a/b/g'], ['../../', bases[1], 'http://a/'], ['../../g' , bases[1], 'http://a/g'], // http://gbiv.com/protocols/uri/test/rel_examples3.html // slashes in path params // all of these changed in RFC 2396bis ['g', bases[2], 'http://a/b/c/d;p=1/g'], ['./g', bases[2], 'http://a/b/c/d;p=1/g'], ['g/', bases[2], 'http://a/b/c/d;p=1/g/'], ['g?y', bases[2], 'http://a/b/c/d;p=1/g?y'], [';x', bases[2], 'http://a/b/c/d;p=1/;x'], ['g;x', bases[2], 'http://a/b/c/d;p=1/g;x'], ['g;x=1/./y', bases[2], 'http://a/b/c/d;p=1/g;x=1/y'], ['g;x=1/../y', bases[2], 'http://a/b/c/d;p=1/y'], ['./', bases[2], 'http://a/b/c/d;p=1/'], ['../', bases[2], 'http://a/b/c/'], ['../g', bases[2], 'http://a/b/c/g'], ['../../', bases[2], 'http://a/b/'], ['../../g' , bases[2], 'http://a/b/g'], // http://gbiv.com/protocols/uri/test/rel_examples4.html // double and triple slash, unknown scheme ['g:h', bases[3], 'g:h'], ['g', bases[3], 'fred:///s//a/b/g'], ['./g', bases[3], 'fred:///s//a/b/g'], ['g/', bases[3], 'fred:///s//a/b/g/'], ['/g', bases[3], 'fred:///g'], // may change to fred:///s//a/g ['//g', bases[3], 'fred://g'], // may change to fred:///s//g ['//g/x', bases[3], 'fred://g/x'], // may change to fred:///s//g/x ['///g', bases[3], 'fred:///g'], ['./', bases[3], 'fred:///s//a/b/'], ['../', bases[3], 'fred:///s//a/'], ['../g', bases[3], 'fred:///s//a/g'], ['../../', bases[3], 'fred:///s//'], ['../../g' , bases[3], 'fred:///s//g'], ['../../../g', bases[3], 'fred:///s/g'], // may change to fred:///s//a/../../../g ['../../../../g', bases[3], 'fred:///g'], // http://gbiv.com/protocols/uri/test/rel_examples5.html // double and triple slash, well-known scheme ['g:h', bases[4], 'g:h'], ['g', bases[4], 'http:///s//a/b/g'], ['./g', bases[4], 'http:///s//a/b/g'], ['g/', bases[4], 'http:///s//a/b/g/'], ['/g', bases[4], 'http:///g'], // may change to http:///s//a/g ['//g', bases[4], 'http://g/'], // may change to http:///s//g ['//g/x', bases[4], 'http://g/x'], // may change to http:///s//g/x ['///g', bases[4], 'http:///g'], ['./', bases[4], 'http:///s//a/b/'], ['../', bases[4], 'http:///s//a/'], ['../g', bases[4], 'http:///s//a/g'], ['../../', bases[4], 'http:///s//'], ['../../g' , bases[4], 'http:///s//g'], // may change to http:///s//a/../../g ['../../../g', bases[4], 'http:///s/g'], // may change to http:///s//a/../../../g ['../../../../g', bases[4], 'http:///g'], // from Dan Connelly's tests in http://www.w3.org/2000/10/swap/uripath.py ['bar:abc', 'foo:xyz', 'bar:abc'], ['../abc', 'http://example/x/y/z', 'http://example/x/abc'], ['http://example/x/abc', 'http://example2/x/y/z', 'http://example/x/abc'], ['../r', 'http://ex/x/y/z', 'http://ex/x/r'], ['q/r', 'http://ex/x/y', 'http://ex/x/q/r'], ['q/r#s', 'http://ex/x/y', 'http://ex/x/q/r#s'], ['q/r#s/t', 'http://ex/x/y', 'http://ex/x/q/r#s/t'], ['ftp://ex/x/q/r', 'http://ex/x/y', 'ftp://ex/x/q/r'], ['', 'http://ex/x/y', 'http://ex/x/y'], ['', 'http://ex/x/y/', 'http://ex/x/y/'], ['', 'http://ex/x/y/pdq', 'http://ex/x/y/pdq'], ['z/', 'http://ex/x/y/', 'http://ex/x/y/z/'], ['#Animal', 'file:/swap/test/animal.rdf', 'file:/swap/test/animal.rdf#Animal'], ['../abc', 'file:/e/x/y/z', 'file:/e/x/abc'], ['/example/x/abc', 'file:/example2/x/y/z', 'file:/example/x/abc'], ['../r', 'file:/ex/x/y/z', 'file:/ex/x/r'], ['/r', 'file:/ex/x/y/z', 'file:/r'], ['q/r', 'file:/ex/x/y', 'file:/ex/x/q/r'], ['q/r#s', 'file:/ex/x/y', 'file:/ex/x/q/r#s'], ['q/r#', 'file:/ex/x/y', 'file:/ex/x/q/r#'], ['q/r#s/t', 'file:/ex/x/y', 'file:/ex/x/q/r#s/t'], ['ftp://ex/x/q/r', 'file:/ex/x/y', 'ftp://ex/x/q/r'], ['', 'file:/ex/x/y', 'file:/ex/x/y'], ['', 'file:/ex/x/y/', 'file:/ex/x/y/'], ['', 'file:/ex/x/y/pdq', 'file:/ex/x/y/pdq'], ['z/', 'file:/ex/x/y/', 'file:/ex/x/y/z/'], ['file://meetings.example.com/cal#m1', 'file:/devel/WWW/2000/10/swap/test/reluri-1.n3', 'file://meetings.example.com/cal#m1'], ['file://meetings.example.com/cal#m1', 'file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3', 'file://meetings.example.com/cal#m1'], ['./#blort', 'file:/some/dir/foo', 'file:/some/dir/#blort'], ['./#', 'file:/some/dir/foo', 'file:/some/dir/#'], // Ryan Lee ['./', 'http://example/x/abc.efg', 'http://example/x/'], // Graham Klyne's tests // http://www.ninebynine.org/Software/HaskellUtils/Network/UriTest.xls // 01-31 are from Connelly's cases // 32-49 ['./q:r', 'http://ex/x/y', 'http://ex/x/q:r'], ['./p=q:r', 'http://ex/x/y', 'http://ex/x/p=q:r'], ['?pp/rr', 'http://ex/x/y?pp/qq', 'http://ex/x/y?pp/rr'], ['y/z', 'http://ex/x/y?pp/qq', 'http://ex/x/y/z'], ['local/qual@domain.org#frag', 'mailto:local', 'mailto:local/qual@domain.org#frag'], ['more/qual2@domain2.org#frag', 'mailto:local/qual1@domain1.org', 'mailto:local/more/qual2@domain2.org#frag'], ['y?q', 'http://ex/x/y?q', 'http://ex/x/y?q'], ['/x/y?q', 'http://ex?p', 'http://ex/x/y?q'], ['c/d', 'foo:a/b', 'foo:a/c/d'], ['/c/d', 'foo:a/b', 'foo:/c/d'], ['', 'foo:a/b?c#d', 'foo:a/b?c'], ['b/c', 'foo:a', 'foo:b/c'], ['../b/c', 'foo:/a/y/z', 'foo:/a/b/c'], ['./b/c', 'foo:a', 'foo:b/c'], ['/./b/c', 'foo:a', 'foo:/b/c'], ['../../d', 'foo://a//b/c', 'foo://a/d'], ['.', 'foo:a', 'foo:'], ['..', 'foo:a', 'foo:'], // 50-57[cf. TimBL comments -- // http://lists.w3.org/Archives/Public/uri/2003Feb/0028.html, // http://lists.w3.org/Archives/Public/uri/2003Jan/0008.html) ['abc', 'http://example/x/y%2Fz', 'http://example/x/abc'], ['../../x%2Fabc', 'http://example/a/x/y/z', 'http://example/a/x%2Fabc'], ['../x%2Fabc', 'http://example/a/x/y%2Fz', 'http://example/a/x%2Fabc'], ['abc', 'http://example/x%2Fy/z', 'http://example/x%2Fy/abc'], ['q%3Ar', 'http://ex/x/y', 'http://ex/x/q%3Ar'], ['/x%2Fabc', 'http://example/x/y%2Fz', 'http://example/x%2Fabc'], ['/x%2Fabc', 'http://example/x/y/z', 'http://example/x%2Fabc'], ['/x%2Fabc', 'http://example/x/y%2Fz', 'http://example/x%2Fabc'], // 70-77 ['local2@domain2', 'mailto:local1@domain1?query1', 'mailto:local2@domain2'], ['local2@domain2?query2', 'mailto:local1@domain1', 'mailto:local2@domain2?query2'], ['local2@domain2?query2', 'mailto:local1@domain1?query1', 'mailto:local2@domain2?query2'], ['?query2', 'mailto:local@domain?query1', 'mailto:local@domain?query2'], ['local@domain?query2', 'mailto:?query1', 'mailto:local@domain?query2'], ['?query2', 'mailto:local@domain?query1', 'mailto:local@domain?query2'], ['http://example/a/b?c/../d', 'foo:bar', 'http://example/a/b?c/../d'], ['http://example/a/b#c/../d', 'foo:bar', 'http://example/a/b#c/../d'], // 82-88 // @isaacs Disagree. Not how browsers do it. // ['http:this', 'http://example.org/base/uri', 'http:this'], // @isaacs Added ['http:this', 'http://example.org/base/uri', 'http://example.org/base/this'], ['http:this', 'http:base', 'http:this'], ['.//g', 'f:/a', 'f://g'], ['b/c//d/e', 'f://example.org/base/a', 'f://example.org/base/b/c//d/e'], ['m2@example.ord/c2@example.org', 'mid:m@example.ord/c@example.org', 'mid:m@example.ord/m2@example.ord/c2@example.org'], ['mini1.xml', 'file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/', 'file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml'], ['../b/c', 'foo:a/y/z', 'foo:a/b/c'], //changeing auth ['http://diff:auth@www.example.com', 'http://asdf:qwer@www.example.com', 'http://diff:auth@www.example.com/'] ]; relativeTests2.forEach(function(relativeTest) { test('resolve(' + [relativeTest[1], relativeTest[0]] + ')', function() { var a = url.resolve(relativeTest[1], relativeTest[0]), e = relativeTest[2]; assert.equal(a, e, 'resolve(' + [relativeTest[1], relativeTest[0]] + ') == ' + e + '\n actual=' + a); }); }); //if format and parse are inverse operations then //resolveObject(parse(x), y) == parse(resolve(x, y)) //host and hostname are special, in this case a '' value is important var emptyIsImportant = {'host': true, 'hostname': ''}; //format: [from, path, expected] relativeTests.forEach(function(relativeTest) { test('resolveObject(' + [relativeTest[0], relativeTest[1]] + ')', function() { var actual = url.resolveObject(url.parse(relativeTest[0]), relativeTest[1]), expected = url.parse(relativeTest[2]); assert.deepEqual(actual, expected); expected = relativeTest[2]; actual = url.format(actual); assert.equal(actual, expected, 'format(' + actual + ') == ' + expected + '\nactual:' + actual); }); }); //format: [to, from, result] // the test: ['.//g', 'f:/a', 'f://g'] is a fundamental problem // url.parse('f:/a') does not have a host // url.resolve('f:/a', './/g') does not have a host because you have moved // down to the g directory. i.e. f: //g, however when this url is parsed // f:// will indicate that the host is g which is not the case. // it is unclear to me how to keep this information from being lost // it may be that a pathname of ////g should collapse to /g but this seems // to be a lot of work for an edge case. Right now I remove the test if (relativeTests2[181][0] === './/g' && relativeTests2[181][1] === 'f:/a' && relativeTests2[181][2] === 'f://g') { relativeTests2.splice(181, 1); } relativeTests2.forEach(function(relativeTest) { test('resolveObject(' + [relativeTest[1], relativeTest[0]] + ')', function() { var actual = url.resolveObject(url.parse(relativeTest[1]), relativeTest[0]), expected = url.parse(relativeTest[2]); assert.deepEqual(actual, expected); var expected = relativeTest[2], actual = url.format(actual); assert.equal(actual, expected, 'format(' + relativeTest[1] + ') == ' + expected + '\nactual:' + actual); }); }); node-url-0.11.0/url.js000066400000000000000000000554251256762722000145020ustar00rootroot00000000000000// 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'; var punycode = require('punycode'); var util = require('./util'); exports.parse = urlParse; exports.resolve = urlResolve; exports.resolveObject = urlResolveObject; exports.format = urlFormat; exports.Url = Url; function Url() { this.protocol = null; this.slashes = null; this.auth = null; this.host = null; this.port = null; this.hostname = null; this.hash = null; this.search = null; this.query = null; this.pathname = null; this.path = null; this.href = 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. unsafeProtocol = { 'javascript': true, 'javascript:': true }, // 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 }, querystring = require('querystring'); function urlParse(url, parseQueryString, slashesDenoteHost) { if (url && util.isObject(url) && url instanceof Url) return url; var u = new Url; u.parse(url, parseQueryString, slashesDenoteHost); return u; } Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { if (!util.isString(url)) { throw new TypeError("Parameter 'url' must be a string, not " + typeof url); } // Copy chrome, IE, opera backslash-handling behavior. // Back slashes before the query string get converted to forward slashes // See: https://code.google.com/p/chromium/issues/detail?id=25916 var queryIndex = url.indexOf('?'), splitter = (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#', uSplit = url.split(splitter), slashRegex = /\\/g; uSplit[0] = uSplit[0].replace(slashRegex, '/'); url = uSplit.join(splitter); var 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.path = rest; this.href = rest; this.pathname = simplePath[1]; if (simplePath[2]) { this.search = simplePath[2]; if (parseQueryString) { this.query = querystring.parse(this.search.substr(1)); } else { this.query = this.search.substr(1); } } else if (parseQueryString) { this.search = ''; this.query = {}; } return this; } } var proto = protocolPattern.exec(rest); if (proto) { proto = proto[0]; var lowerProto = proto.toLowerCase(); this.protocol = lowerProto; 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(/^\/\/[^@\/]+@[^@\/]+/)) { var 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 (var i = 0; i < hostEndingChars.length; i++) { var 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 = decodeURIComponent(auth); } // the host is the remaining to the left of the first non-host char hostEnd = -1; for (var i = 0; i < nonHostChars.length; i++) { var 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; this.host = rest.slice(0, hostEnd); rest = rest.slice(hostEnd); // pull out port. this.parseHost(); // 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 (var 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 = ''; } else { // hostnames are always lower case. this.hostname = this.hostname.toLowerCase(); } if (!ipv6Hostname) { // IDNA Support: Returns a punycoded representation of "domain". // It only converts parts of the domain name that // have non-ASCII characters, i.e. it doesn't matter if // you call it with a domain that already is ASCII-only. this.hostname = punycode.toASCII(this.hostname); } var p = this.port ? ':' + this.port : ''; var h = this.hostname || ''; this.host = h + p; this.href += this.host; // strip [ and ] from the hostname // the host field still retains them, though if (ipv6Hostname) { this.hostname = this.hostname.substr(1, this.hostname.length - 2); if (rest[0] !== '/') { rest = '/' + rest; } } } // now rest is set to the post-host stuff. // chop off any delim chars. if (!unsafeProtocol[lowerProto]) { // First, make 100% sure that any "autoEscape" chars get // escaped, even if encodeURIComponent doesn't think they // need to be. for (var i = 0, l = autoEscape.length; i < l; i++) { var ae = autoEscape[i]; if (rest.indexOf(ae) === -1) continue; var esc = encodeURIComponent(ae); if (esc === ae) { esc = escape(ae); } rest = rest.split(ae).join(esc); } } // 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); this.query = rest.substr(qm + 1); if (parseQueryString) { this.query = querystring.parse(this.query); } rest = rest.slice(0, qm); } else if (parseQueryString) { // no query string, but parseQueryString still requested this.search = ''; this.query = {}; } if (rest) this.pathname = rest; if (slashedProtocol[lowerProto] && this.hostname && !this.pathname) { this.pathname = '/'; } //to support http.request if (this.pathname || this.search) { var p = this.pathname || ''; var s = this.search || ''; this.path = p + s; } // finally, reconstruct the href based on what has been validated. this.href = this.format(); return this; }; // format a parsed object into a url string function urlFormat(obj) { // ensure it's an object, and not a string url. // If it's an obj, this is a no-op. // this way, you can call url_format() on strings // to clean up potentially wonky urls. if (util.isString(obj)) obj = urlParse(obj); if (!(obj instanceof Url)) return Url.prototype.format.call(obj); return obj.format(); } Url.prototype.format = function() { var auth = this.auth || ''; if (auth) { auth = encodeURIComponent(auth); auth = auth.replace(/%3A/i, ':'); auth += '@'; } var protocol = this.protocol || '', pathname = this.pathname || '', hash = this.hash || '', host = false, query = ''; if (this.host) { host = auth + this.host; } else if (this.hostname) { host = auth + (this.hostname.indexOf(':') === -1 ? this.hostname : '[' + this.hostname + ']'); if (this.port) { host += ':' + this.port; } } if (this.query && util.isObject(this.query) && Object.keys(this.query).length) { query = querystring.stringify(this.query); } var search = this.search || (query && ('?' + query)) || ''; if (protocol && protocol.substr(-1) !== ':') protocol += ':'; // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. // unless they had them to begin with. if (this.slashes || (!protocol || slashedProtocol[protocol]) && host !== false) { host = '//' + (host || ''); if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; } else if (!host) { host = ''; } if (hash && hash.charAt(0) !== '#') hash = '#' + hash; if (search && search.charAt(0) !== '?') search = '?' + search; pathname = pathname.replace(/[?#]/g, function(match) { return encodeURIComponent(match); }); search = search.replace('#', '%23'); return protocol + host + pathname + search + hash; }; function urlResolve(source, relative) { return urlParse(source, false, true).resolve(relative); } Url.prototype.resolve = function(relative) { return this.resolveObject(urlParse(relative, false, true)).format(); }; function urlResolveObject(source, relative) { if (!source) return relative; return urlParse(source, false, true).resolveObject(relative); } Url.prototype.resolveObject = function(relative) { if (util.isString(relative)) { var rel = new Url(); rel.parse(relative, false, true); relative = rel; } var result = new Url(); var tkeys = Object.keys(this); for (var tk = 0; tk < tkeys.length; tk++) { var tkey = tkeys[tk]; result[tkey] = this[tkey]; } // hash is always overridden, no matter what. // even href="" will remove it. result.hash = relative.hash; // if the relative url is empty, then there's nothing left to do here. if (relative.href === '') { result.href = result.format(); return result; } // hrefs like //foo/bar always cut to the protocol. if (relative.slashes && !relative.protocol) { // take everything except the protocol from relative var rkeys = Object.keys(relative); for (var rk = 0; rk < rkeys.length; rk++) { var rkey = rkeys[rk]; if (rkey !== 'protocol') result[rkey] = relative[rkey]; } //urlParse appends trailing / to urls like http://www.example.com if (slashedProtocol[result.protocol] && result.hostname && !result.pathname) { result.path = result.pathname = '/'; } result.href = result.format(); return result; } if (relative.protocol && relative.protocol !== result.protocol) { // if it's a known url protocol, then changing // the protocol does weird things // first, if it's not file:, then we MUST have a host, // and if there was a path // to begin with, then we MUST have a path. // if it is file:, then the host is dropped, // because that's known to be hostless. // anything else is assumed to be absolute. if (!slashedProtocol[relative.protocol]) { var keys = Object.keys(relative); for (var v = 0; v < keys.length; v++) { var k = keys[v]; result[k] = relative[k]; } result.href = result.format(); return result; } result.protocol = relative.protocol; if (!relative.host && !hostlessProtocol[relative.protocol]) { var relPath = (relative.pathname || '').split('/'); while (relPath.length && !(relative.host = relPath.shift())); if (!relative.host) relative.host = ''; if (!relative.hostname) relative.hostname = ''; if (relPath[0] !== '') relPath.unshift(''); if (relPath.length < 2) relPath.unshift(''); result.pathname = relPath.join('/'); } else { result.pathname = relative.pathname; } result.search = relative.search; result.query = relative.query; result.host = relative.host || ''; result.auth = relative.auth; result.hostname = relative.hostname || relative.host; result.port = relative.port; // to support http.request if (result.pathname || result.search) { var p = result.pathname || ''; var s = result.search || ''; result.path = p + s; } result.slashes = result.slashes || relative.slashes; result.href = result.format(); return result; } var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), isRelAbs = ( relative.host || relative.pathname && relative.pathname.charAt(0) === '/' ), mustEndAbs = (isRelAbs || isSourceAbs || (result.host && relative.pathname)), removeAllDots = mustEndAbs, srcPath = result.pathname && result.pathname.split('/') || [], relPath = relative.pathname && relative.pathname.split('/') || [], psychotic = result.protocol && !slashedProtocol[result.protocol]; // if the url is a non-slashed url, then relative // links like ../.. should be able // to crawl up to the hostname, as well. This is strange. // result.protocol has already been set by now. // Later on, put the first path part into the host field. if (psychotic) { result.hostname = ''; result.port = null; if (result.host) { if (srcPath[0] === '') srcPath[0] = result.host; else srcPath.unshift(result.host); } result.host = ''; if (relative.protocol) { relative.hostname = null; relative.port = null; if (relative.host) { if (relPath[0] === '') relPath[0] = relative.host; else relPath.unshift(relative.host); } relative.host = null; } mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); } if (isRelAbs) { // it's absolute. result.host = (relative.host || relative.host === '') ? relative.host : result.host; result.hostname = (relative.hostname || relative.hostname === '') ? relative.hostname : result.hostname; result.search = relative.search; result.query = relative.query; srcPath = relPath; // fall through to the dot-handling below. } else if (relPath.length) { // it's relative // throw away the existing file, and take the new path instead. if (!srcPath) srcPath = []; srcPath.pop(); srcPath = srcPath.concat(relPath); result.search = relative.search; result.query = relative.query; } else if (!util.isNullOrUndefined(relative.search)) { // just pull out the search. // like href='?foo'. // Put this after the other two cases because it simplifies the booleans if (psychotic) { result.hostname = result.host = srcPath.shift(); //occationaly the auth can get stuck only in host //this especially happens in cases like //url.resolveObject('mailto:local1@domain1', 'local2@domain2') var authInHost = result.host && result.host.indexOf('@') > 0 ? result.host.split('@') : false; if (authInHost) { result.auth = authInHost.shift(); result.host = result.hostname = authInHost.shift(); } } result.search = relative.search; result.query = relative.query; //to support http.request if (!util.isNull(result.pathname) || !util.isNull(result.search)) { result.path = (result.pathname ? result.pathname : '') + (result.search ? result.search : ''); } result.href = result.format(); return result; } if (!srcPath.length) { // no path at all. easy. // we've already handled the other stuff above. result.pathname = null; //to support http.request if (result.search) { result.path = '/' + result.search; } else { result.path = null; } result.href = result.format(); return result; } // if a url ENDs in . or .., then it must get a trailing slash. // however, if it ends in anything else non-slashy, // then it must NOT get a trailing slash. var last = srcPath.slice(-1)[0]; var hasTrailingSlash = ( (result.host || relative.host || srcPath.length > 1) && (last === '.' || last === '..') || last === ''); // strip single dots, resolve double dots to parent dir // if the path tries to go above the root, `up` ends up > 0 var up = 0; for (var i = srcPath.length; i >= 0; i--) { last = srcPath[i]; if (last === '.') { srcPath.splice(i, 1); } else if (last === '..') { srcPath.splice(i, 1); up++; } else if (up) { srcPath.splice(i, 1); up--; } } // if the path is allowed to go above the root, restore leading ..s if (!mustEndAbs && !removeAllDots) { for (; up--; up) { srcPath.unshift('..'); } } if (mustEndAbs && srcPath[0] !== '' && (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { srcPath.unshift(''); } if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { srcPath.push(''); } var isAbsolute = srcPath[0] === '' || (srcPath[0] && srcPath[0].charAt(0) === '/'); // put the host back if (psychotic) { result.hostname = result.host = isAbsolute ? '' : srcPath.length ? srcPath.shift() : ''; //occationaly the auth can get stuck only in host //this especially happens in cases like //url.resolveObject('mailto:local1@domain1', 'local2@domain2') var authInHost = result.host && result.host.indexOf('@') > 0 ? result.host.split('@') : false; if (authInHost) { result.auth = authInHost.shift(); result.host = result.hostname = authInHost.shift(); } } mustEndAbs = mustEndAbs || (result.host && srcPath.length); if (mustEndAbs && !isAbsolute) { srcPath.unshift(''); } if (!srcPath.length) { result.pathname = null; result.path = null; } else { result.pathname = srcPath.join('/'); } //to support request.http if (!util.isNull(result.pathname) || !util.isNull(result.search)) { result.path = (result.pathname ? result.pathname : '') + (result.search ? result.search : ''); } result.auth = relative.auth || result.auth; result.slashes = result.slashes || relative.slashes; result.href = result.format(); return result; }; Url.prototype.parseHost = function() { var host = this.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; }; node-url-0.11.0/util.js000066400000000000000000000004721256762722000146450ustar00rootroot00000000000000'use strict'; module.exports = { isString: function(arg) { return typeof(arg) === 'string'; }, isObject: function(arg) { return typeof(arg) === 'object' && arg !== null; }, isNull: function(arg) { return arg === null; }, isNullOrUndefined: function(arg) { return arg == null; } };