spdy-http2 / node-spdy

SPDY server on Node.js
2.8k stars 196 forks source link

gracefully shutdown server? #245

Open dy93 opened 8 years ago

dy93 commented 8 years ago

thanks for your help to add public api for getting connection object in issue 238

but my problem still not solved. the file download process started before GOAWAY frame should success in the end. here's the sample code to explain my problem:

var spdy = require('spdy'),
    fs = require('fs');

var options = {
    key: fs.readFileSync(__dirname + '/my.key'),
    cert: fs.readFileSync(__dirname + '/my.crt'),

    // **optional** SPDY-specific options
    spdy: {
        protocols: ['h2'],
        plain: false,

        connection: {
            windowSize: 1024 * 1024, // Server's window size
            // **optional** if true - server will send 3.1 frames on 3.0 *plain* spdy
            autoSpdy31: false
        }
    }
};

var server = spdy.createServer(options, function (req, res) {
    if (req.url !== '/file') {
        // simple web page to show download link
        res.writeHead(200);
        res.end("<html><head><title>test</title></head><body><a href='file'>get file</a></body></html>");
        return;
    }

    var stats = fs.statSync('./large.bin');
    var rs = fs.createReadStream('./large.bin');
    res.writeHead(200, {
        'Content-Type': 'application/octet-stream',
        'Content-Disposition': 'attachment; filename="file"',
        'Content-Length': stats.size
    });
    rs.pipe(res, { end: true });

    setTimeout(function () {
        console.log('send GOAWAY');
        res.spdyStream.connection.end();
    }, 2000);   // simulate shutdown server after 2 seconds. And the file download process *should* successfully complete
});

server.listen(4000);

to run this sample, you should generate a large file named large.bin (the size is depends on your network speed, it should be large enough that can not be complete downloaded in 2 seconds)

  1. start the server
  2. open the browser and navigate to the server: https://ip:4000
  3. click the get file link, and the download process start
  4. after 2 seconds, server will send GOAWAY frame
  5. since download process was started before GOAWAY frame, it should success in the end.

but i just get "network error" in my chrome, and download process failed I think it may be a problem that server lake of "END_STREAM" flag in the last DATA frame ?

here is my environment: node-spdy: 3.2.0 chrome: 47.0.2526.111 m

dy93 commented 8 years ago

Hey! Here is update: I found that the problem was remove stream too early, this is a simpler code to reproduce the situation:

var spdy = require('spdy'),
    fs = require('fs');
var options = {
    key: fs.readFileSync(__dirname + '/my.key'),
    cert: fs.readFileSync(__dirname + '/my.crt'),
    spdy: {
        protocols: ['h2'],
        plain: false,
        connection: {
            windowSize: 1024 * 1024,
            autoSpdy31: false
        }
    }
};

var server = spdy.createServer(options, function(req, res) {
    res.spdyStream.connection.end(); // send GOAWAY frame

    setTimeout(function(){
        res.writeHead('200');
        res.end('hello'); // client should get this "hello"
    }, 1000);
});

server.listen(443);

when I visit the server from the browser, I just get connection closed unexpectedly.

If I comment out self.on('_streamDrain', self._onStreamDrain); in Connection.prototype._goaway in spdy-transport/lib/spdy-transport/connection.js, I can get the "hello" perfectly

The problem was that we remove stream too early (with adding DEBUG=* when executing server, I found that spdy remove the stream just after sending DATA frame which contains "hello" but before the DATA frame which contains "END_STREAM" flag)

Since DATA frame which containing "END_STREAM" cannot be delivered to browser before tcp connection closed, browser abort any DATA frame received previously.

Please solve this problem, thank you!

daviddias commented 7 years ago

@dy93 could you check if this is still a issue?