bayserver-docker-http 3.0.3 → 3.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5a5ca498e7e56434ccef478c2c1895f0c24cfcc424d8c811ea6fcfb3e2daa0a
4
- data.tar.gz: 6178b740f34a7d5411c5923f40a8a090a91f6806be70584c363834243070ba4e
3
+ metadata.gz: 3a4d46496d23a37a8c5bc5f5852b379d0a901f5599aaaa502d949646c134e921
4
+ data.tar.gz: b44a1b58fe21107515516a280654801e24f6cde5f7130b089f4c5d4882377259
5
5
  SHA512:
6
- metadata.gz: ddc09627cb09f5755e26fb56510a838ed5b094a7ee8f85274cb2912360ad301ec0651afc134102dd4a4fcbb92d985f7755e412ae2e3d80d4a37aeaa65d2aa81e
7
- data.tar.gz: 067dba365ddd9a1534a8adb52032dadc7c84815a7f1a6381bf1498b54609d2b51083ee7ab0c9cc0c68e0e6a81190432db49a03b2177ce1a530204f0f4a32d6f3
6
+ metadata.gz: f66955666f1fce85453badd1b76db78a3d3982c0a238e7a3c42c7acfdc8b2ec9420de309031212fa479b47dde6da288faacdafacbde87fb8ea4313a4ff13779d
7
+ data.tar.gz: f304c2c88516c98712406769238d4c261bb637fc21d1d88b9f6d6701c20de967f4def4e1af3f6793015d6d7ac8e78d3a050dbb35db6bea7ab4eb413305238ccf
@@ -99,13 +99,13 @@ module Baykit
99
99
  def send_res_headers(tur)
100
100
 
101
101
  # determine Connection header value
102
- if tur.req.headers.get_connection() != Headers::CONNECTION_KEEP_ALIVE
102
+ if tur.req.headers.get_connection() != Headers::CONNECTION_KEEP_ALIVE && tur.req.headers.get_connection() != Headers::CONNECTION_UNKNOWN
103
103
  # If client doesn't support "Keep-Alive", set "Close"
104
104
  res_con = "Close"
105
105
  else
106
106
  res_con = "Keep-Alive"
107
107
  # Client supports "Keep-Alive"
108
- if tur.res.headers.get_connection() != Headers::CONNECTION_KEEP_ALIVE
108
+ if tur.res.headers.get_connection() != Headers::CONNECTION_KEEP_ALIVE && tur.res.headers.get_connection() != Headers::CONNECTION_UNKNOWN
109
109
  # If tours doesn't need "Keep-Alive"
110
110
  if tur.res.headers.content_length() == -1
111
111
  # If content-length not specified
@@ -175,7 +175,7 @@ module Baykit
175
175
  end
176
176
 
177
177
  tur.res.send_error(Tour::TOUR_ID_NOCHECK, HttpStatus::BAD_REQUEST, err.message, err)
178
- true
178
+ false
179
179
  end
180
180
 
181
181
  ######################################################
@@ -0,0 +1,58 @@
1
+ require 'baykit/bayserver/docker/http/h2/package'
2
+
3
+ #
4
+ # HTTP/2 Continuation payload format
5
+ #
6
+ # +---------------------------------------------------------------+
7
+ # | Header Block Fragment (*) ...
8
+ # +---------------------------------------------------------------+
9
+ #
10
+ module Baykit
11
+ module BayServer
12
+ module Docker
13
+ module Http
14
+ module H2
15
+ module Command
16
+
17
+ class CmdContinuation < Baykit::BayServer::Docker::Http::H2::H2Command
18
+ include Baykit::BayServer::Docker::Http::H2
19
+
20
+ #
21
+ # This class refers external byte array, so this IS NOT mutable
22
+ #
23
+ attr :start
24
+ attr :length
25
+ attr :data
26
+
27
+ def initialize(stream_id, flags = nil)
28
+ super(H2Type::CONTINUATION, stream_id, flags)
29
+ end
30
+
31
+ def unpack(pkt)
32
+ super
33
+ @data = pkt.buf
34
+ @start = pkt.header_len
35
+ @length = pkt.data_len()
36
+ end
37
+
38
+ def pack(pkt)
39
+ acc = pkt.new_data_accessor()
40
+ if @flags.padded?
41
+ raise RuntimeError.new("Padding not supported")
42
+ end
43
+ acc.put_bytes(@data, @start, @length)
44
+ super
45
+ end
46
+
47
+ def handle(cmd_handler)
48
+ return cmd_handler.handle_continuation(self)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+
@@ -25,6 +25,13 @@ module Baykit
25
25
  class CmdHeaders < Baykit::BayServer::Docker::Http::H2::H2Command
26
26
  include Baykit::BayServer::Docker::Http::H2
27
27
 
28
+ #
29
+ # This class refers external byte array, so this IS NOT mutable
30
+ #
31
+ attr_accessor :start
32
+ attr_accessor :length
33
+ attr_accessor :data
34
+
28
35
  attr :pad_length
29
36
  attr_accessor :excluded
30
37
  attr :stream_dependency
@@ -42,7 +49,7 @@ module Baykit
42
49
 
43
50
  def unpack(pkt)
44
51
  super
45
- acc = pkt.new_h2_data_accessor
52
+ acc = pkt.new_data_accessor
46
53
 
47
54
  if pkt.flags.padded?
48
55
  @pad_length = acc.get_byte
@@ -53,11 +60,13 @@ module Baykit
53
60
  @stream_dependency = H2Packet.extract_int31(val)
54
61
  @weight = acc.get_byte
55
62
  end
56
- read_header_block(acc, pkt.data_len())
63
+ @data = pkt.buf
64
+ @start = pkt.header_len + acc.pos
65
+ @length = pkt.data_len - acc.pos
57
66
  end
58
67
 
59
68
  def pack(pkt)
60
- acc = pkt.new_h2_data_accessor
69
+ acc = pkt.new_data_accessor
61
70
 
62
71
  if @flags.padded?
63
72
  acc.put_byte(@pad_length)
@@ -67,7 +76,8 @@ module Baykit
67
76
  acc.put_int(H2Packet.make_stream_dependency32(@excluded, @stream_dependency))
68
77
  acc.put_byte(@weight)
69
78
  end
70
- write_header_block(acc)
79
+
80
+ acc.put_bytes(@data, @start, @length)
71
81
  super
72
82
  end
73
83
 
@@ -75,28 +85,6 @@ module Baykit
75
85
  return cmd_handler.handle_headers(self)
76
86
  end
77
87
 
78
- def read_header_block(acc, len)
79
- while acc.pos < len
80
- blk = HeaderBlock.unpack(acc)
81
- #if(BayLog.trace_mode?)
82
- # BayLog.trace "h2: Read header block: #{blk}"
83
- #end
84
- @header_blocks << blk
85
- end
86
- end
87
-
88
- def write_header_block(acc)
89
- @header_blocks.each do |blk|
90
- #if(BayLog.trace_mode?)
91
- # BayLog.trace "h2: Write header block: #{blk}"
92
- #end
93
- HeaderBlock.pack(blk, acc)
94
- end
95
- end
96
-
97
- def add_header_block(blk)
98
- @header_blocks.append(blk)
99
- end
100
88
  end
101
89
  end
102
90
  end
@@ -33,7 +33,7 @@ module Baykit
33
33
  end
34
34
 
35
35
  def pack(pkt)
36
- acc = pkt.new_h2_data_accessor()
36
+ acc = pkt.new_data_accessor()
37
37
  acc.put_bytes(PREFACE_BYTES)
38
38
  end
39
39
 
@@ -7,3 +7,4 @@ require 'baykit/bayserver/docker/http/h2/command/cmd_priority'
7
7
  require 'baykit/bayserver/docker/http/h2/command/cmd_rst_stream'
8
8
  require 'baykit/bayserver/docker/http/h2/command/cmd_settings'
9
9
  require 'baykit/bayserver/docker/http/h2/command/cmd_window_update'
10
+ require 'baykit/bayserver/docker/http/h2/command/cmd_continuation'
@@ -41,6 +41,10 @@ module Baykit
41
41
  def handle_rst_stream(cmd)
42
42
  raise NotImplementedError.new
43
43
  end
44
+
45
+ def handle_continuation(cmd)
46
+ raise NotImplementedError.new
47
+ end
44
48
  end
45
49
  end
46
50
  end
@@ -54,6 +54,9 @@ module Baykit
54
54
  when H2Type::RST_STREAM
55
55
  cmd = CmdRstStream.new(pkt.stream_id, pkt.flags)
56
56
 
57
+ when H2Type::CONTINUATION
58
+ cmd = CmdContinuation.new(pkt.stream_id, pkt.flags)
59
+
57
60
  else
58
61
  reset()
59
62
  raise RuntimeError.new("Invalid Packet: #{pkt}")
@@ -45,7 +45,6 @@ module Baykit
45
45
 
46
46
  include Baykit::BayServer::Agent
47
47
  include Baykit::BayServer::Protocol
48
- include Baykit::BayServer::WaterCraft
49
48
  include Baykit::BayServer::Tours
50
49
  include Baykit::BayServer::Util
51
50
  include Baykit::BayServer::Docker::Http::H2::Command
@@ -60,6 +59,7 @@ module Baykit
60
59
  attr :http_protocol
61
60
  attr :req_header_tbl
62
61
  attr :res_header_tbl
62
+ attr :header_buffer
63
63
 
64
64
  def initialize
65
65
  @window_size = BayServer.harbor.tour_buffer_size
@@ -67,6 +67,7 @@ module Baykit
67
67
  @analyzer = HeaderBlockAnalyzer.new
68
68
  @req_header_tbl = HeaderTable.create_dynamic_table()
69
69
  @res_header_tbl = HeaderTable.create_dynamic_table()
70
+ @header_buffer = SimpleBuffer.new
70
71
  end
71
72
 
72
73
  ######################################################
@@ -77,6 +78,7 @@ module Baykit
77
78
  @header_read = false
78
79
  @req_cont_len = 0
79
80
  @req_cont_read = 0
81
+ @header_buffer.reset
80
82
  end
81
83
 
82
84
  def init(proto_handler)
@@ -88,10 +90,12 @@ module Baykit
88
90
  ######################################################
89
91
 
90
92
  def send_res_headers(tur)
91
- cmd = CmdHeaders.new(tur.req.key)
92
93
  bld = HeaderBlockBuilder.new()
94
+
95
+ header_blocks = []
96
+
93
97
  blk = bld.build_header_block(":status", tur.res.headers.status.to_s, @res_header_tbl)
94
- cmd.header_blocks << blk
98
+ header_blocks << blk
95
99
 
96
100
  # headers
97
101
  if BayServer.harbor.trace_header
@@ -106,15 +110,46 @@ module Baykit
106
110
  BayLog.info("%s H2 res header: %s=%s", tur, name, value)
107
111
  end
108
112
  blk = bld.build_header_block(name, value, @res_header_tbl)
109
- cmd.header_blocks.append(blk)
113
+ header_blocks.append(blk)
110
114
  end
111
115
  end
112
116
  end
113
117
 
114
- cmd.flags.set_end_headers(true)
115
- cmd.excluded = true
116
- cmd.flags.set_padded(false)
117
- @protocol_handler.post(cmd)
118
+ buf = SimpleBuffer.new
119
+ HeaderBlockRenderer.new(buf).render_header_blocks(header_blocks)
120
+
121
+ pos = 0
122
+ len = buf.length
123
+ while len > 0
124
+ chunk_len = [len, H2Packet::DEFAULT_PAYLOAD_MAXLEN].min
125
+
126
+ if pos == 0
127
+ hcmd = CmdHeaders.new(tur.req.key)
128
+ hcmd.excluded = false
129
+ hcmd.data = buf.bytes
130
+ hcmd.start = pos
131
+ hcmd.length = len
132
+ cmd = hcmd
133
+
134
+ else
135
+ ccmd = CmdContinuation.new(tur.req.key)
136
+ ccmd.data = buf.bytes
137
+ ccmd.start = pos
138
+ ccmd.length = len
139
+ cmd = ccmd
140
+
141
+ end
142
+
143
+ cmd.flags.set_padded(false)
144
+
145
+ pos += chunk_len
146
+ len -= chunk_len
147
+ if len == 0
148
+ cmd.flags.set_end_headers(true)
149
+ end
150
+
151
+ @protocol_handler.post(cmd)
152
+ end
118
153
  end
119
154
 
120
155
  def send_res_content(tur, bytes, ofs, len, &callback)
@@ -132,14 +167,14 @@ module Baykit
132
167
 
133
168
  def on_protocol_error(err)
134
169
  BayLog.error_e err
135
- cmd = CmdGoAway.new(CTL_STREAM_ID)
136
- cmd.stream_id = CTL_STREAM_ID
137
- cmd.last_stream_id = CTL_STREAM_ID
170
+ cmd = CmdGoAway.new(H2ProtocolHandler::CTL_STREAM_ID)
171
+ cmd.stream_id = H2ProtocolHandler::CTL_STREAM_ID
172
+ cmd.last_stream_id = H2ProtocolHandler::CTL_STREAM_ID
138
173
  cmd.error_code = H2ErrorCode::PROTOCOL_ERROR
139
174
  cmd.debug_data = "Thank you!"
140
175
  begin
141
176
  @protocol_handler.post(cmd)
142
- @protocol_handler.end(ship)
177
+ @protocol_handler.ship.post_close()
143
178
  rescue IOError => e
144
179
  BayLog.error_e(e)
145
180
  end
@@ -180,70 +215,14 @@ module Baykit
180
215
  tur.res.send_error(Tour::TOUR_ID_NOCHECK, HttpStatus::SERVICE_UNAVAILABLE, "No available tours")
181
216
  return NextSocketAction::CONTINUE
182
217
  end
183
-
184
- cmd.header_blocks.each do |blk|
185
- if blk.op == HeaderBlock::UPDATE_DYNAMIC_TABLE_SIZE
186
- BayLog.trace("%s header block update table size: %d", tur, blk.size)
187
- @req_header_tbl.set_size(blk.size)
188
- next
189
- end
190
- @analyzer.analyze_header_block(blk, @req_header_tbl)
191
- if BayServer.harbor.trace_header
192
- BayLog.info("%s req header: %s=%s :%s", tur, @analyzer.name, @analyzer.value, blk);
193
- end
194
-
195
- if @analyzer.name == nil
196
- next
197
-
198
- elsif @analyzer.name[0] != ":"
199
- tur.req.headers.add(@analyzer.name, @analyzer.value)
200
-
201
- elsif @analyzer.method != nil
202
- tur.req.method = @analyzer.method
203
-
204
- elsif @analyzer.path != nil
205
- tur.req.uri = @analyzer.path
206
-
207
- elsif @analyzer.scheme != nil
208
-
209
- elsif @analyzer.status != nil
210
- raise RuntimeError.new("Illegal State")
211
- end
218
+ if !tur.preparing?
219
+ raise ProtocolException.new("%s Tour is not preparing.", tur)
212
220
  end
213
221
 
214
222
  if cmd.flags.end_headers?
215
- tur.req.protocol = "HTTP/2.0"
216
- BayLog.debug("%s H2 read header method=%s protocol=%s uri=%s contlen=%d",
217
- ship, tur.req.method, tur.req.protocol, tur.req.uri, tur.req.headers.content_length)
218
-
219
- req_cont_len = tur.req.headers.content_length()
220
-
221
- if req_cont_len > 0
222
- tur.req.set_limit(req_cont_len)
223
- end
224
-
225
- begin
226
- start_tour tur
227
-
228
- if tur.req.headers.content_length <= 0
229
- end_req_content(Tour::TOUR_ID_NOCHECK, tur)
230
- end
231
- rescue HttpException => e
232
- BayLog.debug("%s Http error occurred: %s", self, e);
233
- if req_cont_len <= 0
234
- # no post data
235
- tur.req.abort
236
- tur.res.send_http_exception(Tour::TOUR_ID_NOCHECK, e)
237
-
238
- return NextSocketAction::CONTINUE
239
- else
240
- # Delay send
241
- tur.error = e
242
- tur.req.set_content_handler(ReqContentHandler::DEV_NULL)
243
- return NextSocketAction::CONTINUE
244
- end
245
- end
246
-
223
+ return on_end_header(tur, cmd.data, cmd.start, cmd.length)
224
+ else
225
+ @header_buffer.put(cmd.data, cmd.start, cmd.length)
247
226
  end
248
227
 
249
228
  NextSocketAction::CONTINUE
@@ -256,8 +235,8 @@ module Baykit
256
235
  if tur == nil
257
236
  raise RuntimeError.new("Invalid stream id: #{cmd.stream_id}")
258
237
  end
259
- if tur.req.headers.content_length <= 0
260
- raise ProtocolException.new("Post content not allowed")
238
+ if !tur.reading?
239
+ raise ProtocolException.new("%s Tour is not reading.", tur)
261
240
  end
262
241
 
263
242
  begin
@@ -388,13 +367,22 @@ module Baykit
388
367
  def handle_rst_stream(cmd)
389
368
  BayLog.warn("%s received RstStream: stmid=%d code=%d desc=%s",
390
369
  ship, cmd.stream_id, cmd.error_code, H2ErrorCode.msg.get(cmd.error_code.to_s.to_sym))
370
+ return NextSocketAction::CONTINUE
371
+ end
372
+
373
+ def handle_continuation(cmd)
374
+ BayLog.debug("%s handle_continuation: stm=%d", ship, cmd.stream_id)
391
375
  tur = get_tour(cmd.stream_id)
392
376
  if tur == nil
393
- BayLog.warn("%s stream not found id=%d", ship, cmd.stream_id)
394
- else
395
- tur.req.abort
396
- return NextSocketAction::CONTINUE
377
+ raise ArgumentError("Invalid stream id: " + cmd.stream_id)
378
+ end
379
+
380
+ @header_buffer.put(cmd.data, cmd.start, cmd.length)
381
+ if cmd.flags.end_headers?
382
+ return on_end_header(tur, @header_buffer.bytes, 0, @header_buffer.length)
397
383
  end
384
+
385
+ return NextSocketAction::CONTINUE
398
386
  end
399
387
 
400
388
  private
@@ -427,8 +415,15 @@ module Baykit
427
415
  tur.req.remote_address = client_adr
428
416
  tur.req.remote_port = nil
429
417
  else
430
- remote_addr = skt.getpeername()
431
- tur.req.remote_port, tur.req.remote_address = Socket.unpack_sockaddr_in(remote_addr)
418
+ begin
419
+ remote_addr = skt.getpeername()
420
+ rescue SystemCallError => e
421
+ BayLog.debug_e(e)
422
+ remote_addr = nil
423
+ end
424
+ if remote_addr
425
+ tur.req.remote_port, tur.req.remote_address = Socket.unpack_sockaddr_in(remote_addr)
426
+ end
432
427
  end
433
428
 
434
429
  tur.req.remote_host_func = lambda { HttpUtil.resolve_remote_host(tur.req.remote_address) }
@@ -451,6 +446,75 @@ module Baykit
451
446
  tur.go
452
447
  end
453
448
 
449
+ def on_end_header(tur, buf, start, len)
450
+
451
+ header_blocks = HeaderBlockParser.new(buf, start, len).parse_header_blocks()
452
+
453
+ header_blocks.each do |blk|
454
+ if blk.op == HeaderBlock::UPDATE_DYNAMIC_TABLE_SIZE
455
+ BayLog.trace("%s header block update table size: %d", tur, blk.size)
456
+ @req_header_tbl.set_size(blk.size)
457
+ next
458
+ end
459
+ @analyzer.analyze_header_block(blk, @req_header_tbl)
460
+ if BayServer.harbor.trace_header
461
+ BayLog.info("%s req header: %s=%s :%s", tur, @analyzer.name, @analyzer.value, blk);
462
+ end
463
+
464
+ if @analyzer.name == nil
465
+ next
466
+
467
+ elsif @analyzer.name[0] != ":"
468
+ tur.req.headers.add(@analyzer.name, @analyzer.value)
469
+
470
+ elsif @analyzer.method != nil
471
+ tur.req.method = @analyzer.method
472
+
473
+ elsif @analyzer.path != nil
474
+ tur.req.uri = @analyzer.path
475
+
476
+ elsif @analyzer.scheme != nil
477
+
478
+ elsif @analyzer.status != nil
479
+ raise RuntimeError.new("Illegal State")
480
+ end
481
+ end
482
+
483
+ tur.req.protocol = "HTTP/2.0"
484
+ BayLog.debug("%s H2 read header method=%s protocol=%s uri=%s contlen=%d",
485
+ ship, tur.req.method, tur.req.protocol, tur.req.uri, tur.req.headers.content_length)
486
+
487
+ HttpUtil.check_uri(tur.req.uri)
488
+ req_cont_len = tur.req.headers.content_length
489
+
490
+ if req_cont_len > 0
491
+ tur.req.set_limit(req_cont_len)
492
+ end
493
+
494
+ begin
495
+ start_tour tur
496
+
497
+ if tur.req.headers.content_length <= 0
498
+ end_req_content(Tour::TOUR_ID_NOCHECK, tur)
499
+ end
500
+ rescue HttpException => e
501
+ BayLog.debug("%s Http error occurred: %s", self, e);
502
+ if req_cont_len <= 0
503
+ # no post data
504
+ tur.req.abort
505
+ tur.res.send_http_exception(Tour::TOUR_ID_NOCHECK, e)
506
+
507
+ return NextSocketAction::CONTINUE
508
+ else
509
+ # Delay send
510
+ tur.error = e
511
+ tur.req.set_content_handler(ReqContentHandler::DEV_NULL)
512
+ return NextSocketAction::CONTINUE
513
+ end
514
+ end
515
+
516
+ return NextSocketAction::CONTINUE
517
+ end
454
518
  end
455
519
  end
456
520
  end
@@ -26,105 +26,6 @@ module Baykit
26
26
  include Baykit::BayServer::Protocol
27
27
  include Baykit::BayServer::Docker::Http::H2
28
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
29
  MAX_PAYLOAD_LEN = 0x00FFFFFF # = 2^24-1 = 16777215 = 16MB-1
129
30
  DEFAULT_PAYLOAD_MAXLEN = 0x00004000 # = 2^14 = 16384 = 16KB
130
31
  FRAME_HEADER_LEN = 9
@@ -160,21 +61,13 @@ module Baykit
160
61
  end
161
62
 
162
63
  def pack_header
163
- acc = new_h2_header_accessor()
164
- acc.put_int24(data_len())
64
+ acc = new_header_accessor
65
+ put_int24(acc, data_len)
165
66
  acc.put_byte(@type)
166
67
  acc.put_byte(@flags.flags)
167
68
  acc.put_int(H2Packet.extract_int31(stream_id))
168
69
  end
169
70
 
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
71
  def self.extract_int31(val)
179
72
  val & 0x7FFFFFFF
180
73
  end
@@ -191,6 +84,15 @@ module Baykit
191
84
  (excluded ? 1 : 0) << 31 | extract_int31(dep)
192
85
  end
193
86
 
87
+ def put_int24(acc, len)
88
+ b1 = (len >> 16) & 0xFF
89
+ b2 = (len >> 8) & 0xFF
90
+ b3 = len & 0xFF
91
+ buf = StringUtil.alloc(3)
92
+ buf << b1 << b2 << b3
93
+ acc.put_bytes buf
94
+ end
95
+
194
96
  def to_s
195
97
  "H2Packet(#{@type}) headerLen=#{@header_len} dataLen=#{data_len()} stm=#{@stream_id} flags=#{@flags}"
196
98
  end
@@ -18,165 +18,6 @@ module Baykit
18
18
  attr_accessor :value
19
19
  attr_accessor :size
20
20
 
21
- def self.pack(blk, acc)
22
- case blk.op
23
- when INDEX
24
- acc.put_hpack_int(blk.index, 7, 1)
25
-
26
- when OVERLOAD_KNOWN_HEADER
27
- raise RuntimeError.new("IllegalState")
28
-
29
- when NEW_HEADER
30
- raise RuntimeError.new("Illegal State")
31
-
32
- when KNOWN_HEADER
33
- acc.put_hpack_int(blk.index, 4, 0)
34
- acc.put_hpack_string(blk.value, false)
35
-
36
- when UNKNOWN_HEADER
37
- acc.put_byte(0)
38
- acc.put_hpack_string(blk.name, false)
39
- acc.put_hpack_string(blk.value, false)
40
-
41
- when UPDATE_DYNAMIC_TABLE_SIZE
42
- raise RuntimeError.new("Illegal state")
43
- end
44
- end
45
-
46
-
47
- def self.unpack(acc)
48
- blk = HeaderBlock.new
49
- index = acc.get_byte
50
- is_index_header_field = (index & 0x80) != 0
51
- if is_index_header_field
52
- # index header field
53
- # 0 1 2 3 4 5 6 7
54
- # +---+---+---+---+---+---+---+---+
55
- # | 1 | Index (7+) |
56
- # +---+---------------------------+
57
- blk.op = INDEX
58
- blk.index = index & 0x7F
59
- else
60
- # literal header field
61
- update_index = (index & 0x40) != 0
62
- if update_index
63
- index = index & 0x3F
64
- overload_index = (index != 0)
65
- if overload_index
66
- if index == 0x3F
67
- index = index + acc.get_hpack_int_rest
68
- end
69
- blk.op = OVERLOAD_KNOWN_HEADER
70
- blk.index = index
71
- # 0 1 2 3 4 5 6 7
72
- # +---+---+---+---+---+---+---+---+
73
- # | 0 | 1 | Index (6+) |
74
- # +---+---+-----------------------+
75
- # | H | Value Length (7+) |
76
- # +---+---------------------------+
77
- # | Value String (Length octets) |
78
- # +-------------------------------+
79
- blk.value = acc.get_hpack_string
80
- else
81
- # new header name
82
- # 0 1 2 3 4 5 6 7
83
- # +---+---+---+---+---+---+---+---+
84
- # | 0 | 1 | 0 |
85
- # +---+---+-----------------------+
86
- # | H | Name Length (7+) |
87
- # +---+---------------------------+
88
- # | Name String (Length octets) |
89
- # +---+---------------------------+
90
- # | H | Value Length (7+) |
91
- # +---+---------------------------+
92
- # | Value String (Length octets) |
93
- # +-------------------------------+
94
- blk.op = NEW_HEADER
95
- blk.name = acc.get_hpack_string
96
- blk.value = acc.get_hpack_string
97
- end
98
- else
99
- update_dynamic_table_size = (index & 0x20) != 0
100
- if update_dynamic_table_size
101
- # 0 1 2 3 4 5 6 7
102
- # +---+---+---+---+---+---+---+---+
103
- # | 0 | 0 | 1 | Max size (5+) |
104
- # +---+---------------------------+
105
- size = index & 0x1F
106
- if size == 0x1F
107
- size = size + acc.get_hpack_int_rest
108
- end
109
- blk.op = UPDATE_DYNAMIC_TABLE_SIZE
110
- blk.size = size
111
- else
112
- # not update index
113
- index = (index & 0xF)
114
- if index != 0
115
- # 0 1 2 3 4 5 6 7
116
- # +---+---+---+---+---+---+---+---+
117
- # | 0 | 0 | 0 | 0 | Index (4+) |
118
- # +---+---+-----------------------+
119
- # | H | Value Length (7+) |
120
- # +---+---------------------------+
121
- # | Value String (Length octets) |
122
- # +-------------------------------+
123
- #
124
- # OR
125
- #
126
- # 0 1 2 3 4 5 6 7
127
- # +---+---+---+---+---+---+---+---+
128
- # | 0 | 0 | 0 | 1 | Index (4+) |
129
- # +---+---+-----------------------+
130
- # | H | Value Length (7+) |
131
- # +---+---------------------------+
132
- # | Value String (Length octets) |
133
- # +-------------------------------+
134
- if index == 0xF
135
- index = index + acc.get_hpack_int_rest
136
- end
137
- blk.op = KNOWN_HEADER
138
- blk.index = index
139
- blk.value = acc.get_hpack_string
140
- else
141
- # literal header field
142
- # 0 1 2 3 4 5 6 7
143
- # +---+---+---+---+---+---+---+---+
144
- # | 0 | 0 | 0 | 0 | 0 |
145
- # +---+---+-----------------------+
146
- # | H | Name Length (7+) |
147
- # +---+---------------------------+
148
- # | Name String (Length octets) |
149
- # +---+---------------------------+
150
- # | H | Value Length (7+) |
151
- # +---+---------------------------+
152
- # | Value String (Length octets) |
153
- # +-------------------------------+
154
- #
155
- # OR
156
- #
157
- # 0 1 2 3 4 5 6 7
158
- # +---+---+---+---+---+---+---+---+
159
- # | 0 | 0 | 0 | 1 | 0 |
160
- # +---+---+-----------------------+
161
- # | H | Name Length (7+) |
162
- # +---+---------------------------+
163
- # | Name String (Length octets) |
164
- # +---+---------------------------+
165
- # | H | Value Length (7+) |
166
- # +---+---------------------------+
167
- # | Value String (Length octets) |
168
- # +-------------------------------+
169
- #
170
- blk.op = UNKNOWN_HEADER
171
- blk.name = acc.get_hpack_string
172
- blk.value = acc.get_hpack_string
173
- end
174
- end
175
- end
176
- end
177
-
178
- blk
179
- end
180
21
 
181
22
  def to_s
182
23
  "#{op} index=#{index} name=#{name} value=#{value}"
@@ -0,0 +1,240 @@
1
+ require 'baykit/bayserver/docker/http/h2/header_block'
2
+ require 'baykit/bayserver/docker/http/h2/huffman/htree'
3
+ require 'baykit/bayserver/util/string_util'
4
+
5
+ module Baykit
6
+ module BayServer
7
+ module Docker
8
+ module Http
9
+ module H2
10
+ class HeaderBlockParser
11
+
12
+ include Baykit::BayServer::Util
13
+ include Baykit::BayServer::Docker::Http::H2::Huffman
14
+
15
+ attr :buf
16
+ attr :start
17
+ attr :pos
18
+ attr :length
19
+
20
+
21
+ def initialize(buf, start, length)
22
+ @buf = buf
23
+ @start = start
24
+ @pos = 0
25
+ @length = length
26
+ end
27
+
28
+ def parse_header_blocks
29
+
30
+ header_blocks = []
31
+
32
+ while @pos < @length
33
+ blk = parse_header_block()
34
+ BayLog.trace("h2: header block read: %s", blk)
35
+ header_blocks << blk
36
+ end
37
+
38
+ return header_blocks
39
+ end
40
+
41
+
42
+ private
43
+ def parse_header_block()
44
+ blk = HeaderBlock.new
45
+ index = get_byte
46
+ is_index_header_field = (index & 0x80) != 0
47
+ if is_index_header_field
48
+ # index header field
49
+ # 0 1 2 3 4 5 6 7
50
+ # +---+---+---+---+---+---+---+---+
51
+ # | 1 | Index (7+) |
52
+ # +---+---------------------------+
53
+ blk.op = HeaderBlock::INDEX
54
+ blk.index = index & 0x7F
55
+ else
56
+ # literal header field
57
+ update_index = (index & 0x40) != 0
58
+ if update_index
59
+ index = index & 0x3F
60
+ overload_index = (index != 0)
61
+ if overload_index
62
+ if index == 0x3F
63
+ index = index + get_hpack_int_rest
64
+ end
65
+ blk.op = HeaderBlock::OVERLOAD_KNOWN_HEADER
66
+ blk.index = index
67
+ # 0 1 2 3 4 5 6 7
68
+ # +---+---+---+---+---+---+---+---+
69
+ # | 0 | 1 | Index (6+) |
70
+ # +---+---+-----------------------+
71
+ # | H | Value Length (7+) |
72
+ # +---+---------------------------+
73
+ # | Value String (Length octets) |
74
+ # +-------------------------------+
75
+ blk.value = get_hpack_string
76
+ else
77
+ # new header name
78
+ # 0 1 2 3 4 5 6 7
79
+ # +---+---+---+---+---+---+---+---+
80
+ # | 0 | 1 | 0 |
81
+ # +---+---+-----------------------+
82
+ # | H | Name Length (7+) |
83
+ # +---+---------------------------+
84
+ # | Name String (Length octets) |
85
+ # +---+---------------------------+
86
+ # | H | Value Length (7+) |
87
+ # +---+---------------------------+
88
+ # | Value String (Length octets) |
89
+ # +-------------------------------+
90
+ blk.op = HeaderBlock::NEW_HEADER
91
+ blk.name = get_hpack_string
92
+ blk.value = get_hpack_string
93
+ end
94
+ else
95
+ update_dynamic_table_size = (index & 0x20) != 0
96
+ if update_dynamic_table_size
97
+ # 0 1 2 3 4 5 6 7
98
+ # +---+---+---+---+---+---+---+---+
99
+ # | 0 | 0 | 1 | Max size (5+) |
100
+ # +---+---------------------------+
101
+ size = index & 0x1F
102
+ if size == 0x1F
103
+ size = size + get_hpack_int_rest
104
+ end
105
+ blk.op = HeaderBlock::UPDATE_DYNAMIC_TABLE_SIZE
106
+ blk.size = size
107
+ else
108
+ # not update index
109
+ index = (index & 0xF)
110
+ if index != 0
111
+ # 0 1 2 3 4 5 6 7
112
+ # +---+---+---+---+---+---+---+---+
113
+ # | 0 | 0 | 0 | 0 | Index (4+) |
114
+ # +---+---+-----------------------+
115
+ # | H | Value Length (7+) |
116
+ # +---+---------------------------+
117
+ # | Value String (Length octets) |
118
+ # +-------------------------------+
119
+ #
120
+ # OR
121
+ #
122
+ # 0 1 2 3 4 5 6 7
123
+ # +---+---+---+---+---+---+---+---+
124
+ # | 0 | 0 | 0 | 1 | Index (4+) |
125
+ # +---+---+-----------------------+
126
+ # | H | Value Length (7+) |
127
+ # +---+---------------------------+
128
+ # | Value String (Length octets) |
129
+ # +-------------------------------+
130
+ if index == 0xF
131
+ index = index + get_hpack_int_rest
132
+ end
133
+ blk.op = HeaderBlock::KNOWN_HEADER
134
+ blk.index = index
135
+ blk.value = get_hpack_string
136
+ else
137
+ # literal header field
138
+ # 0 1 2 3 4 5 6 7
139
+ # +---+---+---+---+---+---+---+---+
140
+ # | 0 | 0 | 0 | 0 | 0 |
141
+ # +---+---+-----------------------+
142
+ # | H | Name Length (7+) |
143
+ # +---+---------------------------+
144
+ # | Name String (Length octets) |
145
+ # +---+---------------------------+
146
+ # | H | Value Length (7+) |
147
+ # +---+---------------------------+
148
+ # | Value String (Length octets) |
149
+ # +-------------------------------+
150
+ #
151
+ # OR
152
+ #
153
+ # 0 1 2 3 4 5 6 7
154
+ # +---+---+---+---+---+---+---+---+
155
+ # | 0 | 0 | 0 | 1 | 0 |
156
+ # +---+---+-----------------------+
157
+ # | H | Name Length (7+) |
158
+ # +---+---------------------------+
159
+ # | Name String (Length octets) |
160
+ # +---+---------------------------+
161
+ # | H | Value Length (7+) |
162
+ # +---+---------------------------+
163
+ # | Value String (Length octets) |
164
+ # +-------------------------------+
165
+ #
166
+ blk.op = HeaderBlock::UNKNOWN_HEADER
167
+ blk.name = get_hpack_string
168
+ blk.value = get_hpack_string
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ blk
175
+ end
176
+
177
+ def get_hpack_int(prefix, head)
178
+ max_val = 0xFF >> (8 - prefix)
179
+
180
+ first_byte = get_byte
181
+ first_val = first_byte & max_val
182
+ head[0] = first_byte >> prefix
183
+ if first_val != max_val
184
+ first_val
185
+ else
186
+ max_val + get_hpack_int_rest
187
+ end
188
+ end
189
+
190
+ def get_hpack_int_rest
191
+ rest = 0
192
+ i = 0
193
+ while true
194
+ data = get_byte
195
+ cont = (data & 0x80) != 0
196
+ value = data & 0x7F
197
+ rest = rest + (value << (i*7))
198
+ if !cont
199
+ break
200
+ end
201
+ i += 1
202
+ end
203
+ return rest
204
+ end
205
+
206
+ def get_hpack_string
207
+ is_huffman = [nil]
208
+ len = get_hpack_int(7, is_huffman)
209
+ data = StringUtil.alloc(len)
210
+ get_bytes data, len
211
+ if is_huffman[0] == 1
212
+ return HTree.decode(data)
213
+ else
214
+ # ASCII
215
+ return data
216
+ end
217
+ end
218
+
219
+ def get_byte
220
+ if @pos >= @length
221
+ raise ArgumentError.new("@pos=#{@pos} @len=#{@length}")
222
+ end
223
+
224
+ b = @buf[@start + @pos].ord & 0xff
225
+ @pos += 1
226
+ return b
227
+ end
228
+
229
+ def get_bytes(buf, len)
230
+ buf.replace(@buf[@start + @pos, len])
231
+ @pos += len
232
+ end
233
+
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
240
+
@@ -0,0 +1,101 @@
1
+ require 'baykit/bayserver/docker/http/h2/header_block'
2
+ require 'baykit/bayserver/util/string_util'
3
+
4
+ module Baykit
5
+ module BayServer
6
+ module Docker
7
+ module Http
8
+ module H2
9
+ class HeaderBlockRenderer
10
+
11
+ include Baykit::BayServer::Util
12
+
13
+ attr :buf
14
+
15
+ def initialize(buf)
16
+ @buf = buf
17
+ end
18
+
19
+ def render_header_blocks(header_blocks)
20
+
21
+ header_blocks.each do |blk|
22
+ render_header_block(blk)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def render_header_block(blk)
29
+ case blk.op
30
+ when HeaderBlock::INDEX
31
+ put_hpack_int(blk.index, 7, 1)
32
+
33
+ when HeaderBlock::OVERLOAD_KNOWN_HEADER
34
+ raise RuntimeError.new("IllegalState")
35
+
36
+ when HeaderBlock::NEW_HEADER
37
+ raise RuntimeError.new("Illegal State")
38
+
39
+ when HeaderBlock::KNOWN_HEADER
40
+ put_hpack_int(blk.index, 4, 0)
41
+ put_hpack_string(blk.value, false)
42
+
43
+ when HeaderBlock::UNKNOWN_HEADER
44
+ put_byte(0)
45
+ put_hpack_string(blk.name, false)
46
+ put_hpack_string(blk.value, false)
47
+
48
+ when HeaderBlock::UPDATE_DYNAMIC_TABLE_SIZE
49
+ raise RuntimeError.new("Illegal state")
50
+ end
51
+ end
52
+
53
+ def put_hpack_int(val, prefix, head)
54
+ max_val = 0xFF >> (8 -prefix)
55
+ head_val = (head << prefix) & 0xFF
56
+ if val < max_val
57
+ put_byte (val | head_val)
58
+ else
59
+ put_byte (head_val | max_val)
60
+ put_hpack_int_rest(val - max_val)
61
+ end
62
+ end
63
+
64
+ def put_hpack_int_rest(val)
65
+ while true
66
+ data = val & 0x7F
67
+ next_val = val >> 7
68
+ if next_val == 0
69
+ put_byte(data)
70
+ break
71
+ else
72
+ put_byte(data | 0x80)
73
+ val = next_val
74
+ end
75
+ end
76
+ end
77
+
78
+ def put_hpack_string(value, is_haffman)
79
+ if is_haffman
80
+ raise RuntimeError.new "Illegal State"
81
+ else
82
+ put_hpack_int(value.length, 7, 0)
83
+ put_bytes(value)
84
+ end
85
+ end
86
+
87
+ def put_byte(val)
88
+ @buf.put_byte(val)
89
+ end
90
+
91
+ def put_bytes(data)
92
+ @buf.put(data)
93
+ end
94
+
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
@@ -14,4 +14,6 @@ require 'baykit/bayserver/docker/http/h2/h2_warp_handler'
14
14
  require 'baykit/bayserver/docker/http/h2/header_block'
15
15
  require 'baykit/bayserver/docker/http/h2/header_block_analyzer'
16
16
  require 'baykit/bayserver/docker/http/h2/header_block_builder'
17
+ require 'baykit/bayserver/docker/http/h2/header_block_parser'
18
+ require 'baykit/bayserver/docker/http/h2/header_block_renderer'
17
19
  require 'baykit/bayserver/docker/http/h2/header_table'
@@ -1,4 +1,3 @@
1
- require 'baykit/bayserver/agent/transporter/package'
2
1
  require 'baykit/bayserver/docker/base/port_base'
3
2
  require 'baykit/bayserver/docker/http/h1/package'
4
3
 
@@ -1,4 +1,3 @@
1
- require 'baykit/bayserver/agent/transporter/package'
2
1
  require 'baykit/bayserver/protocol/packet_store'
3
2
  require 'baykit/bayserver/util/io_util'
4
3
  require 'baykit/bayserver/util/string_util'
@@ -17,7 +16,6 @@ module Baykit
17
16
 
18
17
  include Baykit::BayServer::Bcf
19
18
  include Baykit::BayServer::Protocol
20
- include Baykit::BayServer::WaterCraft
21
19
  include Baykit::BayServer::Util
22
20
  include Baykit::BayServer::Docker::Base
23
21
  include Baykit::BayServer::Docker::Http
@@ -1,6 +1,5 @@
1
1
  require 'openssl'
2
2
 
3
- require 'baykit/bayserver/agent/transporter/package'
4
3
  require 'baykit/bayserver/docker/base/port_base'
5
4
  require 'baykit/bayserver/docker/base/warp_base'
6
5
  require 'baykit/bayserver/protocol/packet_store'
@@ -16,7 +15,6 @@ module Baykit
16
15
  include Baykit::BayServer::Docker::Http::HtpDocker # implements
17
16
 
18
17
  include OpenSSL
19
- include Baykit::BayServer::Agent::Transporter
20
18
  include Baykit::BayServer::Protocol
21
19
  include Baykit::BayServer::Docker::Http::H1
22
20
  include Baykit::BayServer::Docker::Http::H2
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bayserver-docker-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michisuke-P
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-24 00:00:00.000000000 Z
11
+ date: 2026-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bayserver-core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 3.0.3
19
+ version: 3.3.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 3.0.3
26
+ version: 3.3.1
27
27
  description: BayServer is one of the high-speed web servers. It operates as a single-threaded,
28
28
  asynchronous server, which makes it exceptionally fast. It also supports multi-core
29
29
  processors, harnessing the full potential of the CPU's capabilities.
@@ -50,6 +50,7 @@ files:
50
50
  - lib/baykit/bayserver/docker/http/h1/h1_type.rb
51
51
  - lib/baykit/bayserver/docker/http/h1/h1_warp_handler.rb
52
52
  - lib/baykit/bayserver/docker/http/h1/package.rb
53
+ - lib/baykit/bayserver/docker/http/h2/command/cmd_continuation.rb
53
54
  - lib/baykit/bayserver/docker/http/h2/command/cmd_data.rb
54
55
  - lib/baykit/bayserver/docker/http/h2/command/cmd_go_away.rb
55
56
  - lib/baykit/bayserver/docker/http/h2/command/cmd_headers.rb
@@ -77,6 +78,8 @@ files:
77
78
  - lib/baykit/bayserver/docker/http/h2/header_block.rb
78
79
  - lib/baykit/bayserver/docker/http/h2/header_block_analyzer.rb
79
80
  - lib/baykit/bayserver/docker/http/h2/header_block_builder.rb
81
+ - lib/baykit/bayserver/docker/http/h2/header_block_parser.rb
82
+ - lib/baykit/bayserver/docker/http/h2/header_block_renderer.rb
80
83
  - lib/baykit/bayserver/docker/http/h2/header_table.rb
81
84
  - lib/baykit/bayserver/docker/http/h2/huffman/hnode.rb
82
85
  - lib/baykit/bayserver/docker/http/h2/huffman/htree.rb
@@ -90,7 +93,7 @@ homepage: https://baykit.yokohama
90
93
  licenses:
91
94
  - MIT
92
95
  metadata: {}
93
- post_install_message:
96
+ post_install_message:
94
97
  rdoc_options: []
95
98
  require_paths:
96
99
  - lib
@@ -105,8 +108,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
108
  - !ruby/object:Gem::Version
106
109
  version: '0'
107
110
  requirements: []
108
- rubygems_version: 3.1.6
109
- signing_key:
111
+ rubygems_version: 3.4.19
112
+ signing_key:
110
113
  specification_version: 4
111
114
  summary: HTTP docker of BayServer
112
115
  test_files: []