spdy-http2 / node-spdy

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

got TypeError when reusing spdy-client #232

Open dy93 opened 8 years ago

dy93 commented 8 years ago

I'm trying to reuse spdy-client to do multiple request to same host, here is my sample code:

var sAgent = spdy.createAgent({
    host: 'accounts.google.com',
    port: 443,
    spdy: {
        protocols: ['spdy/3.1'],
        plain: false,
        ssl: true
    }
});

function task() {
    return new Promise(function (resolve, reject) {
        var req = https.request({
            method: 'GET',
            path: '/favicon.ico',
            accept: '*/*',
            'accept-encoding': 'gzip, deflate, sdch',
            'accept-language': 'en-US,en;q=0.8,zh-TW;q=0.6,zh;q=0.4',
            'cache-control': 'no-cache',
            'cookie': 'NID=73=Bz_F2l5VgqGBoZfksUB7JUfmCZtxJM02OBg1DGsNq6oYrAYp-WFGUOq6dYhEj7Z8AK4seeVpHpnUlnTkVm3XZjrK1cnC4Gv8W55cAHdV-OZzzy549KFgvyUDVBpOv_Kd; PREF=ID=1111111111111111:FF=0:TM=1447133823:LM=1447133823:V=1:S=NF4BFMR8iO6kBPQt; GoogleAccountsLocale_session=en; GAPS=1:QKXOB9_sTsatL8g_JH_phE18KX2Zwg:U0QJedyY1jga4Vuw; GALX=YkJtRVPl2Zk',
            pragma: 'no-cache',
            referer: 'https://accounts.google.com/ServiceLogin?hl=en&continue=https://www.google.com.tw/webhp%3Fei%3DxoJBVpfFKsPZ0gSvqon4DA%26ved%3D0CAQQqS4oAQ',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36',
            'x-firephp-version': '0.0.6',
            agent: sAgent
        }, function (res) {
            console.log(res.statusCode);
            res.on('error', function (err) {
                log.error(err);
            });
            res.on('data', function (chunk) {
                log.info('first on data', chunk);
            });
            res.on('end', function (err) {
                log.info('end');
            });
        });
        req.end();
        resolve();
    });
}
Promise.all([
    task(),
    task(),
    task()
]).then(function (values) {
    log.info('finish');
}).catch(function (err) {
    log.error('on no');
});

above code got following error:

_http_common.js:88
    skipBody = parser.onIncoming(parser.incoming, shouldKeepAlive);
                      ^

TypeError: parser.onIncoming is not a function
    at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
    at HTTPParser.execute (/root/tmp/test-http2/node_modules/spdy/node_modules/http-deceiver/lib/deceiver.js:105:31)
    at Socket.socketOnData (_http_client.js:305:20)
    at emitOne (events.js:77:13)
    at Socket.emit (events.js:169:7)
    at Deceiver._emitEmpty (/root/tmp/test-http2/node_modules/spdy/node_modules/http-deceiver/lib/deceiver.js:229:17)
    at Deceiver.emitResponse (/root/tmp/test-http2/node_modules/spdy/node_modules/http-deceiver/lib/deceiver.js:117:10)
    at Handle.emitResponse (/root/tmp/test-http2/node_modules/spdy/lib/spdy/handle.js:175:18)
    at Stream.<anonymous> (/root/tmp/test-http2/node_modules/spdy/lib/spdy/agent.js:216:14)
    at emitTwo (events.js:87:13)

when I put two task() in Promise.all(), it works fine. but when I put more than three task() into it, I got the error. please tell me how to reuse a spdyAgent.

my node version is v4.2.2, and my node-spdy version is 2.1.0 Thanks

indutny commented 8 years ago

@dy93 may I ask you to run this script with DEBUG="spdy*" environment variable and gist the results?

Thank you!

dy93 commented 8 years ago

@indutny I make some change to the testing code to make it clear, here is my testing code to reproduce and the execution output: https://gist.github.com/dy93/3131b97fdb652249832c/78ef8f718c8b6288b86af4e035f6ffd6e7491d1d

Thanks!

indutny commented 8 years ago

@dy93 sorry for quite a big delay. I have bad news for you, this is not node-spdy bug (at seems it doesn't look like it). It looks like this is a V8 bug instead, if you will run node --no_use_ic test.js - it will work just fine (however it will be much more slower).

I'm still checking it just to be sure, but all evidence that I have so far leads to this conclusion. I will work on resolving V8 issue, but it will probably take more time.

Sorry!

indutny commented 8 years ago

@dy93 btw, it is very likely that the promises are the cause of the problem here. So if you could do what you want without them - I would recommend giving it a try.

indutny commented 8 years ago

@dy93 filed v8 bug: https://code.google.com/p/v8/issues/detail?id=4582&thanks=4582&ts=1448847246 Please star it ;)

dy93 commented 8 years ago

@indutny I think it is not a bug related to promise, because I got same error when I continuously make requests 3 times using spdy agent. here is my sample code that does not use promise: https://gist.github.com/dy93/07936cbcc5e624b1206d

btw, I think you're right, it may be a bug related to v8 I have star it, thank you!

ben-page commented 8 years ago

I think this might be related to the issue that I just reported. #252.

The spdy module depends on the parser object from the ServerResponse object (part of the node http module). However, after res.end() is called the parser is disposed in some fashion, leaving it in an unusable state.

I think (after a few minutes digging around in the node lib source) that the parser is native module or part of V8. So this behavior makes sense (the GC can't clean it up).

I suspect, the solution is not to borrow the parser from the response, but for this module to create it's own instances of the parser who's life cycle can be controlled independently.