Skip to content

Commit 64fed31

Browse files
zhangyongshengruyadorno
authored andcommitted
url: expose urlToHttpOptions utility
PR-URL: #35960Fixes: #34349 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
1 parent 3ea37c2 commit 64fed31

7 files changed

Lines changed: 95 additions & 46 deletions

File tree

‎doc/api/url.md‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,50 @@ new URL('/some/path%.c', 'file:'); // Incorrect: file:///some/path%.c
10291029
pathToFileURL('/some/path%.c'); // Correct: file:///some/path%25.c (POSIX)
10301030
```
10311031

1032+
### `url.urlToHttpOptions(url)`
1033+
<!-- YAML
1034+
added: REPLACEME
1035+
-->
1036+
1037+
*`url` {URL} The [WHATWG URL][] object to convert to an options object.
1038+
* Returns: {Object} Options object
1039+
*`protocol` {string} Protocol to use.
1040+
*`hostname` {string} A domain name or IP address of the server to issue the
1041+
request to.
1042+
*`hash` {string} The fragment portion of the URL.
1043+
*`search` {string} The serialized query portion of the URL.
1044+
*`pathname` {string} The path portion of the URL.
1045+
*`path` {string} Request path. Should include query string if any.
1046+
E.G. `'/index.html?page=12'`. An exception is thrown when the request path
1047+
contains illegal characters. Currently, only spaces are rejected but that
1048+
may change in the future.
1049+
*`href` {string} The serialized URL.
1050+
*`port` {number} Port of remote server.
1051+
*`auth` {string} Basic authentication i.e. `'user:password'` to compute an
1052+
Authorization header.
1053+
1054+
This utility function converts a URL object into an ordinary options object as
1055+
expected by the [`http.request()`][] and [`https.request()`][] APIs.
1056+
1057+
```js
1058+
const { urlToHttpOptions } =require('url');
1059+
constmyURL=newURL('https://a:b@測試?abc#foo');
1060+
1061+
console.log(urlToHttpOptions(myUrl));
1062+
/**
1063+
{
1064+
protocol: 'https:',
1065+
hostname: 'xn--g6w251d',
1066+
hash: '#foo',
1067+
search: '?abc',
1068+
pathname: '/',
1069+
path: '/?abc',
1070+
href: 'https://a:b@xn--g6w251d/?abc#foo',
1071+
auth: 'a:b'
1072+
}
1073+
*/
1074+
```
1075+
10321076
## Legacy URL API
10331077
<!-- YAML
10341078
deprecated: v11.0.0
@@ -1388,6 +1432,8 @@ console.log(myURL.origin);
13881432
[`TypeError`]: errors.md#errors_class_typeerror
13891433
[`URLSearchParams`]: #url_class_urlsearchparams
13901434
[`array.toString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString
1435+
[`http.request()`]: http.md#http_http_request_options_callback
1436+
[`https.request()`]: https.md#https_https_request_options_callback
13911437
[`new URL()`]: #url_new_url_input_base
13921438
[`querystring`]: querystring.md
13931439
[`require('url').format()`]: #url_url_format_url_options

‎lib/_http_client.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const { OutgoingMessage } = require('_http_outgoing');
5858
constAgent=require('_http_agent');
5959
const{ Buffer }=require('buffer');
6060
const{ defaultTriggerAsyncIdScope }=require('internal/async_hooks');
61-
const{URL,urlToOptions, searchParamsSymbol }=require('internal/url');
61+
const{URL,urlToHttpOptions, searchParamsSymbol }=require('internal/url');
6262
const{ kOutHeaders, kNeedDrain }=require('internal/http');
6363
const{ connResetException, codes }=require('internal/errors');
6464
const{
@@ -105,7 +105,7 @@ function ClientRequest(input, options, cb) {
105105
if(typeofinput==='string'){
106106
consturlStr=input;
107107
try{
108-
input=urlToOptions(newURL(urlStr));
108+
input=urlToHttpOptions(newURL(urlStr));
109109
}catch(err){
110110
input=url.parse(urlStr);
111111
if(!input.hostname){
@@ -122,7 +122,7 @@ function ClientRequest(input, options, cb) {
122122
}elseif(input&&input[searchParamsSymbol]&&
123123
input[searchParamsSymbol][searchParamsSymbol]){
124124
// url.URL instance
125-
input=urlToOptions(input);
125+
input=urlToHttpOptions(input);
126126
}else{
127127
cb=options;
128128
options=input;

‎lib/https.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const { ClientRequest } = require('_http_client');
4848
letdebug=require('internal/util/debuglog').debuglog('https',(fn)=>{
4949
debug=fn;
5050
});
51-
const{URL,urlToOptions, searchParamsSymbol }=require('internal/url');
51+
const{URL,urlToHttpOptions, searchParamsSymbol }=require('internal/url');
5252
const{ IncomingMessage, ServerResponse }=require('http');
5353
const{ kIncomingMessage }=require('_http_common');
5454

@@ -303,7 +303,7 @@ function request(...args) {
303303
if(typeofargs[0]==='string'){
304304
consturlStr=ArrayPrototypeShift(args);
305305
try{
306-
options=urlToOptions(newURL(urlStr));
306+
options=urlToHttpOptions(newURL(urlStr));
307307
}catch(err){
308308
options=url.parse(urlStr);
309309
if(!options.hostname){
@@ -320,7 +320,7 @@ function request(...args) {
320320
}elseif(args[0]&&args[0][searchParamsSymbol]&&
321321
args[0][searchParamsSymbol][searchParamsSymbol]){
322322
// url.URL instance
323-
options=urlToOptions(ArrayPrototypeShift(args));
323+
options=urlToHttpOptions(ArrayPrototypeShift(args));
324324
}
325325

326326
if(args[0]&&typeofargs[0]!=='function'){

‎lib/internal/url.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,7 @@ function domainToUnicode(domain) {
12951295
// Utility function that converts a URL object into an ordinary
12961296
// options object as expected by the http.request and https.request
12971297
// APIs.
1298-
functionurlToOptions(url){
1298+
functionurlToHttpOptions(url){
12991299
constoptions={
13001300
protocol: url.protocol,
13011301
hostname: typeofurl.hostname==='string'&&
@@ -1494,7 +1494,7 @@ module.exports = {
14941494
URLSearchParams,
14951495
domainToASCII,
14961496
domainToUnicode,
1497-
urlToOptions,
1497+
urlToHttpOptions,
14981498
formatSymbol: kFormat,
14991499
searchParamsSymbol: searchParams,
15001500
encodeStr

‎lib/url.js‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ const {
4747
URLSearchParams,
4848
domainToASCII,
4949
domainToUnicode,
50+
fileURLToPath,
5051
formatSymbol,
5152
pathToFileURL,
52-
fileURLToPath
53+
urlToHttpOptions,
5354
}=require('internal/url');
5455

5556
// Original url.parse() API
@@ -987,5 +988,6 @@ module.exports = {
987988

988989
// Utilities
989990
pathToFileURL,
990-
fileURLToPath
991+
fileURLToPath,
992+
urlToHttpOptions,
991993
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
require('../common');
3+
constassert=require('assert');
4+
const{ urlToHttpOptions }=require('url');
5+
6+
// Test urlToHttpOptions
7+
consturlObj=newURL('http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test');
8+
constopts=urlToHttpOptions(urlObj);
9+
assert.strictEqual(optsinstanceofURL,false);
10+
assert.strictEqual(opts.protocol,'http:');
11+
assert.strictEqual(opts.auth,'user:pass');
12+
assert.strictEqual(opts.hostname,'foo.bar.com');
13+
assert.strictEqual(opts.port,21);
14+
assert.strictEqual(opts.path,'/aaa/zzz?l=24');
15+
assert.strictEqual(opts.pathname,'/aaa/zzz');
16+
assert.strictEqual(opts.search,'?l=24');
17+
assert.strictEqual(opts.hash,'#test');
18+
19+
const{ hostname }=urlToHttpOptions(newURL('http://[::1]:21'));
20+
assert.strictEqual(hostname,'::1');
21+
22+
// If a WHATWG URL object is copied, it is possible that the resulting copy
23+
// contains the Symbols that Node uses for brand checking, but not the data
24+
// properties, which are getters. Verify that urlToHttpOptions() can handle
25+
// such a case.
26+
constcopiedUrlObj={ ...urlObj};
27+
constcopiedOpts=urlToHttpOptions(copiedUrlObj);
28+
assert.strictEqual(copiedOptsinstanceofURL,false);
29+
assert.strictEqual(copiedOpts.protocol,undefined);
30+
assert.strictEqual(copiedOpts.auth,undefined);
31+
assert.strictEqual(copiedOpts.hostname,undefined);
32+
assert.strictEqual(copiedOpts.port,NaN);
33+
assert.strictEqual(copiedOpts.path,'');
34+
assert.strictEqual(copiedOpts.pathname,undefined);
35+
assert.strictEqual(copiedOpts.search,undefined);
36+
assert.strictEqual(copiedOpts.hash,undefined);
37+
assert.strictEqual(copiedOpts.href,undefined);

‎test/parallel/test-whatwg-url-custom-properties.js‎

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
require('../common');
77
constURL=require('url').URL;
88
constassert=require('assert');
9-
consturlToOptions=require('internal/url').urlToOptions;
109

1110
consturl=newURL('http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test');
1211
constoldParams=url.searchParams;// For test of [SameObject]
@@ -131,41 +130,6 @@ assert.strictEqual(url.toString(),
131130
assert.strictEqual((deleteurl.searchParams),true);
132131
assert.strictEqual(url.searchParams,oldParams);
133132

134-
// Test urlToOptions
135-
{
136-
consturlObj=newURL('http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test');
137-
constopts=urlToOptions(urlObj);
138-
assert.strictEqual(optsinstanceofURL,false);
139-
assert.strictEqual(opts.protocol,'http:');
140-
assert.strictEqual(opts.auth,'user:pass');
141-
assert.strictEqual(opts.hostname,'foo.bar.com');
142-
assert.strictEqual(opts.port,21);
143-
assert.strictEqual(opts.path,'/aaa/zzz?l=24');
144-
assert.strictEqual(opts.pathname,'/aaa/zzz');
145-
assert.strictEqual(opts.search,'?l=24');
146-
assert.strictEqual(opts.hash,'#test');
147-
148-
const{ hostname }=urlToOptions(newURL('http://[::1]:21'));
149-
assert.strictEqual(hostname,'::1');
150-
151-
// If a WHATWG URL object is copied, it is possible that the resulting copy
152-
// contains the Symbols that Node uses for brand checking, but not the data
153-
// properties, which are getters. Verify that urlToOptions() can handle such
154-
// a case.
155-
constcopiedUrlObj={ ...urlObj};
156-
constcopiedOpts=urlToOptions(copiedUrlObj);
157-
assert.strictEqual(copiedOptsinstanceofURL,false);
158-
assert.strictEqual(copiedOpts.protocol,undefined);
159-
assert.strictEqual(copiedOpts.auth,undefined);
160-
assert.strictEqual(copiedOpts.hostname,undefined);
161-
assert.strictEqual(copiedOpts.port,NaN);
162-
assert.strictEqual(copiedOpts.path,'');
163-
assert.strictEqual(copiedOpts.pathname,undefined);
164-
assert.strictEqual(copiedOpts.search,undefined);
165-
assert.strictEqual(copiedOpts.hash,undefined);
166-
assert.strictEqual(copiedOpts.href,undefined);
167-
}
168-
169133
// Test special origins
170134
[
171135
{expected: 'https://whatwg.org',

0 commit comments

Comments
 (0)