summaryrefslogtreecommitdiff
path: root/test/common/http2.js
blob: f84a66861755b950ae34ceb7ca0cb08228c5d9b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* eslint-disable node-core/required-modules */
'use strict';

// An HTTP/2 testing tool used to create mock frames for direct testing
// of HTTP/2 endpoints.

const kFrameData = Symbol('frame-data');
const FLAG_EOS = 0x1;
const FLAG_ACK = 0x1;
const FLAG_EOH = 0x4;
const FLAG_PADDED = 0x8;
const PADDING = Buffer.alloc(255);

const kClientMagic = Buffer.from('505249202a20485454502f322' +
                                 'e300d0a0d0a534d0d0a0d0a', 'hex');

const kFakeRequestHeaders = Buffer.from('828684410f7777772e65' +
                                        '78616d706c652e636f6d', 'hex');


const kFakeResponseHeaders = Buffer.from('4803333032580770726976617465611d' +
                                         '4d6f6e2c203231204f63742032303133' +
                                         '2032303a31333a323120474d546e1768' +
                                         '747470733a2f2f7777772e6578616d70' +
                                         '6c652e636f6d', 'hex');

function isUint32(val) {
  return val >>> 0 === val;
}

function isUint24(val) {
  return val >>> 0 === val && val <= 0xFFFFFF;
}

function isUint8(val) {
  return val >>> 0 === val && val <= 0xFF;
}

function write32BE(array, pos, val) {
  if (!isUint32(val))
    throw new RangeError('val is not a 32-bit number');
  array[pos++] = (val >> 24) & 0xff;
  array[pos++] = (val >> 16) & 0xff;
  array[pos++] = (val >> 8) & 0xff;
  array[pos++] = val & 0xff;
}

function write24BE(array, pos, val) {
  if (!isUint24(val))
    throw new RangeError('val is not a 24-bit number');
  array[pos++] = (val >> 16) & 0xff;
  array[pos++] = (val >> 8) & 0xff;
  array[pos++] = val & 0xff;
}

function write8(array, pos, val) {
  if (!isUint8(val))
    throw new RangeError('val is not an 8-bit number');
  array[pos] = val;
}

class Frame {
  constructor(length, type, flags, id) {
    this[kFrameData] = Buffer.alloc(9);
    write24BE(this[kFrameData], 0, length);
    write8(this[kFrameData], 3, type);
    write8(this[kFrameData], 4, flags);
    write32BE(this[kFrameData], 5, id);
  }

  get data() {
    return this[kFrameData];
  }
}

class SettingsFrame extends Frame {
  constructor(ack = false) {
    let flags = 0;
    if (ack)
      flags |= FLAG_ACK;
    super(0, 4, flags, 0);
  }
}

class DataFrame extends Frame {
  constructor(id, payload, padlen = 0, final = false) {
    let len = payload.length;
    let flags = 0;
    if (final) flags |= FLAG_EOS;
    const buffers = [payload];
    if (padlen > 0) {
      buffers.unshift(Buffer.from([padlen]));
      buffers.push(PADDING.slice(0, padlen));
      len += padlen + 1;
      flags |= FLAG_PADDED;
    }
    super(len, 0, flags, id);
    buffers.unshift(this[kFrameData]);
    this[kFrameData] = Buffer.concat(buffers);
  }
}

class HeadersFrame extends Frame {
  constructor(id, payload, padlen = 0, final = false) {
    let len = payload.length;
    let flags = FLAG_EOH;
    if (final) flags |= FLAG_EOS;
    const buffers = [payload];
    if (padlen > 0) {
      buffers.unshift(Buffer.from([padlen]));
      buffers.push(PADDING.slice(0, padlen));
      len += padlen + 1;
      flags |= FLAG_PADDED;
    }
    super(len, 1, flags, id);
    buffers.unshift(this[kFrameData]);
    this[kFrameData] = Buffer.concat(buffers);
  }
}

class PingFrame extends Frame {
  constructor(ack = false) {
    const buffers = [Buffer.alloc(8)];
    super(8, 6, ack ? 1 : 0, 0);
    buffers.unshift(this[kFrameData]);
    this[kFrameData] = Buffer.concat(buffers);
  }
}

class AltSvcFrame extends Frame {
  constructor(size) {
    const buffers = [Buffer.alloc(size)];
    super(size, 10, 0, 0);
    buffers.unshift(this[kFrameData]);
    this[kFrameData] = Buffer.concat(buffers);
  }
}

module.exports = {
  Frame,
  AltSvcFrame,
  DataFrame,
  HeadersFrame,
  SettingsFrame,
  PingFrame,
  kFakeRequestHeaders,
  kFakeResponseHeaders,
  kClientMagic
};