quicsilver 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +3 -4
- data/CHANGELOG.md +49 -0
- data/Gemfile.lock +8 -4
- data/README.md +7 -6
- data/Rakefile +29 -2
- data/benchmarks/components.rb +191 -0
- data/benchmarks/concurrent.rb +110 -0
- data/benchmarks/helpers.rb +88 -0
- data/benchmarks/quicsilver_server.rb +1 -1
- data/benchmarks/rails.rb +170 -0
- data/benchmarks/throughput.rb +113 -0
- data/ext/quicsilver/quicsilver.c +529 -181
- data/lib/quicsilver/client/client.rb +250 -0
- data/lib/quicsilver/client/request.rb +98 -0
- data/lib/quicsilver/{http3.rb → protocol/frames.rb} +133 -28
- data/lib/quicsilver/protocol/qpack/decoder.rb +165 -0
- data/lib/quicsilver/protocol/qpack/encoder.rb +189 -0
- data/lib/quicsilver/protocol/qpack/header_block_decoder.rb +125 -0
- data/lib/quicsilver/protocol/qpack/huffman.rb +459 -0
- data/lib/quicsilver/protocol/request_encoder.rb +47 -0
- data/lib/quicsilver/protocol/request_parser.rb +387 -0
- data/lib/quicsilver/protocol/response_encoder.rb +72 -0
- data/lib/quicsilver/protocol/response_parser.rb +249 -0
- data/lib/quicsilver/server/listener_data.rb +14 -0
- data/lib/quicsilver/server/request_handler.rb +86 -0
- data/lib/quicsilver/server/request_registry.rb +50 -0
- data/lib/quicsilver/server/server.rb +336 -0
- data/lib/quicsilver/transport/configuration.rb +132 -0
- data/lib/quicsilver/transport/connection.rb +350 -0
- data/lib/quicsilver/transport/event_loop.rb +38 -0
- data/lib/quicsilver/transport/inbound_stream.rb +33 -0
- data/lib/quicsilver/transport/stream.rb +28 -0
- data/lib/quicsilver/transport/stream_event.rb +26 -0
- data/lib/quicsilver/version.rb +1 -1
- data/lib/quicsilver.rb +31 -13
- data/lib/rackup/handler/quicsilver.rb +1 -2
- data/quicsilver.gemspec +3 -1
- metadata +58 -18
- data/benchmarks/benchmark.rb +0 -68
- data/lib/quicsilver/client.rb +0 -261
- data/lib/quicsilver/connection.rb +0 -42
- data/lib/quicsilver/event_loop.rb +0 -38
- data/lib/quicsilver/http3/request_encoder.rb +0 -133
- data/lib/quicsilver/http3/request_parser.rb +0 -176
- data/lib/quicsilver/http3/response_encoder.rb +0 -186
- data/lib/quicsilver/http3/response_parser.rb +0 -160
- data/lib/quicsilver/listener_data.rb +0 -29
- data/lib/quicsilver/quic_stream.rb +0 -36
- data/lib/quicsilver/request_registry.rb +0 -48
- data/lib/quicsilver/server.rb +0 -355
- data/lib/quicsilver/server_configuration.rb +0 -78
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Quicsilver
|
|
4
|
+
module Protocol
|
|
5
|
+
module Qpack
|
|
6
|
+
class Huffman
|
|
7
|
+
# RFC 7541 Appendix B — HPACK Huffman Code Table (reused by QPACK per RFC 9204)
|
|
8
|
+
# Format: byte_value => [hex_code, bit_length] # |MSB binary with byte boundaries|
|
|
9
|
+
TABLE = {
|
|
10
|
+
0 => [0x1ff8, 13], # |11111111|11000
|
|
11
|
+
1 => [0x7fffd8, 23], # |11111111|11111111|1011000
|
|
12
|
+
2 => [0xfffffe2, 28], # |11111111|11111111|11111110|0010
|
|
13
|
+
3 => [0xfffffe3, 28], # |11111111|11111111|11111110|0011
|
|
14
|
+
4 => [0xfffffe4, 28], # |11111111|11111111|11111110|0100
|
|
15
|
+
5 => [0xfffffe5, 28], # |11111111|11111111|11111110|0101
|
|
16
|
+
6 => [0xfffffe6, 28], # |11111111|11111111|11111110|0110
|
|
17
|
+
7 => [0xfffffe7, 28], # |11111111|11111111|11111110|0111
|
|
18
|
+
8 => [0xfffffe8, 28], # |11111111|11111111|11111110|1000
|
|
19
|
+
9 => [0xffffea, 24], # |11111111|11111111|11101010
|
|
20
|
+
10 => [0x3ffffffc, 30], # |11111111|11111111|11111111|111100
|
|
21
|
+
11 => [0xfffffe9, 28], # |11111111|11111111|11111110|1001
|
|
22
|
+
12 => [0xfffffea, 28], # |11111111|11111111|11111110|1010
|
|
23
|
+
13 => [0x3ffffffd, 30], # |11111111|11111111|11111111|111101
|
|
24
|
+
14 => [0xfffffeb, 28], # |11111111|11111111|11111110|1011
|
|
25
|
+
15 => [0xfffffec, 28], # |11111111|11111111|11111110|1100
|
|
26
|
+
16 => [0xfffffed, 28], # |11111111|11111111|11111110|1101
|
|
27
|
+
17 => [0xfffffee, 28], # |11111111|11111111|11111110|1110
|
|
28
|
+
18 => [0xfffffef, 28], # |11111111|11111111|11111110|1111
|
|
29
|
+
19 => [0xffffff0, 28], # |11111111|11111111|11111111|0000
|
|
30
|
+
20 => [0xffffff1, 28], # |11111111|11111111|11111111|0001
|
|
31
|
+
21 => [0xffffff2, 28], # |11111111|11111111|11111111|0010
|
|
32
|
+
22 => [0x3ffffffe, 30], # |11111111|11111111|11111111|111110
|
|
33
|
+
23 => [0xffffff3, 28], # |11111111|11111111|11111111|0011
|
|
34
|
+
24 => [0xffffff4, 28], # |11111111|11111111|11111111|0100
|
|
35
|
+
25 => [0xffffff5, 28], # |11111111|11111111|11111111|0101
|
|
36
|
+
26 => [0xffffff6, 28], # |11111111|11111111|11111111|0110
|
|
37
|
+
27 => [0xffffff7, 28], # |11111111|11111111|11111111|0111
|
|
38
|
+
28 => [0xffffff8, 28], # |11111111|11111111|11111111|1000
|
|
39
|
+
29 => [0xffffff9, 28], # |11111111|11111111|11111111|1001
|
|
40
|
+
30 => [0xffffffa, 28], # |11111111|11111111|11111111|1010
|
|
41
|
+
31 => [0xffffffb, 28], # |11111111|11111111|11111111|1011
|
|
42
|
+
32 => [0x14, 6], # |010100
|
|
43
|
+
33 => [0x3f8, 10], # |11111110|00
|
|
44
|
+
34 => [0x3f9, 10], # |11111110|01
|
|
45
|
+
35 => [0xffa, 12], # |11111111|1010
|
|
46
|
+
36 => [0x1ff9, 13], # |11111111|11001
|
|
47
|
+
37 => [0x15, 6], # |010101
|
|
48
|
+
38 => [0xf8, 8], # |11111000
|
|
49
|
+
39 => [0x7fa, 11], # |11111111|010
|
|
50
|
+
40 => [0x3fa, 10], # |11111110|10
|
|
51
|
+
41 => [0x3fb, 10], # |11111110|11
|
|
52
|
+
42 => [0xf9, 8], # |11111001
|
|
53
|
+
43 => [0x7fb, 11], # |11111111|011
|
|
54
|
+
44 => [0xfa, 8], # |11111010
|
|
55
|
+
45 => [0x16, 6], # |010110
|
|
56
|
+
46 => [0x17, 6], # |010111
|
|
57
|
+
47 => [0x18, 6], # |011000
|
|
58
|
+
48 => [0x0, 5], # |00000
|
|
59
|
+
49 => [0x1, 5], # |00001
|
|
60
|
+
50 => [0x2, 5], # |00010
|
|
61
|
+
51 => [0x19, 6], # |011001
|
|
62
|
+
52 => [0x1a, 6], # |011010
|
|
63
|
+
53 => [0x1b, 6], # |011011
|
|
64
|
+
54 => [0x1c, 6], # |011100
|
|
65
|
+
55 => [0x1d, 6], # |011101
|
|
66
|
+
56 => [0x1e, 6], # |011110
|
|
67
|
+
57 => [0x1f, 6], # |011111
|
|
68
|
+
58 => [0x5c, 7], # |1011100
|
|
69
|
+
59 => [0xfb, 8], # |11111011
|
|
70
|
+
60 => [0x7ffc, 15], # |11111111|1111100
|
|
71
|
+
61 => [0x20, 6], # |100000
|
|
72
|
+
62 => [0xffb, 12], # |11111111|1011
|
|
73
|
+
63 => [0x3fc, 10], # |11111111|00
|
|
74
|
+
64 => [0x1ffa, 13], # |11111111|11010
|
|
75
|
+
65 => [0x21, 6], # |100001
|
|
76
|
+
66 => [0x5d, 7], # |1011101
|
|
77
|
+
67 => [0x5e, 7], # |1011110
|
|
78
|
+
68 => [0x5f, 7], # |1011111
|
|
79
|
+
69 => [0x60, 7], # |1100000
|
|
80
|
+
70 => [0x61, 7], # |1100001
|
|
81
|
+
71 => [0x62, 7], # |1100010
|
|
82
|
+
72 => [0x63, 7], # |1100011
|
|
83
|
+
73 => [0x64, 7], # |1100100
|
|
84
|
+
74 => [0x65, 7], # |1100101
|
|
85
|
+
75 => [0x66, 7], # |1100110
|
|
86
|
+
76 => [0x67, 7], # |1100111
|
|
87
|
+
77 => [0x68, 7], # |1101000
|
|
88
|
+
78 => [0x69, 7], # |1101001
|
|
89
|
+
79 => [0x6a, 7], # |1101010
|
|
90
|
+
80 => [0x6b, 7], # |1101011
|
|
91
|
+
81 => [0x6c, 7], # |1101100
|
|
92
|
+
82 => [0x6d, 7], # |1101101
|
|
93
|
+
83 => [0x6e, 7], # |1101110
|
|
94
|
+
84 => [0x6f, 7], # |1101111
|
|
95
|
+
85 => [0x70, 7], # |1110000
|
|
96
|
+
86 => [0x71, 7], # |1110001
|
|
97
|
+
87 => [0x72, 7], # |1110010
|
|
98
|
+
88 => [0xfc, 8], # |11111100
|
|
99
|
+
89 => [0x73, 7], # |1110011
|
|
100
|
+
90 => [0xfd, 8], # |11111101
|
|
101
|
+
91 => [0x1ffb, 13], # |11111111|11011
|
|
102
|
+
92 => [0x7fff0, 19], # |11111111|11111110|000
|
|
103
|
+
93 => [0x1ffc, 13], # |11111111|11100
|
|
104
|
+
94 => [0x3ffc, 14], # |11111111|111100
|
|
105
|
+
95 => [0x22, 6], # |100010
|
|
106
|
+
96 => [0x7ffd, 15], # |11111111|1111101
|
|
107
|
+
97 => [0x3, 5], # |00011
|
|
108
|
+
98 => [0x23, 6], # |100011
|
|
109
|
+
99 => [0x4, 5], # |00100
|
|
110
|
+
100 => [0x24, 6], # |100100
|
|
111
|
+
101 => [0x5, 5], # |00101
|
|
112
|
+
102 => [0x25, 6], # |100101
|
|
113
|
+
103 => [0x26, 6], # |100110
|
|
114
|
+
104 => [0x27, 6], # |100111
|
|
115
|
+
105 => [0x6, 5], # |00110
|
|
116
|
+
106 => [0x74, 7], # |1110100
|
|
117
|
+
107 => [0x75, 7], # |1110101
|
|
118
|
+
108 => [0x28, 6], # |101000
|
|
119
|
+
109 => [0x29, 6], # |101001
|
|
120
|
+
110 => [0x2a, 6], # |101010
|
|
121
|
+
111 => [0x7, 5], # |00111
|
|
122
|
+
112 => [0x2b, 6], # |101011
|
|
123
|
+
113 => [0x76, 7], # |1110110
|
|
124
|
+
114 => [0x2c, 6], # |101100
|
|
125
|
+
115 => [0x8, 5], # |01000
|
|
126
|
+
116 => [0x9, 5], # |01001
|
|
127
|
+
117 => [0x2d, 6], # |101101
|
|
128
|
+
118 => [0x77, 7], # |1110111
|
|
129
|
+
119 => [0x78, 7], # |1111000
|
|
130
|
+
120 => [0x79, 7], # |1111001
|
|
131
|
+
121 => [0x7a, 7], # |1111010
|
|
132
|
+
122 => [0x7b, 7], # |1111011
|
|
133
|
+
123 => [0x7ffe, 15], # |11111111|1111110
|
|
134
|
+
124 => [0x7fc, 11], # |11111111|100
|
|
135
|
+
125 => [0x3ffd, 14], # |11111111|111101
|
|
136
|
+
126 => [0x1ffd, 13], # |11111111|11101
|
|
137
|
+
127 => [0xffffffc, 28], # |11111111|11111111|11111111|1100
|
|
138
|
+
128 => [0xfffe6, 20], # |11111111|11111110|0110
|
|
139
|
+
129 => [0x3fffd2, 22], # |11111111|11111111|010010
|
|
140
|
+
130 => [0xfffe7, 20], # |11111111|11111110|0111
|
|
141
|
+
131 => [0xfffe8, 20], # |11111111|11111110|1000
|
|
142
|
+
132 => [0x3fffd3, 22], # |11111111|11111111|010011
|
|
143
|
+
133 => [0x3fffd4, 22], # |11111111|11111111|010100
|
|
144
|
+
134 => [0x3fffd5, 22], # |11111111|11111111|010101
|
|
145
|
+
135 => [0x7fffd9, 23], # |11111111|11111111|1011001
|
|
146
|
+
136 => [0x3fffd6, 22], # |11111111|11111111|010110
|
|
147
|
+
137 => [0x7fffda, 23], # |11111111|11111111|1011010
|
|
148
|
+
138 => [0x7fffdb, 23], # |11111111|11111111|1011011
|
|
149
|
+
139 => [0x7fffdc, 23], # |11111111|11111111|1011100
|
|
150
|
+
140 => [0x7fffdd, 23], # |11111111|11111111|1011101
|
|
151
|
+
141 => [0x7fffde, 23], # |11111111|11111111|1011110
|
|
152
|
+
142 => [0xffffeb, 24], # |11111111|11111111|11101011
|
|
153
|
+
143 => [0x7fffdf, 23], # |11111111|11111111|1011111
|
|
154
|
+
144 => [0xffffec, 24], # |11111111|11111111|11101100
|
|
155
|
+
145 => [0xffffed, 24], # |11111111|11111111|11101101
|
|
156
|
+
146 => [0x3fffd7, 22], # |11111111|11111111|010111
|
|
157
|
+
147 => [0x7fffe0, 23], # |11111111|11111111|1100000
|
|
158
|
+
148 => [0xffffee, 24], # |11111111|11111111|11101110
|
|
159
|
+
149 => [0x7fffe1, 23], # |11111111|11111111|1100001
|
|
160
|
+
150 => [0x7fffe2, 23], # |11111111|11111111|1100010
|
|
161
|
+
151 => [0x7fffe3, 23], # |11111111|11111111|1100011
|
|
162
|
+
152 => [0x7fffe4, 23], # |11111111|11111111|1100100
|
|
163
|
+
153 => [0x1fffdc, 21], # |11111111|11111110|11100
|
|
164
|
+
154 => [0x3fffd8, 22], # |11111111|11111111|011000
|
|
165
|
+
155 => [0x7fffe5, 23], # |11111111|11111111|1100101
|
|
166
|
+
156 => [0x3fffd9, 22], # |11111111|11111111|011001
|
|
167
|
+
157 => [0x7fffe6, 23], # |11111111|11111111|1100110
|
|
168
|
+
158 => [0x7fffe7, 23], # |11111111|11111111|1100111
|
|
169
|
+
159 => [0xffffef, 24], # |11111111|11111111|11101111
|
|
170
|
+
160 => [0x3fffda, 22], # |11111111|11111111|011010
|
|
171
|
+
161 => [0x1fffdd, 21], # |11111111|11111110|11101
|
|
172
|
+
162 => [0xfffe9, 20], # |11111111|11111110|1001
|
|
173
|
+
163 => [0x3fffdb, 22], # |11111111|11111111|011011
|
|
174
|
+
164 => [0x3fffdc, 22], # |11111111|11111111|011100
|
|
175
|
+
165 => [0x7fffe8, 23], # |11111111|11111111|1101000
|
|
176
|
+
166 => [0x7fffe9, 23], # |11111111|11111111|1101001
|
|
177
|
+
167 => [0x1fffde, 21], # |11111111|11111110|11110
|
|
178
|
+
168 => [0x7fffea, 23], # |11111111|11111111|1101010
|
|
179
|
+
169 => [0x3fffdd, 22], # |11111111|11111111|011101
|
|
180
|
+
170 => [0x3fffde, 22], # |11111111|11111111|011110
|
|
181
|
+
171 => [0xfffff0, 24], # |11111111|11111111|11110000
|
|
182
|
+
172 => [0x1fffdf, 21], # |11111111|11111110|11111
|
|
183
|
+
173 => [0x3fffdf, 22], # |11111111|11111111|011111
|
|
184
|
+
174 => [0x7fffeb, 23], # |11111111|11111111|1101011
|
|
185
|
+
175 => [0x7fffec, 23], # |11111111|11111111|1101100
|
|
186
|
+
176 => [0x1fffe0, 21], # |11111111|11111111|00000
|
|
187
|
+
177 => [0x1fffe1, 21], # |11111111|11111111|00001
|
|
188
|
+
178 => [0x3fffe0, 22], # |11111111|11111111|100000
|
|
189
|
+
179 => [0x1fffe2, 21], # |11111111|11111111|00010
|
|
190
|
+
180 => [0x7fffed, 23], # |11111111|11111111|1101101
|
|
191
|
+
181 => [0x3fffe1, 22], # |11111111|11111111|100001
|
|
192
|
+
182 => [0x7fffee, 23], # |11111111|11111111|1101110
|
|
193
|
+
183 => [0x7fffef, 23], # |11111111|11111111|1101111
|
|
194
|
+
184 => [0xfffea, 20], # |11111111|11111110|1010
|
|
195
|
+
185 => [0x3fffe2, 22], # |11111111|11111111|100010
|
|
196
|
+
186 => [0x3fffe3, 22], # |11111111|11111111|100011
|
|
197
|
+
187 => [0x3fffe4, 22], # |11111111|11111111|100100
|
|
198
|
+
188 => [0x7ffff0, 23], # |11111111|11111111|1110000
|
|
199
|
+
189 => [0x3fffe5, 22], # |11111111|11111111|100101
|
|
200
|
+
190 => [0x3fffe6, 22], # |11111111|11111111|100110
|
|
201
|
+
191 => [0x7ffff1, 23], # |11111111|11111111|1110001
|
|
202
|
+
192 => [0x3ffffe0, 26], # |11111111|11111111|11111110|00
|
|
203
|
+
193 => [0x3ffffe1, 26], # |11111111|11111111|11111110|01
|
|
204
|
+
194 => [0xfffeb, 20], # |11111111|11111110|1011
|
|
205
|
+
195 => [0x7fff1, 19], # |11111111|11111110|001
|
|
206
|
+
196 => [0x3fffe7, 22], # |11111111|11111111|100111
|
|
207
|
+
197 => [0x7ffff2, 23], # |11111111|11111111|1110010
|
|
208
|
+
198 => [0x3fffe8, 22], # |11111111|11111111|101000
|
|
209
|
+
199 => [0x1ffffec, 25], # |11111111|11111111|11111110|1100
|
|
210
|
+
200 => [0x3ffffe2, 26], # |11111111|11111111|11111110|10
|
|
211
|
+
201 => [0x3ffffe3, 26], # |11111111|11111111|11111110|11
|
|
212
|
+
202 => [0x3ffffe4, 26], # |11111111|11111111|11111111|00
|
|
213
|
+
203 => [0x7ffffde, 27], # |11111111|11111111|11111111|011
|
|
214
|
+
204 => [0x7ffffdf, 27], # |11111111|11111111|11111111|100
|
|
215
|
+
205 => [0x3ffffe5, 26], # |11111111|11111111|11111111|01
|
|
216
|
+
206 => [0xfffff1, 24], # |11111111|11111111|11110001
|
|
217
|
+
207 => [0x1ffffed, 25], # |11111111|11111111|11111110|1101
|
|
218
|
+
208 => [0x7fff2, 19], # |11111111|11111110|010
|
|
219
|
+
209 => [0x1fffe3, 21], # |11111111|11111111|00011
|
|
220
|
+
210 => [0x3ffffe6, 26], # |11111111|11111111|11111111|10
|
|
221
|
+
211 => [0x7ffffe0, 27], # |11111111|11111111|11111111|110
|
|
222
|
+
212 => [0x7ffffe1, 27], # |11111111|11111111|11111111|111
|
|
223
|
+
213 => [0x3ffffe7, 26], # |11111111|11111111|11111111|11
|
|
224
|
+
214 => [0x7ffffe2, 27], # |11111111|11111111|11111110|000
|
|
225
|
+
215 => [0xfffff2, 24], # |11111111|11111111|11110010
|
|
226
|
+
216 => [0x1fffe4, 21], # |11111111|11111111|00100
|
|
227
|
+
217 => [0x1fffe5, 21], # |11111111|11111111|00101
|
|
228
|
+
218 => [0x3ffffe8, 26], # |11111111|11111111|11111110|0000
|
|
229
|
+
219 => [0x3ffffe9, 26], # |11111111|11111111|11111110|0001
|
|
230
|
+
220 => [0xffffffd, 28], # |11111111|11111111|11111111|1101
|
|
231
|
+
221 => [0x7ffffe3, 27], # |11111111|11111111|11111110|001
|
|
232
|
+
222 => [0x7ffffe4, 27], # |11111111|11111111|11111110|010
|
|
233
|
+
223 => [0x7ffffe5, 27], # |11111111|11111111|11111110|011
|
|
234
|
+
224 => [0xfffec, 20], # |11111111|11111110|1100
|
|
235
|
+
225 => [0xfffff3, 24], # |11111111|11111111|11110011
|
|
236
|
+
226 => [0xfffed, 20], # |11111111|11111110|1101
|
|
237
|
+
227 => [0x1fffe6, 21], # |11111111|11111111|00110
|
|
238
|
+
228 => [0x3fffe9, 22], # |11111111|11111111|101001
|
|
239
|
+
229 => [0x1fffe7, 21], # |11111111|11111111|00111
|
|
240
|
+
230 => [0x1fffe8, 21], # |11111111|11111111|01000
|
|
241
|
+
231 => [0x7ffff3, 23], # |11111111|11111111|1110011
|
|
242
|
+
232 => [0x3fffea, 22], # |11111111|11111111|101010
|
|
243
|
+
233 => [0x3fffeb, 22], # |11111111|11111111|101011
|
|
244
|
+
234 => [0x1ffffee, 25], # |11111111|11111111|11111110|1110
|
|
245
|
+
235 => [0x1ffffef, 25], # |11111111|11111111|11111110|1111
|
|
246
|
+
236 => [0xfffff4, 24], # |11111111|11111111|11110100
|
|
247
|
+
237 => [0xfffff5, 24], # |11111111|11111111|11110101
|
|
248
|
+
238 => [0x3ffffea, 26], # |11111111|11111111|11111110|1010
|
|
249
|
+
239 => [0x7ffff4, 23], # |11111111|11111111|1110100
|
|
250
|
+
240 => [0x3ffffeb, 26], # |11111111|11111111|11111110|1011
|
|
251
|
+
241 => [0x7ffffe6, 27], # |11111111|11111111|11111110|110
|
|
252
|
+
242 => [0x3ffffec, 26], # |11111111|11111111|11111110|1100
|
|
253
|
+
243 => [0x3ffffed, 26], # |11111111|11111111|11111110|1101
|
|
254
|
+
244 => [0x7ffffe7, 27], # |11111111|11111111|11111110|111
|
|
255
|
+
245 => [0x7ffffe8, 27], # |11111111|11111111|11111111|000
|
|
256
|
+
246 => [0x7ffffe9, 27], # |11111111|11111111|11111111|001
|
|
257
|
+
247 => [0x7ffffea, 27], # |11111111|11111111|11111111|010
|
|
258
|
+
248 => [0x7ffffeb, 27], # |11111111|11111111|11111111|011
|
|
259
|
+
249 => [0xffffffe, 28], # |11111111|11111111|11111111|1110
|
|
260
|
+
250 => [0x7ffffec, 27], # |11111111|11111111|11111111|100
|
|
261
|
+
251 => [0x7ffffed, 27], # |11111111|11111111|11111111|101
|
|
262
|
+
252 => [0x7ffffee, 27], # |11111111|11111111|11111111|110
|
|
263
|
+
253 => [0x7ffffef, 27], # |11111111|11111111|11111111|111
|
|
264
|
+
254 => [0x7fffff0, 27], # |11111111|11111111|11111110|0000
|
|
265
|
+
255 => [0x3ffffee, 26], # |11111111|11111111|11111110|1110
|
|
266
|
+
}.freeze
|
|
267
|
+
|
|
268
|
+
EOS = [0x3fffffff, 30] # |11111111|11111111|11111111|111111
|
|
269
|
+
|
|
270
|
+
REVERSE_TABLE = TABLE.each_with_object({}) do |(byte, (code, length)), tree|
|
|
271
|
+
node = tree
|
|
272
|
+
# Walk bits MSB-first
|
|
273
|
+
(length - 1).downto(0) do |i|
|
|
274
|
+
bit = (code >> i) & 1
|
|
275
|
+
node[bit] ||= {}
|
|
276
|
+
node = node[bit]
|
|
277
|
+
end
|
|
278
|
+
node[:value] = byte
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Build 8-bit-at-a-time decode acceleration table.
|
|
282
|
+
# DECODE_ACCEL[state_id][byte] = [new_state_id, emitted_bytes_array]
|
|
283
|
+
# State 0 = root node.
|
|
284
|
+
DECODE_ACCEL = begin
|
|
285
|
+
# Assign integer IDs to all tree nodes
|
|
286
|
+
node_to_id = {}
|
|
287
|
+
id_to_node = []
|
|
288
|
+
queue = [REVERSE_TABLE]
|
|
289
|
+
node_to_id[REVERSE_TABLE.object_id] = 0
|
|
290
|
+
id_to_node << REVERSE_TABLE
|
|
291
|
+
|
|
292
|
+
i = 0
|
|
293
|
+
while i < queue.size
|
|
294
|
+
node = queue[i]
|
|
295
|
+
[0, 1].each do |bit|
|
|
296
|
+
child = node[bit]
|
|
297
|
+
next unless child
|
|
298
|
+
unless node_to_id.key?(child.object_id)
|
|
299
|
+
node_to_id[child.object_id] = id_to_node.size
|
|
300
|
+
id_to_node << child
|
|
301
|
+
queue << child
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
i += 1
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
num_states = id_to_node.size
|
|
308
|
+
table = Array.new(num_states) { Array.new(256) }
|
|
309
|
+
|
|
310
|
+
num_states.times do |sid|
|
|
311
|
+
256.times do |byte_val|
|
|
312
|
+
node = id_to_node[sid]
|
|
313
|
+
emitted = []
|
|
314
|
+
valid = true
|
|
315
|
+
trailing_bits = 0 # bits since last emitted symbol
|
|
316
|
+
7.downto(0) do |bit_idx|
|
|
317
|
+
bit = (byte_val >> bit_idx) & 1
|
|
318
|
+
child = node[bit]
|
|
319
|
+
unless child
|
|
320
|
+
valid = false
|
|
321
|
+
break
|
|
322
|
+
end
|
|
323
|
+
if child.key?(:value)
|
|
324
|
+
emitted << child[:value]
|
|
325
|
+
node = REVERSE_TABLE
|
|
326
|
+
trailing_bits = 0
|
|
327
|
+
else
|
|
328
|
+
node = child
|
|
329
|
+
trailing_bits += 1
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
if valid
|
|
333
|
+
new_sid = node_to_id[node.object_id]
|
|
334
|
+
table[sid][byte_val] = [new_sid, emitted, trailing_bits].freeze
|
|
335
|
+
else
|
|
336
|
+
table[sid][byte_val] = nil
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
table[sid].freeze
|
|
340
|
+
end
|
|
341
|
+
table.freeze
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# Pre-compute flat arrays for faster table access (avoid hash lookup per byte)
|
|
348
|
+
ENCODE_CODES = Array.new(256) { |i| TABLE[i][0] }
|
|
349
|
+
ENCODE_LENGTHS = Array.new(256) { |i| TABLE[i][1] }
|
|
350
|
+
|
|
351
|
+
# Thread-safe caches for frequently encoded/decoded strings
|
|
352
|
+
# Using module-level constants for caches — YJIT can inline constant access
|
|
353
|
+
HUFF_ENCODE_CACHE = {}
|
|
354
|
+
HUFF_ENCODE_MUTEX = Mutex.new
|
|
355
|
+
HUFF_DECODE_CACHE = {}
|
|
356
|
+
HUFF_DECODE_MUTEX = Mutex.new
|
|
357
|
+
CACHE_MAX = 256
|
|
358
|
+
|
|
359
|
+
class << self
|
|
360
|
+
def encode(data)
|
|
361
|
+
# Check cache first (fast path) — returns frozen string
|
|
362
|
+
cached = HUFF_ENCODE_CACHE[data]
|
|
363
|
+
return cached if cached
|
|
364
|
+
|
|
365
|
+
result = encode_uncached(data)
|
|
366
|
+
|
|
367
|
+
# Cache short strings (frozen)
|
|
368
|
+
if data.bytesize <= 128 && HUFF_ENCODE_CACHE.size < CACHE_MAX
|
|
369
|
+
HUFF_ENCODE_MUTEX.synchronize do
|
|
370
|
+
HUFF_ENCODE_CACHE[data.frozen? ? data : data.dup.freeze] = result.freeze if HUFF_ENCODE_CACHE.size < CACHE_MAX
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
result
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def encode_uncached(data)
|
|
378
|
+
buf = 0
|
|
379
|
+
buf_len = 0
|
|
380
|
+
out = []
|
|
381
|
+
|
|
382
|
+
data.each_byte do |byte|
|
|
383
|
+
code = ENCODE_CODES[byte]
|
|
384
|
+
length = ENCODE_LENGTHS[byte]
|
|
385
|
+
buf = (buf << length) | code
|
|
386
|
+
buf_len += length
|
|
387
|
+
|
|
388
|
+
# Flush complete bytes
|
|
389
|
+
while buf_len >= 8
|
|
390
|
+
buf_len -= 8
|
|
391
|
+
out << ((buf >> buf_len) & 0xff)
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Pad with EOS prefix (1-bits) to next byte boundary
|
|
396
|
+
if buf_len > 0
|
|
397
|
+
padding = 8 - buf_len
|
|
398
|
+
out << (((buf << padding) | ((1 << padding) - 1)) & 0xff)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
out.pack("C*")
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def decode(encoded_data)
|
|
405
|
+
# Check cache first (fast path) — returns frozen string
|
|
406
|
+
cached = HUFF_DECODE_CACHE[encoded_data]
|
|
407
|
+
return cached if cached
|
|
408
|
+
|
|
409
|
+
return "".b if encoded_data.empty?
|
|
410
|
+
|
|
411
|
+
result = decode_uncached(encoded_data)
|
|
412
|
+
|
|
413
|
+
# Cache short encoded data (frozen)
|
|
414
|
+
if encoded_data.bytesize <= 128 && result && HUFF_DECODE_CACHE.size < CACHE_MAX
|
|
415
|
+
HUFF_DECODE_MUTEX.synchronize do
|
|
416
|
+
key = encoded_data.frozen? ? encoded_data : encoded_data.dup.freeze
|
|
417
|
+
HUFF_DECODE_CACHE[key] = result.freeze if HUFF_DECODE_CACHE.size < CACHE_MAX
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
result
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def decode_uncached(encoded_data)
|
|
425
|
+
return "".b if encoded_data.empty?
|
|
426
|
+
|
|
427
|
+
state = 0
|
|
428
|
+
output = []
|
|
429
|
+
bits_since_symbol = 0
|
|
430
|
+
|
|
431
|
+
encoded_data.each_byte do |byte|
|
|
432
|
+
entry = DECODE_ACCEL[state][byte]
|
|
433
|
+
return nil unless entry # invalid code
|
|
434
|
+
|
|
435
|
+
new_state, emitted, trailing = entry
|
|
436
|
+
output.concat(emitted) unless emitted.empty?
|
|
437
|
+
# trailing = bits since last emitted symbol within this byte processing
|
|
438
|
+
# If no symbols were emitted, add 8 to running count
|
|
439
|
+
bits_since_symbol = emitted.empty? ? bits_since_symbol + 8 : trailing
|
|
440
|
+
state = new_state
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# Padding validation (RFC 7541 §5.2):
|
|
444
|
+
return nil if bits_since_symbol >= 8
|
|
445
|
+
|
|
446
|
+
# Padding bits must all be 1
|
|
447
|
+
if bits_since_symbol > 0
|
|
448
|
+
last_byte = encoded_data.getbyte(-1)
|
|
449
|
+
mask = (1 << bits_since_symbol) - 1
|
|
450
|
+
return nil if (last_byte & mask) != mask
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
output.pack("C*")
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Quicsilver
|
|
4
|
+
module Protocol
|
|
5
|
+
class RequestEncoder
|
|
6
|
+
def initialize(method:, path:, scheme: "https", authority: "localhost:4433", headers: {}, body: nil, encoder: Qpack::Encoder.new)
|
|
7
|
+
@method = method.upcase
|
|
8
|
+
@path = path
|
|
9
|
+
@scheme = scheme
|
|
10
|
+
@authority = authority
|
|
11
|
+
@headers = headers
|
|
12
|
+
@body = body
|
|
13
|
+
@encoder = encoder
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def encode
|
|
17
|
+
frames = "".b
|
|
18
|
+
frames << build_frame(FRAME_HEADERS, @encoder.encode(all_headers))
|
|
19
|
+
|
|
20
|
+
if @body && !@body.empty?
|
|
21
|
+
body_data = @body.is_a?(String) ? @body : @body.join
|
|
22
|
+
frames << build_frame(FRAME_DATA, body_data)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
frames
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def all_headers
|
|
31
|
+
headers = [[":method", @method]]
|
|
32
|
+
if @method == "CONNECT"
|
|
33
|
+
headers << [":authority", @authority]
|
|
34
|
+
else
|
|
35
|
+
headers << [":scheme", @scheme]
|
|
36
|
+
headers << [":authority", @authority]
|
|
37
|
+
headers << [":path", @path]
|
|
38
|
+
end
|
|
39
|
+
headers + @headers.map { |k, v| [k.to_s, v.to_s] }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def build_frame(type, payload)
|
|
43
|
+
Protocol.encode_varint(type) + Protocol.encode_varint(payload.bytesize) + payload
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|