molnarg / node-http2

An HTTP/2 client and server implementation for node.js
MIT License
1.79k stars 187 forks source link

Can't make server work, whilst identical code works with require('https') #161

Closed akc42 closed 8 years ago

akc42 commented 8 years ago

I am trying to make an http2 server work, and all that happens is my initial static file request remains pending when using serve-static. The identical code works when I replace require('http2') with require('https'), so I assume it is worth reporting as the goal is compatability. I am running on linux with node v5.0.0 and chrome as the browser version 47.0.2526.106

Here is the core of my code - first most of the requires

  const PORT = 5443;
  var fs = require('fs');
  var path = require('path');
  var enableDestroy = require('server-destroy');
  var PROJECT_ROOT = path.resolve(__dirname, '..');
  var Router = require('router');
  var emitter = require('events').EventEmitter;
  var util = require('util');
  var logger = require('./log');
  var router = Router();
  var component = Router();
  var api = Router();
  var serveStatic = require('serve-static');
  var app = serveStatic(path.resolve(PROJECT_ROOT,'app'));
  var bodyParser = require('body-parser');

then the inside of the function creating the web server I can replace require('http2') with require('https') in the first line below and it all works perfectly.

    this.server = require('http2').createServer(cert,(req,res) =>{
      var done = finalhandler(req,res);
      function donewrapper(err) {
        logger('debug','donewrapper called');
        done(err);
      }
      logger('debug','server request received for ' + req.url );
      router(req,res,donewrapper);
    });
    this.server.listen(PORT,hostname);
    enableDestroy(this.server); //enhance server with ability to shut it down
    router.use('/components/',component);
    component.use(serveStatic(path.resolve(PROJECT_ROOT,'app/elements')));
    component.use(serveStatic(path.resolve(PROJECT_ROOT,'bower_components')));
    router.route('/logon').all(bodyParser.json()).post((req,res) => {
//This route not tested yet
    });
    router.use('/api/',api);
    api.use(bodyParser.json());
    api.post('/api',(req, res, next) => {
//This route not tested yet
    });
    router.use('/', (req,res,next) => {
      logger('debug', 'got a request that should use the static app');
      app(req,res,next);
    });
    logger('debug','server ready for use');

The certificates in use (passed in as the cert parameter in the first position of CreateServer) are from letsEncrypt, and refer to a real ip address from the outside, but I have tweeked by internal dns server to point the hostname (pastrial.hartley-consultants.com) to my development machine. So I make a browser request for https://pastrial.hartley-consultants.com:5443 and with http2 this never completes - yet with https it completes (and all the followup requests too).

index.html is a real file within PROJECT_ROOT/app/

akc42 commented 8 years ago

I have been doing some digging, and I think the problem arises because serve-static uses send which in turn uses on-finished. This is expecting the response stream to have a boolean finished field. When I use the http2 module the response stream that gets passed is outgoingMessage when I use the https module the response stream that gets passed is serverResponse which is something derived from outgoingMessage this has the additional boolean.

I am not sure I yet understand about this additional field yet and why on-finished needs to use it. So more digging

akc42 commented 8 years ago

I think my previous message is a bit confused. What I now understand is that OutgoingResponse is http2's equivalent of 'ServerResponse. However it is missing thefinished` boolean that that spec calls for.

I tried patching it in = this.finished = false in the constructor and this.finished = true in the _finish() function and I appear to be my test system working. No idea if that is the right solution, so no pull request.