Skip to content
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

fetch throws UND_ERR_SOCKET error #1412

Closed
regseb opened this issue May 4, 2022 · 5 comments
Closed

fetch throws UND_ERR_SOCKET error #1412

regseb opened this issue May 4, 2022 · 5 comments
Labels
bug Something isn't working

Comments

@regseb
Copy link
Contributor

regseb commented May 4, 2022

Bug Description

A request on this page of the Daily Mail throws an UND_ERR_SOCKET error. There is no problem with https.

Reproducible By

Execute this script:

import https from "node:https";
import zlib from "node:zlib";

const testWithHttps = (url) => {
    return new Promise((resolve, reject) => {
        const req = https.request(new URL(url), (res) => {
            const gunzip = zlib.createGunzip();
            res.pipe(gunzip);

            const buffer = [];
            gunzip.on("data", (chunk) => buffer.push(chunk))
                  .on("error", (err) => reject(err))
                  .on("end", () => resolve(buffer.join("")));
        });
        req.on("error", (err) => reject(err));
        req.setHeader("Accept", "*/*");
        req.setHeader("Accept-Encoding", "br, gzip, deflate");
        req.setHeader("Accept-Language", "*");
        req.setHeader("Sec-Fetch-Mode", "cors");
        req.setHeader("User-Agent", "undici");
        req.end();
    });
};

const testWithFetch = async (url) => {
    const response = await fetch(url);
    return response.text();
};


console.log("PTS (https://ptsv2.com/t/undici)");
let url = "https://ptsv2.com/t/undici/post";
console.log("HTTPS: " + (await testWithHttps(url)).substring(0, 100));
console.log("FETCH: " + (await testWithFetch(url)).substring(0, 100));

console.log("\nDaily Mail");
url = "https://www.dailymail.co.uk/sciencetech/article-8057229" +
                                  "/Scientists-create-stunning-gifs-Mars-sand" +
                                "-dunes-understand-conditions-impact-them.html";
console.log("HTTPS: " + (await testWithHttps(url)).substring(0, 100));
console.log("FETCH: " + (await testWithFetch(url)).substring(0, 100));

Expected Behavior

PTS (https://ptsv2.com/t/undici)
HTTPS: Thank you for this dump. I hope you have a lovely day!
(node:22125) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
FETCH: Thank you for this dump. I hope you have a lovely day!

Daily Mail
HTTPS: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-tr
FETCH: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-tr

Logs & Screenshots

PTS (https://ptsv2.com/t/undici)
HTTPS: Thank you for this dump. I hope you have a lovely day!
(node:22125) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
FETCH: Thank you for this dump. I hope you have a lovely day!

Daily Mail
HTTPS: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-tr
node:internal/deps/undici/undici:6266
            fetchParams.controller.controller.error(new TypeError("terminated", {
                                                    ^

TypeError: terminated
    at Fetch.onAborted (node:internal/deps/undici/undici:6266:53)
    at Fetch.emit (node:events:527:28)
    at Fetch.terminate (node:internal/deps/undici/undici:5522:14)
    at Object.onError (node:internal/deps/undici/undici:6357:36)
    at Request.onError (node:internal/deps/undici/undici:2023:31)
    at errorRequest (node:internal/deps/undici/undici:3949:17)
    at TLSSocket.onSocketClose (node:internal/deps/undici/undici:3411:9)
    at TLSSocket.emit (node:events:539:35)
    at node:net:715:12
    at TCP.done (node:_tls_wrap:581:7) {
  [cause]: SocketError: closed
      at TLSSocket.onSocketClose (node:internal/deps/undici/undici:3399:35)
      at TLSSocket.emit (node:events:539:35)
      at node:net:715:12
      at TCP.done (node:_tls_wrap:581:7) {
    code: 'UND_ERR_SOCKET',
    socket: {
      localAddress: undefined,
      localPort: undefined,
      remoteAddress: undefined,
      remotePort: undefined,
      remoteFamily: 'IPvundefined',
      timeout: undefined,
      bytesWritten: 294,
      bytesRead: 83018
    }
  }
}

Node.js v18.1.0

Environment

  • Ubuntu: 20.04.4 LTS
  • Node: v18.1.0
  • npm: 8.8.0

Additional context

In test case, I modified the https headers to have the same values as fetch. You can see the requests (with their headers) on this page of PTS.

@regseb regseb added the bug Something isn't working label May 4, 2022
@mcollina
Copy link
Member

mcollina commented May 4, 2022

Could you reproduce with a self-hosted server?

@regseb
Copy link
Contributor Author

regseb commented May 5, 2022

@mcollina I reproduce the same error with a secure HTTP2 server.

// node server.js
import fs from "node:fs/promises";
import http2 from "node:http2";

// openssl genrsa -out key.pem
// openssl req -new -key key.pem -out csr.pem
// openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem
// rm csr.pem
const server = http2.createSecureServer({
    key:  await fs.readFile("key.pem"),
    cert: await fs.readFile("cert.pem"),
});
server.on("error", (err) => console.log(err));
server.on("stream", (stream) => stream.end("foo"));
server.listen(11011);
// NODE_TLS_REJECT_UNAUTHORIZED='0' node client.js
import http2 from "node:http2";

const testWithHttp2 = (url) => {
    return new Promise((resolve, reject) => {
        const client = http2.connect(url);
        const req = client.request();
        const buffer = [];
        req.on("data", (chunk) => buffer.push(chunk));
        req.on("error", (err) => reject(err));
        req.on("end", () => {
            resolve(buffer.join(""));
            client.close();
        });
        req.end();
    });
};

const testWithFetch = async (url) => {
    const response = await fetch(url);
    return response.text();
};


let url = "https://localhost:11011/";
console.log("HTTP2: " + (await testWithHttp2(url)));
console.log("FETCH: " + (await testWithFetch(url)));
(node:23659) Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure by disabling certificate verification.
(Use `node --trace-warnings ...` to show where the warning was created)
HTTP2: foo
(node:23659) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
node:internal/deps/undici/undici:6266
            fetchParams.controller.controller.error(new TypeError("terminated", {
                                                    ^

TypeError: terminated
    at Fetch.onAborted (node:internal/deps/undici/undici:6266:53)
    at Fetch.emit (node:events:527:28)
    at Fetch.terminate (node:internal/deps/undici/undici:5522:14)
    at Object.onError (node:internal/deps/undici/undici:6357:36)
    at Request.onError (node:internal/deps/undici/undici:2023:31)
    at errorRequest (node:internal/deps/undici/undici:3949:17)
    at TLSSocket.onSocketClose (node:internal/deps/undici/undici:3411:9)
    at TLSSocket.emit (node:events:539:35)
    at node:net:715:12
    at TCP.done (node:_tls_wrap:581:7) {
  [cause]: SocketError: closed
      at TLSSocket.onSocketClose (node:internal/deps/undici/undici:3399:35)
      at TLSSocket.emit (node:events:539:35)
      at node:net:715:12
      at TCP.done (node:_tls_wrap:581:7) {
    code: 'UND_ERR_SOCKET',
    socket: {
      localAddress: undefined,
      localPort: undefined,
      remoteAddress: undefined,
      remotePort: undefined,
      remoteFamily: 'IPvundefined',
      timeout: undefined,
      bytesWritten: 176,
      bytesRead: 239
    }
  }
}

Node.js v18.1.0

With a unsecure HTTP2 server, fetch throws a HPE_INVALID_CONSTANT error:

node:internal/deps/undici/undici:5575
          p.reject(Object.assign(new TypeError("fetch failed"), { cause: response.error }));
                                 ^

TypeError: fetch failed
    at Object.processResponse (node:internal/deps/undici/undici:5575:34)
    at node:internal/deps/undici/undici:5901:42
    at node:internal/process/task_queues:140:7
    at AsyncResource.runInAsyncScope (node:async_hooks:202:9)
    at AsyncResource.runMicrotask (node:internal/process/task_queues:137:8) {
  cause: HTTPParserError: Expected HTTP/
      at Parser.execute (node:internal/deps/undici/undici:3075:19)
      at Parser.readMore (node:internal/deps/undici/undici:3034:16)
      at Socket.onSocketReadable (node:internal/deps/undici/undici:3364:14)
      at Socket.emit (node:events:527:28)
      at emitReadable_ (node:internal/streams/readable:590:12)
      at process.processTicksAndRejections (node:internal/process/task_queues:81:21) {
    code: 'HPE_INVALID_CONSTANT',
    data: '\x00\x00\x00\x04\x00\x00\x00\x00\x00'
  }
}

Node.js v18.1.0

There is issues and pull request to add support for HTTP/2:

@ronag
Copy link
Member

ronag commented May 5, 2022

undici doesn't support http2 yet

@FourCinnamon0
Copy link

I have the same issue with this url

@mcollina
Copy link
Member

Closing as a duplicate of #902.
fetch is missing HTTP/2 support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants