Skip to content

http2 throws ERR_HTTP2_INVALID_STREAM with minor amount of concurrency #22135

Description

@buu700
  • Version: v10.8.0
  • Platform: Linux 86f664ae731c 4.9.93-linuxkit-aufs #1 SMP Wed Jun 6 16:55:56 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux (ubuntu:18.04 Docker image)
  • Subsystem: http2

After a small handful of concurrent requests, http2 fails with the following error:

internal/http2/core.js:1791
      throw new ERR_HTTP2_INVALID_STREAM();
      ^

Error [ERR_HTTP2_INVALID_STREAM]: The stream has been destroyed
    at ServerHttp2Stream.sendTrailers (internal/http2/core.js:1791:13)
    at ServerHttp2Stream.onStreamTrailersReady (internal/http2/compat.js:377:8)
    at ServerHttp2Stream.emit (events.js:182:13)
    at Http2Stream.onStreamTrailers [as ontrailers] (internal/http2/core.js:318:15)
    at ServerHttp2Stream.submitRstStream (internal/http2/core.js:328:19)
    at ServerHttp2Stream.finishCloseStream (internal/http2/core.js:1533:3)
    at closeStream (internal/http2/core.js:1517:7)
    at ServerHttp2Stream.close (internal/http2/core.js:1846:5)
    at state.streams.forEach (internal/http2/core.js:2691:46)
    at Map.forEach (<anonymous>)

Test case:

cat > server.js << EOM
	const app = new (require('koa'))();
	const crypto = require('crypto');
	const fs = require('fs');
	const http2 = require('http2');


	app.use(async ctx => {
		await new Promise(resolve => setTimeout(resolve, 1000));

		ctx.body = 'balls';
		ctx.status = 200;
	});

	http2.createSecureServer(
		{
			allowHTTP1: true,
			cert: fs.readFileSync('cert.pem'),
			key: fs.readFileSync('key.pem'),
			dhparam: fs.readFileSync('dhparams.pem'),
			secureOptions:
				crypto.constants.SSL_OP_NO_SSLv3 |
				crypto.constants.SSL_OP_NO_TLSv1
		},
		app.callback()
	).listen(
		31337
	);
EOM

killall node
node server.js &
echo -n > count
while ps ux | grep server.js | grep -v grep 2> /dev/null ; do
	echo -e '1\n2\n3\n4\n5\n6\n7\n8\n9\n10'
done | xargs -P10 bash -c '
	echo >> count
	curl -sk https://localhost:31337 > /dev/null
'

When the error occurs, you can manually kill the command with ctrl+C and wc -l count to view how many requests were initiated before the failure. For me it's been anywhere between 10 and 70.

This doesn't seem to be reproducible when using either https or spdy instead of http2.

Activity

  1. mscdex commented on Aug 5, 2018

    @mscdex
    Contributor

    Can you reproduce the issue without koa?

  2. buu700 commented on Aug 5, 2018

    @buu700
    Author

    Ah right, good point. After giving it a few minutes, the koa-free alternative below doesn't seem affected. I'll close this and open a ticket there.

    cat > server.js << EOM
    	const crypto = require('crypto');
    	const fs = require('fs');
    	const http2 = require('http2');
    
    
    	const server = http2.createSecureServer({
    		allowHTTP1: true,
    		cert: fs.readFileSync('cert.pem'),
    		key: fs.readFileSync('key.pem'),
    		dhparam: fs.readFileSync('dhparams.pem'),
    		secureOptions:
    			crypto.constants.SSL_OP_NO_SSLv3 |
    			crypto.constants.SSL_OP_NO_TLSv1
    	});
    
    	server.on('stream', stream => {
    		setTimeout(
    			() => {
    				stream.respond({'content-type': 'text/plain', ':status': 200});
    				stream.end('balls');
    			},
    			1000
    		);
    	});
    
    	server.listen(31337);
    EOM
    

    Edit: compatibility API version:

    cat > server.js << EOM
    	const crypto = require('crypto');
    	const fs = require('fs');
    	const http2 = require('http2');
    
    
    	const server = http2.createSecureServer(
    		{
    			allowHTTP1: true,
    			cert: fs.readFileSync('cert.pem'),
    			key: fs.readFileSync('key.pem'),
    			dhparam: fs.readFileSync('dhparams.pem'),
    			secureOptions:
    				crypto.constants.SSL_OP_NO_SSLv3 |
    				crypto.constants.SSL_OP_NO_TLSv1
    		},
    		(req, res) => {
    			setTimeout(
    				() => {
    					res.writeHead(200, {'content-type': 'text/plain'});
    					res.end('balls');
    				},
    				1000
    			);
    		}
    	);
    
    	server.listen(31337);
    EOM
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions