• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const common = require('../common');
4const fixtures = require('../common/fixtures');
5
6if (!common.hasCrypto)
7  common.skip('missing crypto');
8
9const { strictEqual, ok } = require('assert');
10const { createSecureContext } = require('tls');
11const { createSecureServer, connect } = require('http2');
12const { get } = require('https');
13const { parse } = require('url');
14const { connect: tls } = require('tls');
15
16const countdown = (count, done) => () => --count === 0 && done();
17
18const key = fixtures.readKey('agent8-key.pem');
19const cert = fixtures.readKey('agent8-cert.pem');
20const ca = fixtures.readKey('fake-startcom-root-cert.pem');
21
22const clientOptions = { secureContext: createSecureContext({ ca }) };
23
24function onRequest(request, response) {
25  const { socket: { alpnProtocol } } = request.httpVersion === '2.0' ?
26    request.stream.session : request;
27  response.writeHead(200, { 'content-type': 'application/json' });
28  response.end(JSON.stringify({
29    alpnProtocol,
30    httpVersion: request.httpVersion
31  }));
32}
33
34function onSession(session, next) {
35  const headers = {
36    ':path': '/',
37    ':method': 'GET',
38    ':scheme': 'https',
39    ':authority': `localhost:${this.server.address().port}`
40  };
41
42  const request = session.request(headers);
43  request.on('response', common.mustCall((headers) => {
44    strictEqual(headers[':status'], 200);
45    strictEqual(headers['content-type'], 'application/json');
46  }));
47  request.setEncoding('utf8');
48  let raw = '';
49  request.on('data', (chunk) => { raw += chunk; });
50  request.on('end', common.mustCall(() => {
51    const { alpnProtocol, httpVersion } = JSON.parse(raw);
52    strictEqual(alpnProtocol, 'h2');
53    strictEqual(httpVersion, '2.0');
54
55    session.close();
56    this.cleanup();
57
58    if (typeof next === 'function') {
59      next();
60    }
61  }));
62  request.end();
63}
64
65// HTTP/2 & HTTP/1.1 server
66{
67  const server = createSecureServer(
68    { cert, key, allowHTTP1: true },
69    common.mustCall(onRequest, 2)
70  );
71
72  server.listen(0);
73
74  server.on('listening', common.mustCall(() => {
75    const { port } = server.address();
76    const origin = `https://localhost:${port}`;
77
78    const cleanup = countdown(2, () => server.close());
79
80    // HTTP/2 client
81    connect(
82      origin,
83      clientOptions,
84      common.mustCall(onSession.bind({ cleanup, server }))
85    );
86
87    // HTTP/1.1 client
88    get(
89      Object.assign(parse(origin), clientOptions),
90      common.mustCall((response) => {
91        strictEqual(response.statusCode, 200);
92        strictEqual(response.statusMessage, 'OK');
93        strictEqual(response.headers['content-type'], 'application/json');
94
95        response.setEncoding('utf8');
96        let raw = '';
97        response.on('data', (chunk) => { raw += chunk; });
98        response.on('end', common.mustCall(() => {
99          const { alpnProtocol, httpVersion } = JSON.parse(raw);
100          strictEqual(alpnProtocol, false);
101          strictEqual(httpVersion, '1.1');
102
103          cleanup();
104        }));
105      })
106    );
107  }));
108}
109
110// HTTP/2-only server
111{
112  const server = createSecureServer(
113    { cert, key },
114    common.mustCall(onRequest)
115  );
116
117  server.once('unknownProtocol', common.mustCall((socket) => {
118    socket.destroy();
119  }));
120
121  server.listen(0);
122
123  server.on('listening', common.mustCall(() => {
124    const { port } = server.address();
125    const origin = `https://localhost:${port}`;
126
127    const cleanup = countdown(3, () => server.close());
128
129    // HTTP/2 client
130    connect(
131      origin,
132      clientOptions,
133      common.mustCall(function(session) {
134        onSession.call({ cleanup, server },
135                       session,
136                       common.mustCall(testNoTls));
137      })
138    );
139
140    function testNoTls() {
141      // HTTP/1.1 client
142      get(Object.assign(parse(origin), clientOptions), common.mustNotCall)
143        .on('error', common.mustCall(cleanup))
144        .on('error', common.mustCall(testWrongALPN))
145        .end();
146    }
147
148    function testWrongALPN() {
149      // Incompatible ALPN TLS client
150      let text = '';
151      tls(Object.assign({ port, ALPNProtocols: ['fake'] }, clientOptions))
152        .setEncoding('utf8')
153        .on('data', (chunk) => text += chunk)
154        .on('end', common.mustCall(() => {
155          ok(/Unknown ALPN Protocol, expected `h2` to be available/.test(text));
156          cleanup();
157        }));
158    }
159  }));
160}
161