• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* eslint-disable node-core/require-common-first, node-core/required-modules */
2'use strict';
3
4// An HTTP/2 testing tool used to create mock frames for direct testing
5// of HTTP/2 endpoints.
6
7const kFrameData = Symbol('frame-data');
8const FLAG_EOS = 0x1;
9const FLAG_ACK = 0x1;
10const FLAG_EOH = 0x4;
11const FLAG_PADDED = 0x8;
12const PADDING = Buffer.alloc(255);
13
14const kClientMagic = Buffer.from('505249202a20485454502f322' +
15                                 'e300d0a0d0a534d0d0a0d0a', 'hex');
16
17const kFakeRequestHeaders = Buffer.from('828684410f7777772e65' +
18                                        '78616d706c652e636f6d', 'hex');
19
20
21const kFakeResponseHeaders = Buffer.from('4803333032580770726976617465611d' +
22                                         '4d6f6e2c203231204f63742032303133' +
23                                         '2032303a31333a323120474d546e1768' +
24                                         '747470733a2f2f7777772e6578616d70' +
25                                         '6c652e636f6d', 'hex');
26
27function isUint32(val) {
28  return val >>> 0 === val;
29}
30
31function isUint24(val) {
32  return val >>> 0 === val && val <= 0xFFFFFF;
33}
34
35function isUint8(val) {
36  return val >>> 0 === val && val <= 0xFF;
37}
38
39function write32BE(array, pos, val) {
40  if (!isUint32(val))
41    throw new RangeError('val is not a 32-bit number');
42  array[pos++] = (val >> 24) & 0xff;
43  array[pos++] = (val >> 16) & 0xff;
44  array[pos++] = (val >> 8) & 0xff;
45  array[pos++] = val & 0xff;
46}
47
48function write24BE(array, pos, val) {
49  if (!isUint24(val))
50    throw new RangeError('val is not a 24-bit number');
51  array[pos++] = (val >> 16) & 0xff;
52  array[pos++] = (val >> 8) & 0xff;
53  array[pos++] = val & 0xff;
54}
55
56function write8(array, pos, val) {
57  if (!isUint8(val))
58    throw new RangeError('val is not an 8-bit number');
59  array[pos] = val;
60}
61
62class Frame {
63  constructor(length, type, flags, id) {
64    this[kFrameData] = Buffer.alloc(9);
65    write24BE(this[kFrameData], 0, length);
66    write8(this[kFrameData], 3, type);
67    write8(this[kFrameData], 4, flags);
68    write32BE(this[kFrameData], 5, id);
69  }
70
71  get data() {
72    return this[kFrameData];
73  }
74}
75
76class SettingsFrame extends Frame {
77  constructor(ack = false) {
78    let flags = 0;
79    if (ack)
80      flags |= FLAG_ACK;
81    super(0, 4, flags, 0);
82  }
83}
84
85class DataFrame extends Frame {
86  constructor(id, payload, padlen = 0, final = false) {
87    let len = payload.length;
88    let flags = 0;
89    if (final) flags |= FLAG_EOS;
90    const buffers = [payload];
91    if (padlen > 0) {
92      buffers.unshift(Buffer.from([padlen]));
93      buffers.push(PADDING.slice(0, padlen));
94      len += padlen + 1;
95      flags |= FLAG_PADDED;
96    }
97    super(len, 0, flags, id);
98    buffers.unshift(this[kFrameData]);
99    this[kFrameData] = Buffer.concat(buffers);
100  }
101}
102
103class HeadersFrame extends Frame {
104  constructor(id, payload, padlen = 0, final = false) {
105    let len = payload.length;
106    let flags = FLAG_EOH;
107    if (final) flags |= FLAG_EOS;
108    const buffers = [payload];
109    if (padlen > 0) {
110      buffers.unshift(Buffer.from([padlen]));
111      buffers.push(PADDING.slice(0, padlen));
112      len += padlen + 1;
113      flags |= FLAG_PADDED;
114    }
115    super(len, 1, flags, id);
116    buffers.unshift(this[kFrameData]);
117    this[kFrameData] = Buffer.concat(buffers);
118  }
119}
120
121class PingFrame extends Frame {
122  constructor(ack = false) {
123    const buffers = [Buffer.alloc(8)];
124    super(8, 6, ack ? 1 : 0, 0);
125    buffers.unshift(this[kFrameData]);
126    this[kFrameData] = Buffer.concat(buffers);
127  }
128}
129
130class AltSvcFrame extends Frame {
131  constructor(size) {
132    const buffers = [Buffer.alloc(size)];
133    super(size, 10, 0, 0);
134    buffers.unshift(this[kFrameData]);
135    this[kFrameData] = Buffer.concat(buffers);
136  }
137}
138
139module.exports = {
140  Frame,
141  AltSvcFrame,
142  DataFrame,
143  HeadersFrame,
144  SettingsFrame,
145  PingFrame,
146  kFakeRequestHeaders,
147  kFakeResponseHeaders,
148  kClientMagic
149};
150