Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Passing username from URL object to http.clientRequest without decoding #31439

Copy link
Copy link
@izonder

Description

@izonder
Issue body actions
  • 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: ''
}

References

szmarczak, sindresorhus, zedd3v, HLA-242, robert-gruner and 1 more

Metadata

Metadata

Assignees

No one assigned

    Labels

    httpIssues or PRs related to the http subsystem.Issues or PRs related to the http subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.