-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wish: add unix domain socket support #336
Comments
Do browsers support Unix domain sockets? We try to align with browsers, not always other Node.js libraries. |
I think browsers doesn't support them, but node supports serving HTTP from a unix domain socket (https://nodejs.org/api/http.html#http_server_listen_path_callback ), making requests to them (https://nodejs.org/api/http.html#http_http_request_options_callback ) and many utilities like |
I'm going to close this for the same reason we don't support |
@TimothyGu This is unfortunate, because it makes it impossible to use |
in theory this could work: const http = require('http');
const fetch = require('node-fetch');
const agent = new http.Agent();
agent.createConnection({ path: '/var/run/docker.sock' });
fetch('http:/v1.37/containers/json', { agent }).then(console.log, console.error) We get and with fetch('http:/v1.37/containers/json', { agent }).then(console.log, console.error)
even if curl works fine (from the doc https://docs.docker.com/develop/sdk/examples/#list-all-images) > curl --unix-socket /var/run/docker.sock http:/v1.37/containers/json
[] Sharing this nice solution using const http = require('http');
const get = o => new Promise((resolve, reject) => {
const req = http.get(o);
req.once('error', reject);
req.once('response', async res => {
const bufs = [];
for await (const buf of res) bufs.push(buf);
resolve(JSON.parse(Buffer.concat(bufs)));
});
});
get({ path: '/v1.37/containers/json', socketPath: '/var/run/docker.sock' }).then(console.log, console.error); |
@caub We can do some stuff with an HTTP client directly, but the whole point of having the |
Please reconsider this. Not having this functionality in Nobody is expecting a complete 1:1 parity with the w3 module - meaning, I don't think anyone would care or even notice if an extra option was available to specify the connection should be made over a domain socket. Even if there was Please note that
Saying you won't support domain sockets for the same reasons as |
I use this small http/https.request wrapper https://github.com/caub/fetchu/blob/master/fetchu-node.js |
While we have no plan to fix this, can people try creating an ref: |
EDIT: it was already tested in a comment above and it doesn't work. Sorry for the duplicate. @bitinn, Could you please give me some hints about how to test your providden solution? I might not have understand how to test it the right way... My test setup is a NodeJS app listening on // test.js (inside the guest)
const fetch = require('node-fetch')
const { Agent } = require('http')
const agent = new Agent({ path: '/var/run/nodejs/nodejs.sock' })
fetch('http://0.0.0.0:8000/api/categories/index.json', { agent })
.then(res => res.json())
.then(console.log)
.catch(console.log)
// Output : { ...parsed JSON } and an entry is appended to Nginx access log.
fetch('/api/categories/index.json', { agent })
.then(res => res.json())
.then(console.log)
.catch(console.log)
// Output : Error: only absolute urls are supported |
Your first example appear to work (network-wise). The error you got seems to suggest the JSON response was invalid JSON, you should post the full error.
(From my phone)
… On Nov 19, 2018, at 18:14, Guillaume ***@***.***> wrote:
@bitinn, Could you please give me some hints about how to test your providden solution? I might not have understand how to test it the right way...
My test setup is a NodeJS app listening on /var/run/nodejs/nodejs.sock proxyied by Nginx listening on port 8000 inside a Vagrant guest. Port 8000 and Vagrant are non important details but I'm mentioning them just in case.
// test.js (inside the guest)
const fetch = require('node-fetch')
const { Agent } = require('http')
const agent = new Agent({ path: '/var/run/nodejs/nodejs.sock' })
fetch('http://0.0.0.0:8000/api/categories/index.json', { agent })
.then(res => res.json())
.then(console.log)
.catch(console.log)
// Output : { ...parsed JSON } and an entry is appended to Nginx access log.
fetch('/api/categories/index.json', { agent })
.then(res => res.json())
.then(console.log)
.catch(console.log)
// Output : Error: only absolute urls are supported
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
EDIT: it was already tested in a comment above and it doesn't work. Sorry for the duplicate. Sorry, I was very brief on my last comment and I realize that I could simplify the test. But just to not be confusing and to answer you, the first example is working if we mean by that that the expected data is returned but it's returned from NodeJS via Nginx, not directly from NodeJS. And the second example outputs an error from Simplified test: // server.js
require('http').createServer((_, response) => {
response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
response.end('Hello')
}).listen('/var/run/nodejs/nodejs.sock')
// Just to prove that the server created above is correctly handling request via unix socket
require('http').get({ socketPath: '/var/run/nodejs/nodejs.sock' }, response => {
response.setEncoding('utf8')
let data = ''
response.on('data', chunk => { data += chunk })
response.on('end', () => console.log(data))
}) When running const fetch = require('node-fetch')
const { Agent } = require('http')
const agent = new Agent({ path: '/var/run/nodejs/nodejs.sock' })
fetch('http://0.0.0.0', { agent })
.then(res => res.text())
.then(console.log)
.catch(console.log)
// Output : { FetchError: request to http://0.0.0.0 failed, reason: connect ECONNREFUSED 0.0.0.0:80
fetch('/', { agent })
.then(res => res.text())
.then(console.log)
.catch(console.log)
// Output : Error: only absolute urls are supported at /var/www/node-fetch-socket/node_modules/node-fetch/index.js:54:10 |
@cdoublev I guess the problem comes down to whether you can construct a "valid" absolute url that can go pass Due to lack of I originally thought it might work if you construct the Seeing how non-standard unix domain socket url are (I still don't know if |
Ok, I'm fine with that. Thank you for your quick feed back. |
just a note, I tried that with docker a few months ago, and it doesn't work: var fetch = require('node-fetch');
var agent = new http.Agent({ path: '/var/run/docker.sock' });
fetch('http:/v1.37/containers/json', {agent}).then(console.log); // .then is never invoked |
This was a major blow for my homebrew docker util. 🤷♂️ |
I thought node-fetch was a high-level http library, but now I need an alternative because of the transport layer?? I'm still talking HTTP! For a bit of context, I want to use unix sockets for tests so they can run in parallel without port conflicts. My http server is happily capable of attaching to a unix socket.. why can't the client?? I can switch to got for my node.js usage, but this seems like a silly reason to ditch node-fetch... |
@ericvicenti I commented above a few years ago about this, and since they have a hard stance against it, I switched all of my projects to |
looks like i'll have to do the same, i found this which looks like it'll make the transition easier https://www.npmjs.com/package/got-fetch |
Unix domain sockets are not a "Node.js library". It's a feature of the unix platform. I think the proper goal ought to be aligning with the fetch interface provided by the browsers; not blindly align with "browser the platform". The point of this library is being platform-agnostic; but that doesn't necessarily justify leaving out support for platform specific features. What developers are looking for is one-fetch-library-to-rule-them-all. If I have to switch libraries whenever I need a platform specific feature, what's the point? |
I mistook Let's make a correction: The point of this library is having the same interface as the browsers' fetch; but that doesn't necessarily justify leaving out support for server-side features. |
Supporting unix sockets is not aligning with other libraries, it's aligning with the environment. And for node-fetch that is node.js. I think not supporting unix socket via the agent is unexpected (btw also unnecessary) behavior and can therefore be considered a bug. It's not that hard to fix. I would love to do it, but i guess there has been some effort already that will not be merged. |
So in the end it seems that this is a bug (as in unexpected behavior). The problem is, however not with node-fetch! Here we can read about the http.Agent. The documentation says
Check out those options here. It says:
And yes, an IPC socket is a unix socket So we can configure the agent to talk to a unix socket, just like explained earlier in this post. Only problem is that this does not work. But why? Well, one reason is that the path option is set to null in the constructor of the Agent. The path option will always be null! At some point, while making the actual request, the agent will call the createConnection function, via it's createSocket method. Now in this method look at this piece of code:
Yes, the path property that was so brutally set to null in the constructor is set again! But with the value of the socketPath property of the options that we pass to the Agent (this.options). So when we pass the unix path as a socketPath option to the agent, everything works as expected, so something like:
After all this was a bug! But not in node-fetch. The node.js documentation is a bit off here. I am very happy that can keep using node-fetch for everything http! |
I'm trying to connect to snap socket located in |
Not tested yet, but the native node's fetch could support unix socket and there are some pointers in the code. And no documentation ATM. |
Here, have an unofficial example. It's still fetch, so it's still sending http requests. I'm using it for Apollo GraphQL over a unix socket. // Node 18 uses undici fetch, so you don't have to import fetch. But you can.
import { Agent } from "undici";
// The URL must parse as a valid url, but the hostname doesn't matter for the connection.
// I've included a dummy value of... dummy. But you could use real host names if proxying, or route off the host name.
fetch("http://dummy/path/in/http/request/over/socket", {
dispatcher: new Agent({
connect: {
socketPath: "/tmp/test-unix-socket"
}
})
}); |
Add the option to connect to a unix socket, like https://github.com/request/request#unix-domain-sockets
The text was updated successfully, but these errors were encountered: