Description
- Version: v12.16.3, v14.3.0
- Platform: Darwin **** 18.7.0 Darwin Kernel Version 18.7.0: Mon Feb 10 21:08:45 PST 2020; root:xnu-4903.278.28~1/RELEASE_X86_64 x86_64
- Subsystem: http2
- Google Chrome: Version 83.0.4103.61 (Official Build) (64-bit)
- Firefox: 76.0.1 (64-bit)
What steps will reproduce the bug?
Here is a simple echo server: return posted data to the client. This reproducing program runs locally.
const https = require("https");
const http2 = require("http2");
const fs = require("fs");
const serverKeyPath = "ssl_certs/server.key";
const serverCrtPath = "ssl_certs/server.crt";
const httpsPort = 8443;
const handler = (req, res) => {
console.log(`${req.method} ${req.url}`);
if (req.method === "GET") {
res.writeHead(200, {
'Content-Type': "text/html",
});
res.end(`\
<input type="file" id="myfile" style="font-size: 1.5em;">
<button id="post_btn" onclick="post()">Post</button><br>
<img id="myimage">
<script>
function post() {
console.log(window.myfile.files);
const xhr = new XMLHttpRequest();
xhr.open("POST", "/post_test", true);
const file = window.myfile.files[0];
xhr.responseType = 'blob';
xhr.onload = () => {
window.myimage.src = URL.createObjectURL(xhr.response);
};
xhr.send(file);
}
</script>
`);
return;
}
// Echo-server
req.pipe(res);
req.on('close', () => {
console.log(req.url, "closed");
});
req.on('end', () => {
console.log(req.url, "ended");
});
};
// You can switch
// const usesHttp2 = false;
const usesHttp2 = true;
const listenListener = () => {
console.log(`Listen on ${httpsPort} with '${usesHttp2 ? "http2" : "https"}'...`);
};
if (usesHttp2) {
http2.createSecureServer(
{
key: fs.readFileSync(serverKeyPath),
cert: fs.readFileSync(serverCrtPath),
// allowHTTP1: true,
},
handler,
).listen(httpsPort, listenListener);
} else {
https.createServer(
{
key: fs.readFileSync(serverKeyPath),
cert: fs.readFileSync(serverCrtPath),
},
handler,
).listen(httpsPort, listenListener);
}
After run, you can access to https://localhost:8443/ on your browser.
You can create server.key
and server.crt
as follows.
openssl req \
-newkey rsa:2048 \
-x509 \
-nodes \
-keyout server.key \
-new \
-out server.crt \
-subj /CN=localhost \
-reqexts SAN \
-extensions SAN \
-config <(cat /etc/ssl/openssl.cnf \
<(printf '[SAN]\nsubjectAltName=DNS:localhost,IP:192.168.0.1')) \
-sha256 \
-days 3650
How often does it reproduce? Is there a required condition?
Always.
What is the expected behavior?
Here is the expected behavior. When using const usesHttp2 = false;
, we have the expected behavior with the "https" module.
What do you see instead?
With the "http2" module, we have the following when const usesHttp2 = true;
.
When the first POST, the server never returns the posted image and callbacks for on("close")
and on("end")
are not called. But, when you push the "post" button again, the first data are returned and the image is displayed.
In summary, a handler with "https" works well, but the handler with "http2" doesn't work well.
Additional information
This behavior is reproduced on Google Chrome and Firefox. The posted image is https://en.wikipedia.org/wiki/File:Lenna_(test_image).png#file.
Maybe related: #32978