Description
- Version: v8.x.x+
- Platform: any
- Subsystem: any
Description
Passing username
with "unsafe" symbols (e.g. @
) to URL
object causes wrongly computed Basic-Authorization header string.
Pre-requisites
The next code looks good enough (Node.js CLI):
const {URL} = require('url');
const url = new URL('http://localhost');
url.username = 'test@test';
url.password = '123456';
console.log(url);
This should result in:
URL {
href: 'http://test%40test:123456@localhost/',
origin: 'http://localhost',
protocol: 'http:',
username: 'test%40test',
password: '123456',
host: 'localhost',
hostname: 'localhost',
port: '',
pathname: '/',
search: '',
searchParams: URLSearchParams {},
hash: ''
}
The field username
turned to percent-encoded as mentioned in the documentation (https://nodejs.org/api/url.html#url_url_username). According to the composed URI in the field href
it's working as expected.
Expected behavior
Reference calls via cURL will look like:
curl -u 'test@test:123456' -v 'http://localhost/'
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
* Server auth using Basic with user 'test@test'
> GET / HTTP/1.1
> Host: localhost
> Authorization: Basic dGVzdEB0ZXN0OjEyMzQ1Ng==
> User-Agent: curl/7.58.0
> Accept: */*
curl -v 'http://test%40test:123456@localhost/'
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
* Server auth using Basic with user 'test@test'
> GET / HTTP/1.1
> Host: localhost
> Authorization: Basic dGVzdEB0ZXN0OjEyMzQ1Ng==
> User-Agent: curl/7.58.0
> Accept: */*
Decoding the header Authorization: Basic dGVzdEB0ZXN0OjEyMzQ1Ng==
results to test@test:123456
as expected.
Actual behavior
Again try to make the same call from Node.js CLI:
const {URL} = require('url');
const url = new URL('http://localhost');
url.username = 'test@test';
url.password = '123456';
const http = require('http');
console.log(http.get(url, () => {}).outputData);
That will output something like:
[
{
data: 'GET /profile HTTP/1.1\r\n' +
'Host: localhost\r\n' +
'Authorization: Basic dGVzdCU0MHRlc3Q6MTIzNDU2\r\n' +
'Connection: close\r\n' +
'\r\n',
encoding: 'latin1',
callback: [Function: bound onFinish]
}
]
Decoding Authorization header results to test%40test:123456
, which is wrong.
Expectation
When http.request(<URL>)
grabs a value from href
or username
fields, it should sanitize and decode values before composing Authorization
header.
-or-
WHATWG-URL
should keep raw username
and provide it like:
URL {
href: 'http://test%40test:123456@localhost/', # here encoded values
origin: 'http://localhost',
protocol: 'http:',
username: 'test@test', # here should be raw value
password: '123456',
host: 'localhost',
hostname: 'localhost',
port: '',
pathname: '/',
search: '',
searchParams: URLSearchParams {},
hash: ''
}