Skip to content

Commit cbe9d7d

Browse files
committed
[v10.x backport] http: allow url and options to be passed to http*.request and http*.get
1 parent af6b824 commit cbe9d7d

File tree

5 files changed

+94
-18
lines changed

5 files changed

+94
-18
lines changed

doc/api/http.md

+16-3
Original file line numberDiff line numberDiff line change
@@ -1792,15 +1792,20 @@ The `requestListener` is a function which is automatically
17921792
added to the [`'request'`][] event.
17931793

17941794
## http.get(options[, callback])
1795+
## http.get(url[, options][, callback])
17951796
<!-- YAML
17961797
added: v0.3.6
17971798
changes:
1799+
- version: REPLACEME
1800+
pr-url: https://github.com/nodejs/node/pull/21616
1801+
description: allow both url and options to be passed to `http.get()`
17981802
- version: v7.5.0
17991803
pr-url: https://github.com/nodejs/node/pull/10638
18001804
description: The `options` parameter can be a WHATWG `URL` object.
18011805
-->
18021806

1803-
* `options` {Object | string | URL} Accepts the same `options` as
1807+
* `url` {string | URL}
1808+
* `options` {Object} Accepts the same `options` as
18041809
[`http.request()`][], with the `method` always set to `GET`.
18051810
Properties that are inherited from the prototype are ignored.
18061811
* `callback` {Function}
@@ -1864,15 +1869,20 @@ Global instance of `Agent` which is used as the default for all HTTP client
18641869
requests.
18651870

18661871
## http.request(options[, callback])
1872+
## http.request(url[, options][, callback])
18671873
<!-- YAML
18681874
added: v0.3.6
18691875
changes:
1876+
- version: REPLACEME
1877+
pr-url: https://github.com/nodejs/node/pull/21616
1878+
description: allow both url and options to be passed to `http.request()`
18701879
- version: v7.5.0
18711880
pr-url: https://github.com/nodejs/node/pull/10638
18721881
description: The `options` parameter can be a WHATWG `URL` object.
18731882
-->
18741883

1875-
* `options` {Object | string | URL}
1884+
* `url` {string | URL}
1885+
* `options` {Object}
18761886
* `protocol` {string} Protocol to use. **Default:** `'http:'`.
18771887
* `host` {string} A domain name or IP address of the server to issue the
18781888
request to. **Default:** `'localhost'`.
@@ -1914,10 +1924,13 @@ changes:
19141924
Node.js maintains several connections per server to make HTTP requests.
19151925
This function allows one to transparently issue requests.
19161926

1917-
`options` can be an object, a string, or a [`URL`][] object. If `options` is a
1927+
`url` can be a string or a [`URL`][] object. If `url` is a
19181928
string, it is automatically parsed with [`url.parse()`][]. If it is a [`URL`][]
19191929
object, it will be automatically converted to an ordinary `options` object.
19201930

1931+
If both `url` and `options` are specified, the objects are merged, with the
1932+
`options` properties taking precedence.
1933+
19211934
The optional `callback` parameter will be added as a one-time listener for
19221935
the [`'response'`][] event.
19231936

doc/api/https.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,19 @@ https.createServer(options, (req, res) => {
112112
```
113113

114114
## https.get(options[, callback])
115+
## https.get(url[, options][, callback])
115116
<!-- YAML
116117
added: v0.3.6
117118
changes:
119+
- version: REPLACEME
120+
pr-url: https://github.com/nodejs/node/pull/21616
121+
description: allow both url and options to be passed to `https.get()`
118122
- version: v7.5.0
119123
pr-url: https://github.com/nodejs/node/pull/10638
120124
description: The `options` parameter can be a WHATWG `URL` object.
121125
-->
122-
- `options` {Object | string | URL} Accepts the same `options` as
126+
- `url` {string | URL}
127+
- `options` {Object} Accepts the same `options` as
123128
[`https.request()`][], with the `method` always set to `GET`.
124129
- `callback` {Function}
125130

@@ -155,17 +160,22 @@ added: v0.5.9
155160
Global instance of [`https.Agent`][] for all HTTPS client requests.
156161

157162
## https.request(options[, callback])
163+
## https.request(url[, options][, callback])
158164
<!-- YAML
159165
added: v0.3.6
160166
changes:
167+
- version: REPLACEME
168+
pr-url: https://github.com/nodejs/node/pull/21616
169+
description: allow both url and options to be passed to `https.request()`
161170
- version: v9.3.0
162171
pr-url: https://github.com/nodejs/node/pull/14903
163172
description: The `options` parameter can now include `clientCertEngine`.
164173
- version: v7.5.0
165174
pr-url: https://github.com/nodejs/node/pull/10638
166175
description: The `options` parameter can be a WHATWG `URL` object.
167176
-->
168-
- `options` {Object | string | URL} Accepts all `options` from
177+
- `url` {string | URL}
178+
- `options` {Object} Accepts all `options` from
169179
[`http.request()`][], with some differences in default values:
170180
- `protocol` **Default:** `'https:'`
171181
- `port` **Default:** `443`

lib/_http_client.js

+34-9
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,47 @@ function validateHost(host, name) {
6060
return host;
6161
}
6262

63-
function ClientRequest(options, cb) {
63+
let urlWarningEmitted = false;
64+
function ClientRequest(input, options, cb) {
6465
OutgoingMessage.call(this);
6566

66-
if (typeof options === 'string') {
67-
options = url.parse(options);
68-
if (!options.hostname) {
69-
throw new ERR_INVALID_DOMAIN_NAME();
67+
if (typeof input === 'string') {
68+
const urlStr = input;
69+
try {
70+
input = url.parse(options);
71+
if (!input.hostname) {
72+
throw new ERR_INVALID_DOMAIN_NAME();
73+
}
74+
} catch (err) {
75+
input = url.parse(urlStr);
76+
if (!input.hostname) {
77+
throw err;
78+
}
79+
if (!urlWarningEmitted && !process.noDeprecation) {
80+
urlWarningEmitted = true;
81+
process.emitWarning(
82+
`The provided URL ${urlStr} is not a valid URL, and is supported ` +
83+
'in the http module solely for compatibility.',
84+
'DeprecationWarning', 'DEP0109');
85+
}
7086
}
71-
} else if (options && options[searchParamsSymbol] &&
72-
options[searchParamsSymbol][searchParamsSymbol]) {
87+
} else if (input && input[searchParamsSymbol] &&
88+
input[searchParamsSymbol][searchParamsSymbol]) {
7389
// url.URL instance
74-
options = urlToOptions(options);
90+
input = urlToOptions(input);
7591
} else {
76-
options = util._extend({}, options);
92+
cb = options;
93+
options = input;
94+
input = null;
7795
}
7896

97+
if (typeof options === 'function') {
98+
cb = options;
99+
options = null;
100+
}
101+
102+
options = util._extend(input || {}, options || {});
103+
79104
var agent = options.agent;
80105
var defaultAgent = options._defaultAgent || Agent.globalAgent;
81106
if (agent === false) {

lib/http.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ function createServer(opts, requestListener) {
3737
return new Server(opts, requestListener);
3838
}
3939

40-
function request(options, cb) {
41-
return new ClientRequest(options, cb);
40+
function request(url, options, cb) {
41+
return new ClientRequest(url, options, cb);
4242
}
4343

44-
function get(options, cb) {
45-
var req = request(options, cb);
44+
function get(url, options, cb) {
45+
var req = request(url, options, cb);
4646
req.end();
4747
return req;
4848
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const http = require('http');
5+
6+
// Test providing both a url and options, with the options partially
7+
// replacing address and port portions of the URL provided.
8+
{
9+
const server = http.createServer(
10+
common.mustCall((req, res) => {
11+
assert.strictEqual(req.url, '/testpath');
12+
res.end();
13+
server.close();
14+
})
15+
);
16+
server.listen(
17+
0,
18+
common.mustCall(() => {
19+
http.get(
20+
'http://example.com/testpath',
21+
{ hostname: 'localhost', port: server.address().port },
22+
common.mustCall((res) => {
23+
res.resume();
24+
})
25+
);
26+
})
27+
);
28+
}

0 commit comments

Comments
 (0)