sindresorhus / got

🌐 Human-friendly and powerful HTTP request library for Node.js
MIT License
14.27k stars 935 forks source link

Got doesn't pass query-string when calling via unix-socket #1036

Closed izonder closed 4 years ago

izonder commented 4 years ago

Describe the bug

Actual behavior

Making a call via UNIX-socket results in not passing query string in URL. When making a call via normal TCP/IP port it works correctly. For example, for the code below we have received the output:

call to /tmp/app.sock, URL = /tmp/app.sock:/http?foo=bar
call to /tmp/app.sock, URL = /got # here should be a query-string
call to 3000, URL = /http?foo=bar
call to 3000, URL = /got?foo=bar

Expected behavior

Having query string in request in both cases. For example, for the code below it's expected the output:

call to /tmp/app.sock, URL = /tmp/app.sock:/http?foo=bar
call to /tmp/app.sock, URL = /tmp/app.sock:/got?foo=bar # here should be a query-string
call to 3000, URL = /http?foo=bar
call to 3000, URL = /got?foo=bar

or at least:

call to /tmp/app.sock, URL = /tmp/app.sock:/http?foo=bar
call to /tmp/app.sock, URL = /got?foo=bar # here should be a query-string
call to 3000, URL = /http?foo=bar
call to 3000, URL = /got?foo=bar

Code to reproduce

const fs = require('fs'),
    http = require('http'),
    got = require('got');

const port = 3000,
    socket = '/tmp/app.sock',
    search = '?foo=bar',
    handler = (listen) => (req, res) => {
        console.log(`call to ${listen}, URL = ${req.url}`);

        res.statusCode = 204;
        res.end();
    },
    cb = () => {};

//clean up and establish http server with unix-socket
if (fs.existsSync(socket)) fs.unlinkSync(socket);
http.createServer(handler(port)).listen(port);
http.createServer(handler(socket)).listen(socket);

//reference call with http via TCP/IP port
http.get(
    new URL(`http://localhost:${port}/http${search}`),
    {headers: {authorization: 'Basic aaa'}},
    cb
);

//reference call with got via TCP/IP port
got
    .get(`http://localhost:${port}/got${search}`, {headers: {authorization: 'Basic aaa'}})
    .then(cb);

//reference call with http via unix-socket
http.get(
    new URL(`http://unix:${socket}:/http${search}`),
    {socketPath: '/tmp/app.sock', headers: {authorization: 'Basic aaa'}},
    cb
);

//testing call with got via unix-socket
got
    .get(`http://unix:${socket}:/got${search}`, {headers: {authorization: 'Basic aaa'}})
    .then(cb);

Checklist

izonder commented 4 years ago

If make the reproducing code consistent and pass WHATWG-URL objects as a parameter everywhere, nothing will change:

//reference call with http via TCP/IP port
http.get(
    new URL(`http://localhost:${port}/http${search}`),
    {headers: {authorization: 'Basic aaa'}},
    cb
);

//reference call with got via TCP/IP port
got
    .get(new URL(`http://localhost:${port}/got${search}`), {headers: {authorization: 'Basic aaa'}})
    .then(cb);

//reference call with http via unix-socket
http.get(
    new URL(`http://unix:${socket}:/http${search}`),
    {socketPath: '/tmp/app.sock', headers: {authorization: 'Basic aaa'}},
    cb
);

//testing call with got via unix-socket
got
    .get(new URL(`http://unix:${socket}:/got${search}`), {headers: {authorization: 'Basic aaa'}})
    .then(cb);

The output is the same:

$ node ./test.js 
call to /tmp/app.sock, URL = /tmp/app.sock:/http?foo=bar
call to /tmp/app.sock, URL = /got
call to 3000, URL = /http?foo=bar
call to 3000, URL = /got?foo=bar
psylence303 commented 4 years ago

Confirmed for macOS as well:

Node.js version: v12.13.1 OS & version: macOS 10.14.6 (Darwin 18.7.0) Got: v10.2.2

silverwind commented 4 years ago

Also noticed this. This is a regression, v9.6.0 does work.

thedillonb commented 4 years ago

Is there any workaround for this?