URL.prototype.set = function set(part, value, fn) { var url = this; if ('query' === part) { if ('string' === typeof value) value = (fn || qs.parse)(value); url[part] = value; } else if ('port' === part) { url[part] = value; if (!required(value, url.protocol)) { url.host = url.hostname; url[part] = ''; } else if (value) { url.host = url.hostname +':'+ value; } } else if ('hostname' === part) { url[part] = value; if (url.port) value += ':'+ url.port; url.host = value; } else if ('host' === part) { url[part] = value; if (/\:\d+/.test(value)) { value = value.split(':'); url.hostname = value[0]; url.port = value[1]; } } else { url[part] = value; } url.href = url.toString(); return url; };
common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.port = options[forward || 'target'].port || (isSSL.test(options[forward || 'target'].protocol) ? 443 : 80); ['host', 'hostname', 'socketPath', 'pfx', 'key', 'passphrase', 'cert', 'ca', 'ciphers', 'secureProtocol'].forEach( function(e) { outgoing[e] = options[forward || 'target'][e]; } ); outgoing.method = req.method; outgoing.headers = extend({}, req.headers); if (options.headers){ extend(outgoing.headers, options.headers); } if (options.auth) { outgoing.auth = options.auth; } if (isSSL.test(options[forward || 'target'].protocol)) { outgoing.rejectUnauthorized = (typeof options.secure === "undefined") ? true : options.secure; } outgoing.agent = options.agent || false; outgoing.localAddress = options.localAddress; // // Remark: If we are false and not upgrading, set the connection: close. This is the right thing to do // as node core doesn't handle this COMPLETELY properly yet. // if (!outgoing.agent) { outgoing.headers = outgoing.headers || {}; if (typeof outgoing.headers.connection !== 'string' || !upgradeHeader.test(outgoing.headers.connection) ) { outgoing.headers.connection = 'close'; } } // the final path is target path + relative path requested by user: var target = options[forward || 'target']; var targetPath = target && options.prependPath !== false ? (target.path || '') : ''; // // Remark: Can we somehow not use url.parse as a perf optimization? // var outgoingPath = !options.toProxy ? (url.parse(req.url).path || '') : req.url; // // Remark: ignorePath will just straight up ignore whatever the request's // path is. This can be labeled as FOOT-GUN material if you do not know what // you are doing and are using conflicting options. // outgoingPath = !options.ignorePath ? outgoingPath : ''; outgoing.path = common.urlJoin(targetPath, outgoingPath); if (options.changeOrigin) { outgoing.headers.host = required(outgoing.port, options[forward || 'target'].protocol) && !hasPort(outgoing.host) ? outgoing.host + ':' + outgoing.port : outgoing.host; } return outgoing; };
/** * The actual URL instance. Instead of returning an object we've opted-in to * create an actual constructor as it's much more memory efficient and * faster and it pleases my CDO. * * @constructor * @param {String} address URL we want to parse. * @param {Boolean|function} parser Parser for the query string. * @param {Object} location Location defaults for relative paths. * @api public */ function URL(address, location, parser) { if (!(this instanceof URL)) { return new URL(address, location, parser); } var relative = relativere.test(address) , parse, instruction, index, key , type = typeof location , url = this , i = 0; // // The following if statements allows this module two have compatibility with // 2 different API: // // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments // where the boolean indicates that the query string should also be parsed. // // 2. The `URL` interface of the browser which accepts a URL, object as // arguments. The supplied object will be used as default values / fall-back // for relative paths. // if ('object' !== type && 'string' !== type) { parser = location; location = null; } if (parser && 'function' !== typeof parser) { parser = qs.parse; } location = lolcation(location); for (; i < instructions.length; i++) { instruction = instructions[i]; parse = instruction[0]; key = instruction[1]; if (parse !== parse) { url[key] = address; } else if ('string' === typeof parse) { if (~(index = address.indexOf(parse))) { if ('number' === typeof instruction[2]) { url[key] = address.slice(0, index); address = address.slice(index + instruction[2]); } else { url[key] = address.slice(index); address = address.slice(0, index); } } } else if (index = parse.exec(address)) { url[key] = index[1]; address = address.slice(0, address.length - index[0].length); } url[key] = url[key] || (instruction[3] || ('port' === key && relative) ? location[key] || '' : ''); // // Hostname, host and protocol should be lowercased so they can be used to // create a proper `origin`. // if (instruction[4]) { url[key] = url[key].toLowerCase(); } } // // Also parse the supplied query string in to an object. If we're supplied // with a custom parser as function use that instead of the default build-in // parser. // if (parser) url.query = parser(url.query); // // We should not add port numbers if they are already the default port number // for a given protocol. As the host also contains the port number we're going // override it with the hostname which contains no port number. // if (!required(url.port, url.protocol)) { url.host = url.hostname; url.port = ''; } // // Parse down the `auth` for the username and password. // url.username = url.password = ''; if (url.auth) { instruction = url.auth.split(':'); url.username = instruction[0] || ''; url.password = instruction[1] || ''; } // // The href is just the compiled result. // url.href = url.toString(); }
/** * This is convenience method for changing properties in the URL instance to * insure that they all propagate correctly. * * @param {String} part Property we need to adjust. * @param {Mixed} value The newly assigned value. * @param {Boolean|Function} fn When setting the query, it will be the function * used to parse the query. * When setting the protocol, double slash will be * removed from the final url if it is true. * @returns {URL} * @api public */ function set(part, value, fn) { var url = this; switch (part) { case 'query': if ('string' === typeof value && value.length) { value = (fn || qs.parse)(value); } url[part] = value; break; case 'port': url[part] = value; if (!required(value, url.protocol)) { url.host = url.hostname; url[part] = ''; } else if (value) { url.host = url.hostname +':'+ value; } break; case 'hostname': url[part] = value; if (url.port) value += ':'+ url.port; url.host = value; break; case 'host': url[part] = value; if (/:\d+$/.test(value)) { value = value.split(':'); url.port = value.pop(); url.hostname = value.join(':'); } else { url.hostname = value; url.port = ''; } break; case 'protocol': url.protocol = value.toLowerCase(); url.slashes = !fn; break; case 'pathname': case 'hash': if (value) { var char = part === 'pathname' ? '/' : '#'; url[part] = value.charAt(0) !== char ? char + value : value; } else { url[part] = value; } break; default: url[part] = value; } for (var i = 0; i < rules.length; i++) { var ins = rules[i]; if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase(); } url.origin = url.protocol && url.host && url.protocol !== 'file:' ? url.protocol +'//'+ url.host : 'null'; url.href = url.toString(); return url; }
/** * The actual URL instance. Instead of returning an object we've opted-in to * create an actual constructor as it's much more memory efficient and * faster and it pleases my OCD. * * @constructor * @param {String} address URL we want to parse. * @param {Object|String} location Location defaults for relative paths. * @param {Boolean|Function} parser Parser for the query string. * @api public */ function URL(address, location, parser) { if (!(this instanceof URL)) { return new URL(address, location, parser); } var relative, extracted, parse, instruction, index, key , instructions = rules.slice() , type = typeof location , url = this , i = 0; // // The following if statements allows this module two have compatibility with // 2 different API: // // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments // where the boolean indicates that the query string should also be parsed. // // 2. The `URL` interface of the browser which accepts a URL, object as // arguments. The supplied object will be used as default values / fall-back // for relative paths. // if ('object' !== type && 'string' !== type) { parser = location; location = null; } if (parser && 'function' !== typeof parser) parser = qs.parse; location = lolcation(location); // // Extract protocol information before running the instructions. // extracted = extractProtocol(address || ''); relative = !extracted.protocol && !extracted.slashes; url.slashes = extracted.slashes || relative && location.slashes; url.protocol = extracted.protocol || location.protocol || ''; address = extracted.rest; // // When the authority component is absent the URL starts with a path // component. // if (!extracted.slashes) instructions[2] = [/(.*)/, 'pathname']; for (; i < instructions.length; i++) { instruction = instructions[i]; parse = instruction[0]; key = instruction[1]; if (parse !== parse) { url[key] = address; } else if ('string' === typeof parse) { if (~(index = address.indexOf(parse))) { if ('number' === typeof instruction[2]) { url[key] = address.slice(0, index); address = address.slice(index + instruction[2]); } else { url[key] = address.slice(index); address = address.slice(0, index); } } } else if ((index = parse.exec(address))) { url[key] = index[1]; address = address.slice(0, index.index); } url[key] = url[key] || ( relative && instruction[3] ? location[key] || '' : '' ); // // Hostname, host and protocol should be lowercased so they can be used to // create a proper `origin`. // if (instruction[4]) url[key] = url[key].toLowerCase(); } // // Also parse the supplied query string in to an object. If we're supplied // with a custom parser as function use that instead of the default build-in // parser. // if (parser) url.query = parser(url.query); // // If the URL is relative, resolve the pathname against the base URL. // if ( relative && location.slashes && url.pathname.charAt(0) !== '/' && (url.pathname !== '' || location.pathname !== '') ) { url.pathname = resolve(url.pathname, location.pathname); } // // We should not add port numbers if they are already the default port number // for a given protocol. As the host also contains the port number we're going // override it with the hostname which contains no port number. // if (!required(url.port, url.protocol)) { url.host = url.hostname; url.port = ''; } // // Parse down the `auth` for the username and password. // url.username = url.password = ''; if (url.auth) { instruction = url.auth.split(':'); url.username = instruction[0] || ''; url.password = instruction[1] || ''; } url.origin = url.protocol && url.host && url.protocol !== 'file:' ? url.protocol +'//'+ url.host : 'null'; // // The href is just the compiled result. // url.href = url.toString(); }
/** * The actual URL instance. Instead of returning an object we've opted-in to * create an actual constructor as it's much more memory efficient and * faster and it pleases my CDO. * * @constructor * @param {String} address URL we want to parse. * @param {Boolean|function} parser Parser for the query string. * @param {Object} location Location defaults for relative paths. * @api public */ function URL(address, location, parser) { if (!(this instanceof URL)) { return new URL(address, location, parser); } var type = typeof location , bits = parse(address) , url = this , i = 0 , key; // // The following if statements allows this module two have compatibility with // 2 different API: // // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments // where the boolean indicates that the query string should also be parsed. // // 2. The `URL` interface of the browser which accepts a URL, object as // arguments. The supplied object will be used as default values / fall-back // for relative paths. // if ('object' !== type && 'string' !== type) { parser = location; location = null; } if (parser && 'function' !== typeof parser) { parser = qs.parse; } location = lolcation(location); for (; i < parts; key = keys[++i]) { if (!key) continue; url[key] = bits[i] || (key in inherit ? location[key] || '' : ''); // // The protocol, host, host name should always be lower cased even if they // are supplied in uppercase. This way, when people generate an `origin` // it be correct. // if (i === 2 || i === 5 || i === 6) url[key] = url[key].toLowerCase(); } // // Also parse the supplied query string in to an object. If we're supplied // with a custom parser as function use that instead of the default build-in // parser. // if (parser) url.query = parser(url.query); // // We should not add port numbers if they are already the default port number // for a given protocol. As the host also contains the port number we're going // override it with the hostname which contains no port number. // if (!required(url.port, url.protocol)) { url.host = url.hostname; url.port = ''; } // // The href is just the compiled result. // url.href = url.toString(); }