http: allow url and options to be passed to http*.request and http*.get

Fixes: https://github.com/nodejs/node/issues/20795
PR-URL: https://github.com/nodejs/node/pull/21616
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ron Korving <ron@ronkorving.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
Sam Ruby 2018-07-01 11:00:24 -04:00 committed by Matteo Collina
parent 19bc893c75
commit f9b739ebbc
5 changed files with 79 additions and 19 deletions

View File

@ -1796,15 +1796,20 @@ The `requestListener` is a function which is automatically
added to the [`'request'`][] event. added to the [`'request'`][] event.
## http.get(options[, callback]) ## http.get(options[, callback])
## http.get(url[, options][, callback])
<!-- YAML <!-- YAML
added: v0.3.6 added: v0.3.6
changes: changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/21616
description: allow both url and options to be passed to `http.get()`
- version: v7.5.0 - version: v7.5.0
pr-url: https://github.com/nodejs/node/pull/10638 pr-url: https://github.com/nodejs/node/pull/10638
description: The `options` parameter can be a WHATWG `URL` object. description: The `options` parameter can be a WHATWG `URL` object.
--> -->
* `options` {Object | string | URL} Accepts the same `options` as * `url` {string | URL}
* `options` {Object} Accepts the same `options` as
[`http.request()`][], with the `method` always set to `GET`. [`http.request()`][], with the `method` always set to `GET`.
Properties that are inherited from the prototype are ignored. Properties that are inherited from the prototype are ignored.
* `callback` {Function} * `callback` {Function}
@ -1868,15 +1873,20 @@ Global instance of `Agent` which is used as the default for all HTTP client
requests. requests.
## http.request(options[, callback]) ## http.request(options[, callback])
## http.request(url[, options][, callback])
<!-- YAML <!-- YAML
added: v0.3.6 added: v0.3.6
changes: changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/21616
description: allow both url and options to be passed to `http.request()`
- version: v7.5.0 - version: v7.5.0
pr-url: https://github.com/nodejs/node/pull/10638 pr-url: https://github.com/nodejs/node/pull/10638
description: The `options` parameter can be a WHATWG `URL` object. description: The `options` parameter can be a WHATWG `URL` object.
--> -->
* `options` {Object | string | URL} * `url` {string | URL}
* `options` {Object}
* `protocol` {string} Protocol to use. **Default:** `'http:'`. * `protocol` {string} Protocol to use. **Default:** `'http:'`.
* `host` {string} A domain name or IP address of the server to issue the * `host` {string} A domain name or IP address of the server to issue the
request to. **Default:** `'localhost'`. request to. **Default:** `'localhost'`.
@ -1918,10 +1928,13 @@ changes:
Node.js maintains several connections per server to make HTTP requests. Node.js maintains several connections per server to make HTTP requests.
This function allows one to transparently issue requests. This function allows one to transparently issue requests.
`options` can be an object, a string, or a [`URL`][] object. If `options` is a `url` can be a string or a [`URL`][] object. If `url` is a
string, it is automatically parsed with [`new URL()`][]. If it is a [`URL`][] string, it is automatically parsed with [`new URL()`][]. If it is a [`URL`][]
object, it will be automatically converted to an ordinary `options` object. object, it will be automatically converted to an ordinary `options` object.
If both `url` and `options` are specified, the objects are merged, with the
`options` properties taking precedence.
The optional `callback` parameter will be added as a one-time listener for The optional `callback` parameter will be added as a one-time listener for
the [`'response'`][] event. the [`'response'`][] event.

View File

@ -112,14 +112,19 @@ https.createServer(options, (req, res) => {
``` ```
## https.get(options[, callback]) ## https.get(options[, callback])
## https.get(url[, options][, callback])
<!-- YAML <!-- YAML
added: v0.3.6 added: v0.3.6
changes: changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/21616
description: allow both url and options to be passed to `https.get()`
- version: v7.5.0 - version: v7.5.0
pr-url: https://github.com/nodejs/node/pull/10638 pr-url: https://github.com/nodejs/node/pull/10638
description: The `options` parameter can be a WHATWG `URL` object. description: The `options` parameter can be a WHATWG `URL` object.
--> -->
- `options` {Object | string | URL} Accepts the same `options` as - `url` {string | URL}
- `options` {Object} Accepts the same `options` as
[`https.request()`][], with the `method` always set to `GET`. [`https.request()`][], with the `method` always set to `GET`.
- `callback` {Function} - `callback` {Function}
@ -155,9 +160,13 @@ added: v0.5.9
Global instance of [`https.Agent`][] for all HTTPS client requests. Global instance of [`https.Agent`][] for all HTTPS client requests.
## https.request(options[, callback]) ## https.request(options[, callback])
## https.request(url[, options][, callback])
<!-- YAML <!-- YAML
added: v0.3.6 added: v0.3.6
changes: changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/21616
description: allow both url and options to be passed to `https.request()`
- version: v9.3.0 - version: v9.3.0
pr-url: https://github.com/nodejs/node/pull/14903 pr-url: https://github.com/nodejs/node/pull/14903
description: The `options` parameter can now include `clientCertEngine`. description: The `options` parameter can now include `clientCertEngine`.
@ -165,7 +174,8 @@ changes:
pr-url: https://github.com/nodejs/node/pull/10638 pr-url: https://github.com/nodejs/node/pull/10638
description: The `options` parameter can be a WHATWG `URL` object. description: The `options` parameter can be a WHATWG `URL` object.
--> -->
- `options` {Object | string | URL} Accepts all `options` from - `url` {string | URL}
- `options` {Object} Accepts all `options` from
[`http.request()`][], with some differences in default values: [`http.request()`][], with some differences in default values:
- `protocol` **Default:** `'https:'` - `protocol` **Default:** `'https:'`
- `port` **Default:** `443` - `port` **Default:** `443`

View File

@ -60,16 +60,16 @@ function validateHost(host, name) {
} }
let urlWarningEmitted = false; let urlWarningEmitted = false;
function ClientRequest(options, cb) { function ClientRequest(input, options, cb) {
OutgoingMessage.call(this); OutgoingMessage.call(this);
if (typeof options === 'string') { if (typeof input === 'string') {
const urlStr = options; const urlStr = input;
try { try {
options = urlToOptions(new URL(urlStr)); input = urlToOptions(new URL(urlStr));
} catch (err) { } catch (err) {
options = url.parse(urlStr); input = url.parse(urlStr);
if (!options.hostname) { if (!input.hostname) {
throw err; throw err;
} }
if (!urlWarningEmitted && !process.noDeprecation) { if (!urlWarningEmitted && !process.noDeprecation) {
@ -80,14 +80,23 @@ function ClientRequest(options, cb) {
'DeprecationWarning', 'DEP0109'); 'DeprecationWarning', 'DEP0109');
} }
} }
} else if (options && options[searchParamsSymbol] && } else if (input && input[searchParamsSymbol] &&
options[searchParamsSymbol][searchParamsSymbol]) { input[searchParamsSymbol][searchParamsSymbol]) {
// url.URL instance // url.URL instance
options = urlToOptions(options); input = urlToOptions(input);
} else { } else {
options = util._extend({}, options); cb = options;
options = input;
input = null;
} }
if (typeof options === 'function') {
cb = options;
options = null;
}
options = util._extend(input || {}, options || {});
var agent = options.agent; var agent = options.agent;
var defaultAgent = options._defaultAgent || Agent.globalAgent; var defaultAgent = options._defaultAgent || Agent.globalAgent;
if (agent === false) { if (agent === false) {

View File

@ -37,12 +37,12 @@ function createServer(opts, requestListener) {
return new Server(opts, requestListener); return new Server(opts, requestListener);
} }
function request(options, cb) { function request(url, options, cb) {
return new ClientRequest(options, cb); return new ClientRequest(url, options, cb);
} }
function get(options, cb) { function get(url, options, cb) {
var req = request(options, cb); var req = request(url, options, cb);
req.end(); req.end();
return req; return req;
} }

View File

@ -0,0 +1,28 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
// Test providing both a url and options, with the options partially
// replacing address and port portions of the URL provided.
{
const server = http.createServer(
common.mustCall((req, res) => {
assert.strictEqual(req.url, '/testpath');
res.end();
server.close();
})
);
server.listen(
0,
common.mustCall(() => {
http.get(
'http://example.com/testpath',
{ hostname: 'localhost', port: server.address().port },
common.mustCall((res) => {
res.resume();
})
);
})
);
}