Attempting a got request against a host which is registered in my hosts files fails with an ENOTFOUND; where doing an https.get for the same host and path does not.
This used to work with got 10, but got 10 hangs on node 12 on an ubuntu 14 machine, which happens to be my target for this project :/
Should be able to retrieve data from a server by hostname according to system hosts file
(not so much code as steps):
got to that server(not so much code as steps):
Please include the code and the entire hosts file.
as per description:
// this works:
const opts = {
host: "foo.dev.local",
path: "/user"
}
const response = await new Promise((resolve, reject) => {
let result = {
body: "",
statusCode: 0
};
try {
h.get(opts, res => {
res.on("data", d => result.body += d.toString());
res.on("end", () => {
result.statusCode = 200;
resolve(result);
});
res.on("error", e => {
// can we get the status from e?
result.statusCode = 500;
reject(result);
});
});
} catch (err) {
reject(err);
}
});
// this does not:
const response2 = await got("https://goo.dev.local/user");
hosts file:
127.0.0.1 foo.dev.local
I need the server code too.
I originally left out code because the situation is easy enough to replicate, but specific to the host system; however, as per your request, here's a full set of steps:
127.0.0.1 server.dev.local
mkdir got-issue
cd got-issue
npm init -y
npm install --save got express
app.js file:var app = require("express")();
var got = require("got");
var http = require("http");
app.get('/user', (req, res) => {
res.send({
id: 1,
name: "Han",
likes: "to shoot first"
});
});
app.get("/fails", (req, res) => {
got("http://server.dev.local/user")
.then(result => res.send(result.body))
.catch(err => {
res.status(500);
res.send(err);
});
});
app.get("/by-ip", (req, res) => {
got("http://127.0.0.1/user")
.then(result => res.send(result.body))
.catch(err => {
res.status(500);
res.send(err);
});
});
app.get("/by-http", (req, res) => {
http.get("http://server.dev.local/user", r => {
let data = "";
r.on("data", d => data += d.toString());
r.on("end", () => res.send(data));
});
});
var server = app.listen(80, () => {
const address = server.address();
console.log(`listening on ${address.address}:${address.port}`);
});
{
"name": "got-issue",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"got": "^11.0.2"
}
}
npm start
curl http://localhost/user
curl http://localhost/fails
curl http://localhost/by-ip
curl http://localhost/by-http
C:\code\scratch\got-issue>curl http://localhost/user
{"id":1,"name":"Han","likes":"to shoot first"}
C:\code\scratch\got-issue>curl http://localhost/fails
{"name":"RequestError","code":"ENOTFOUND","timings":{"start":1587992852528,"socket":1587992852529,"lookup":1587992852534,"error":1587992852534,"abort":1587992852535,"phases":{"wait":1,"dns":5,"total":7}}}
C:\code\scratch\got-issue>curl http://localhost/by-ip
{"id":1,"name":"Han","likes":"to shoot first"}
C:\code\scratch\got-issue>curl http://localhost/by-http
{"id":1,"name":"Han","likes":"to shoot first"}
I cannot reproduce even with your example:
The server is running on Windows 10, with the hosts entry described.
$ curl http://localhost/fails
{"id":1,"name":"Han","likes":"to shoot first"}
Can you show your entire hosts file?
no, I can't share all of that. A single hosts entry should be enough to demonstrate this, as per the details above. Suffice to say that, for this test, I had to add the single entry for server.dev.local to make the ones that pass, pass. That's all that should be required.
no, I can't share all of that.
Then can you temporarily replace its contents to only contain the localhost entry and the server.dev.local? Make sure to reboot.
ok, so with a hosts file consisting of exactly:
127.0.0.1 server.dev.local
the test app fails, both before and after a reboot.
I've found the error. It's in your upstream cacheable-lookup and I've raised a PR to fix it: https://github.com/szmarczak/cacheable-lookup/pull/23
Please +1 or something there so that perhaps this gets accepted (in one form or another) sooner rather than later.
imo, this is a result of trying to be "too clever": node's dns module has a really simple lookup function which resolves via system methods (so hosts file entries are observed). cacheable-lookup is doing manual work to read from the system hosts file which means it is vulnerable to
I understand what cacheable-lookup is trying to do -- in-memory cache for dns requests -- but this could have been done more robustly and simply without trying to be smart about hosts files and the like.
but this could have been done more robustly and simply without trying to be smart about hosts files and the like.
You are actually wrong. There are other places to retrieve the entries. The hosts file is only a part of it. The kernel does not respond with a information whether the entry is coming from the hosts file, custom DNS rules (e.g. suffixes), internal OS cache or direct DNS query.
For reference see https://github.com/sindresorhus/got/issues/1175
Note that process bindings are not so fast. Not to mention that the underlying OS implementation doesn't support TTL.
does not update if the hosts file is updated
You're wrong here also.
I've found the error. It's in your upstream cacheable-lookup and I've raised a PR to fix it:
Thanks for taking the time to locate the bug! I really appreciate it :) Will look at this ASAP.
You're wrong here also.
szmarczak/cacheable-lookup:source/hosts-resolver.js@35b0352#L37-L46
It seems that I'm wrong in theory only (I can see the watcher, but it appears to _not_ be working); I did this test to repro:
127.0.0.1 server.dev.local, unix line-endings{"id":1,"name":"Han","likes":"to shoot first"})196.25.1.1 server.dev.local{"id":1,"name":"Han","likes":"to shoot first"}), when I shouldn't{"name":"RequestError","code":"ECONNREFUSED","timings":{"start":1588691301843,"socket":1588691301844,"error":1588691303997,"abort":1588691303997,"phases":{"wait":1,"total":2154}}}You are actually wrong. There are other places to retrieve the entries. The hosts file is only a part of it. The kernel does not respond with a information whether the entry is coming from the hosts file, custom DNS rules (e.g. suffixes), internal OS cache or direct DNS query.
I'm well aware that the hosts file is only part of dns resolution. So if I understand correctly, the reasons for customising behavior of dns.lookup are:
I can see the use-case for the first from the linked issue, and I _guess_ someone might be interested in the latter. The first sounds like you've had to work around a dns bug (imo, dns.lookup should "just work" with the same resolution as ping might, but perhaps there are "good reasons" for behaving differently?). I would guess that most clients wouldn't care about extended information as to _where_ the resolution came from, but I suppose if you have that info, then might as well pass it on 馃し
@szmarczak would you like me to raise a separate issue about the hosts-file watcher not triggering a refresh?
You sure that it doesn't watch it? By default Node.js performs the check every 5s. I haven't changed this setting.
If it still doesn't update the entries, please make another issue :)
ok, I was testing quite quickly, so let me try a little slower (:
yeah, I'm afraid that, even waiting 30s, the updated hosts entries aren't picked up. I'll raise another issue. Perhaps it's related to node on windows or something like that... Anyways, I'll add all the details in a new issue.
I've raised https://github.com/szmarczak/cacheable-lookup/issues/24 -- please let me know if you need more info (:
Fixed in cacheable-lookup.