Error when sending sending HTTP/2 request using existing TLS socket.

huangapple go评论62阅读模式
英文:

Error when sending sending HTTP/2 request using existing TLS socket

问题

I wrote a script to establish a TCP connection to target website, wrap it with TLS connection and then use that TLS connection to open HTTP/2 session. It works normal for all websites, but when I do an HTTP/2 request to m.twitch.tv, the script shows this error:

node:events:491
      throw er; // Unhandled 'error' event
      ^

Error: Client network socket disconnected before secure TLS connection was established
    at connResetException (node:internal/errors:717:14)
    at TLSSocket.onConnectEnd (node:_tls_wrap:1595:19)
    at TLSSocket.emit (node:events:525:35)
    at endReadableNT (node:internal/streams/readable:1359:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted 'error' event on TLSSocket instance at:
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ECONNRESET',
  path: undefined,
  host: undefined,
  port: undefined,
  localAddress: undefined
}

This is my script:

// Usage: node file.js m.twitch.tv 443
const net = require("net");
const tls = require("tls");
const http2 = require("http2");
const crypto = require("crypto");
const host = process.argv[2];
const port = ~~process.argv[3];
const headers = {};
headers[":authority"] = host;
headers[":method"] = "GET";
headers[":path"] = "/";
headers[":scheme"] = "https";
headers["accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
headers["accept-language"] = "en-US,en;q=0.9";
headers["dnt"] = "1";
headers["sec-ch-ua"] = '"Chromium";v="112", "Google Chrome";v="112", "Not:A-Brand";v="99"';
headers["sec-ch-ua-mobile"] = "?0";
headers["sec-ch-ua-platform"] = '"Windows"';
headers["sec-fetch-dest"] = "document";
headers["sec-fetch-mode"] = "navigate";
headers["sec-fetch-site"] = "none";
headers["sec-fetch-user"] = "?1";
headers["upgrade-insecure-requests"] = "1";
headers["user-agent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.7.7895.91 Safari/537.36";
const socket = net.connect(port, host);
const tlsOptions = {
    ALPNProtocols: ["h2"],
    servername: host,
    socket: socket,
};
const tlsConn = tls.connect(tlsOptions);
tlsConn.on("secureConnect", () => {
    const client = http2.connect("https://" + host, {
        createConnection: () => tlsConn
    });
    client.on("connect", () => {
        let responseCode = 0;
        const request = client.request(headers);
        request.on("response", response => {
            responseCode = response[":status"];
        });
        request.on("data", data => {
            console.log(data.toString(), "\nResponse status: " + responseCode);
            client.close();
        });
    });
})

With www.google.com, it works fine:

$ node file.js www.google.com 443
...
<!-- Google Home -->
...
</html>
Response status: 200

But with m.twitch.tv, the program exited with this error:

$ node file.js m.twitch.tv 443
node:events:491
      throw er; // Unhandled 'error' event
      ^

Error: Client network socket disconnected before secure TLS connection was established
    at connResetException (node:internal/errors:717:14)
    at TLSSocket.onConnectEnd (node:_tls_wrap:1595:19)
    at TLSSocket.emit (node:events:525:35)
    at endReadableNT (node:internal/streams/readable:1359:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted 'error' event on TLSSocket instance at:
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ECONNRESET',
  path: undefined,
  host: undefined,
  port: undefined,
  localAddress: undefined
}
英文:

I wrote a script to establish a TCP connection to target website, wrap it with TLS connection and then use that TLS connection to open HTTP/2 session. It works normal for all website, but when I do HTTP/2 request to m.twitch.tv, the script show this error:

node:events:491
throw er; // Unhandled &#39;error&#39; event
^
Error: Client network socket disconnected before secure TLS connection was established
at connResetException (node:internal/errors:717:14)
at TLSSocket.onConnectEnd (node:_tls_wrap:1595:19)
at TLSSocket.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted &#39;error&#39; event on TLSSocket instance at:
at emitErrorNT (node:internal/streams/destroy:151:8)
at emitErrorCloseNT (node:internal/streams/destroy:116:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: &#39;ECONNRESET&#39;,
path: undefined,
host: undefined,
port: undefined,
localAddress: undefined
}

This is my script:

// Usage: node file.js m.twitch.tv 443
const net = require(&quot;net&quot;);
const tls = require(&quot;tls&quot;);
const http2 = require(&quot;http2&quot;);
const crypto = require(&quot;crypto&quot;);
const host = process.argv[2];
const port = ~~process.argv[3];
const headers = {};
headers[&quot;:authority&quot;] = host;
headers[&quot;:method&quot;] = &quot;GET&quot;;
headers[&quot;:path&quot;] = &quot;/&quot;;
headers[&quot;:scheme&quot;] = &quot;https&quot;;
headers[&quot;accept&quot;] = &quot;text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7&quot;;
headers[&quot;accept-language&quot;] = &quot;en-US,en;q=0.9&quot;;
headers[&quot;dnt&quot;] = &quot;1&quot;;
headers[&quot;sec-ch-ua&quot;] = &#39;&quot;Chromium&quot;;v=&quot;112&quot;, &quot;Google Chrome&quot;;v=&quot;112&quot;, &quot;Not:A-Brand&quot;;v=&quot;99&quot;&#39;;
headers[&quot;sec-ch-ua-mobile&quot;] = &quot;?0&quot;;
headers[&quot;sec-ch-ua-platform&quot;] = &#39;&quot;Windows&quot;&#39;;
headers[&quot;sec-fetch-dest&quot;] = &quot;document&quot;;
headers[&quot;sec-fetch-mode&quot;] = &quot;navigate&quot;;
headers[&quot;sec-fetch-site&quot;] = &quot;none&quot;;
headers[&quot;sec-fetch-user&quot;] = &quot;?1&quot;;
headers[&quot;upgrade-insecure-requests&quot;] = &quot;1&quot;;
headers[&quot;user-agent&quot;] = &quot;Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.7.7895.91 Safari/537.36&quot;;
const socket = net.connect(port, host);
const tlsOptions = {
    ALPNProtocols: [&quot;h2&quot;],
    servername: host,
    socket: socket,
};
const tlsConn = tls.connect(tlsOptions);
tlsConn.on(&quot;secureConnect&quot;, () =&gt; {
    const client = http2.connect(&quot;https://&quot; + host, {
        createConnection: () =&gt; tlsConn
    });
    client.on(&quot;connect&quot;, () =&gt; {
        let responseCode = 0;
        const request = client.request(headers);
        request.on(&quot;response&quot;, response =&gt; {
            responseCode = response[&quot;:status&quot;];
        });
        request.on(&quot;data&quot;, data =&gt; {
            console.log(data.toString(), &quot;\nResponse status: &quot; + responseCode);
            client.close();
        });
    });
})

With www.google.com it works fine.

$ node file.js www.google.com 443
...
events:none;position:fixed;right:0;top:-80px;transition:opacity 0.218s,box-shadow 0.218s}.s2wfp .permission-bar-gradient{box-shadow:0 1px 80px #4285f4;opacity:1;pointer-events:none;animation:allow-alert .75s 0 infinite;animation-direction:alternate;animation-timing-function:ease-out;transition:opacity 0.218s,box-shadow 0.218s}@-webkit-keyframes allow-alert {from{opacity:1}to{opacity:.35}}\x3c/style\x3e\x3cdiv class\x3d\x22permission-bar-gradient\x22\x3e\x3c/div\x3e\x3c/div\x3e\x3c/div\x3e&#39;);})();(function(){google.drty&amp;&amp;google.drty(undefined,true);})();});google.drty&amp;&amp;google.drty(undefined,true);&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;
Response status: 200

But with m.twitch.tv, the program exited with this error.

$ node file.js m.twitch.tv 443
node:events:491
throw er; // Unhandled &#39;error&#39; event
^
Error: Client network socket disconnected before secure TLS connection was established
at connResetException (node:internal/errors:717:14)
at TLSSocket.onConnectEnd (node:_tls_wrap:1595:19)
at TLSSocket.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted &#39;error&#39; event on TLSSocket instance at:
at emitErrorNT (node:internal/streams/destroy:151:8)
at emitErrorCloseNT (node:internal/streams/destroy:116:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: &#39;ECONNRESET&#39;,
path: undefined,
host: undefined,
port: undefined,
localAddress: undefined
}

答案1

得分: 0

twitch.tv,在撰写时不支持HTTP2。您可以使用cURL进行检查:

curl -v -o /dev/null --http2 https://m.twitch.tv

请注意,在协商后的输出(*)中,您将得到一个HTTP1.1的响应。

Twitch支持HTTP3,但是这个协议与HTTP2非常不同。服务器可以支持HTTP1、2和3,但他们选择不这样做。可能是因为他们的目标受众都在使用现代浏览器,所以只支持1和3就足够了。


(*) 如果您运行上述命令,您将得到以下输出:

# curl指示它了解这两种协议:
* ALPN: offers h2
* ALPN: offers http/1.1
...
# 服务器从这个列表中选择:
* ALPN: server accepted http/1.1
...
# 响应:
&lt; HTTP/1.1 200 OK

与以下示例(此示例使用google.com)相反:

* ALPN: offers h2
* ALPN: offers http/1.1
...
* ALPN: server accepted h2
...
&lt; HTTP/2 200
英文:

twitch.tv, as of writing, does not support HTTP2. You can check with cURL:

curl -v -o /dev/null --http2 https://m.twitch.tv

Note how in the output after negotiation(*) you get a HTTP1.1 response.

Twitch does support HTTP3 but this protocol very different from HTTP2. It's possible for servers to support HTTP1, 2 and 3, but they've chosen not to. It's likely that their target audience is all using modern browsers and that it's fine for them to support just 1 and 3.


(*) You'll get the following output if you run the command:

# curl indicates that it understands these two protocols:
* ALPN: offers h2
* ALPN: offers http/1.1
...
# The server picks from this list:
* ALPN: server accepted http/1.1
...
# Response:
&lt; HTTP/1.1 200 OK

As opposed to the following (this example uses google.com):

* ALPN: offers h2
* ALPN: offers http/1.1
...
* ALPN: server accepted h2
...
&lt; HTTP/2 200

huangapple
  • 本文由 发表于 2023年5月17日 22:25:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76273186.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定