Got: Password with special characters throws a URI malformed exception

Created on 15 Jun 2020  路  10Comments  路  Source: sindresorhus/got

Describe the bug

  • Node.js version: 12.18.0
  • OS & version: MacOS 10.15.5

My password for the URL has special characters in it. It has the dollar sign ($) and the percent (%). These characters normally need to go through encodeURIComponent().

Actual behavior

RequestError: URI malformed
    at PromisableRequest._destroy (/node_modules/got/dist/source/core/index.js:1132:21)
    at PromisableRequest.destroy (internal/streams/destroy.js:38:8)
    at /node_modules/got/dist/source/core/index.js:288:26
    at new Request (/node_modules/got/dist/source/core/index.js:291:11)
    at new PromisableRequest (/node_modules/got/dist/source/as-promise/core.js:32:1)
    at makeRequest (/node_modules/got/dist/source/as-promise/index.js:37:29)
    at /node_modules/got/dist/source/as-promise/index.js:196:9
    at /node_modules/p-cancelable/index.js:61:11
    at new Promise (<anonymous>)
    at new PCancelable (/node_modules/p-cancelable/index.js:31:19)
    at decodeURI (<anonymous>)
    at /node_modules/got/dist/source/core/index.js:268:17
    at new Request (/node_modules/got/dist/source/core/index.js:291:11)
    at new PromisableRequest (/node_modules/got/dist/source/as-promise/core.js:32:1)
    at makeRequest (/node_modules/got/dist/source/as-promise/index.js:37:29)
    at /node_modules/got/dist/source/as-promise/index.js:196:9
    at /node_modules/p-cancelable/index.js:61:11
    at new Promise (<anonymous>)
    at new PCancelable (/node_modules/p-cancelable/index.js:31:19)
    at Object.asPromise [as default] (/node_modules/got/dist/source/as-promise/index.js:26:21)

Expected behavior

A password can have special characters in it, and the library should seamlessly handle it.

Code to reproduce

const got = require('got');
const url = 'https://enzmjqa4r8u7.x.pipedream.net';
const options = {
    username: 'test',
    password: 't$es%t',
};
response = got(url, options);

Checklist

  • [X] I have read the documentation.
  • [X] I have tried my code with the latest version of Node.js and Got.
bug external nodejs bug

Most helpful comment

You can try to polyfill it (if that's the right term) as follow

const got = require('got')

const authGot = got.extend({
    handlers: [
        (options, next) => {
            if (options.username || options.password) {
                options.headers = {
                    ...options.headers,
                    'Authorization': 'Basic ' + Buffer.from(options.username + ':' + options.password).toString('base64')
                };

                options.username = '';
                options.password = '';
            }

            return next(options);
       }
    ],
});

(async () => {
    const response = await got('https://guest:[email protected]/HTTP/Basic/');

    console.log(response.body);
})();

All 10 comments

I think this is the same as #1169

@sindresorhus I don't think Node.js will fix this anytime soon. What about if we throw when the URL already contains a username / password and encode the username & password option on our own?

Seems like there's some activity: https://github.com/nodejs/node/pull/31450#issuecomment-647719491 I'd prefer to wait.

@sindresorhus What about now?

That PR just got some activity.

The last commit was in January.

@szmarczak Feel free to spend time on this if you want. I just don't think it's important enough, and if we implement a workaround, Node.js has even less incentive to land the fix.

I am having the same problem. Why can't we encode the uri ourselves using?

http://${encodeURIComponent(user)}:${encodeURIComponent(pass)}@${host}:${port}/

@mctrivia https://github.com/sindresorhus/got/issues/1317#issuecomment-678688287

if we implement a workaround, Node.js has even less incentive to land the fix.

You can try to polyfill it (if that's the right term) as follow

const got = require('got')

const authGot = got.extend({
    handlers: [
        (options, next) => {
            if (options.username || options.password) {
                options.headers = {
                    ...options.headers,
                    'Authorization': 'Basic ' + Buffer.from(options.username + ':' + options.password).toString('base64')
                };

                options.username = '';
                options.password = '';
            }

            return next(options);
       }
    ],
});

(async () => {
    const response = await got('https://guest:[email protected]/HTTP/Basic/');

    console.log(response.body);
})();
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jamestalmage picture jamestalmage  路  3Comments

dAnjou picture dAnjou  路  3Comments

lukehorvat picture lukehorvat  路  3Comments

f-mer picture f-mer  路  4Comments

tkoelpin picture tkoelpin  路  3Comments