bayserver-docker-http 2.2.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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/lib/baykit/bayserver/docker/http/h1/command/cmd_content.rb +46 -0
  3. data/lib/baykit/bayserver/docker/http/h1/command/cmd_end_content.rb +37 -0
  4. data/lib/baykit/bayserver/docker/http/h1/command/cmd_header.rb +306 -0
  5. data/lib/baykit/bayserver/docker/http/h1/command/package.rb +3 -0
  6. data/lib/baykit/bayserver/docker/http/h1/h1_command.rb +19 -0
  7. data/lib/baykit/bayserver/docker/http/h1/h1_command_handler.rb +31 -0
  8. data/lib/baykit/bayserver/docker/http/h1/h1_command_unpacker.rb +58 -0
  9. data/lib/baykit/bayserver/docker/http/h1/h1_inbound_handler.rb +371 -0
  10. data/lib/baykit/bayserver/docker/http/h1/h1_packet.rb +28 -0
  11. data/lib/baykit/bayserver/docker/http/h1/h1_packet_factory.rb +21 -0
  12. data/lib/baykit/bayserver/docker/http/h1/h1_packet_unpacker.rb +180 -0
  13. data/lib/baykit/bayserver/docker/http/h1/h1_protocol_handler.rb +66 -0
  14. data/lib/baykit/bayserver/docker/http/h1/h1_type.rb +18 -0
  15. data/lib/baykit/bayserver/docker/http/h1/h1_warp_handler.rb +228 -0
  16. data/lib/baykit/bayserver/docker/http/h1/package.rb +11 -0
  17. data/lib/baykit/bayserver/docker/http/h2/command/cmd_data.rb +65 -0
  18. data/lib/baykit/bayserver/docker/http/h2/command/cmd_go_away.rb +67 -0
  19. data/lib/baykit/bayserver/docker/http/h2/command/cmd_headers.rb +108 -0
  20. data/lib/baykit/bayserver/docker/http/h2/command/cmd_ping.rb +50 -0
  21. data/lib/baykit/bayserver/docker/http/h2/command/cmd_preface.rb +51 -0
  22. data/lib/baykit/bayserver/docker/http/h2/command/cmd_priority.rb +59 -0
  23. data/lib/baykit/bayserver/docker/http/h2/command/cmd_rst_stream.rb +50 -0
  24. data/lib/baykit/bayserver/docker/http/h2/command/cmd_settings.rb +98 -0
  25. data/lib/baykit/bayserver/docker/http/h2/command/cmd_window_update.rb +53 -0
  26. data/lib/baykit/bayserver/docker/http/h2/command/package.rb +9 -0
  27. data/lib/baykit/bayserver/docker/http/h2/h2_command.rb +42 -0
  28. data/lib/baykit/bayserver/docker/http/h2/h2_command_handler.rb +29 -0
  29. data/lib/baykit/bayserver/docker/http/h2/h2_command_unpacker.rb +73 -0
  30. data/lib/baykit/bayserver/docker/http/h2/h2_error_code.rb +53 -0
  31. data/lib/baykit/bayserver/docker/http/h2/h2_flags.rb +82 -0
  32. data/lib/baykit/bayserver/docker/http/h2/h2_inbound_handler.rb +417 -0
  33. data/lib/baykit/bayserver/docker/http/h2/h2_packet.rb +204 -0
  34. data/lib/baykit/bayserver/docker/http/h2/h2_packet_factory.rb +21 -0
  35. data/lib/baykit/bayserver/docker/http/h2/h2_packet_unpacker.rb +224 -0
  36. data/lib/baykit/bayserver/docker/http/h2/h2_protocol_handler.rb +58 -0
  37. data/lib/baykit/bayserver/docker/http/h2/h2_settings.rb +42 -0
  38. data/lib/baykit/bayserver/docker/http/h2/h2_type.rb +26 -0
  39. data/lib/baykit/bayserver/docker/http/h2/h2_warp_handler.rb +142 -0
  40. data/lib/baykit/bayserver/docker/http/h2/header_block.rb +191 -0
  41. data/lib/baykit/bayserver/docker/http/h2/header_block_analyzer.rb +88 -0
  42. data/lib/baykit/bayserver/docker/http/h2/header_block_builder.rb +68 -0
  43. data/lib/baykit/bayserver/docker/http/h2/header_table.rb +167 -0
  44. data/lib/baykit/bayserver/docker/http/h2/huffman/hnode.rb +28 -0
  45. data/lib/baykit/bayserver/docker/http/h2/huffman/htree.rb +339 -0
  46. data/lib/baykit/bayserver/docker/http/h2/package.rb +17 -0
  47. data/lib/baykit/bayserver/docker/http/htp_docker.rb +23 -0
  48. data/lib/baykit/bayserver/docker/http/htp_port_docker.rb +107 -0
  49. data/lib/baykit/bayserver/docker/http/htp_warp_docker.rb +125 -0
  50. data/lib/baykit/bayserver/docker/http/htp_warp_ship_helper.rb +19 -0
  51. data/lib/baykit/bayserver/docker/http/package.rb +6 -0
  52. metadata +106 -0
@@ -0,0 +1,417 @@
1
+ require 'baykit/bayserver/docker/base/inbound_handler'
2
+
3
+ require 'baykit/bayserver/docker/http/h2/package'
4
+ require 'baykit/bayserver/docker/http/h2/h2_protocol_handler'
5
+ require 'baykit/bayserver/docker/http/h2/command/package'
6
+ require 'baykit/bayserver/protocol/package'
7
+ require 'baykit/bayserver/tours/req_content_handler'
8
+ require 'baykit/bayserver/tours/tour_req'
9
+ require 'baykit/bayserver/util/http_status'
10
+ require 'baykit/bayserver/util/url_encoder'
11
+ require 'baykit/bayserver/util/http_util'
12
+
13
+ module Baykit
14
+ module BayServer
15
+ module Docker
16
+ module Http
17
+ module H2
18
+ class H2InboundHandler < Baykit::BayServer::Docker::Http::H2::H2ProtocolHandler
19
+
20
+ class InboundProtocolHandlerFactory
21
+ include Baykit::BayServer::Protocol::ProtocolHandlerFactory # implements
22
+
23
+ def create_protocol_handler(pkt_store)
24
+ return H2InboundHandler.new(pkt_store)
25
+ end
26
+ end
27
+
28
+ include Baykit::BayServer::Docker::Base::InboundHandler # implements
29
+ include Baykit::BayServer::Agent
30
+ include Baykit::BayServer::Protocol
31
+ include Baykit::BayServer::WaterCraft
32
+ include Baykit::BayServer::Tours
33
+ include Baykit::BayServer::Util
34
+ include Baykit::BayServer::Docker::Http::H2::Command
35
+
36
+ attr :req_cont_len
37
+ attr :req_cont_read
38
+ attr :header_read
39
+ attr :window_size
40
+ attr :settings
41
+ attr :analyzer
42
+ attr :http_protocol
43
+
44
+ def initialize(pkt_store)
45
+ super(pkt_store, true)
46
+ @window_size = BayServer.harbor.tour_buffer_size
47
+ @settings = H2Settings.new
48
+ @analyzer = HeaderBlockAnalyzer.new
49
+ end
50
+
51
+ ######################################################
52
+ # implements Reusable
53
+ ######################################################
54
+
55
+ def reset()
56
+ super
57
+ @header_read = false
58
+ @req_cont_len = 0
59
+ @req_cont_read = 0
60
+ end
61
+
62
+ ######################################################
63
+ # implements InboundHandler
64
+ ######################################################
65
+
66
+ def send_res_headers(tur)
67
+ cmd = CmdHeaders.new(tur.req.key)
68
+ bld = HeaderBlockBuilder.new()
69
+ blk = bld.build_header_block(":status", tur.res.headers.status.to_s, @res_header_tbl)
70
+ cmd.header_blocks << blk
71
+
72
+ # headers
73
+ if BayServer.harbor.trace_header?
74
+ BayLog.info("%s res status: %d", tur, tur.res.headers.status)
75
+ end
76
+ tur.res.headers.names.each do |name|
77
+ if name.casecmp?("connection")
78
+ BayLog.trace("%s Connection header is discarded", tur)
79
+ else
80
+ tur.res.headers.values(name).each do |value|
81
+ if BayServer.harbor.trace_header?
82
+ BayLog.info("%s H2 res header: %s=%s", tur, name, value)
83
+ end
84
+ blk = bld.build_header_block(name, value, @res_header_tbl)
85
+ cmd.header_blocks.append(blk)
86
+ end
87
+ end
88
+ end
89
+
90
+ cmd.flags.set_end_headers(true)
91
+ cmd.excluded = true
92
+ cmd.flags.set_padded(false)
93
+ @command_packer.post(@ship, cmd)
94
+ end
95
+
96
+ def send_res_content(tur, bytes, ofs, len, &lis)
97
+ cmd = CmdData.new(tur.req.key, nil, bytes, ofs, len);
98
+ @command_packer.post(@ship, cmd, &lis)
99
+ end
100
+
101
+ def send_end_tour(tur, keep_alive, &callback)
102
+ cmd = CmdData.new(tur.req.key, nil, [], 0, 0)
103
+ cmd.flags.set_end_stream(true)
104
+ @command_packer.post(@ship, cmd, &callback)
105
+ end
106
+
107
+ def send_req_protocol_error(err)
108
+ BayLog.error_e err
109
+ cmd = CmdGoAway.new(CTL_STREAM_ID)
110
+ cmd.stream_id = CTL_STREAM_ID
111
+ cmd.last_stream_id = CTL_STREAM_ID
112
+ cmd.error_code = H2ErrorCode::PROTOCOL_ERROR
113
+ cmd.debug_data = "Thank you!"
114
+ begin
115
+ @command_packer.post(@ship, cmd)
116
+ @command_packer.end(@ship)
117
+ rescue IOError => e
118
+ BayLog.error_e(e)
119
+ end
120
+ return false
121
+ end
122
+
123
+
124
+ ######################################################
125
+ # implements H2CommandHandler
126
+ ######################################################
127
+
128
+ def handle_preface(cmd)
129
+ BayLog.debug("%s h2: handle_preface: proto=%s", @ship, cmd.protocol)
130
+
131
+ @http_protocol = cmd.protocol
132
+
133
+ set = CmdSettings.new(H2ProtocolHandler::CTL_STREAM_ID)
134
+ set.stream_id = 0
135
+ set.items.append(CmdSettings::Item.new(CmdSettings::MAX_CONCURRENT_STREAMS, TourStore::MAX_TOURS))
136
+ set.items.append(CmdSettings::Item.new(CmdSettings::INITIAL_WINDOW_SIZE, @window_size))
137
+ @command_packer.post(@ship, set)
138
+
139
+ set = CmdSettings.new(H2ProtocolHandler::CTL_STREAM_ID)
140
+ set.stream_id = 0
141
+ set.flags.set_ack(true)
142
+
143
+ return NextSocketAction::CONTINUE
144
+ end
145
+
146
+
147
+ def handle_headers(cmd)
148
+ BayLog.debug("%s handle_headers: stm=%d dep=%d weight=%d", @ship, cmd.stream_id, cmd.stream_dependency, cmd.weight)
149
+
150
+ tur = get_tour(cmd.stream_id)
151
+ if tur == nil
152
+ BayLog.error(BayMessage.get(:INT_NO_MORE_TOURS))
153
+ tur = @ship.get_tour(cmd.stream_id, true)
154
+ tur.res.send_error(Tour::TOUR_ID_NOCHECK, HttpStatus::SERVICE_UNAVAILABLE, "No available tours")
155
+ return NextSocketAction::CONTINUE
156
+ end
157
+
158
+ cmd.header_blocks.each do |blk|
159
+ if blk.op == HeaderBlock::UPDATE_DYNAMIC_TABLE_SIZE
160
+ BayLog.trace("%s header block update table size: %d", tur, blk.size)
161
+ @req_header_tbl.set_size(blk.size)
162
+ next
163
+ end
164
+ @analyzer.analyze_header_block(blk, @req_header_tbl)
165
+ if BayServer.harbor.trace_header?
166
+ BayLog.info("%s req header: %s=%s :%s", tur, @analyzer.name, @analyzer.value, blk);
167
+ end
168
+
169
+ if @analyzer.name == nil
170
+ next
171
+
172
+ elsif @analyzer.name[0] != ":"
173
+ tur.req.headers.add(@analyzer.name, @analyzer.value)
174
+
175
+ elsif @analyzer.method != nil
176
+ tur.req.method = @analyzer.method
177
+
178
+ elsif @analyzer.path != nil
179
+ tur.req.uri = @analyzer.path
180
+
181
+ elsif @analyzer.scheme != nil
182
+
183
+ elsif @analyzer.status != nil
184
+ raise RuntimeError.new("Illegal State")
185
+ end
186
+ end
187
+
188
+ if cmd.flags.end_headers?
189
+ tur.req.protocol = "HTTP/2.0"
190
+ BayLog.debug("%s H2 read header method=%s protocol=%s uri=%s contlen=%d",
191
+ @ship, tur.req.method, tur.req.protocol, tur.req.uri, tur.req.headers.content_length)
192
+
193
+ req_cont_len = tur.req.headers.content_length()
194
+
195
+ if req_cont_len > 0
196
+ sid = @ship.ship_id
197
+ tur.req.set_consume_listener(req_cont_len) do |len, resume|
198
+ @ship.check_ship_id(sid)
199
+ if len > 0
200
+ upd = CmdWindowUpdate.new(cmd.stream_id)
201
+ upd.window_size_increment = len
202
+ upd2 = CmdWindowUpdate.new( 0)
203
+ upd2.window_size_increment = len
204
+ cmd_packer = @command_packer
205
+ begin
206
+ cmd_packer.post(@ship, upd)
207
+ cmd_packer.post(@ship, upd2)
208
+ rescue IOError => e
209
+ BayLog.error_e(e)
210
+ end
211
+ end
212
+
213
+ if resume
214
+ @ship.resume(Ship::SHIP_ID_NOCHECK)
215
+ end
216
+ end
217
+
218
+ end
219
+
220
+ begin
221
+ start_tour tur
222
+
223
+ if tur.req.headers.content_length <= 0
224
+ end_req_content(Tour::TOUR_ID_NOCHECK, tur)
225
+ end
226
+ rescue HttpException => e
227
+ BayLog.debug("%s Http error occurred: %s", self, e);
228
+ if req_cont_len <= 0
229
+ # no post data
230
+ tur.res.send_http_exception(Tour::TOUR_ID_NOCHECK, e)
231
+
232
+ return NextSocketAction::CONTINUE
233
+ else
234
+ # Delay send
235
+ tur.error = e
236
+ tur.req.set_content_handler(ReqContentHandler::DEV_NULL)
237
+ return NextSocketAction::CONTINUE
238
+ end
239
+ end
240
+
241
+ end
242
+
243
+ NextSocketAction::CONTINUE
244
+ end
245
+
246
+ def handle_data(cmd)
247
+ BayLog.debug("%s handle_data: stm=%d len=%d", @ship, cmd.stream_id, cmd.length)
248
+
249
+ tur = get_tour(cmd.stream_id)
250
+ if tur == nil
251
+ raise RuntimeError.new("Invalid stream id: #{cmd.stream_id}")
252
+ end
253
+ if tur.req.headers.content_length <= 0
254
+ raise ProtocolException.new("Post content not allowed")
255
+ end
256
+
257
+ success = false
258
+ if cmd.length > 0
259
+ success = tur.req.post_content(Tour::TOUR_ID_NOCHECK, cmd.data, cmd.start, cmd.length)
260
+ if tur.req.bytes_posted >= tur.req.headers.content_length
261
+ if tur.error != nil
262
+ # Error has occurred on header completed
263
+
264
+ tur.res.send_http_exception(Tour::TOUR_ID_NOCHECK, tur.error)
265
+ return NextSocketAction::CONTINUE
266
+ else
267
+ begin
268
+ end_req_content(tur.id(), tur)
269
+ rescue HttpException => e
270
+ tur.res.send_http_exception(Tour::TOUR_ID_NOCHECK, e)
271
+ return NextSocketAction::CONTINUE
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ if !success
278
+ return NextSocketAction::SUSPEND
279
+ else
280
+ return NextSocketAction::CONTINUE
281
+ end
282
+
283
+ end
284
+
285
+ def handle_priority(cmd)
286
+ if cmd.stream_id == 0
287
+ raise ProtocolException.new("Invalid stream id")
288
+ end
289
+
290
+ BayLog.debug("%s handlePriority: stmid=%d dep=%d, wgt=%d",
291
+ @ship, cmd.stream_id, cmd.stream_dependency, cmd.weight);
292
+
293
+ return NextSocketAction::CONTINUE
294
+ end
295
+
296
+ def handle_settings(cmd)
297
+ BayLog.debug("%s handleSettings: stmid=%d", @ship, cmd.stream_id);
298
+
299
+ if cmd.flags.ack?
300
+ return NextSocketAction::CONTINUE
301
+ end
302
+
303
+ cmd.items.each do |item|
304
+ BayLog.debug("%s handle: Setting id=%d, value=%d", @ship, item.id, item.value);
305
+ case item.id
306
+ when CmdSettings::HEADER_TABLE_SIZE
307
+ @settings.header_table_size = item.value
308
+
309
+ when CmdSettings::ENABLE_PUSH
310
+ @settings.enable_push = (item.value != 0)
311
+
312
+ when CmdSettings::MAX_CONCURRENT_STREAMS
313
+ @settings.max_concurrent_streams = item.value
314
+
315
+ when CmdSettings::INITIAL_WINDOW_SIZE
316
+ @settings.initial_window_size = item.value
317
+
318
+ when CmdSettings::MAX_FRAME_SIZE
319
+ @settings.max_frame_size = item.value
320
+
321
+ when CmdSettings::MAX_HEADER_LIST_SIZE
322
+ @settings.max_header_list_size = item.value
323
+
324
+ else
325
+ BayLog.debug("Invalid settings id (Ignore): %d", item.id)
326
+
327
+ end
328
+ end
329
+
330
+ res = CmdSettings.new(0, H2Flags.new(H2Flags::FLAGS_ACK))
331
+ @command_packer.post(@ship, res)
332
+ return NextSocketAction::CONTINUE
333
+ end
334
+
335
+ def handle_window_update(cmd)
336
+ BayLog.debug("%s handleWindowUpdate: stmid=%d siz=%d", @ship, cmd.stream_id, cmd.window_size_increment);
337
+
338
+ if cmd.window_size_increment == 0
339
+ raise ProtocolException.new("Invalid increment value")
340
+ end
341
+
342
+ window_size = cmd.window_size_increment
343
+ return NextSocketAction::CONTINUE
344
+ end
345
+
346
+ def handle_go_away(cmd)
347
+ BayLog.debug("%s received GoAway: lastStm=%d code=%d desc=%s debug=%s",
348
+ @ship, cmd.last_stream_id, cmd.error_code, H2ErrorCode.msg.get(cmd.error_code.to_s.to_sym), cmd.debug_data);
349
+ return NextSocketAction::CLOSE
350
+ end
351
+
352
+ def handle_ping(cmd)
353
+ BayLog.debug("%s handle_ping: stm=%d", @ship, cmd.stream_id)
354
+
355
+ res = CmdPing.new(cmd.stream_id, H2Flags.new(H2Flags::FLAGS_ACK), cmd.opaque_data)
356
+ @command_packer.post(@ship, res)
357
+ return NextSocketAction::CONTINUE
358
+ end
359
+
360
+ def handle_rst_stream(cmd)
361
+ BayLog.debug("%s received RstStream: stmid=%d code=%d desc=%s",
362
+ @ship, cmd.stream_id, cmd.error_code, H2ErrorCode.msg.get(cmd.error_code.to_s.to_sym))
363
+ return NextSocketAction::CONTINUE
364
+ end
365
+
366
+ private
367
+ def get_tour(key)
368
+ @ship.get_tour(key)
369
+ end
370
+
371
+ def end_req_content(check_id, tur)
372
+ tur.req.end_content check_id
373
+ end
374
+
375
+ def start_tour(tur)
376
+ HttpUtil.parse_host_port(tur, @ship.port_docker.secure ? 443 : 80)
377
+ HttpUtil.parse_authorization(tur)
378
+
379
+ tur.req.protocol = @http_protocol
380
+
381
+ skt = @ship.socket
382
+
383
+ client_adr = tur.req.headers.get(Headers::X_FORWARDED_FOR)
384
+ if client_adr
385
+ tur.req.remote_address = client_adr
386
+ tur.req.remote_port = nil
387
+ else
388
+ remote_addr = skt.getpeername()
389
+ tur.req.remote_port, tur.req.remote_address = Socket.unpack_sockaddr_in(remote_addr)
390
+ end
391
+
392
+ tur.req.remote_host_func = lambda { HttpUtil.resolve_remote_host(tur.req.remote_address) }
393
+
394
+
395
+
396
+
397
+ begin
398
+ server_addr = skt.getsockname
399
+ server_port, tur.req.server_address = Socket.unpack_sockaddr_in(server_addr)
400
+ rescue => e
401
+ BayLog.error_e(e)
402
+ BayLog.debug("%s Caught error (Continue)", @ship)
403
+ end
404
+
405
+ tur.req.server_port = tur.req.req_port
406
+ tur.req.server_name = tur.req.req_host
407
+ tur.is_secure = @ship.port_docker.secure
408
+
409
+ tur.go
410
+ end
411
+
412
+ end
413
+ end
414
+ end
415
+ end
416
+ end
417
+ end
@@ -0,0 +1,204 @@
1
+ require 'baykit/bayserver/protocol/package'
2
+ require 'baykit/bayserver/docker/http/h2/huffman/htree'
3
+
4
+ #
5
+ # Http2 spec
6
+ # https://www.rfc-editor.org/rfc/rfc7540.txt
7
+ #
8
+ # Http2 Frame format
9
+ # +-----------------------------------------------+
10
+ # | Length (24) |
11
+ # +---------------+---------------+---------------+
12
+ # | Type (8) | Flags (8) |
13
+ # +-+-+-----------+---------------+-------------------------------+
14
+ # |R| Stream Identifier (31) |
15
+ # +=+=============================================================+
16
+ # | Frame Payload (0...) ...
17
+ # +---------------------------------------------------------------+
18
+ #
19
+ module Baykit
20
+ module BayServer
21
+ module Docker
22
+ module Http
23
+ module H2
24
+ class H2Packet < Baykit::BayServer::Protocol::Packet
25
+
26
+ include Baykit::BayServer::Protocol
27
+ include Baykit::BayServer::Docker::Http::H2
28
+
29
+ class H2HeaderAccessor < PacketPartAccessor
30
+ def initialize(pkt, start, max_len)
31
+ super
32
+ end
33
+
34
+ def put_int24(len)
35
+ b1 = (len >> 16) & 0xFF
36
+ b2 = (len >> 8) & 0xFF
37
+ b3 = len & 0xFF
38
+ buf = StringUtil.alloc(3)
39
+ buf << b1 << b2 << b3
40
+ put_bytes buf
41
+ end
42
+ end
43
+
44
+ class H2DataAccessor < PacketPartAccessor
45
+ include Baykit::BayServer::Docker::Http::H2::Huffman
46
+
47
+ def initialize(pkt, start, max_len)
48
+ super
49
+ end
50
+
51
+ def get_hpack_int(prefix, head)
52
+ max_val = 0xFF >> (8 - prefix)
53
+
54
+ first_byte = get_byte
55
+ first_val = first_byte & max_val
56
+ head[0] = first_byte >> prefix
57
+ if first_val != max_val
58
+ first_val
59
+ else
60
+ max_val + get_hpack_int_rest
61
+ end
62
+ end
63
+
64
+ def get_hpack_int_rest
65
+ rest = 0
66
+ i = 0
67
+ while true
68
+ data = get_byte
69
+ cont = (data & 0x80) != 0
70
+ value = data & 0x7F
71
+ rest = rest + (value << (i*7))
72
+ if !cont
73
+ break
74
+ end
75
+ i += 1
76
+ end
77
+ return rest
78
+ end
79
+
80
+ def get_hpack_string
81
+ is_huffman = [nil]
82
+ len = get_hpack_int(7, is_huffman)
83
+ data = StringUtil.alloc(len)
84
+ get_bytes data, 0, len
85
+ if is_huffman[0] == 1
86
+ return HTree.decode(data)
87
+ else
88
+ # ASCII
89
+ return data
90
+ end
91
+ end
92
+
93
+ def put_hpack_int(val, prefix, head)
94
+ max_val = 0xFF >> (8 -prefix)
95
+ head_val = (head << prefix) & 0xFF
96
+ if val < max_val
97
+ put_byte (val | head_val)
98
+ else
99
+ put_byte (head_val | max_val)
100
+ put_hpack_int_rest(val - max_val)
101
+ end
102
+ end
103
+
104
+ def put_hpack_int_rest(val)
105
+ while true
106
+ data = val & 0x7F
107
+ next_val = val >> 7
108
+ if next_val == 0
109
+ put_byte(data)
110
+ break
111
+ else
112
+ put_byte(data | 0x80)
113
+ val = next_val
114
+ end
115
+ end
116
+ end
117
+
118
+ def put_hpack_string(value, is_haffman)
119
+ if is_haffman
120
+ raise RuntimeError.new "Illegal State"
121
+ else
122
+ put_hpack_int(value.length, 7, 0)
123
+ put_bytes(value)
124
+ end
125
+ end
126
+ end
127
+
128
+ MAX_PAYLOAD_LEN = 0x00FFFFFF # = 2^24-1 = 16777215 = 16MB-1
129
+ DEFAULT_PAYLOAD_MAXLEN = 0x00004000 # = 2^14 = 16384 = 16KB
130
+ FRAME_HEADER_LEN = 9
131
+
132
+ NO_ERROR = 0x0
133
+ PROTOCOL_ERROR = 0x1
134
+ INTERNAL_ERROR = 0x2
135
+ FLOW_CONTROL_ERROR = 0x3
136
+ SETTINGS_TIMEOUT = 0x4
137
+ STREAM_CLOSED = 0x5
138
+ FRAME_SIZE_ERROR = 0x6
139
+ REFUSED_STREAM = 0x7
140
+ CANCEL = 0x8
141
+ COMPRESSION_ERROR = 0x9
142
+ CONNECT_ERROR = 0xa
143
+ ENHANCE_YOUR_CALM = 0xb
144
+ INADEQUATE_SECURITY = 0xc
145
+ HTTP_1_1_REQUIRED = 0xd
146
+
147
+ attr_accessor :flags
148
+ attr_accessor :stream_id
149
+
150
+ def initialize(type)
151
+ super(type, FRAME_HEADER_LEN, DEFAULT_PAYLOAD_MAXLEN)
152
+ @flags = H2Flags::FLAGS_NONE
153
+ @stream_id = -1
154
+ end
155
+
156
+ def reset
157
+ @flags = H2Flags::FLAGS_NONE
158
+ @stream_id = -1
159
+ super
160
+ end
161
+
162
+ def pack_header
163
+ acc = new_h2_header_accessor()
164
+ acc.put_int24(data_len())
165
+ acc.put_byte(@type)
166
+ acc.put_byte(@flags.flags)
167
+ acc.put_int(H2Packet.extract_int31(stream_id))
168
+ end
169
+
170
+ def new_h2_header_accessor
171
+ H2HeaderAccessor.new(self, 0, @header_len)
172
+ end
173
+
174
+ def new_h2_data_accessor
175
+ H2DataAccessor.new(self, @header_len, -1)
176
+ end
177
+
178
+ def self.extract_int31(val)
179
+ val & 0x7FFFFFFF
180
+ end
181
+
182
+ def self.extract_flag(val)
183
+ (val & 0x80000000) >> 31 & 1
184
+ end
185
+
186
+ def self.consolidate_flag_and_int32(flag, val)
187
+ ((flag & 1) << 31) | (val & 0x7FFFFFFF)
188
+ end
189
+
190
+ def self.make_stream_dependency32(excluded, dep)
191
+ (excluded ? 1 : 0) << 31 | extract_int31(dep)
192
+ end
193
+
194
+ def to_s
195
+ "H2Packet(#{@type}) headerLen=#{@header_len} dataLen=#{data_len()} stm=#{@stream_id} flags=#{@flags}"
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+
@@ -0,0 +1,21 @@
1
+ require 'baykit/bayserver/protocol/packet_factory'
2
+
3
+ module Baykit
4
+ module BayServer
5
+ module Docker
6
+ module Http
7
+ module H2
8
+ class H2PacketFactory <Baykit::BayServer::Protocol::PacketFactory
9
+
10
+ def create_packet(type)
11
+ H2Packet.new(type)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+