macgyver 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +20 -0
  5. data/README.md +45 -0
  6. data/Rakefile +1 -0
  7. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Growl +0 -0
  8. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Growl +0 -0
  9. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/Growl.h +5 -0
  10. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h +551 -0
  11. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlDefines.h +341 -0
  12. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Resources/Info.plist +40 -0
  13. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/_CodeSignature/CodeResources +34 -0
  14. data/assets/MacGap.app/Contents/Info.plist +48 -0
  15. data/assets/MacGap.app/Contents/MacOS/MacGap +0 -0
  16. data/assets/MacGap.app/Contents/PkgInfo +1 -0
  17. data/assets/MacGap.app/Contents/Resources/_debugger.js +1718 -0
  18. data/assets/MacGap.app/Contents/Resources/_http_agent.js +310 -0
  19. data/assets/MacGap.app/Contents/Resources/_http_client.js +533 -0
  20. data/assets/MacGap.app/Contents/Resources/_http_common.js +222 -0
  21. data/assets/MacGap.app/Contents/Resources/_http_incoming.js +194 -0
  22. data/assets/MacGap.app/Contents/Resources/_http_outgoing.js +597 -0
  23. data/assets/MacGap.app/Contents/Resources/_http_server.js +510 -0
  24. data/assets/MacGap.app/Contents/Resources/_linklist.js +76 -0
  25. data/assets/MacGap.app/Contents/Resources/_stream_duplex.js +69 -0
  26. data/assets/MacGap.app/Contents/Resources/_stream_passthrough.js +41 -0
  27. data/assets/MacGap.app/Contents/Resources/_stream_readable.js +900 -0
  28. data/assets/MacGap.app/Contents/Resources/_stream_transform.js +204 -0
  29. data/assets/MacGap.app/Contents/Resources/_stream_writable.js +456 -0
  30. data/assets/MacGap.app/Contents/Resources/_tls_legacy.js +887 -0
  31. data/assets/MacGap.app/Contents/Resources/_tls_wrap.js +831 -0
  32. data/assets/MacGap.app/Contents/Resources/application.icns +0 -0
  33. data/assets/MacGap.app/Contents/Resources/assert.js +326 -0
  34. data/assets/MacGap.app/Contents/Resources/buffer.js +724 -0
  35. data/assets/MacGap.app/Contents/Resources/child_process.js +1107 -0
  36. data/assets/MacGap.app/Contents/Resources/cluster.js +613 -0
  37. data/assets/MacGap.app/Contents/Resources/console.js +108 -0
  38. data/assets/MacGap.app/Contents/Resources/constants.js +22 -0
  39. data/assets/MacGap.app/Contents/Resources/crypto.js +691 -0
  40. data/assets/MacGap.app/Contents/Resources/dgram.js +459 -0
  41. data/assets/MacGap.app/Contents/Resources/dns.js +274 -0
  42. data/assets/MacGap.app/Contents/Resources/domain.js +292 -0
  43. data/assets/MacGap.app/Contents/Resources/en.lproj/Credits.rtf +29 -0
  44. data/assets/MacGap.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  45. data/assets/MacGap.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
  46. data/assets/MacGap.app/Contents/Resources/en.lproj/Window.nib +0 -0
  47. data/assets/MacGap.app/Contents/Resources/events.js +312 -0
  48. data/assets/MacGap.app/Contents/Resources/freelist.js +43 -0
  49. data/assets/MacGap.app/Contents/Resources/fs.js +1732 -0
  50. data/assets/MacGap.app/Contents/Resources/http.js +119 -0
  51. data/assets/MacGap.app/Contents/Resources/https.js +134 -0
  52. data/assets/MacGap.app/Contents/Resources/module.js +529 -0
  53. data/assets/MacGap.app/Contents/Resources/net.js +1378 -0
  54. data/assets/MacGap.app/Contents/Resources/nodelike.js +195 -0
  55. data/assets/MacGap.app/Contents/Resources/os.js +64 -0
  56. data/assets/MacGap.app/Contents/Resources/path.js +517 -0
  57. data/assets/MacGap.app/Contents/Resources/public/index.html +38 -0
  58. data/assets/MacGap.app/Contents/Resources/punycode.js +507 -0
  59. data/assets/MacGap.app/Contents/Resources/querystring.js +206 -0
  60. data/assets/MacGap.app/Contents/Resources/readline.js +1311 -0
  61. data/assets/MacGap.app/Contents/Resources/repl.js +945 -0
  62. data/assets/MacGap.app/Contents/Resources/smalloc.js +90 -0
  63. data/assets/MacGap.app/Contents/Resources/stream.js +127 -0
  64. data/assets/MacGap.app/Contents/Resources/string_decoder.js +189 -0
  65. data/assets/MacGap.app/Contents/Resources/sys.js +24 -0
  66. data/assets/MacGap.app/Contents/Resources/timers.js +568 -0
  67. data/assets/MacGap.app/Contents/Resources/tls.js +220 -0
  68. data/assets/MacGap.app/Contents/Resources/tty.js +129 -0
  69. data/assets/MacGap.app/Contents/Resources/url.js +693 -0
  70. data/assets/MacGap.app/Contents/Resources/util.js +688 -0
  71. data/assets/MacGap.app/Contents/Resources/vm.js +73 -0
  72. data/assets/MacGap.app/Contents/Resources/zlib.js +524 -0
  73. data/assets/index.html +38 -0
  74. data/bin/macgyver +104 -0
  75. data/macgyver.gemspec +19 -0
  76. data/test/public/index.html +27 -0
  77. metadata +121 -0
@@ -0,0 +1,220 @@
1
+ // Copyright Joyent, Inc. and other Node contributors.
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a
4
+ // copy of this software and associated documentation files (the
5
+ // "Software"), to deal in the Software without restriction, including
6
+ // without limitation the rights to use, copy, modify, merge, publish,
7
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ // persons to whom the Software is furnished to do so, subject to the
9
+ // following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included
12
+ // in all copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ var net = require('net');
23
+ var url = require('url');
24
+ var util = require('util');
25
+
26
+ exports.DEFAULT_CIPHERS =
27
+ 'ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:' + // TLS 1.2
28
+ 'RC4:HIGH:!MD5:!aNULL:!EDH'; // TLS 1.0
29
+
30
+ exports.DEFAULT_ECDH_CURVE = 'prime256v1';
31
+
32
+ // Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations
33
+ // every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more
34
+ // renegotations are seen. The settings are applied to all remote client
35
+ // connections.
36
+ exports.CLIENT_RENEG_LIMIT = 3;
37
+ exports.CLIENT_RENEG_WINDOW = 600;
38
+
39
+ exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024;
40
+
41
+ exports.getCiphers = function() {
42
+ var names = process.binding('crypto').getSSLCiphers();
43
+ // Drop all-caps names in favor of their lowercase aliases,
44
+ var ctx = {};
45
+ names.forEach(function(name) {
46
+ if (/^[0-9A-Z\-]+$/.test(name)) name = name.toLowerCase();
47
+ ctx[name] = true;
48
+ });
49
+ return Object.getOwnPropertyNames(ctx).sort();
50
+ };
51
+
52
+ // Convert protocols array into valid OpenSSL protocols list
53
+ // ("\x06spdy/2\x08http/1.1\x08http/1.0")
54
+ exports.convertNPNProtocols = function convertNPNProtocols(NPNProtocols, out) {
55
+ // If NPNProtocols is Array - translate it into buffer
56
+ if (util.isArray(NPNProtocols)) {
57
+ var buff = new Buffer(NPNProtocols.reduce(function(p, c) {
58
+ return p + 1 + Buffer.byteLength(c);
59
+ }, 0));
60
+
61
+ NPNProtocols.reduce(function(offset, c) {
62
+ var clen = Buffer.byteLength(c);
63
+ buff[offset] = clen;
64
+ buff.write(c, offset + 1);
65
+
66
+ return offset + 1 + clen;
67
+ }, 0);
68
+
69
+ NPNProtocols = buff;
70
+ }
71
+
72
+ // If it's already a Buffer - store it
73
+ if (util.isBuffer(NPNProtocols)) {
74
+ out.NPNProtocols = NPNProtocols;
75
+ }
76
+ };
77
+
78
+ exports.checkServerIdentity = function checkServerIdentity(host, cert) {
79
+ // Create regexp to much hostnames
80
+ function regexpify(host, wildcards) {
81
+ // Add trailing dot (make hostnames uniform)
82
+ if (!/\.$/.test(host)) host += '.';
83
+
84
+ // The same applies to hostname with more than one wildcard,
85
+ // if hostname has wildcard when wildcards are not allowed,
86
+ // or if there are less than two dots after wildcard (i.e. *.com or *d.com)
87
+ //
88
+ // also
89
+ //
90
+ // "The client SHOULD NOT attempt to match a presented identifier in
91
+ // which the wildcard character comprises a label other than the
92
+ // left-most label (e.g., do not match bar.*.example.net)."
93
+ // RFC6125
94
+ if (!wildcards && /\*/.test(host) || /[\.\*].*\*/.test(host) ||
95
+ /\*/.test(host) && !/\*.*\..+\..+/.test(host)) {
96
+ return /$./;
97
+ }
98
+
99
+ // Replace wildcard chars with regexp's wildcard and
100
+ // escape all characters that have special meaning in regexps
101
+ // (i.e. '.', '[', '{', '*', and others)
102
+ var re = host.replace(
103
+ /\*([a-z0-9\\-_\.])|[\.,\-\\\^\$+?*\[\]\(\):!\|{}]/g,
104
+ function(all, sub) {
105
+ if (sub) return '[a-z0-9\\-_]*' + (sub === '-' ? '\\-' : sub);
106
+ return '\\' + all;
107
+ });
108
+
109
+ return new RegExp('^' + re + '$', 'i');
110
+ }
111
+
112
+ var dnsNames = [],
113
+ uriNames = [],
114
+ ips = [],
115
+ matchCN = true,
116
+ valid = false;
117
+
118
+ // There're several names to perform check against:
119
+ // CN and altnames in certificate extension
120
+ // (DNS names, IP addresses, and URIs)
121
+ //
122
+ // Walk through altnames and generate lists of those names
123
+ if (cert.subjectaltname) {
124
+ cert.subjectaltname.split(/, /g).forEach(function(altname) {
125
+ if (/^DNS:/.test(altname)) {
126
+ dnsNames.push(altname.slice(4));
127
+ } else if (/^IP Address:/.test(altname)) {
128
+ ips.push(altname.slice(11));
129
+ } else if (/^URI:/.test(altname)) {
130
+ var uri = url.parse(altname.slice(4));
131
+ if (uri) uriNames.push(uri.hostname);
132
+ }
133
+ });
134
+ }
135
+
136
+ // If hostname is an IP address, it should be present in the list of IP
137
+ // addresses.
138
+ if (net.isIP(host)) {
139
+ valid = ips.some(function(ip) {
140
+ return ip === host;
141
+ });
142
+ } else {
143
+ // Transform hostname to canonical form
144
+ if (!/\.$/.test(host)) host += '.';
145
+
146
+ // Otherwise check all DNS/URI records from certificate
147
+ // (with allowed wildcards)
148
+ dnsNames = dnsNames.map(function(name) {
149
+ return regexpify(name, true);
150
+ });
151
+
152
+ // Wildcards ain't allowed in URI names
153
+ uriNames = uriNames.map(function(name) {
154
+ return regexpify(name, false);
155
+ });
156
+
157
+ dnsNames = dnsNames.concat(uriNames);
158
+
159
+ if (dnsNames.length > 0) matchCN = false;
160
+
161
+ // Match against Common Name (CN) only if no supported identifiers are
162
+ // present.
163
+ //
164
+ // "As noted, a client MUST NOT seek a match for a reference identifier
165
+ // of CN-ID if the presented identifiers include a DNS-ID, SRV-ID,
166
+ // URI-ID, or any application-specific identifier types supported by the
167
+ // client."
168
+ // RFC6125
169
+ if (matchCN) {
170
+ var commonNames = cert.subject.CN;
171
+ if (util.isArray(commonNames)) {
172
+ for (var i = 0, k = commonNames.length; i < k; ++i) {
173
+ dnsNames.push(regexpify(commonNames[i], true));
174
+ }
175
+ } else {
176
+ dnsNames.push(regexpify(commonNames, true));
177
+ }
178
+ }
179
+
180
+ valid = dnsNames.some(function(re) {
181
+ return re.test(host);
182
+ });
183
+ }
184
+
185
+ return valid;
186
+ };
187
+
188
+ // Example:
189
+ // C=US\nST=CA\nL=SF\nO=Joyent\nOU=Node.js\nCN=ca1\nemailAddress=ry@clouds.org
190
+ exports.parseCertString = function parseCertString(s) {
191
+ var out = {};
192
+ var parts = s.split('\n');
193
+ for (var i = 0, len = parts.length; i < len; i++) {
194
+ var sepIndex = parts[i].indexOf('=');
195
+ if (sepIndex > 0) {
196
+ var key = parts[i].slice(0, sepIndex);
197
+ var value = parts[i].slice(sepIndex + 1);
198
+ if (key in out) {
199
+ if (!util.isArray(out[key])) {
200
+ out[key] = [out[key]];
201
+ }
202
+ out[key].push(value);
203
+ } else {
204
+ out[key] = value;
205
+ }
206
+ }
207
+ }
208
+ return out;
209
+ };
210
+
211
+ // Public API
212
+ exports.TLSSocket = require('_tls_wrap').TLSSocket;
213
+ exports.Server = require('_tls_wrap').Server;
214
+ exports.createServer = require('_tls_wrap').createServer;
215
+ exports.connect = require('_tls_wrap').connect;
216
+
217
+ // Legacy API
218
+ exports.__defineGetter__('createSecurePair', util.deprecate(function() {
219
+ return require('_tls_legacy').createSecurePair;
220
+ }, 'createSecurePair() is deprecated, use TLSSocket instead'));
@@ -0,0 +1,129 @@
1
+ // Copyright Joyent, Inc. and other Node contributors.
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a
4
+ // copy of this software and associated documentation files (the
5
+ // "Software"), to deal in the Software without restriction, including
6
+ // without limitation the rights to use, copy, modify, merge, publish,
7
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ // persons to whom the Software is furnished to do so, subject to the
9
+ // following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included
12
+ // in all copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ var inherits = require('util').inherits;
23
+ var net = require('net');
24
+ var TTY = process.binding('tty_wrap').TTY;
25
+ var isTTY = process.binding('tty_wrap').isTTY;
26
+ var util = require('util');
27
+
28
+ var errnoException = util._errnoException;
29
+
30
+
31
+ exports.isatty = function(fd) {
32
+ return isTTY(fd);
33
+ };
34
+
35
+
36
+ // backwards-compat
37
+ exports.setRawMode = util.deprecate(function(flag) {
38
+ if (!process.stdin.isTTY) {
39
+ throw new Error('can\'t set raw mode on non-tty');
40
+ }
41
+ process.stdin.setRawMode(flag);
42
+ }, 'tty.setRawMode: Use `process.stdin.setRawMode()` instead.');
43
+
44
+
45
+ function ReadStream(fd, options) {
46
+ if (!(this instanceof ReadStream))
47
+ return new ReadStream(fd, options);
48
+
49
+ options = util._extend({
50
+ highWaterMark: 0,
51
+ readable: true,
52
+ writable: false,
53
+ handle: new TTY(fd, true)
54
+ }, options);
55
+
56
+ net.Socket.call(this, options);
57
+
58
+ this.isRaw = false;
59
+ this.isTTY = true;
60
+ }
61
+ inherits(ReadStream, net.Socket);
62
+
63
+ exports.ReadStream = ReadStream;
64
+
65
+ ReadStream.prototype.setRawMode = function(flag) {
66
+ flag = !!flag;
67
+ this._handle.setRawMode(flag);
68
+ this.isRaw = flag;
69
+ };
70
+
71
+
72
+
73
+ function WriteStream(fd) {
74
+ if (!(this instanceof WriteStream)) return new WriteStream(fd);
75
+ net.Socket.call(this, {
76
+ handle: new TTY(fd, false),
77
+ readable: false,
78
+ writable: true
79
+ });
80
+
81
+ var winSize = [];
82
+ var err = this._handle.getWindowSize(winSize);
83
+ if (!err) {
84
+ this.columns = winSize[0];
85
+ this.rows = winSize[1];
86
+ }
87
+ }
88
+ inherits(WriteStream, net.Socket);
89
+ exports.WriteStream = WriteStream;
90
+
91
+
92
+ WriteStream.prototype.isTTY = true;
93
+
94
+
95
+ WriteStream.prototype._refreshSize = function() {
96
+ var oldCols = this.columns;
97
+ var oldRows = this.rows;
98
+ var winSize = [];
99
+ var err = this._handle.getWindowSize(winSize);
100
+ if (err) {
101
+ this.emit('error', errnoException(err, 'getWindowSize'));
102
+ return;
103
+ }
104
+ var newCols = winSize[0];
105
+ var newRows = winSize[1];
106
+ if (oldCols !== newCols || oldRows !== newRows) {
107
+ this.columns = newCols;
108
+ this.rows = newRows;
109
+ this.emit('resize');
110
+ }
111
+ };
112
+
113
+
114
+ // backwards-compat
115
+ WriteStream.prototype.cursorTo = function(x, y) {
116
+ require('readline').cursorTo(this, x, y);
117
+ };
118
+ WriteStream.prototype.moveCursor = function(dx, dy) {
119
+ require('readline').moveCursor(this, dx, dy);
120
+ };
121
+ WriteStream.prototype.clearLine = function(dir) {
122
+ require('readline').clearLine(this, dir);
123
+ };
124
+ WriteStream.prototype.clearScreenDown = function() {
125
+ require('readline').clearScreenDown(this);
126
+ };
127
+ WriteStream.prototype.getWindowSize = function() {
128
+ return [this.columns, this.rows];
129
+ };
@@ -0,0 +1,693 @@
1
+ // Copyright Joyent, Inc. and other Node contributors.
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a
4
+ // copy of this software and associated documentation files (the
5
+ // "Software"), to deal in the Software without restriction, including
6
+ // without limitation the rights to use, copy, modify, merge, publish,
7
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ // persons to whom the Software is furnished to do so, subject to the
9
+ // following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included
12
+ // in all copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ var punycode = require('punycode');
23
+ var util = require('util');
24
+
25
+ exports.parse = urlParse;
26
+ exports.resolve = urlResolve;
27
+ exports.resolveObject = urlResolveObject;
28
+ exports.format = urlFormat;
29
+
30
+ exports.Url = Url;
31
+
32
+ function Url() {
33
+ this.protocol = null;
34
+ this.slashes = null;
35
+ this.auth = null;
36
+ this.host = null;
37
+ this.port = null;
38
+ this.hostname = null;
39
+ this.hash = null;
40
+ this.search = null;
41
+ this.query = null;
42
+ this.pathname = null;
43
+ this.path = null;
44
+ this.href = null;
45
+ }
46
+
47
+ // Reference: RFC 3986, RFC 1808, RFC 2396
48
+
49
+ // define these here so at least they only have to be
50
+ // compiled once on the first module load.
51
+ var protocolPattern = /^([a-z0-9.+-]+:)/i,
52
+ portPattern = /:[0-9]*$/,
53
+
54
+ // RFC 2396: characters reserved for delimiting URLs.
55
+ // We actually just auto-escape these.
56
+ delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
57
+
58
+ // RFC 2396: characters not allowed for various reasons.
59
+ unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
60
+
61
+ // Allowed by RFCs, but cause of XSS attacks. Always escape these.
62
+ autoEscape = ['\''].concat(unwise),
63
+ // Characters that are never ever allowed in a hostname.
64
+ // Note that any invalid chars are also handled, but these
65
+ // are the ones that are *expected* to be seen, so we fast-path
66
+ // them.
67
+ nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
68
+ hostEndingChars = ['/', '?', '#'],
69
+ hostnameMaxLen = 255,
70
+ hostnamePartPattern = /^[a-z0-9A-Z_-]{0,63}$/,
71
+ hostnamePartStart = /^([a-z0-9A-Z_-]{0,63})(.*)$/,
72
+ // protocols that can allow "unsafe" and "unwise" chars.
73
+ unsafeProtocol = {
74
+ 'javascript': true,
75
+ 'javascript:': true
76
+ },
77
+ // protocols that never have a hostname.
78
+ hostlessProtocol = {
79
+ 'javascript': true,
80
+ 'javascript:': true
81
+ },
82
+ // protocols that always contain a // bit.
83
+ slashedProtocol = {
84
+ 'http': true,
85
+ 'https': true,
86
+ 'ftp': true,
87
+ 'gopher': true,
88
+ 'file': true,
89
+ 'http:': true,
90
+ 'https:': true,
91
+ 'ftp:': true,
92
+ 'gopher:': true,
93
+ 'file:': true
94
+ },
95
+ querystring = require('querystring');
96
+
97
+ function urlParse(url, parseQueryString, slashesDenoteHost) {
98
+ if (url && util.isObject(url) && url instanceof Url) return url;
99
+
100
+ var u = new Url;
101
+ u.parse(url, parseQueryString, slashesDenoteHost);
102
+ return u;
103
+ }
104
+
105
+ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
106
+ if (!util.isString(url)) {
107
+ throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
108
+ }
109
+
110
+ var rest = url;
111
+
112
+ // trim before proceeding.
113
+ // This is to support parse stuff like " http://foo.com \n"
114
+ rest = rest.trim();
115
+
116
+ var proto = protocolPattern.exec(rest);
117
+ if (proto) {
118
+ proto = proto[0];
119
+ var lowerProto = proto.toLowerCase();
120
+ this.protocol = lowerProto;
121
+ rest = rest.substr(proto.length);
122
+ }
123
+
124
+ // figure out if it's got a host
125
+ // user@server is *always* interpreted as a hostname, and url
126
+ // resolution will treat //foo/bar as host=foo,path=bar because that's
127
+ // how the browser resolves relative URLs.
128
+ if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
129
+ var slashes = rest.substr(0, 2) === '//';
130
+ if (slashes && !(proto && hostlessProtocol[proto])) {
131
+ rest = rest.substr(2);
132
+ this.slashes = true;
133
+ }
134
+ }
135
+
136
+ if (!hostlessProtocol[proto] &&
137
+ (slashes || (proto && !slashedProtocol[proto]))) {
138
+
139
+ // there's a hostname.
140
+ // the first instance of /, ?, ;, or # ends the host.
141
+ //
142
+ // If there is an @ in the hostname, then non-host chars *are* allowed
143
+ // to the left of the last @ sign, unless some host-ending character
144
+ // comes *before* the @-sign.
145
+ // URLs are obnoxious.
146
+ //
147
+ // ex:
148
+ // http://a@b@c/ => user:a@b host:c
149
+ // http://a@b?@c => user:a host:c path:/?@c
150
+
151
+ // v0.12 TODO(isaacs): This is not quite how Chrome does things.
152
+ // Review our test case against browsers more comprehensively.
153
+
154
+ // find the first instance of any hostEndingChars
155
+ var hostEnd = -1;
156
+ for (var i = 0; i < hostEndingChars.length; i++) {
157
+ var hec = rest.indexOf(hostEndingChars[i]);
158
+ if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
159
+ hostEnd = hec;
160
+ }
161
+
162
+ // at this point, either we have an explicit point where the
163
+ // auth portion cannot go past, or the last @ char is the decider.
164
+ var auth, atSign;
165
+ if (hostEnd === -1) {
166
+ // atSign can be anywhere.
167
+ atSign = rest.lastIndexOf('@');
168
+ } else {
169
+ // atSign must be in auth portion.
170
+ // http://a@b/c@d => host:b auth:a path:/c@d
171
+ atSign = rest.lastIndexOf('@', hostEnd);
172
+ }
173
+
174
+ // Now we have a portion which is definitely the auth.
175
+ // Pull that off.
176
+ if (atSign !== -1) {
177
+ auth = rest.slice(0, atSign);
178
+ rest = rest.slice(atSign + 1);
179
+ this.auth = decodeURIComponent(auth);
180
+ }
181
+
182
+ // the host is the remaining to the left of the first non-host char
183
+ hostEnd = -1;
184
+ for (var i = 0; i < nonHostChars.length; i++) {
185
+ var hec = rest.indexOf(nonHostChars[i]);
186
+ if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
187
+ hostEnd = hec;
188
+ }
189
+ // if we still have not hit it, then the entire thing is a host.
190
+ if (hostEnd === -1)
191
+ hostEnd = rest.length;
192
+
193
+ this.host = rest.slice(0, hostEnd);
194
+ rest = rest.slice(hostEnd);
195
+
196
+ // pull out port.
197
+ this.parseHost();
198
+
199
+ // we've indicated that there is a hostname,
200
+ // so even if it's empty, it has to be present.
201
+ this.hostname = this.hostname || '';
202
+
203
+ // if hostname begins with [ and ends with ]
204
+ // assume that it's an IPv6 address.
205
+ var ipv6Hostname = this.hostname[0] === '[' &&
206
+ this.hostname[this.hostname.length - 1] === ']';
207
+
208
+ // validate a little.
209
+ if (!ipv6Hostname) {
210
+ var hostparts = this.hostname.split(/\./);
211
+ for (var i = 0, l = hostparts.length; i < l; i++) {
212
+ var part = hostparts[i];
213
+ if (!part) continue;
214
+ if (!part.match(hostnamePartPattern)) {
215
+ var newpart = '';
216
+ for (var j = 0, k = part.length; j < k; j++) {
217
+ if (part.charCodeAt(j) > 127) {
218
+ // we replace non-ASCII char with a temporary placeholder
219
+ // we need this to make sure size of hostname is not
220
+ // broken by replacing non-ASCII by nothing
221
+ newpart += 'x';
222
+ } else {
223
+ newpart += part[j];
224
+ }
225
+ }
226
+ // we test again with ASCII char only
227
+ if (!newpart.match(hostnamePartPattern)) {
228
+ var validParts = hostparts.slice(0, i);
229
+ var notHost = hostparts.slice(i + 1);
230
+ var bit = part.match(hostnamePartStart);
231
+ if (bit) {
232
+ validParts.push(bit[1]);
233
+ notHost.unshift(bit[2]);
234
+ }
235
+ if (notHost.length) {
236
+ rest = '/' + notHost.join('.') + rest;
237
+ }
238
+ this.hostname = validParts.join('.');
239
+ break;
240
+ }
241
+ }
242
+ }
243
+ }
244
+
245
+ if (this.hostname.length > hostnameMaxLen) {
246
+ this.hostname = '';
247
+ } else {
248
+ // hostnames are always lower case.
249
+ this.hostname = this.hostname.toLowerCase();
250
+ }
251
+
252
+ if (!ipv6Hostname) {
253
+ // IDNA Support: Returns a puny coded representation of "domain".
254
+ // It only converts the part of the domain name that
255
+ // has non ASCII characters. I.e. it dosent matter if
256
+ // you call it with a domain that already is in ASCII.
257
+ var domainArray = this.hostname.split('.');
258
+ var newOut = [];
259
+ for (var i = 0; i < domainArray.length; ++i) {
260
+ var s = domainArray[i];
261
+ newOut.push(s.match(/[^A-Za-z0-9_-]/) ?
262
+ 'xn--' + punycode.encode(s) : s);
263
+ }
264
+ this.hostname = newOut.join('.');
265
+ }
266
+
267
+ var p = this.port ? ':' + this.port : '';
268
+ var h = this.hostname || '';
269
+ this.host = h + p;
270
+ this.href += this.host;
271
+
272
+ // strip [ and ] from the hostname
273
+ // the host field still retains them, though
274
+ if (ipv6Hostname) {
275
+ this.hostname = this.hostname.substr(1, this.hostname.length - 2);
276
+ if (rest[0] !== '/') {
277
+ rest = '/' + rest;
278
+ }
279
+ }
280
+ }
281
+
282
+ // now rest is set to the post-host stuff.
283
+ // chop off any delim chars.
284
+ if (!unsafeProtocol[lowerProto]) {
285
+
286
+ // First, make 100% sure that any "autoEscape" chars get
287
+ // escaped, even if encodeURIComponent doesn't think they
288
+ // need to be.
289
+ for (var i = 0, l = autoEscape.length; i < l; i++) {
290
+ var ae = autoEscape[i];
291
+ var esc = encodeURIComponent(ae);
292
+ if (esc === ae) {
293
+ esc = escape(ae);
294
+ }
295
+ rest = rest.split(ae).join(esc);
296
+ }
297
+ }
298
+
299
+
300
+ // chop off from the tail first.
301
+ var hash = rest.indexOf('#');
302
+ if (hash !== -1) {
303
+ // got a fragment string.
304
+ this.hash = rest.substr(hash);
305
+ rest = rest.slice(0, hash);
306
+ }
307
+ var qm = rest.indexOf('?');
308
+ if (qm !== -1) {
309
+ this.search = rest.substr(qm);
310
+ this.query = rest.substr(qm + 1);
311
+ if (parseQueryString) {
312
+ this.query = querystring.parse(this.query);
313
+ }
314
+ rest = rest.slice(0, qm);
315
+ } else if (parseQueryString) {
316
+ // no query string, but parseQueryString still requested
317
+ this.search = '';
318
+ this.query = {};
319
+ }
320
+ if (rest) this.pathname = rest;
321
+ if (slashedProtocol[lowerProto] &&
322
+ this.hostname && !this.pathname) {
323
+ this.pathname = '/';
324
+ }
325
+
326
+ //to support http.request
327
+ if (this.pathname || this.search) {
328
+ var p = this.pathname || '';
329
+ var s = this.search || '';
330
+ this.path = p + s;
331
+ }
332
+
333
+ // finally, reconstruct the href based on what has been validated.
334
+ this.href = this.format();
335
+ return this;
336
+ };
337
+
338
+ // format a parsed object into a url string
339
+ function urlFormat(obj) {
340
+ // ensure it's an object, and not a string url.
341
+ // If it's an obj, this is a no-op.
342
+ // this way, you can call url_format() on strings
343
+ // to clean up potentially wonky urls.
344
+ if (util.isString(obj)) obj = urlParse(obj);
345
+ if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
346
+ return obj.format();
347
+ }
348
+
349
+ Url.prototype.format = function() {
350
+ var auth = this.auth || '';
351
+ if (auth) {
352
+ auth = encodeURIComponent(auth);
353
+ auth = auth.replace(/%3A/i, ':');
354
+ auth += '@';
355
+ }
356
+
357
+ var protocol = this.protocol || '',
358
+ pathname = this.pathname || '',
359
+ hash = this.hash || '',
360
+ host = false,
361
+ query = '';
362
+
363
+ if (this.host) {
364
+ host = auth + this.host;
365
+ } else if (this.hostname) {
366
+ host = auth + (this.hostname.indexOf(':') === -1 ?
367
+ this.hostname :
368
+ '[' + this.hostname + ']');
369
+ if (this.port) {
370
+ host += ':' + this.port;
371
+ }
372
+ }
373
+
374
+ if (this.query &&
375
+ util.isObject(this.query) &&
376
+ Object.keys(this.query).length) {
377
+ query = querystring.stringify(this.query);
378
+ }
379
+
380
+ var search = this.search || (query && ('?' + query)) || '';
381
+
382
+ if (protocol && protocol.substr(-1) !== ':') protocol += ':';
383
+
384
+ // only the slashedProtocols get the //. Not mailto:, xmpp:, etc.
385
+ // unless they had them to begin with.
386
+ if (this.slashes ||
387
+ (!protocol || slashedProtocol[protocol]) && host !== false) {
388
+ host = '//' + (host || '');
389
+ if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
390
+ } else if (!host) {
391
+ host = '';
392
+ }
393
+
394
+ if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
395
+ if (search && search.charAt(0) !== '?') search = '?' + search;
396
+
397
+ pathname = pathname.replace(/[?#]/g, function(match) {
398
+ return encodeURIComponent(match);
399
+ });
400
+ search = search.replace('#', '%23');
401
+
402
+ return protocol + host + pathname + search + hash;
403
+ };
404
+
405
+ function urlResolve(source, relative) {
406
+ return urlParse(source, false, true).resolve(relative);
407
+ }
408
+
409
+ Url.prototype.resolve = function(relative) {
410
+ return this.resolveObject(urlParse(relative, false, true)).format();
411
+ };
412
+
413
+ function urlResolveObject(source, relative) {
414
+ if (!source) return relative;
415
+ return urlParse(source, false, true).resolveObject(relative);
416
+ }
417
+
418
+ Url.prototype.resolveObject = function(relative) {
419
+ if (util.isString(relative)) {
420
+ var rel = new Url();
421
+ rel.parse(relative, false, true);
422
+ relative = rel;
423
+ }
424
+
425
+ var result = new Url();
426
+ Object.keys(this).forEach(function(k) {
427
+ result[k] = this[k];
428
+ }, this);
429
+
430
+ // hash is always overridden, no matter what.
431
+ // even href="" will remove it.
432
+ result.hash = relative.hash;
433
+
434
+ // if the relative url is empty, then there's nothing left to do here.
435
+ if (relative.href === '') {
436
+ result.href = result.format();
437
+ return result;
438
+ }
439
+
440
+ // hrefs like //foo/bar always cut to the protocol.
441
+ if (relative.slashes && !relative.protocol) {
442
+ // take everything except the protocol from relative
443
+ Object.keys(relative).forEach(function(k) {
444
+ if (k !== 'protocol')
445
+ result[k] = relative[k];
446
+ });
447
+
448
+ //urlParse appends trailing / to urls like http://www.example.com
449
+ if (slashedProtocol[result.protocol] &&
450
+ result.hostname && !result.pathname) {
451
+ result.path = result.pathname = '/';
452
+ }
453
+
454
+ result.href = result.format();
455
+ return result;
456
+ }
457
+
458
+ if (relative.protocol && relative.protocol !== result.protocol) {
459
+ // if it's a known url protocol, then changing
460
+ // the protocol does weird things
461
+ // first, if it's not file:, then we MUST have a host,
462
+ // and if there was a path
463
+ // to begin with, then we MUST have a path.
464
+ // if it is file:, then the host is dropped,
465
+ // because that's known to be hostless.
466
+ // anything else is assumed to be absolute.
467
+ if (!slashedProtocol[relative.protocol]) {
468
+ Object.keys(relative).forEach(function(k) {
469
+ result[k] = relative[k];
470
+ });
471
+ result.href = result.format();
472
+ return result;
473
+ }
474
+
475
+ result.protocol = relative.protocol;
476
+ if (!relative.host && !hostlessProtocol[relative.protocol]) {
477
+ var relPath = (relative.pathname || '').split('/');
478
+ while (relPath.length && !(relative.host = relPath.shift()));
479
+ if (!relative.host) relative.host = '';
480
+ if (!relative.hostname) relative.hostname = '';
481
+ if (relPath[0] !== '') relPath.unshift('');
482
+ if (relPath.length < 2) relPath.unshift('');
483
+ result.pathname = relPath.join('/');
484
+ } else {
485
+ result.pathname = relative.pathname;
486
+ }
487
+ result.search = relative.search;
488
+ result.query = relative.query;
489
+ result.host = relative.host || '';
490
+ result.auth = relative.auth;
491
+ result.hostname = relative.hostname || relative.host;
492
+ result.port = relative.port;
493
+ // to support http.request
494
+ if (result.pathname || result.search) {
495
+ var p = result.pathname || '';
496
+ var s = result.search || '';
497
+ result.path = p + s;
498
+ }
499
+ result.slashes = result.slashes || relative.slashes;
500
+ result.href = result.format();
501
+ return result;
502
+ }
503
+
504
+ var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
505
+ isRelAbs = (
506
+ relative.host ||
507
+ relative.pathname && relative.pathname.charAt(0) === '/'
508
+ ),
509
+ mustEndAbs = (isRelAbs || isSourceAbs ||
510
+ (result.host && relative.pathname)),
511
+ removeAllDots = mustEndAbs,
512
+ srcPath = result.pathname && result.pathname.split('/') || [],
513
+ relPath = relative.pathname && relative.pathname.split('/') || [],
514
+ psychotic = result.protocol && !slashedProtocol[result.protocol];
515
+
516
+ // if the url is a non-slashed url, then relative
517
+ // links like ../.. should be able
518
+ // to crawl up to the hostname, as well. This is strange.
519
+ // result.protocol has already been set by now.
520
+ // Later on, put the first path part into the host field.
521
+ if (psychotic) {
522
+ result.hostname = '';
523
+ result.port = null;
524
+ if (result.host) {
525
+ if (srcPath[0] === '') srcPath[0] = result.host;
526
+ else srcPath.unshift(result.host);
527
+ }
528
+ result.host = '';
529
+ if (relative.protocol) {
530
+ relative.hostname = null;
531
+ relative.port = null;
532
+ if (relative.host) {
533
+ if (relPath[0] === '') relPath[0] = relative.host;
534
+ else relPath.unshift(relative.host);
535
+ }
536
+ relative.host = null;
537
+ }
538
+ mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
539
+ }
540
+
541
+ if (isRelAbs) {
542
+ // it's absolute.
543
+ result.host = (relative.host || relative.host === '') ?
544
+ relative.host : result.host;
545
+ result.hostname = (relative.hostname || relative.hostname === '') ?
546
+ relative.hostname : result.hostname;
547
+ result.search = relative.search;
548
+ result.query = relative.query;
549
+ srcPath = relPath;
550
+ // fall through to the dot-handling below.
551
+ } else if (relPath.length) {
552
+ // it's relative
553
+ // throw away the existing file, and take the new path instead.
554
+ if (!srcPath) srcPath = [];
555
+ srcPath.pop();
556
+ srcPath = srcPath.concat(relPath);
557
+ result.search = relative.search;
558
+ result.query = relative.query;
559
+ } else if (!util.isNullOrUndefined(relative.search)) {
560
+ // just pull out the search.
561
+ // like href='?foo'.
562
+ // Put this after the other two cases because it simplifies the booleans
563
+ if (psychotic) {
564
+ result.hostname = result.host = srcPath.shift();
565
+ //occationaly the auth can get stuck only in host
566
+ //this especialy happens in cases like
567
+ //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
568
+ var authInHost = result.host && result.host.indexOf('@') > 0 ?
569
+ result.host.split('@') : false;
570
+ if (authInHost) {
571
+ result.auth = authInHost.shift();
572
+ result.host = result.hostname = authInHost.shift();
573
+ }
574
+ }
575
+ result.search = relative.search;
576
+ result.query = relative.query;
577
+ //to support http.request
578
+ if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
579
+ result.path = (result.pathname ? result.pathname : '') +
580
+ (result.search ? result.search : '');
581
+ }
582
+ result.href = result.format();
583
+ return result;
584
+ }
585
+
586
+ if (!srcPath.length) {
587
+ // no path at all. easy.
588
+ // we've already handled the other stuff above.
589
+ result.pathname = null;
590
+ //to support http.request
591
+ if (result.search) {
592
+ result.path = '/' + result.search;
593
+ } else {
594
+ result.path = null;
595
+ }
596
+ result.href = result.format();
597
+ return result;
598
+ }
599
+
600
+ // if a url ENDs in . or .., then it must get a trailing slash.
601
+ // however, if it ends in anything else non-slashy,
602
+ // then it must NOT get a trailing slash.
603
+ var last = srcPath.slice(-1)[0];
604
+ var hasTrailingSlash = (
605
+ (result.host || relative.host) && (last === '.' || last === '..') ||
606
+ last === '');
607
+
608
+ // strip single dots, resolve double dots to parent dir
609
+ // if the path tries to go above the root, `up` ends up > 0
610
+ var up = 0;
611
+ for (var i = srcPath.length; i >= 0; i--) {
612
+ last = srcPath[i];
613
+ if (last == '.') {
614
+ srcPath.splice(i, 1);
615
+ } else if (last === '..') {
616
+ srcPath.splice(i, 1);
617
+ up++;
618
+ } else if (up) {
619
+ srcPath.splice(i, 1);
620
+ up--;
621
+ }
622
+ }
623
+
624
+ // if the path is allowed to go above the root, restore leading ..s
625
+ if (!mustEndAbs && !removeAllDots) {
626
+ for (; up--; up) {
627
+ srcPath.unshift('..');
628
+ }
629
+ }
630
+
631
+ if (mustEndAbs && srcPath[0] !== '' &&
632
+ (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
633
+ srcPath.unshift('');
634
+ }
635
+
636
+ if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
637
+ srcPath.push('');
638
+ }
639
+
640
+ var isAbsolute = srcPath[0] === '' ||
641
+ (srcPath[0] && srcPath[0].charAt(0) === '/');
642
+
643
+ // put the host back
644
+ if (psychotic) {
645
+ result.hostname = result.host = isAbsolute ? '' :
646
+ srcPath.length ? srcPath.shift() : '';
647
+ //occationaly the auth can get stuck only in host
648
+ //this especialy happens in cases like
649
+ //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
650
+ var authInHost = result.host && result.host.indexOf('@') > 0 ?
651
+ result.host.split('@') : false;
652
+ if (authInHost) {
653
+ result.auth = authInHost.shift();
654
+ result.host = result.hostname = authInHost.shift();
655
+ }
656
+ }
657
+
658
+ mustEndAbs = mustEndAbs || (result.host && srcPath.length);
659
+
660
+ if (mustEndAbs && !isAbsolute) {
661
+ srcPath.unshift('');
662
+ }
663
+
664
+ if (!srcPath.length) {
665
+ result.pathname = null;
666
+ result.path = null;
667
+ } else {
668
+ result.pathname = srcPath.join('/');
669
+ }
670
+
671
+ //to support request.http
672
+ if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
673
+ result.path = (result.pathname ? result.pathname : '') +
674
+ (result.search ? result.search : '');
675
+ }
676
+ result.auth = relative.auth || result.auth;
677
+ result.slashes = result.slashes || relative.slashes;
678
+ result.href = result.format();
679
+ return result;
680
+ };
681
+
682
+ Url.prototype.parseHost = function() {
683
+ var host = this.host;
684
+ var port = portPattern.exec(host);
685
+ if (port) {
686
+ port = port[0];
687
+ if (port !== ':') {
688
+ this.port = port.substr(1);
689
+ }
690
+ host = host.substr(0, host.length - port.length);
691
+ }
692
+ if (host) this.hostname = host;
693
+ };