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.
- checksums.yaml +7 -0
- data/lib/baykit/bayserver/docker/http/h1/command/cmd_content.rb +46 -0
- data/lib/baykit/bayserver/docker/http/h1/command/cmd_end_content.rb +37 -0
- data/lib/baykit/bayserver/docker/http/h1/command/cmd_header.rb +306 -0
- data/lib/baykit/bayserver/docker/http/h1/command/package.rb +3 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_command.rb +19 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_command_handler.rb +31 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_command_unpacker.rb +58 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_inbound_handler.rb +371 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_packet.rb +28 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_packet_factory.rb +21 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_packet_unpacker.rb +180 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_protocol_handler.rb +66 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_type.rb +18 -0
- data/lib/baykit/bayserver/docker/http/h1/h1_warp_handler.rb +228 -0
- data/lib/baykit/bayserver/docker/http/h1/package.rb +11 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_data.rb +65 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_go_away.rb +67 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_headers.rb +108 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_ping.rb +50 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_preface.rb +51 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_priority.rb +59 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_rst_stream.rb +50 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_settings.rb +98 -0
- data/lib/baykit/bayserver/docker/http/h2/command/cmd_window_update.rb +53 -0
- data/lib/baykit/bayserver/docker/http/h2/command/package.rb +9 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_command.rb +42 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_command_handler.rb +29 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_command_unpacker.rb +73 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_error_code.rb +53 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_flags.rb +82 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_inbound_handler.rb +417 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_packet.rb +204 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_packet_factory.rb +21 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_packet_unpacker.rb +224 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_protocol_handler.rb +58 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_settings.rb +42 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_type.rb +26 -0
- data/lib/baykit/bayserver/docker/http/h2/h2_warp_handler.rb +142 -0
- data/lib/baykit/bayserver/docker/http/h2/header_block.rb +191 -0
- data/lib/baykit/bayserver/docker/http/h2/header_block_analyzer.rb +88 -0
- data/lib/baykit/bayserver/docker/http/h2/header_block_builder.rb +68 -0
- data/lib/baykit/bayserver/docker/http/h2/header_table.rb +167 -0
- data/lib/baykit/bayserver/docker/http/h2/huffman/hnode.rb +28 -0
- data/lib/baykit/bayserver/docker/http/h2/huffman/htree.rb +339 -0
- data/lib/baykit/bayserver/docker/http/h2/package.rb +17 -0
- data/lib/baykit/bayserver/docker/http/htp_docker.rb +23 -0
- data/lib/baykit/bayserver/docker/http/htp_port_docker.rb +107 -0
- data/lib/baykit/bayserver/docker/http/htp_warp_docker.rb +125 -0
- data/lib/baykit/bayserver/docker/http/htp_warp_ship_helper.rb +19 -0
- data/lib/baykit/bayserver/docker/http/package.rb +6 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 527c638e9d578ec45401fdc8c854159c1d58c296f5376d2b0b6300cd09bd1369
|
4
|
+
data.tar.gz: 7af1ab702f3e1187aae38cd475be969f2fa14acdb302435b31b8eebfa8d3aa98
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 19584a94d22d79d4e77ada86ecaa3a89bca4abb3be6a370795043b70ff62f22744cdb54fac6eaf1af54e13c943b1a43e69867613ab3dfe597347ed26d02bada6
|
7
|
+
data.tar.gz: a492ea9fc756c6399e6a68a28d977763c53def2c6141734dab1c8c8be176a6e35255e65b22b9d5bf0d2330aa4c3e20252f07adbe70378ccd008410325e16a2dd
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'baykit/bayserver/docker/http/h1/h1_command'
|
2
|
+
|
3
|
+
module Baykit
|
4
|
+
module BayServer
|
5
|
+
module Docker
|
6
|
+
module Http
|
7
|
+
module H1
|
8
|
+
module Command
|
9
|
+
|
10
|
+
class CmdContent < Baykit::BayServer::Docker::Http::H1::H1Command
|
11
|
+
|
12
|
+
attr :buf
|
13
|
+
attr :start
|
14
|
+
attr :len
|
15
|
+
|
16
|
+
def initialize(buf = nil, start = nil, len = nil)
|
17
|
+
super(H1Type::CONTENT)
|
18
|
+
@buf = buf
|
19
|
+
@start = start
|
20
|
+
@len = len
|
21
|
+
end
|
22
|
+
|
23
|
+
def unpack(pkt)
|
24
|
+
@buf = pkt.buf
|
25
|
+
@start = pkt.header_len
|
26
|
+
@len = pkt.data_len()
|
27
|
+
end
|
28
|
+
|
29
|
+
def pack(pkt)
|
30
|
+
acc = pkt.new_data_accessor
|
31
|
+
acc.put_bytes(@buf, @start, @len)
|
32
|
+
end
|
33
|
+
|
34
|
+
def handle(cmd_handler)
|
35
|
+
return cmd_handler.handle_content(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'baykit/bayserver/docker/http/h1/h1_command'
|
2
|
+
|
3
|
+
module Baykit
|
4
|
+
module BayServer
|
5
|
+
module Docker
|
6
|
+
module Http
|
7
|
+
module H1
|
8
|
+
module Command
|
9
|
+
|
10
|
+
#
|
11
|
+
# Dummy packet (empty packet) to notify contents are sent
|
12
|
+
#
|
13
|
+
class CmdEndContent < Baykit::BayServer::Docker::Http::H1::H1Command
|
14
|
+
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
super(H1Type::END_CONTENT)
|
18
|
+
end
|
19
|
+
|
20
|
+
def unpack(pkt)
|
21
|
+
end
|
22
|
+
|
23
|
+
def pack(pkt)
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle(cmd_handler)
|
27
|
+
return cmd_handler.handle_end_content(self)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,306 @@
|
|
1
|
+
require 'baykit/bayserver/docker/http/h1/command/package'
|
2
|
+
require 'baykit/bayserver/protocol/package'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Header format
|
6
|
+
#
|
7
|
+
# generic-message = start-line
|
8
|
+
# *(message-header CRLF)
|
9
|
+
# CRLF
|
10
|
+
# [ message-body ]
|
11
|
+
# start-line = Request-Line | Status-Line
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# message-header = field-name ":" [ field-value ]
|
15
|
+
# field-name = token
|
16
|
+
# field-value = *( field-content | LWS )
|
17
|
+
# field-content = <the OCTETs making up the field-value
|
18
|
+
# and consisting of either *TEXT or combinations
|
19
|
+
# of token, separators, and quoted-string>
|
20
|
+
#
|
21
|
+
module Baykit
|
22
|
+
module BayServer
|
23
|
+
module Docker
|
24
|
+
module Http
|
25
|
+
module H1
|
26
|
+
module Command
|
27
|
+
|
28
|
+
class CmdHeader < Baykit::BayServer::Docker::Http::H1::H1Command
|
29
|
+
include Baykit::BayServer::Protocol
|
30
|
+
include Baykit::BayServer::Util
|
31
|
+
|
32
|
+
STATE_READ_FIRST_LINE = 1
|
33
|
+
STATE_READ_MESSAGE_HEADERS = 2
|
34
|
+
|
35
|
+
CR_CODE_POINT = "\r".codepoints[0]
|
36
|
+
LF_CODE_POINT = "\n".codepoints[0]
|
37
|
+
|
38
|
+
attr :headers
|
39
|
+
attr :is_req_header # request packet
|
40
|
+
attr_accessor :method, :uri, :version
|
41
|
+
attr_accessor :status
|
42
|
+
|
43
|
+
def initialize(is_req_header)
|
44
|
+
super(H1Type::HEADER)
|
45
|
+
@headers = []
|
46
|
+
@is_req_header = is_req_header
|
47
|
+
@method = nil
|
48
|
+
@uri = nil
|
49
|
+
@version = nil
|
50
|
+
@status = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def CmdHeader.new_req_header(method, uri, version)
|
54
|
+
h = CmdHeader.new(true)
|
55
|
+
h.method = method
|
56
|
+
h.uri = uri
|
57
|
+
h.version = version
|
58
|
+
return h
|
59
|
+
end
|
60
|
+
|
61
|
+
def CmdHeader.new_res_header(headers, version)
|
62
|
+
h = CmdHeader.new(false)
|
63
|
+
h.version = version
|
64
|
+
h.status = headers.status
|
65
|
+
headers.names.each do |name|
|
66
|
+
headers.values(name).each do |value|
|
67
|
+
h.add_header name, value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
return h
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_header(name, value)
|
74
|
+
if name == nil
|
75
|
+
raise Sink.new("name is nil")
|
76
|
+
end
|
77
|
+
if value == nil
|
78
|
+
BayLog.warn("Header value is nil: %s", name)
|
79
|
+
return
|
80
|
+
end
|
81
|
+
|
82
|
+
if !name.kind_of?(String)
|
83
|
+
BayLog.error("header name is not string: name=%s value=%s", name, value)
|
84
|
+
raise Sink.new("IllegalArgument")
|
85
|
+
end
|
86
|
+
if !value.kind_of?(String)
|
87
|
+
BayLog.error("header value is not string: name=%s value=%s", name, value)
|
88
|
+
raise Sink.new("IllegalArgument")
|
89
|
+
end
|
90
|
+
|
91
|
+
@headers.append([name, value])
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_header(name, value)
|
95
|
+
if name == nil
|
96
|
+
raise Sink.new("Nil")
|
97
|
+
end
|
98
|
+
if value == nil
|
99
|
+
BayLog.warn("Header value is null: %s", name)
|
100
|
+
return
|
101
|
+
end
|
102
|
+
|
103
|
+
if !name.kind_of?(String)
|
104
|
+
raise Sink.new("IllegalArgument")
|
105
|
+
end
|
106
|
+
if !value.kind_of?(String)
|
107
|
+
raise Sink.new("IllegalArgument")
|
108
|
+
end
|
109
|
+
|
110
|
+
@headers.each do |nv|
|
111
|
+
if nv[0].casecmp?(name)
|
112
|
+
nv[1] = value
|
113
|
+
return
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
headers.append([name, value])
|
118
|
+
end
|
119
|
+
|
120
|
+
def unpack(pkt)
|
121
|
+
acc = pkt.new_data_accessor
|
122
|
+
data_len = pkt.data_len()
|
123
|
+
state = STATE_READ_FIRST_LINE
|
124
|
+
|
125
|
+
line_start_pos = 0
|
126
|
+
line_len = 0
|
127
|
+
|
128
|
+
data_len.times do |pos|
|
129
|
+
b = acc.get_byte
|
130
|
+
case b
|
131
|
+
when CharUtil::CR_BYTE
|
132
|
+
next
|
133
|
+
|
134
|
+
when CharUtil::LF_BYTE
|
135
|
+
if line_len == 0
|
136
|
+
break
|
137
|
+
end
|
138
|
+
if state == STATE_READ_FIRST_LINE
|
139
|
+
if @is_req_header
|
140
|
+
unpack_request_line(pkt.buf, line_start_pos, line_len)
|
141
|
+
else
|
142
|
+
unpack_status_line(pkt.buf, line_start_pos, line_len)
|
143
|
+
end
|
144
|
+
|
145
|
+
state = STATE_READ_MESSAGE_HEADERS
|
146
|
+
else
|
147
|
+
unpack_message_header(pkt.buf, line_start_pos, line_len)
|
148
|
+
end
|
149
|
+
|
150
|
+
line_len = 0
|
151
|
+
line_start_pos = pos + 1
|
152
|
+
|
153
|
+
else
|
154
|
+
line_len += 1
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
if state == STATE_READ_FIRST_LINE
|
160
|
+
raise RuntimeError.new("Invalid HTTP header format")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def pack(pkt)
|
165
|
+
acc = pkt.new_data_accessor
|
166
|
+
if @is_req_header
|
167
|
+
pack_request_line(acc)
|
168
|
+
else
|
169
|
+
pack_status_line(acc)
|
170
|
+
end
|
171
|
+
|
172
|
+
@headers.each do |nv|
|
173
|
+
#@BayServer.debug "Packe header #{nv[0]}=#{nv[1]}"
|
174
|
+
pack_message_header(acc, nv[0], nv[1])
|
175
|
+
end
|
176
|
+
|
177
|
+
pack_end_header(acc)
|
178
|
+
#BayLog.debug "#{self} pack header data header=#{pkt.header.length} bytes data=#{pkt.data.length} bytes"
|
179
|
+
#BayLog.debug "#{self} pack header data: #{pkt.data.bytes}"
|
180
|
+
end
|
181
|
+
|
182
|
+
def handle(cmd_handler)
|
183
|
+
return cmd_handler.handle_header(self)
|
184
|
+
end
|
185
|
+
|
186
|
+
def to_s
|
187
|
+
"CommandHeader[H1]"
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
def unpack_request_line (buf, start, len)
|
192
|
+
line = buf[start, len]
|
193
|
+
items = line.split(" ")
|
194
|
+
if items.length != 3
|
195
|
+
raise ProtocolException.new(BayMessage.get(:HTP_INVALID_FIRST_LINE, line))
|
196
|
+
end
|
197
|
+
|
198
|
+
@method = items[0]
|
199
|
+
@uri = items[1]
|
200
|
+
@version = items[2]
|
201
|
+
end
|
202
|
+
|
203
|
+
def unpack_status_line(buf, start, len)
|
204
|
+
line = buf[start, len]
|
205
|
+
items = line.split(" ")
|
206
|
+
|
207
|
+
if items.length < 2
|
208
|
+
raise ProtocolException.new BayMessage.get(:HTP_INVALID_FIRST_LINE, line)
|
209
|
+
end
|
210
|
+
|
211
|
+
@version = items[0]
|
212
|
+
@status = items[1].to_i
|
213
|
+
end
|
214
|
+
|
215
|
+
def unpack_message_header(bytes, start, len)
|
216
|
+
buf = ""
|
217
|
+
read_name = true
|
218
|
+
name = nil
|
219
|
+
skipping = true
|
220
|
+
|
221
|
+
len.times do |i|
|
222
|
+
b = bytes[start + i]
|
223
|
+
if skipping && b == ' '
|
224
|
+
next
|
225
|
+
elsif read_name && b == ":"
|
226
|
+
# header name completed
|
227
|
+
name = buf
|
228
|
+
buf = ""
|
229
|
+
skipping = true
|
230
|
+
read_name = false
|
231
|
+
else
|
232
|
+
if read_name
|
233
|
+
# make the case of header name be lower force
|
234
|
+
buf.concat(b.downcase)
|
235
|
+
else
|
236
|
+
# header value
|
237
|
+
buf.concat(b)
|
238
|
+
end
|
239
|
+
skipping = false
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
if name == nil
|
244
|
+
raise ProtocolException.new BayMessage.get(:HTP_INVALID_HEADER_FORMAT, "")
|
245
|
+
end
|
246
|
+
|
247
|
+
value = buf
|
248
|
+
|
249
|
+
add_header(name, value)
|
250
|
+
|
251
|
+
#if(BayLog.trace_mode?)
|
252
|
+
# BayLog.trace("#{self} receive header: #{name}(#{name.length})=#{value}(#{value.length})")
|
253
|
+
#end
|
254
|
+
end
|
255
|
+
|
256
|
+
def pack_request_line(acc)
|
257
|
+
acc.put_string(@method)
|
258
|
+
acc.put_bytes(" ")
|
259
|
+
acc.put_string(@uri)
|
260
|
+
acc.put_bytes(" ")
|
261
|
+
acc.put_string(@version);
|
262
|
+
acc.put_bytes(CharUtil::CRLF)
|
263
|
+
end
|
264
|
+
|
265
|
+
def pack_status_line(acc)
|
266
|
+
desc = HttpStatus.description(@status)
|
267
|
+
|
268
|
+
if version != nil && version.casecmp?("HTTP/1.1")
|
269
|
+
acc.put_bytes("HTTP/1.1")
|
270
|
+
else
|
271
|
+
acc.put_bytes("HTTP/1.0")
|
272
|
+
end
|
273
|
+
|
274
|
+
# status
|
275
|
+
acc.put_bytes(" ")
|
276
|
+
acc.put_string(@status.to_s)
|
277
|
+
acc.put_bytes(" ")
|
278
|
+
acc.put_string(desc)
|
279
|
+
acc.put_bytes(CharUtil::CRLF)
|
280
|
+
end
|
281
|
+
|
282
|
+
def pack_message_header(acc, name, value)
|
283
|
+
if !name.kind_of?(String)
|
284
|
+
raise RuntimeError.new("IllegalArgument: #{name}")
|
285
|
+
end
|
286
|
+
if !value.kind_of?(String)
|
287
|
+
raise RuntimeError.new("IllegalArgument: #{value}")
|
288
|
+
end
|
289
|
+
acc.put_string(name)
|
290
|
+
acc.put_bytes(":")
|
291
|
+
acc.put_string(value)
|
292
|
+
acc.put_bytes(CharUtil::CRLF)
|
293
|
+
end
|
294
|
+
|
295
|
+
def pack_end_header(acc)
|
296
|
+
acc.put_bytes(CharUtil::CRLF)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'baykit/bayserver/protocol/command'
|
2
|
+
|
3
|
+
module Baykit
|
4
|
+
module BayServer
|
5
|
+
module Docker
|
6
|
+
module Http
|
7
|
+
module H1
|
8
|
+
class H1Command < Baykit::BayServer::Protocol::Command
|
9
|
+
def initialize(type)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
module Baykit
|
3
|
+
module BayServer
|
4
|
+
module Docker
|
5
|
+
module Http
|
6
|
+
module H1
|
7
|
+
module H1CommandHandler # interface
|
8
|
+
include Baykit::BayServer::Protocol::CommandHandler # implements
|
9
|
+
|
10
|
+
def handle_header(cmd)
|
11
|
+
raise NotImplementedError.new()
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_content(cmd)
|
15
|
+
raise NotImplementedError.new()
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle_end_content(cmd)
|
19
|
+
raise NotImplementedError.new()
|
20
|
+
end
|
21
|
+
|
22
|
+
def finished()
|
23
|
+
raise NotImplementedError.new()
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'baykit/bayserver/sink'
|
2
|
+
require 'baykit/bayserver/protocol/package'
|
3
|
+
require 'baykit/bayserver/agent/next_socket_action'
|
4
|
+
require 'baykit/bayserver/docker/http/h1/package'
|
5
|
+
require 'baykit/bayserver/docker/http/h1/command/package'
|
6
|
+
|
7
|
+
module Baykit
|
8
|
+
module BayServer
|
9
|
+
module Docker
|
10
|
+
module Http
|
11
|
+
module H1
|
12
|
+
class H1CommandUnPacker < Baykit::BayServer::Protocol::CommandUnPacker
|
13
|
+
|
14
|
+
include Baykit::BayServer::Agent
|
15
|
+
include Baykit::BayServer::Docker::Http::H1::Command
|
16
|
+
|
17
|
+
attr :command_handler
|
18
|
+
attr :server_mode
|
19
|
+
|
20
|
+
def initialize(cmd_handler, svr_mode)
|
21
|
+
@cmd_handler = cmd_handler
|
22
|
+
@server_mode = svr_mode
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def packet_received(pkt)
|
30
|
+
BayLog.debug("h1: read packet type=%d length=%d", pkt.type, pkt.data_len())
|
31
|
+
|
32
|
+
case pkt.type
|
33
|
+
when H1Type::HEADER
|
34
|
+
cmd = CmdHeader.new(@server_mode)
|
35
|
+
|
36
|
+
when H1Type::CONTENT
|
37
|
+
cmd = CmdContent.new()
|
38
|
+
|
39
|
+
else
|
40
|
+
reset
|
41
|
+
raise Sink.new("IllegalState")
|
42
|
+
end
|
43
|
+
|
44
|
+
cmd.unpack pkt
|
45
|
+
return cmd.handle(@cmd_handler)
|
46
|
+
end
|
47
|
+
|
48
|
+
def finished()
|
49
|
+
return @cmd_handler.finished()
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|