node.jshttp2server-pushpush-promisepushstream

Server Push with Nodejs pushStream method is not working


I am studying http2 on nodejs, but find out a issue pushStream method not working

enter image description here (client side do not show "Pushed/[fileName]" on developer tool)

I wonder if the reason is nodejs version (I installed the latest version v9.8.0)

My codes is the following :

server.js

'use strict'

const fs = require('fs');
const path = require('path');
const http2 = require('http2');
const utils = require('./utils');

const { HTTP2_HEADER_PATH } = http2.constants;

const PORT = process.env.PORT || 3000;

// The files are pushed to stream here
function push(stream, path) {
  const file = utils.getFile(path);
  if (!file) {
    return;
  }
  stream.pushStream({ [HTTP2_HEADER_PATH]: path}, (err, pushStream, headers) => {
    if (err) throw err;
    pushStream.respondWithFD(file.content, file.headers)
  });
}

// Request handler
function onRequest(req, res) {
  const reqPath = req.headers[':path'] === '/' ? '/index.html' : req.headers[':path']
  const file = utils.getFile(reqPath);

  // 404 - File not found
  if (!file) {
    res.statusCode = 404;
    res.end();
    return;
  }

  // Push with index.html
  if (reqPath === '/index.html') {
    push(res.stream, '/assets/main.js');
    push(res.stream, '/assets/style.css');
  } else {
    console.log("requiring non index.html")
  }

  // Serve file
  res.stream.respondWithFD(file.content, file.headers);
}

// creating an http2 server
const server = http2.createSecureServer({
  cert: fs.readFileSync(path.join(__dirname, '/certificate.crt')),
  key: fs.readFileSync(path.join(__dirname, '/privateKey.key'))
}, onRequest);

// start listening
server.listen(PORT, (err) => {
  if (err) {
    console.error(err);
    return -1;
  }
  console.log(`Server listening to port ${PORT}`);
});

utils.js

'use strict';
const fs = require('fs');
const mime = require('mime');

module.exports = {
  getFile: function (path) {
    const filePath = `${__dirname}/public${path}`;
    try {
      const content = fs.openSync(filePath, 'r');
      const contentType = mime.getType(filePath);
      return {
        content,
        headers: {
          'content-type': contentType
        }
      };
    } catch (e) {
      return null;
    }
  }
}

Updated 2020 01 28

Resolved: The reason is the latest version of chrome v65. has bug, cause client do not trust PUSH_PROMISE frame. I backup chrome v64 then it working now.


Solution

  • I haven’t tried to run your code but have noticed that Chrome does not allow HTTP/2 push with an untrusted HTTPS certificate (e.g. a self-signed one not yet added to the trust store). Raised a bug with the Chrome team.

    If you have the red unsecure padlock item then you could be hitting this issue too. Add the certificate into your trust store, restart Chrome and reload the site where you should get a green padlock.

    Note Chrome needs a certificate with a Subject Alternative Name (SAN) field matching the domain so if you’ve just got the older Subject field then it won’t go green even after adding it to your trust store.

    Another option is to look at the Chrome HTTP2 frames by typing this into your URL:

    chrome://net- internals/#http2
    

    If you see the push promise frames (with a promised_stream_id), followed by the headers and data on that promised_stream_id then you know the sever side is working.