1'use strict'; 2 3const common = require('../common'); 4if (!common.hasCrypto) 5 common.skip('missing crypto'); 6 7const async_hooks = require('async_hooks'); 8const assert = require('assert'); 9const http2 = require('http2'); 10 11const pings = new Set(); 12const events = [0, 0, 0, 0]; 13 14const hook = async_hooks.createHook({ 15 init(id, type, trigger, resource) { 16 if (type === 'HTTP2PING') { 17 pings.add(id); 18 events[0]++; 19 } 20 }, 21 before(id) { 22 if (pings.has(id)) { 23 events[1]++; 24 } 25 }, 26 after(id) { 27 if (pings.has(id)) { 28 events[2]++; 29 } 30 }, 31 destroy(id) { 32 if (pings.has(id)) { 33 events[3]++; 34 } 35 } 36}); 37hook.enable(); 38 39process.on('exit', () => { 40 assert.deepStrictEqual(events, [4, 4, 4, 4]); 41}); 42 43const server = http2.createServer(); 44server.on('stream', common.mustCall((stream) => { 45 assert(stream.session.ping(common.mustCall((err, duration, ret) => { 46 assert.strictEqual(err, null); 47 assert.strictEqual(typeof duration, 'number'); 48 assert.strictEqual(ret.length, 8); 49 stream.end('ok'); 50 }))); 51 stream.respond(); 52})); 53 54server.listen(0, common.mustCall(() => { 55 const client = http2.connect(`http://localhost:${server.address().port}`, 56 { maxOutstandingPings: 2 }); 57 client.on('connect', common.mustCall(() => { 58 { 59 const payload = Buffer.from('abcdefgh'); 60 assert(client.ping(payload, common.mustCall((err, duration, ret) => { 61 assert.strictEqual(err, null); 62 assert.strictEqual(typeof duration, 'number'); 63 assert.deepStrictEqual(payload, ret); 64 }))); 65 } 66 { 67 const payload = Buffer.from('abcdefgi'); 68 assert(client.ping(payload, common.mustCall((err, duration, ret) => { 69 assert.strictEqual(err, null); 70 assert.strictEqual(typeof duration, 'number'); 71 assert.deepStrictEqual(payload, ret); 72 }))); 73 } 74 75 // Only max 2 pings at a time based on the maxOutstandingPings option 76 assert(!client.ping(common.expectsError({ 77 code: 'ERR_HTTP2_PING_CANCEL', 78 name: 'Error', 79 message: 'HTTP2 ping cancelled' 80 }))); 81 82 // Should throw if payload is not of type ArrayBufferView 83 { 84 [1, true, {}, []].forEach((payload) => 85 assert.throws( 86 () => client.ping(payload), 87 { 88 name: 'TypeError', 89 code: 'ERR_INVALID_ARG_TYPE', 90 message: 'The "payload" argument must be an instance of Buffer, ' + 91 'TypedArray, or DataView.' + 92 common.invalidArgTypeHelper(payload) 93 } 94 ) 95 ); 96 } 97 98 // Should throw if payload length is not 8 99 { 100 const shortPayload = Buffer.from('abcdefg'); 101 const longPayload = Buffer.from('abcdefghi'); 102 [shortPayload, longPayload].forEach((payloadWithInvalidLength) => 103 assert.throws( 104 () => client.ping(payloadWithInvalidLength), 105 { 106 name: 'RangeError', 107 code: 'ERR_HTTP2_PING_LENGTH', 108 message: 'HTTP2 ping payload must be 8 bytes' 109 } 110 ) 111 ); 112 } 113 114 // Should throw error is callback is not of type function 115 { 116 const payload = Buffer.from('abcdefgh'); 117 [1, true, {}, []].forEach((invalidCallback) => 118 assert.throws( 119 () => client.ping(payload, invalidCallback), 120 { 121 name: 'TypeError', 122 code: 'ERR_INVALID_ARG_TYPE', 123 } 124 ) 125 ); 126 } 127 128 const req = client.request(); 129 req.resume(); 130 req.on('end', common.mustCall(() => { 131 client.close(); 132 server.close(); 133 })); 134 })); 135})); 136