bayserver-docker-terminal 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 33d1e39cac0afb5af49bc8cc177e7bb275a63965dc9cf17ac288e5284dacab67
4
+ data.tar.gz: f27f672fb7d691d506accfdc699e121990d0b1e67994039657a96d79cdd306cf
5
+ SHA512:
6
+ metadata.gz: 2994251e531a31afd3d27f368bc321e8857d201d02834b438bcacaf5da0df72d40d5fd9d00b4817da71b865d37ed14d1dbdfdc38ae9806b635ce373d7cc38f19
7
+ data.tar.gz: be8c6e48f562cef7fd34f861a99fa582c2e84f468803bacc6ab49129aaf1856cfe8a77f6f1a469535e7f9289ccc7514e38753e99b4136e1db71699e8359514c8
@@ -0,0 +1,155 @@
1
+ require 'baykit/bayserver/agent/next_socket_action'
2
+ require 'baykit/bayserver/watercraft/yacht'
3
+ require 'baykit/bayserver/util/string_util'
4
+ require 'baykit/bayserver/util/reusable'
5
+
6
+ require 'baykit/bayserver/docker/terminal/hijackers_yacht'
7
+
8
+ require 'baykit/bayserver/docker/http/h1/h1_command_handler'
9
+
10
+ module Baykit
11
+ module BayServer
12
+ module Docker
13
+ module Terminal
14
+ class FullyHijackersYacht < HijackersYacht
15
+ include Baykit::BayServer::Docker::Http::H1::H1CommandHandler # implements
16
+
17
+ include Baykit::BayServer::Util
18
+ include Baykit::BayServer::Protocol
19
+ include Baykit::BayServer::Docker::Http::H1
20
+
21
+ STATE_READ_HEADER = 1
22
+ STATE_READ_CONTENT = 2
23
+ STATE_FINISHED = 3
24
+
25
+ attr :state
26
+ attr :packet_store
27
+ attr :packet_unpacker
28
+ attr :command_unpacker
29
+
30
+ def initialize
31
+ super
32
+ end
33
+
34
+ ######################################################
35
+ # Init method
36
+ ######################################################
37
+ #
38
+ def init(tur, io, tp)
39
+ super
40
+ @packet_store = PacketStore.new(tur.ship, H1PacketFactory.new)
41
+ @command_unpacker = H1CommandUnPacker.new(self, false)
42
+ @packet_unpacker = H1PacketUnPacker.new(@command_unpacker, @packet_store)
43
+ end
44
+
45
+ ######################################################
46
+ # implements Reusable
47
+ ######################################################
48
+
49
+ def reset()
50
+ super
51
+ @state = STATE_FINISHED
52
+ end
53
+
54
+ ######################################################
55
+ # implements Yacht
56
+ ######################################################
57
+
58
+ # Override
59
+ def notify_read(buf, adr)
60
+ @file_wrote_len += buf.length
61
+
62
+ BayLog.debug "#{self} read hijack #{buf.length} bytes: total=#{@file_wrote_len}"
63
+
64
+ return @packet_unpacker.bytes_received(buf)
65
+
66
+ end
67
+
68
+
69
+ ######################################################
70
+ # Implements H1CommandHandler
71
+ ######################################################
72
+
73
+ def handle_header(cmd)
74
+ if @state == STATE_FINISHED
75
+ change_state(STATE_READ_HEADER)
76
+ end
77
+
78
+ if @state != STATE_READ_HEADER
79
+ raise ProtocolException("Header command not expected: state=%d", @state)
80
+ end
81
+
82
+ if BayServer.harbor.trace_header?
83
+ BayLog.info("%s hijack: resStatus: %d", self, cmd.status)
84
+ end
85
+
86
+ cmd.headers.each do |nv|
87
+ @tour.res.headers.add(nv[0], nv[1])
88
+ if BayServer.harbor.trace_header?
89
+ BayLog.info("%s hijack: resHeader: %s=%s", self, nv[0], nv[1]);
90
+ end
91
+ end
92
+
93
+ @tour.res.headers.status = cmd.status != nil ? cmd.status : HttpStatus::OK
94
+ @tour.res.send_headers(@tour_id)
95
+
96
+ res_cont_len = @tour.res.headers.content_length
97
+ BayLog.debug("%s contLen in header: %d", self, res_cont_len)
98
+
99
+ if res_cont_len == 0 || cmd.status == HttpStatus::NOT_MODIFIED
100
+ end_res_content(@tour)
101
+ else
102
+ change_state(STATE_READ_CONTENT)
103
+ sid = @tour.ship.id()
104
+ @tour.res.set_consume_listener do |len, resume|
105
+ if resume
106
+ @tour.ship.resume(sid)
107
+ end
108
+ end
109
+ end
110
+ return NextSocketAction::CONTINUE
111
+ end
112
+
113
+ def handle_content(cmd)
114
+
115
+ if @state != STATE_READ_CONTENT
116
+ raise ProtocolException.new("Content command not expected")
117
+ end
118
+
119
+ available = @tour.res.send_content(@tour_id, cmd.buf, cmd.start, cmd.len)
120
+ if @tour.res.bytes_posted == @tour.res.bytes_limit
121
+ end_res_content(@tour)
122
+ return NextSocketAction::CONTINUE
123
+ elsif !available
124
+ return NextSocketAction::SUSPEND
125
+ else
126
+ NextSocketAction::CONTINUE
127
+ end
128
+ end
129
+
130
+ def handle_end_content(cmd)
131
+ # never called
132
+ raise Sink.new()
133
+ end
134
+
135
+ def finished()
136
+ return @state == STATE_FINISHED
137
+ end
138
+
139
+
140
+ private
141
+
142
+ def end_res_content(tur)
143
+ tur.res.end_content(Tour::TOUR_ID_NOCHECK)
144
+ reset()
145
+ end
146
+
147
+ def change_state(new_state)
148
+ @state = new_state
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+
@@ -0,0 +1,170 @@
1
+ require 'baykit/bayserver/agent/next_socket_action'
2
+ require 'baykit/bayserver/protocol/packet_store'
3
+ require 'baykit/bayserver/docker/http/h1/h1_packet_unpacker'
4
+ require 'baykit/bayserver/docker/http/h1/h1_command_unpacker'
5
+ require 'baykit/bayserver/util/string_util'
6
+ require 'baykit/bayserver/util/http_status'
7
+
8
+
9
+ module Baykit
10
+ module BayServer
11
+ module Docker
12
+ module Terminal
13
+ #
14
+ # Send data of hijacked response
15
+ #
16
+ class HijackedDataSender
17
+ include Baykit::BayServer::Agent::NonBlockingHandler::ChannelListener # implements
18
+ include Baykit::BayServer::Util
19
+ include Baykit::BayServer::Agent
20
+ include Baykit::BayServer::Protocol
21
+ include Baykit::BayServer::Docker::Http::H1
22
+
23
+ attr :tour
24
+ attr :tour_id
25
+ attr :fully
26
+
27
+ attr :file_wrote_len
28
+ attr :file_buf_list
29
+ attr :cur_file_idx
30
+ attr :read_buf_size
31
+ attr :cur_file_idx
32
+ attr :pipe_io
33
+
34
+ attr :packet_store
35
+ attr :packet_unpacker
36
+ attr :command_unpacker
37
+
38
+ DEFAULT_FREAD_BUF_SIZE = 8192
39
+
40
+ def initialize(tur, fully)
41
+ @tour = tur
42
+ @tour_id = @tour.tour_id
43
+ @fully = fully
44
+ @file_buf_list = []
45
+ @read_buf_size = tour.ship.protocol_handler.max_res_packet_data_size
46
+
47
+ if @fully
48
+ @packet_store = PacketStore.new(tur.ship, H1PacketFactory.new)
49
+ @command_unpacker = H1CommandUnPacker.new(self, false)
50
+ @packet_unpacker = H1PacketUnPacker.new(@command_unpacker, @packet_store)
51
+ end
52
+ reset
53
+ end
54
+
55
+ def reset
56
+ @file_wrote_len = 0
57
+ @cur_file_idx = -1
58
+ end
59
+
60
+ def ship
61
+ @tour.ship
62
+ end
63
+
64
+ def on_readable(chk_fd)
65
+ BayLog.debug "#{self} Hijack Readable"
66
+ check_socket(chk_fd)
67
+
68
+ buf = new_file_buffer
69
+ begin
70
+ @pipe_io.read_nonblock(@read_buf_size, buf)
71
+ rescue EOFError => e
72
+ BayLog.debug "#{self} Hijack EOF"
73
+ @tour.res.end_content(@tour_id)
74
+ return NextSocketAction::CLOSE
75
+ end
76
+
77
+ @file_wrote_len += buf.length
78
+
79
+ BayLog.debug "#{self} read hijack #{buf.length} bytes: total=#{@file_wrote_len}"
80
+
81
+ if @fully
82
+ return @packet_unpacker.bytes_received(buf)
83
+ else
84
+ available = @tour.res.send_content(@tour_id, buf, 0, buf.length)
85
+ if !available
86
+ NextSocketAction::SUSPEND
87
+ else
88
+ NextSocketAction::CONTINUE
89
+ end
90
+ end
91
+
92
+ end
93
+
94
+ def check_timeout(chk_fd, duration)
95
+ BayLog.debug "#{self} Hijack timeout(Ignore)"
96
+ end
97
+
98
+ def on_error(chk_fd, e)
99
+ BayLog.debug "#{self} Hijack Error"
100
+ check_socket(chk_fd)
101
+
102
+ BayLog.error_e e
103
+ end
104
+
105
+ def on_closed(chk_fd)
106
+ BayLog.debug "#{self} Hijack Closed(Ignore)"
107
+ check_socket(chk_fd)
108
+ end
109
+
110
+
111
+ def send_pipe_data(io)
112
+ BayLog.debug("#{self} Send hijacked data #{io.inspect}")
113
+ @pipe_io = io
114
+ @file_wrote_len = 0
115
+ @tour.ship.agent.non_blocking_handler.ask_to_read(@pipe_io)
116
+ end
117
+
118
+ # Implements H1CommandHandler
119
+ # Fully hijacked mode
120
+ def handle_header(cmd)
121
+ cmd.headers.each do |nv|
122
+ @tour.res.headers.add(nv[0], nv[1])
123
+ end
124
+
125
+ @tour.res.headers.status = cmd.status != nil ? cmd.status : HttpStatus::OK
126
+ @tour.send_headers(@tour_id)
127
+
128
+ return NextSocketAction::CONTINUE
129
+ end
130
+
131
+ # Implements H1CommandHandler
132
+ # Fully hijacked mode
133
+ def handle_content(cmd)
134
+ available = @tour.res.send_content(@tour_id, cmd.buf, cmd.start, cmd.len)
135
+ if !available
136
+ NextSocketAction::SUSPEND
137
+ else
138
+ NextSocketAction::CONTINUE
139
+ end
140
+ end
141
+
142
+ def resume
143
+ BayLog.debug("#{self} resume")
144
+ @tour.ship.agent.non_blocking_handler.ask_to_read(@pipe_io)
145
+ end
146
+
147
+ def to_s
148
+ "hijack[#{@pipe_io.inspect}]"
149
+ end
150
+
151
+ private
152
+ def check_socket(chk_fd)
153
+ if chk_fd != @pipe_io
154
+ raise RuntimeError.new("BUG: Invalid hijacked data sender instance (file was returned?): #{chk_fd}")
155
+ end
156
+ end
157
+
158
+ def new_file_buffer
159
+ @cur_file_idx += 1
160
+ if @file_buf_list.length == @cur_file_idx
161
+ @file_buf_list << StringUtil.alloc(@read_buf_size)
162
+ end
163
+ @file_buf_list[@cur_file_idx]
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+
@@ -0,0 +1,106 @@
1
+ require 'baykit/bayserver/agent/next_socket_action'
2
+ require 'baykit/bayserver/watercraft/yacht'
3
+ require 'baykit/bayserver/util/string_util'
4
+ require 'baykit/bayserver/util/reusable'
5
+
6
+ require 'baykit/bayserver/docker/http/h1/h1_command_handler'
7
+
8
+ module Baykit
9
+ module BayServer
10
+ module Docker
11
+ module Terminal
12
+ class HijackersYacht < Baykit::BayServer::WaterCraft::Yacht
13
+ include Baykit::BayServer::Docker::Http::H1::H1CommandHandler # implements
14
+
15
+ include Baykit::BayServer::Util
16
+ include Baykit::BayServer::Agent
17
+ include Baykit::BayServer::Protocol
18
+ include Baykit::BayServer::Docker::Http::H1
19
+
20
+ attr :tour
21
+ attr :tour_id
22
+
23
+ attr :file_wrote_len
24
+ attr :pipe_io
25
+
26
+ attr :packet_store
27
+ attr :packet_unpacker
28
+ attr :command_unpacker
29
+
30
+ def initialize
31
+ super
32
+ reset()
33
+ end
34
+
35
+ def to_s()
36
+ return "hijack##{@yacht_id}/#{@object_id} tour=#{@tour} id=#{@tour_id}";
37
+ end
38
+
39
+ ######################################################
40
+ # Init method
41
+ ######################################################
42
+
43
+ def init(tur, io, tp)
44
+ init_yacht()
45
+ @tour = tur
46
+ @tour_id = @tour.tour_id
47
+
48
+ tur.res.set_consume_listener do |len, resume|
49
+ if resume
50
+ tp.open_valve();
51
+ end
52
+ end
53
+ @pipe_io = io
54
+ @file_wrote_len = 0
55
+ @tour.ship.agent.non_blocking_handler.ask_to_read(@pipe_io)
56
+ end
57
+
58
+
59
+ ######################################################
60
+ # implements Reusable
61
+ ######################################################
62
+
63
+ def reset()
64
+ @file_wrote_len = 0
65
+ @file_len = 0
66
+ @tour = nil
67
+ @tour_id = 0
68
+ end
69
+
70
+ ######################################################
71
+ # implements Yacht
72
+ ######################################################
73
+
74
+ def notify_read(buf, adr)
75
+ @file_wrote_len += buf.length
76
+
77
+ BayLog.debug "#{self} read hijack #{buf.length} bytes: total=#{@file_wrote_len}"
78
+
79
+ available = @tour.res.send_content(@tour_id, buf, 0, buf.length)
80
+ if !available
81
+ return NextSocketAction::SUSPEND
82
+ else
83
+ return NextSocketAction::CONTINUE
84
+ end
85
+ end
86
+
87
+ def notify_eof()
88
+ BayLog.debug "#{self} Hijack EOF"
89
+ @tour.res.end_content(@tour_id)
90
+ return NextSocketAction::CLOSE
91
+ end
92
+
93
+ def notify_close()
94
+ BayLog.debug("%s Hijack Closed(Ignore)", self)
95
+ end
96
+
97
+ def check_timeout(duration)
98
+ BayLog.debug("%s Hijack timeout(Ignore)", self)
99
+ end
100
+
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+
@@ -0,0 +1,204 @@
1
+ require 'baykit/bayserver/agent/transporter/plain_transporter'
2
+ require 'baykit/bayserver/docker/base/port_base'
3
+ require 'baykit/bayserver/tours/content_consume_listener'
4
+
5
+ require 'baykit/bayserver/docker/terminal/fully_hijackers_yacht'
6
+ require 'baykit/bayserver/docker/terminal/terminal_train'
7
+
8
+ module Baykit
9
+ module BayServer
10
+ module Docker
11
+ module Terminal
12
+ class TerminalDocker < Baykit::BayServer::Docker::Base::ClubBase
13
+ include Baykit::BayServer::Bcf
14
+ include Baykit::BayServer::Util
15
+ include Baykit::BayServer::Agent::Transporter
16
+ include Baykit::BayServer::Tours
17
+
18
+ RACK_TERMINAL_PIPE = "rack.terminal.pipe"
19
+ DEFAULT_POST_CACHE_THRESHOLD = 1024 * 128 # 128 KB
20
+ RACK_ERR = "Cannot find rack package. If you want to use terminal docker, please install rack package like 'gem install rack'."
21
+
22
+ RACK_MULTITHREAD = 'rack.multithread'
23
+ RACK_MULTIPROCESS = 'rack.multiprocess'
24
+ RACK_RUNONCE = 'rack.run_once'
25
+ RACK_HIJACK_IO = 'rack.hijack_io'
26
+ HTTP_VERSION = 'HTTP_VERSION'
27
+
28
+ attr_accessor :app
29
+ attr :config
30
+ attr :environment
31
+ attr :post_cache_threshold
32
+ attr :available
33
+
34
+ def initialize
35
+ @post_cache_threshold = DEFAULT_POST_CACHE_THRESHOLD
36
+ @available = false
37
+ end
38
+
39
+ ######################################################
40
+ # Implements Docker
41
+ ######################################################
42
+
43
+ def init(elm, parent)
44
+ super
45
+
46
+ begin
47
+ require 'rack'
48
+ rescue LoadError => e
49
+ BayLog.error(RACK_ERR)
50
+ return
51
+ end
52
+
53
+ require 'rack/handler/bayserver'
54
+
55
+ if Rack::Handler::BayServer.app != nil
56
+ # rackup mode
57
+ @app = Rack::Handler::BayServer.app
58
+ else
59
+ if !StringUtil.set?(@config)
60
+ raise ConfigException.new(elm.file_name, elm.line_no, "Config not specified")
61
+ elsif not ::File.exist?(@config)
62
+ raise ConfigException.new(elm.file_name, elm.line_no, "Config not found: %s", @config)
63
+ end
64
+ if @environment == nil
65
+ @environment = "deployment"
66
+ end
67
+ options = {
68
+ :server => "terminal",
69
+ :config => @config,
70
+ :environment => @environment,
71
+ :docker => self,
72
+ }
73
+ Rack::Server.start options
74
+ end
75
+
76
+ @available = true
77
+ end
78
+
79
+ ######################################################
80
+ # Implements DockerBase
81
+ ######################################################
82
+
83
+ def init_key_val(kv)
84
+ case kv.key.downcase
85
+ when "config"
86
+ @config = Baykit::BayServer::BayServer.parse_path(kv.value)
87
+ when "environment"
88
+ @environment = kv.value
89
+ when "postcachethreshold"
90
+ @post_cache_threshold = kv.value.to_i
91
+ else
92
+ return super
93
+ end
94
+ return true
95
+ end
96
+
97
+ ######################################################
98
+ # Implements Club
99
+ ######################################################
100
+
101
+ def arrive(tur)
102
+
103
+ if not @available
104
+ tur.res.headers.set_content_type("text/plain")
105
+ tur.res.set_consume_listener(&ContentConsumeListener::DEV_NULL)
106
+ tur.res.send_headers(tur.id)
107
+ tur.res.send_content(tur.id, RACK_ERR, 0, RACK_ERR.length)
108
+ tur.res.end_content(tur.id)
109
+ return
110
+ end
111
+
112
+ if tur.req.uri.include? ".."
113
+ raise HttpException.new HttpStatus::FORBIDDEN, tur.req.uri
114
+ end
115
+
116
+ env = create_env tur
117
+ train = TerminalTrain.new(self, tur, @app, env)
118
+ train.start_tour()
119
+ end
120
+
121
+ def create_env(tur)
122
+ env = {}
123
+
124
+ cont_len = tur.req.headers.content_length()
125
+ if cont_len > 0
126
+ env["CONTENT_LENGTH"] = cont_len.to_s
127
+ end
128
+ cont_type = tur.req.headers.content_type()
129
+ if StringUtil.set? cont_type
130
+ env["CONTENT_TYPE"] = cont_type
131
+ end
132
+
133
+
134
+ env["GATEWAY_INTERFACE"] = "CGI/1.1"
135
+ #env[Rack::PATH_INFO] = tur.req.path_info == nil ? "" : tur.req.path_info
136
+ pos = tur.req.uri.index('?')
137
+ if pos and pos > 0
138
+ env[Rack::PATH_INFO] = tur.req.uri[0 .. pos-1]
139
+ else
140
+ env[Rack::PATH_INFO] = tur.req.uri
141
+ end
142
+ env[Rack::QUERY_STRING] = tur.req.query_string == nil ? "" : tur.req.query_string
143
+ env["REMOTE_ADDR"] = tur.req.remote_address
144
+ env["REMOTE_HOST"] = tur.req.remote_address # for performance reason
145
+ env["REMOTE_USER"] = tur.req.remote_user == nil ? "" : tur.req.remote_user
146
+ env[Rack::REQUEST_METHOD] = tur.req.method
147
+ env["REQUEST_URI"] = tur.req.uri
148
+ #env[Rack::SCRIPT_NAME] = tur.req.script_name == nil ? "" : tur.req.script_name
149
+ env[Rack::SCRIPT_NAME] = ""
150
+ env[Rack::SERVER_NAME] = tur.req.server_name
151
+ env[Rack::SERVER_PORT] = tur.req.server_port.to_s
152
+ env[Rack::SERVER_PROTOCOL] = tur.req.protocol
153
+ env["SERVER_SOFTWARE"] = Baykit::BayServer::BayServer.get_software_name
154
+
155
+ tur.req.headers.names.each do |name|
156
+ tur.req.headers.values(name).each do |val|
157
+ if /^content-type$/i =~ name || /^content-length$/i =~ name
158
+ next
159
+ end
160
+ name = "HTTP_" + name
161
+ name.gsub!(/-/o, "_")
162
+ name.upcase!
163
+ env[name] = val
164
+ end
165
+ end
166
+
167
+ env[Rack::RACK_VERSION] = Rack::VERSION
168
+ env[Rack::RACK_ERRORS] = STDERR
169
+ env[Rack::RACK_INPUT] = nil
170
+ env[RACK_MULTITHREAD] = true
171
+ env[RACK_MULTIPROCESS] = BayServer.harbor.multi_core?
172
+ env[RACK_RUNONCE] = false
173
+ env[Rack::RACK_URL_SCHEME] = tur.is_secure ? "https" : "http"
174
+ env[Rack::RACK_IS_HIJACK] = true
175
+
176
+ env[Rack::RACK_HIJACK] = lambda do
177
+ pip = IO.pipe
178
+ env[RACK_TERMINAL_PIPE] = pip
179
+
180
+ w_pipe = pip[1]
181
+
182
+ env[RACK_HIJACK_IO] = w_pipe
183
+
184
+ yat = FullyHijackersYacht.new()
185
+ bufsize = tur.ship.protocol_handler.max_res_packet_data_size()
186
+ tp = PlainTransporter.new(false, bufsize)
187
+
188
+ yat.init(tur, pip[0], tp)
189
+ tp.init(tur.ship.agent.non_blocking_handler, pip[0], yat)
190
+ tur.ship.resume(tur.ship_id)
191
+
192
+ w_pipe
193
+ end
194
+
195
+ env[RACK_HIJACK_IO] = nil
196
+
197
+ env[HTTP_VERSION] = tur.req.protocol
198
+ env
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,209 @@
1
+ require 'baykit/bayserver/agent/transporter/plain_transporter'
2
+ require 'baykit/bayserver/train/train'
3
+ require 'baykit/bayserver/train/train_runner'
4
+ require 'baykit/bayserver/tours/tour'
5
+ require 'baykit/bayserver/tours/req_content_handler'
6
+
7
+ require 'baykit/bayserver/util/string_util'
8
+ require 'baykit/bayserver/util/http_status'
9
+
10
+ require 'baykit/bayserver/docker/terminal/hijackers_yacht'
11
+
12
+ module Baykit
13
+ module BayServer
14
+ module Docker
15
+ module Terminal
16
+ class TerminalTrain < Baykit::BayServer::Train::Train
17
+ include Baykit::BayServer::Tours::ReqContentHandler # implements
18
+
19
+ include Baykit::BayServer::Agent::Transporter
20
+ include Baykit::BayServer::Util
21
+ include Baykit::BayServer::Train
22
+ include Baykit::BayServer::Tours
23
+
24
+ attr :terminal_docker
25
+ attr :tour
26
+ attr :tour_id
27
+ attr :app
28
+ attr :env
29
+
30
+ attr :req_available
31
+ attr :lock
32
+ attr :tmpfile
33
+ attr :req_cont
34
+
35
+ def initialize(terminal_docker, tur, app, env)
36
+ BayLog.debug "%s New Rack Train", tur
37
+ @terminal_docker = terminal_docker
38
+ @tour = tur
39
+ @tour_id = tur.tour_id
40
+ @app = app
41
+ @env = env
42
+ @available = false
43
+ @tmpfile = nil
44
+ @req_cont = nil
45
+
46
+ @lock = Mutex.new
47
+ end
48
+
49
+ def start_tour()
50
+ @tour.req.set_content_handler(self)
51
+ @tmpfile = nil
52
+
53
+ if @env["CONTENT_LENGTH"]
54
+ req_cont_len = @env["CONTENT_LENGTH"].to_i
55
+ else
56
+ req_cont_len = 0
57
+ end
58
+
59
+ if req_cont_len <= @terminal_docker.post_cache_threshold
60
+ # Cache content in memory
61
+ @req_cont = StringUtil.alloc(0)
62
+ else
63
+ # Content save on disk
64
+ @tmpfile = Tempfile.new("terminal_upload")
65
+ @tmpfile.binmode
66
+ end
67
+
68
+ end
69
+
70
+ def depart
71
+
72
+ begin
73
+ if @tour.req.method.casecmp?("post")
74
+ BayLog.debug("%s Terminal: posted: content-length: %s", @tour, @env["CONTENT_LENGTH"])
75
+ end
76
+
77
+
78
+ if BayServer.harbor.trace_header?
79
+ @env.keys.each do |key|
80
+ value = @env[key]
81
+ BayLog.info("%s Terminal: env:%s=%s", @tour, key, value)
82
+ end
83
+ end
84
+
85
+ status, headers, body = @app.call(@env)
86
+
87
+ # Hijack check
88
+ pip = @env[TerminalDocker::RACK_TERMINAL_PIPE]
89
+
90
+ if pip != nil
91
+ # Fully hijacked (Do nothing)
92
+ BayLog.debug("%s Tour is fully hijacked", @tour)
93
+
94
+ else
95
+ @tour.res.headers.status = status
96
+
97
+ hijack = nil
98
+ headers.each do | key, value |
99
+ if key == Rack::RACK_HIJACK
100
+ hijack = value
101
+ else
102
+ @tour.res.headers.add key, value
103
+ end
104
+ end
105
+
106
+ # Send headers
107
+ @tour.res.send_headers @tour_id
108
+
109
+ if hijack != nil
110
+ # Partially hijacked
111
+ BayLog.debug("%s Tour is partially hijacked", @tour)
112
+
113
+ pip = IO.pipe
114
+ yat = HijackersYacht.new()
115
+ bufsize = @tour.ship.protocol_handler.max_res_packet_data_size()
116
+ tp = PlainTransporter.new(false, bufsize)
117
+
118
+ yat.init(@tour, pip[0], tp)
119
+ tp.init(@tour.ship.agent.non_blocking_handler, pip[0], yat)
120
+ @tour.ship.resume(@tour.ship_id)
121
+
122
+ hijack.call pip[1]
123
+
124
+ else
125
+ # Not hijacked
126
+
127
+ # Setup consume listener
128
+ @tour.res.set_consume_listener() do |len, resume|
129
+ if(resume)
130
+ @available = true
131
+ end
132
+ end
133
+
134
+ # Send contents
135
+ body.each do | str |
136
+ bstr = StringUtil.to_bytes(str)
137
+ BayLog.trace("%s TerminalTask: read body: len=%d", @tour, bstr.length)
138
+ @available = @tour.res.send_content(@tour_id, bstr, 0, bstr.length)
139
+ while !@available
140
+ sleep 0.1
141
+ end
142
+ end
143
+
144
+ @tour.res.end_content(@tour_id)
145
+
146
+ end
147
+ end
148
+ rescue HttpException => e
149
+ raise e
150
+ rescue => e
151
+ BayLog.error_e e
152
+ raise HttpException.new HttpStatus::INTERNAL_SERVER_ERROR, "Terminal error"
153
+ ensure
154
+ if @tmpfile
155
+ @tmpfile.close()
156
+ end
157
+ end
158
+ end
159
+
160
+ def on_read_content(tur, buf, start, len)
161
+ BayLog.trace("%s TerminalTask:onReadContent: len=%d", @tour, len)
162
+
163
+ if @req_cont != nil
164
+ # Cache content in memory
165
+ @req_cont << buf[start, len]
166
+ else
167
+ # Content save on disk
168
+ @tmpfile.write(buf[start, len])
169
+ end
170
+
171
+ tur.req.consumed(Tour::TOUR_ID_NOCHECK, len)
172
+ true
173
+ end
174
+
175
+ def on_end_content(tur)
176
+ BayLog.trace("%s TerminalTask:endContent", @tour)
177
+
178
+ if @req_cont != nil
179
+ # Cache content in memory
180
+ rack_input = StringIO.new(@req_cont)
181
+ else
182
+ # Content save on disk
183
+ @tmpfile.rewind()
184
+ rack_input = @tmpfile
185
+ end
186
+ env[Rack::RACK_INPUT] = rack_input
187
+
188
+ if !TrainRunner.post(self)
189
+ raise HttpException.new(HttpStatus::SERVICE_UNAVAILABLE, "TrainRunner is busy")
190
+ end
191
+ end
192
+
193
+ def on_abort(tur)
194
+ BayLog.trace("%s TerminalTask:abort", @tour)
195
+ if @tmpfile
196
+ @tmpfile.close()
197
+ @tmpfile = nil
198
+ end
199
+ return false
200
+ end
201
+
202
+ def inspect
203
+ "TerminalTask #{@tour}"
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,66 @@
1
+ require 'rack/handler'
2
+ require 'baykit/bayserver/bayserver'
3
+ require 'baykit/bayserver/util/string_util'
4
+
5
+ module Rack
6
+ module Handler
7
+ module BayServer
8
+ include Baykit::BayServer::Util
9
+
10
+ class << self
11
+ attr :app
12
+ end
13
+ @app = nil
14
+
15
+ ENV_BSERV_HOME = Baykit::BayServer::BayServer::ENV_BSERV_HOME
16
+ ENV_BSERV_PLAN = Baykit::BayServer::BayServer::ENV_BSERV_PLAN
17
+
18
+ def self.run(app, **options)
19
+
20
+ @app = app
21
+
22
+ port = options[:Port]
23
+ host = options[:Host]
24
+ config = options[:config]
25
+ environment = options[:environment]
26
+ access_log = options[:AccessLog]
27
+
28
+ # Get bayserver home from environment
29
+ if StringUtil.set? ENV[ENV_BSERV_HOME]
30
+ bserv_home = ENV[ENV_BSERV_HOME]
31
+ else
32
+ raise "Set #{ENV_BSERV_HOME} environment variable"
33
+ end
34
+
35
+ # Get bayserver plan from evironment
36
+ if StringUtil.set? ENV[ENV_BSERV_PLAN]
37
+ bserv_plan = ENV[ENV_BSERV_PLAN]
38
+ else
39
+ bserv_plan = "/tmp/rack.plan"
40
+ plan_str = <<EOF
41
+ [harbor]
42
+ grandAgents 4
43
+
44
+ [port #{port}]
45
+ docker http
46
+
47
+ [city *]
48
+ [town /]
49
+ [club *]
50
+ docker terminal
51
+ EOF
52
+ ::File.write(bserv_plan, plan_str)
53
+ end
54
+
55
+ Baykit::BayServer::BayServer.init bserv_home, bserv_plan
56
+ Baykit::BayServer::BayServer.start
57
+ end
58
+
59
+ end
60
+
61
+
62
+
63
+
64
+ register :bayserver, BayServer
65
+ end
66
+ end
@@ -0,0 +1,17 @@
1
+ require 'rack/handler'
2
+
3
+
4
+ module Rack
5
+ module Handler
6
+ module Terminal
7
+
8
+ def self.run(app, **options)
9
+ dkr = options[:docker]
10
+ dkr.app = app
11
+ end
12
+ end
13
+
14
+ register :terminal, Terminal
15
+ end
16
+ end
17
+
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bayserver-docker-terminal
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Michisuke-P
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-08-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bayserver-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 2.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 2.2.0
27
+ description: AJP docker of BayServer
28
+ email: michisukep@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/baykit/bayserver/docker/terminal/fully_hijackers_yacht.rb
34
+ - lib/baykit/bayserver/docker/terminal/hijacked_data_sender.rb
35
+ - lib/baykit/bayserver/docker/terminal/hijackers_yacht.rb
36
+ - lib/baykit/bayserver/docker/terminal/terminal_docker.rb
37
+ - lib/baykit/bayserver/docker/terminal/terminal_train.rb
38
+ - lib/rack/handler/bayserver.rb
39
+ - lib/rack/handler/terminal.rb
40
+ homepage: https://baykit.yokohama
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.1.6
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: AJP docker of BayServer
63
+ test_files: []