1'use strict'; 2// Flags: --expose-internals 3 4const common = require('../common'); 5if (!common.hasCrypto) 6 common.skip('missing crypto'); 7 8const { internalBinding } = require('internal/test/binding'); 9const { 10 constants, 11 Http2Session, 12 nghttp2ErrorString 13} = internalBinding('http2'); 14const http2 = require('http2'); 15const { NghttpError } = require('internal/http2/util'); 16 17// Tests error handling within requestOnConnect 18// - NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE (should emit session error) 19// - NGHTTP2_ERR_INVALID_ARGUMENT (should emit stream error) 20// - every other NGHTTP2 error from binding (should emit session error) 21 22const specificTestKeys = [ 23 'NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE', 24 'NGHTTP2_ERR_INVALID_ARGUMENT', 25]; 26 27const specificTests = [ 28 { 29 ngError: constants.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE, 30 error: { 31 code: 'ERR_HTTP2_OUT_OF_STREAMS', 32 name: 'Error', 33 message: 'No stream ID is available because ' + 34 'maximum stream ID has been reached' 35 }, 36 type: 'stream' 37 }, 38 { 39 ngError: constants.NGHTTP2_ERR_INVALID_ARGUMENT, 40 error: { 41 code: 'ERR_HTTP2_STREAM_SELF_DEPENDENCY', 42 name: 'Error', 43 message: 'A stream cannot depend on itself' 44 }, 45 type: 'stream' 46 }, 47]; 48 49const genericTests = Object.getOwnPropertyNames(constants) 50 .filter((key) => ( 51 key.indexOf('NGHTTP2_ERR') === 0 && specificTestKeys.indexOf(key) < 0 52 )) 53 .map((key) => ({ 54 ngError: constants[key], 55 error: { 56 code: 'ERR_HTTP2_ERROR', 57 constructor: NghttpError, 58 name: 'Error', 59 message: nghttp2ErrorString(constants[key]) 60 }, 61 type: 'session' 62 })); 63 64const tests = specificTests.concat(genericTests); 65 66let currentError; 67 68// Mock submitRequest because we only care about testing error handling 69Http2Session.prototype.request = () => currentError; 70 71const server = http2.createServer(common.mustNotCall()); 72 73server.listen(0, common.mustCall(() => runTest(tests.shift()))); 74 75function runTest(test) { 76 const client = http2.connect(`http://localhost:${server.address().port}`); 77 client.on('close', common.mustCall()); 78 79 const req = client.request({ ':method': 'POST' }); 80 81 currentError = test.ngError; 82 req.resume(); 83 req.end(); 84 85 const errorMustCall = common.expectsError(test.error); 86 const errorMustNotCall = common.mustNotCall( 87 `${test.error.code} should emit on ${test.type}` 88 ); 89 90 if (test.type === 'stream') { 91 client.on('error', errorMustNotCall); 92 req.on('error', errorMustCall); 93 } else { 94 client.on('error', errorMustCall); 95 req.on('error', (err) => { 96 common.expectsError({ 97 code: 'ERR_HTTP2_STREAM_CANCEL' 98 })(err); 99 common.expectsError({ 100 code: 'ERR_HTTP2_ERROR' 101 })(err.cause); 102 }); 103 } 104 105 req.on('end', common.mustNotCall()); 106 req.on('close', common.mustCall(() => { 107 client.destroy(); 108 109 if (!tests.length) { 110 server.close(); 111 } else { 112 runTest(tests.shift()); 113 } 114 })); 115} 116