Skip to content

Commit

Permalink
url: allow extension of user provided URL objects
Browse files Browse the repository at this point in the history
PR-URL: #46989
Fixes: #46981
Reviewed-By: Yagiz Nizipli <[email protected]>
  • Loading branch information
aduh95 authored and danielleadams committed Jul 6, 2023
1 parent 5fc2bb7 commit b04ea5a
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 14 deletions.
5 changes: 5 additions & 0 deletions doc/api/url.md
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,11 @@ pathToFileURL('/some/path%.c'); // Correct: file:///some/path%25.c (POSI
added:
- v15.7.0
- v14.18.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/46989
description: The returned object will also contain all the own enumerable
properties of the `url` argument.
-->
* `url` {URL} The [WHATWG URL][] object to convert to an options object.
Expand Down
33 changes: 19 additions & 14 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -1136,27 +1136,32 @@ function domainToUnicode(domain) {
return _domainToUnicode(`${domain}`);
}

// Utility function that converts a URL object into an ordinary
// options object as expected by the http.request and https.request
// APIs.
/**
* Utility function that converts a URL object into an ordinary options object
* as expected by the `http.request` and `https.request` APIs.
* @param {URL} url
* @returns {Record<string, unknown>}
*/
function urlToHttpOptions(url) {
const { hostname, pathname, port, username, password, search } = url;
const options = {
__proto__: null,
...url, // In case the url object was extended by the user.
protocol: url.protocol,
hostname: typeof url.hostname === 'string' &&
StringPrototypeStartsWith(url.hostname, '[') ?
StringPrototypeSlice(url.hostname, 1, -1) :
url.hostname,
hostname: typeof url.hostname === 'string' && StringPrototypeStartsWith(hostname, '[') ?
StringPrototypeSlice(hostname, 1, -1) :
hostname,
hash: url.hash,
search: url.search,
pathname: url.pathname,
path: `${url.pathname || ''}${url.search || ''}`,
search: search,
pathname: pathname,
path: `${pathname || ''}${search || ''}`,
href: url.href,
};
if (url.port !== '') {
options.port = Number(url.port);
if (port !== '') {
options.port = Number(port);
}
if (url.username || url.password) {
options.auth = `${decodeURIComponent(url.username)}:${decodeURIComponent(url.password)}`;
if (username || password) {
options.auth = `${decodeURIComponent(username)}:${decodeURIComponent(password)}`;
}
return options;
}
Expand Down
27 changes: 27 additions & 0 deletions test/parallel/test-http-client-request-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

const common = require('../common');
const assert = require('node:assert');
const http = require('node:http');

const headers = { foo: 'Bar' };
const server = http.createServer(common.mustCall((req, res) => {
assert.strictEqual(req.url, '/ping?q=term');
assert.strictEqual(req.headers?.foo, headers.foo);
req.resume();
req.on('end', () => {
res.writeHead(200);
res.end('pong');
});
}));

server.listen(0, common.localhostIPv4, () => {
const { address, port } = server.address();
const url = new URL(`http://${address}:${port}/ping?q=term`);
url.headers = headers;
const clientReq = http.request(url);
clientReq.on('close', common.mustCall(() => {
server.close();
}));
clientReq.end();
});

0 comments on commit b04ea5a

Please sign in to comment.