1'use strict'; 2 3const { 4 hasCrypto, 5 mustCall, 6 mustNotCall, 7 skip 8} = require('../common'); 9if (!hasCrypto) 10 skip('missing crypto'); 11 12const { 13 deepStrictEqual, 14 strictEqual, 15 throws 16} = require('assert'); 17const { 18 createSecureServer, 19 createServer, 20 connect 21} = require('http2'); 22const Countdown = require('../common/countdown'); 23 24const { readKey } = require('../common/fixtures'); 25 26const key = readKey('agent8-key.pem', 'binary'); 27const cert = readKey('agent8-cert.pem', 'binary'); 28const ca = readKey('fake-startcom-root-cert.pem', 'binary'); 29 30{ 31 const server = createSecureServer({ key, cert }); 32 server.on('stream', mustCall((stream) => { 33 stream.session.origin('https://example.org/a/b/c', 34 new URL('https://example.com')); 35 stream.respond(); 36 stream.end('ok'); 37 })); 38 server.on('session', mustCall((session) => { 39 session.origin('https://foo.org/a/b/c', new URL('https://bar.org')); 40 41 // Won't error, but won't send anything 42 session.origin(); 43 44 [0, true, {}, []].forEach((input) => { 45 throws( 46 () => session.origin(input), 47 { 48 code: 'ERR_INVALID_ARG_TYPE', 49 name: 'TypeError' 50 } 51 ); 52 }); 53 54 [new URL('foo://bar'), 'foo://bar'].forEach((input) => { 55 throws( 56 () => session.origin(input), 57 { 58 code: 'ERR_HTTP2_INVALID_ORIGIN', 59 name: 'TypeError' 60 } 61 ); 62 }); 63 64 ['not a valid url'].forEach((input) => { 65 throws( 66 () => session.origin(input), 67 { 68 code: 'ERR_INVALID_URL', 69 name: 'TypeError' 70 } 71 ); 72 }); 73 const longInput = `http://foo.bar${'a'.repeat(16383)}`; 74 throws( 75 () => session.origin(longInput), 76 { 77 code: 'ERR_HTTP2_ORIGIN_LENGTH', 78 name: 'TypeError' 79 } 80 ); 81 })); 82 83 server.listen(0, mustCall(() => { 84 const originSet = [`https://localhost:${server.address().port}`]; 85 const client = connect(originSet[0], { ca }); 86 const checks = [ 87 ['https://foo.org', 'https://bar.org'], 88 ['https://example.org', 'https://example.com'], 89 ]; 90 91 const countdown = new Countdown(3, () => { 92 client.close(); 93 server.close(); 94 }); 95 96 client.on('origin', mustCall((origins) => { 97 const check = checks.shift(); 98 originSet.push(...check); 99 deepStrictEqual(client.originSet, originSet); 100 deepStrictEqual(origins, check); 101 countdown.dec(); 102 }, 2)); 103 104 client.request().on('close', mustCall(() => countdown.dec())).resume(); 105 })); 106} 107 108// Test automatically sending origin on connection start 109{ 110 const origins = ['https://foo.org/a/b/c', 'https://bar.org']; 111 const server = createSecureServer({ key, cert, origins }); 112 server.on('stream', mustCall((stream) => { 113 stream.respond(); 114 stream.end('ok'); 115 })); 116 117 server.listen(0, mustCall(() => { 118 const check = ['https://foo.org', 'https://bar.org']; 119 const originSet = [`https://localhost:${server.address().port}`]; 120 const client = connect(originSet[0], { ca }); 121 122 const countdown = new Countdown(2, () => { 123 client.close(); 124 server.close(); 125 }); 126 127 client.on('origin', mustCall((origins) => { 128 originSet.push(...check); 129 deepStrictEqual(client.originSet, originSet); 130 deepStrictEqual(origins, check); 131 countdown.dec(); 132 })); 133 134 client.request().on('close', mustCall(() => countdown.dec())).resume(); 135 })); 136} 137 138// If return status is 421, the request origin must be removed from the 139// originSet 140{ 141 const server = createSecureServer({ key, cert }); 142 server.on('stream', mustCall((stream) => { 143 stream.respond({ ':status': 421 }); 144 stream.end(); 145 })); 146 server.on('session', mustCall((session) => { 147 session.origin('https://foo.org'); 148 })); 149 150 server.listen(0, mustCall(() => { 151 const origin = `https://localhost:${server.address().port}`; 152 const client = connect(origin, { ca }); 153 154 client.on('origin', mustCall((origins) => { 155 deepStrictEqual(client.originSet, [origin, 'https://foo.org']); 156 const req = client.request({ ':authority': 'foo.org' }); 157 req.on('response', mustCall((headers) => { 158 strictEqual(headers[':status'], 421); 159 deepStrictEqual(client.originSet, [origin]); 160 })); 161 req.resume(); 162 req.on('close', mustCall(() => { 163 client.close(); 164 server.close(); 165 })); 166 }, 1)); 167 })); 168} 169 170// Origin is ignored on plain text HTTP/2 connections... server will still 171// send them, but client will ignore them. 172{ 173 const server = createServer(); 174 server.on('stream', mustCall((stream) => { 175 stream.session.origin('https://example.org', 176 new URL('https://example.com')); 177 stream.respond(); 178 stream.end('ok'); 179 })); 180 server.listen(0, mustCall(() => { 181 const client = connect(`http://localhost:${server.address().port}`); 182 client.on('origin', mustNotCall()); 183 strictEqual(client.originSet, undefined); 184 const req = client.request(); 185 req.resume(); 186 req.on('close', mustCall(() => { 187 client.close(); 188 server.close(); 189 })); 190 })); 191} 192