bayserver-docker-cgi 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/baykit/bayserver/docker/cgi/cgi_docker.rb +226 -0
- data/lib/baykit/bayserver/docker/cgi/cgi_message.rb +33 -0
- data/lib/baykit/bayserver/docker/cgi/cgi_req_content_handler.rb +136 -0
- data/lib/baykit/bayserver/docker/cgi/cgi_std_err_yacht.rb +81 -0
- data/lib/baykit/bayserver/docker/cgi/cgi_std_out_yacht.rb +158 -0
- data/lib/baykit/bayserver/docker/cgi/cgi_train.rb +182 -0
- data/lib/baykit/bayserver/docker/cgi/php_cgi_docker.rb +41 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8c40b3461b0d48853cda84ce66339ccd38cb7c8df440545db4704bc977d7d222
|
4
|
+
data.tar.gz: 55fbb0b776f0f507ea2c992d42e763ee8b4be06c3832f9bf0edb639a22724604
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aab5f4a311b0d0b1f5290485b8bffa43f149dc34b541618ead9b4c814494505f9d353c37cc129f4859d439b30aa123bf8012e0f25a9a7c377d744846401d2d42
|
7
|
+
data.tar.gz: d2e34ba6288296842337128f1bd13dc35b219fb6ad6dce045e0ba6aa963a36bfc2c92a2b12eefe4d99407395a449f9666d0f5dc7d7b526a5e07c10a4d4d3dcaf
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'baykit/bayserver/bcf/package'
|
2
|
+
require 'baykit/bayserver/agent/transporter/plain_transporter'
|
3
|
+
require 'baykit/bayserver/agent/transporter/spin_read_transporter'
|
4
|
+
require 'baykit/bayserver/tours/tour'
|
5
|
+
require 'baykit/bayserver/tours/read_file_taxi'
|
6
|
+
require 'baykit/bayserver/docker/base/club_base'
|
7
|
+
require 'baykit/bayserver/docker/harbor'
|
8
|
+
require 'baykit/bayserver/docker/cgi/cgi_req_content_handler'
|
9
|
+
require 'baykit/bayserver/docker/cgi/cgi_std_out_yacht'
|
10
|
+
require 'baykit/bayserver/docker/cgi/cgi_std_err_yacht'
|
11
|
+
require 'baykit/bayserver/docker/cgi/cgi_message'
|
12
|
+
require 'baykit/bayserver/taxi/taxi_runner'
|
13
|
+
require 'baykit/bayserver/util/http_status'
|
14
|
+
require 'baykit/bayserver/util/cgi_util'
|
15
|
+
require 'baykit/bayserver/util/sys_util'
|
16
|
+
|
17
|
+
module Baykit
|
18
|
+
module BayServer
|
19
|
+
module Docker
|
20
|
+
module Cgi
|
21
|
+
class CgiDocker < Baykit::BayServer::Docker::Base::ClubBase
|
22
|
+
include Baykit::BayServer::Bcf
|
23
|
+
include Baykit::BayServer::Util
|
24
|
+
include Baykit::BayServer::Agent
|
25
|
+
include Baykit::BayServer::Agent::Transporter
|
26
|
+
include Baykit::BayServer::Docker
|
27
|
+
include Baykit::BayServer::Docker::Cgi
|
28
|
+
include Baykit::BayServer::Tours
|
29
|
+
include Baykit::BayServer::Taxi
|
30
|
+
|
31
|
+
DEFAULT_PROC_READ_METHOD = Harbor::FILE_SEND_METHOD_TAXI
|
32
|
+
DEFAULT_TIMEOUT_SEC = 60
|
33
|
+
|
34
|
+
attr :interpreter
|
35
|
+
attr :script_base
|
36
|
+
attr :doc_root
|
37
|
+
|
38
|
+
# Method to read stdin/stderr
|
39
|
+
attr :proc_read_method
|
40
|
+
|
41
|
+
def initialize()
|
42
|
+
super
|
43
|
+
@interpreter = nil
|
44
|
+
@script_base = nil
|
45
|
+
@doc_root = nil
|
46
|
+
@proc_read_method = CgiDocker::DEFAULT_PROC_READ_METHOD
|
47
|
+
@timeout_sec = CgiDocker::DEFAULT_TIMEOUT_SEC
|
48
|
+
end
|
49
|
+
|
50
|
+
######################################################
|
51
|
+
# Implements Docker
|
52
|
+
######################################################
|
53
|
+
|
54
|
+
def init(elm, parent)
|
55
|
+
super
|
56
|
+
|
57
|
+
if @proc_read_method == Harbor::FILE_SEND_METHOD_SELECT and !SysUtil.support_select_pipe()
|
58
|
+
BayLog.warn(BayMessage.get(:CGI_PROC_READ_METHOD_SELECT_NOT_SUPPORTED))
|
59
|
+
@proc_read_method = Harbor::FILE_SEND_METHOD_TAXI
|
60
|
+
end
|
61
|
+
|
62
|
+
if @proc_read_method == Harbor::FILE_SEND_METHOD_SPIN and !SysUtil.support_nonblock_pipe_read()
|
63
|
+
BayLog.warn(BayMessage.get(:CGI_PROC_READ_METHOD_SPIN_NOT_SUPPORTED))
|
64
|
+
@proc_read_method = Harbor::FILE_SEND_METHOD_TAXI
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
######################################################
|
70
|
+
# Implements DockerBase
|
71
|
+
######################################################
|
72
|
+
|
73
|
+
def init_key_val(kv)
|
74
|
+
case kv.key.downcase
|
75
|
+
when "interpreter"
|
76
|
+
@interpreter = kv.value
|
77
|
+
|
78
|
+
when "scriptbase"
|
79
|
+
@script_base = kv.value
|
80
|
+
|
81
|
+
when "docroot"
|
82
|
+
@doc_root = kv.value
|
83
|
+
|
84
|
+
when "processreadmethod"
|
85
|
+
case kv.value.downcase()
|
86
|
+
|
87
|
+
when "select"
|
88
|
+
@proc_read_method = Harbor::FILE_SEND_METHOD_SELECT
|
89
|
+
|
90
|
+
when "spin"
|
91
|
+
@proc_read_method = Harbor::FILE_SEND_METHOD_SPIN
|
92
|
+
|
93
|
+
when "taxi"
|
94
|
+
@proc_read_method = Harbor::FILE_SEND_METHOD_TAXI
|
95
|
+
|
96
|
+
when "timeout"
|
97
|
+
@timeout_sec = int(kv.value)
|
98
|
+
|
99
|
+
else
|
100
|
+
raise ConfigException.new(kv.file_name, kv.line_no, BayMessage.get(:CFG_INVALID_PARAMETER_VALUE, kv.value))
|
101
|
+
end
|
102
|
+
else
|
103
|
+
return super
|
104
|
+
end
|
105
|
+
return true
|
106
|
+
end
|
107
|
+
|
108
|
+
######################################################
|
109
|
+
# Implements Club
|
110
|
+
######################################################
|
111
|
+
|
112
|
+
def arrive(tur)
|
113
|
+
|
114
|
+
if tur.req.uri.include?("..")
|
115
|
+
raise HttpException.new(HttpStatus::FORBIDDEN, tur.req.uri)
|
116
|
+
return
|
117
|
+
end
|
118
|
+
|
119
|
+
base = script_base
|
120
|
+
if base == nil
|
121
|
+
base = tur.town.location()
|
122
|
+
end
|
123
|
+
|
124
|
+
if StringUtil.empty?(base)
|
125
|
+
raise HttpException.new(HttpStatus::INTERNAL_SERVER_ERROR, "%s scriptBase of cgi docker or location of town is not specified.", tur.town)
|
126
|
+
end
|
127
|
+
|
128
|
+
root = doc_root
|
129
|
+
if root == nil
|
130
|
+
root = tur.town.location()
|
131
|
+
end
|
132
|
+
|
133
|
+
if StringUtil.empty?(root)
|
134
|
+
raise HttpException.new(HttpStatus::INTERNAL_SERVER_ERROR, "$s docRoot of cgi docker or location of town is not specified.", tur.town)
|
135
|
+
end
|
136
|
+
|
137
|
+
env = CgiUtil.get_env_hash(tur.town.name, root, base, tur)
|
138
|
+
if BayServer.harbor.trace_header?
|
139
|
+
env.keys.each do |name|
|
140
|
+
value = env[name]
|
141
|
+
BayLog.info("%s cgi: env: %s=%s", tur, name, value)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
file_name = env[CgiUtil::SCRIPT_FILENAME]
|
146
|
+
if !File.file?(file_name)
|
147
|
+
raise HttpException.new(HttpStatus::NOT_FOUND, file_name)
|
148
|
+
end
|
149
|
+
|
150
|
+
bufsize = 8192;
|
151
|
+
handler = CgiReqContentHandler.new(self, tur)
|
152
|
+
tur.req.set_content_handler(handler)
|
153
|
+
handler.start_tour(env)
|
154
|
+
fname = "cgi#"
|
155
|
+
|
156
|
+
out_yat = CgiStdOutYacht.new()
|
157
|
+
err_yat = CgiStdErrYacht.new()
|
158
|
+
|
159
|
+
case(@proc_read_method)
|
160
|
+
when Harbor::FILE_SEND_METHOD_SELECT
|
161
|
+
out_tp = PlainTransporter.new(false, bufsize)
|
162
|
+
out_yat.init(tur, out_tp)
|
163
|
+
out_tp.init(tur.ship.agent.non_blocking_handler, handler.std_out[0], out_yat)
|
164
|
+
out_tp.open_valve()
|
165
|
+
|
166
|
+
err_tp = PlainTransporter.new(false, bufsize)
|
167
|
+
err_yat.init(tur)
|
168
|
+
err_tp.init(tur.ship.agent.non_blocking_handler, handler.std_err[0], err_yat)
|
169
|
+
err_tp.open_valve()
|
170
|
+
|
171
|
+
when Harbor::FILE_SEND_METHOD_SPIN
|
172
|
+
|
173
|
+
def eof_checker()
|
174
|
+
begin
|
175
|
+
pid = Process.wait(handler.pid, Process::WNOHANG)
|
176
|
+
return pid != nil
|
177
|
+
rescue Errno::ECHILD => e
|
178
|
+
BayLog.error_e(e)
|
179
|
+
return true
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
out_tp = SpinReadTransporter.new(bufsize)
|
184
|
+
out_yat.init(tur, out_tp)
|
185
|
+
out_tp.init(tur.ship.agent.spin_handler, out_yat, handler.std_out[0], -1, @timeout_sec, eof_checker)
|
186
|
+
out_tp.open_valve()
|
187
|
+
|
188
|
+
err_tp = SpinReadTransporter.new(bufsize)
|
189
|
+
err_yat.init(tur)
|
190
|
+
err_tp.init(tur.ship.agent.spin_handler, err_yat, handler.std_out[0], -1, @timeout_sec, eof_checker)
|
191
|
+
err_tp.open_valve()
|
192
|
+
|
193
|
+
when Harbor::FILE_SEND_METHOD_TAXI
|
194
|
+
out_txi = ReadFileTaxi.new(bufsize)
|
195
|
+
out_yat.init(tur, out_txi)
|
196
|
+
out_txi.init(handler.std_out[0], out_yat)
|
197
|
+
if !TaxiRunner.post(out_txi)
|
198
|
+
raise HttpException.new(HttpStatus.SERVICE_UNAVAILABLE, "Taxi is busy!")
|
199
|
+
end
|
200
|
+
|
201
|
+
err_txi = ReadFileTaxi.new(bufsize)
|
202
|
+
err_yat.init(tur)
|
203
|
+
err_txi.init(handler.std_err[0], err_yat)
|
204
|
+
if !TaxiRunner.post(err_txi)
|
205
|
+
raise HttpException.new(HttpStatus.SERVICE_UNAVAILABLE, "Taxi is busy!")
|
206
|
+
end
|
207
|
+
|
208
|
+
else
|
209
|
+
raise Sink.new();
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def create_command(env)
|
214
|
+
script = env[CgiUtil::SCRIPT_FILENAME]
|
215
|
+
if @interpreter == nil
|
216
|
+
command = script
|
217
|
+
else
|
218
|
+
command = @interpreter + " " + script
|
219
|
+
end
|
220
|
+
command
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'baykit/bayserver/bayserver'
|
2
|
+
require 'baykit/bayserver/util/message'
|
3
|
+
require 'baykit/bayserver/util/locale'
|
4
|
+
|
5
|
+
module Baykit
|
6
|
+
module BayServer
|
7
|
+
module Docker
|
8
|
+
module Cgi
|
9
|
+
class CgiMessage
|
10
|
+
include Util
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def initialize()
|
14
|
+
self.init()
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
@@msg = Message.new
|
19
|
+
|
20
|
+
def self.init()
|
21
|
+
@msg.init(BayServer.bserv_home + "/lib/conf/cgi_messages", Locale.default())
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.get(key, *args)
|
25
|
+
return @@msg.get(key, *args)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'baykit/bayserver/train/train'
|
2
|
+
require 'baykit/bayserver/tours/req_content_handler'
|
3
|
+
|
4
|
+
require 'baykit/bayserver/util/string_util'
|
5
|
+
require 'baykit/bayserver/util/http_status'
|
6
|
+
|
7
|
+
module Baykit
|
8
|
+
module BayServer
|
9
|
+
module Docker
|
10
|
+
module Cgi
|
11
|
+
class CgiReqContentHandler
|
12
|
+
include Baykit::BayServer::Tours::ReqContentHandler # implements
|
13
|
+
|
14
|
+
include Baykit::BayServer::Agent
|
15
|
+
include Baykit::BayServer::Train
|
16
|
+
include Baykit::BayServer::Tours
|
17
|
+
include Baykit::BayServer::Util
|
18
|
+
|
19
|
+
READ_CHUNK_SIZE = 8192
|
20
|
+
|
21
|
+
attr :cgi_docker
|
22
|
+
attr :tour
|
23
|
+
attr :tour_id
|
24
|
+
attr :available
|
25
|
+
attr :pid
|
26
|
+
attr :std_in
|
27
|
+
attr :std_out
|
28
|
+
attr :std_err
|
29
|
+
attr :std_out_closed
|
30
|
+
attr :std_err_closed
|
31
|
+
|
32
|
+
def initialize(cgi_docker, tur)
|
33
|
+
@cgi_docker = cgi_docker
|
34
|
+
@tour = tur
|
35
|
+
@tour_id = tur.tour_id
|
36
|
+
end
|
37
|
+
|
38
|
+
######################################################
|
39
|
+
# Implements ReqContentHandler
|
40
|
+
######################################################
|
41
|
+
|
42
|
+
def on_read_content(tur, buf, start, len)
|
43
|
+
BayLog.debug("%s CGI:onReadReqContent: len=%d", tur, len)
|
44
|
+
|
45
|
+
wrote_len = @std_in[1].write(buf[start, len])
|
46
|
+
BayLog.debug("%s CGI:onReadReqContent: wrote=%d", tur, wrote_len)
|
47
|
+
tur.req.consumed(Tour::TOUR_ID_NOCHECK, len)
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_end_content(tur)
|
51
|
+
BayLog.trace("%s CGI:endReqContent", tur)
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_abort(tur)
|
55
|
+
BayLog.debug("%s CGI:abortReq", tur)
|
56
|
+
if !@std_out_closed
|
57
|
+
@tour.ship.agent.non_blocking_handler.ask_to_close(@std_out[0])
|
58
|
+
end
|
59
|
+
if !@std_err_closed
|
60
|
+
@tour.ship.agent.non_blocking_handler.ask_to_close(@std_err[0])
|
61
|
+
end
|
62
|
+
|
63
|
+
BayLog.debug("%s KILL PROCESS!: %d", tur, @pid)
|
64
|
+
Process.kill('KILL', @pid)
|
65
|
+
|
66
|
+
return false # not aborted immediately
|
67
|
+
end
|
68
|
+
|
69
|
+
######################################################
|
70
|
+
# Other methods
|
71
|
+
######################################################
|
72
|
+
|
73
|
+
def start_tour(env)
|
74
|
+
@available = false
|
75
|
+
|
76
|
+
@std_in = IO.pipe()
|
77
|
+
@std_out = IO.pipe()
|
78
|
+
@std_err = IO.pipe()
|
79
|
+
@std_in[1].set_encoding("ASCII-8BIT")
|
80
|
+
@std_out[0].set_encoding("ASCII-8BIT")
|
81
|
+
@std_err[0].set_encoding("ASCII-8BIT")
|
82
|
+
|
83
|
+
command = @cgi_docker.create_command(env)
|
84
|
+
BayLog.debug("%s Spawn: %s", @tour, command)
|
85
|
+
@pid = Process.spawn(env, command, :in => @std_in[0], :out => @std_out[1], :err => @std_err[1])
|
86
|
+
BayLog.debug("%s created process; %s", @tour, @pid)
|
87
|
+
|
88
|
+
@std_in[0].close()
|
89
|
+
@std_out[1].close()
|
90
|
+
@std_err[1].close()
|
91
|
+
BayLog.debug("#{@tour} PID: #{pid}")
|
92
|
+
|
93
|
+
@std_out_closed = false
|
94
|
+
@std_err_closed = false
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
def std_out_closed()
|
99
|
+
@std_out_closed = true
|
100
|
+
if @std_out_closed && @std_err_closed
|
101
|
+
process_finished()
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def std_err_closed()
|
106
|
+
@std_err_closed = true
|
107
|
+
if @std_out_closed && @std_err_closed
|
108
|
+
process_finished()
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def process_finished()
|
113
|
+
pid, stat = Process.wait2(@pid)
|
114
|
+
|
115
|
+
BayLog.debug("%s CGI Process finished: pid=%s code=%s", @tour, pid, stat.exitstatus)
|
116
|
+
if pid == nil
|
117
|
+
BayLog.error("Process not finished: %d", @pid)
|
118
|
+
end
|
119
|
+
|
120
|
+
begin
|
121
|
+
if stat.exitstatus != 0
|
122
|
+
# Exec failed
|
123
|
+
BayLog.error("%s CGI Invalid exit status pid=%d code=%s", @tour, @pid, stat.exitstatus)
|
124
|
+
@tour.res.send_error(@tour_id, HttpStatus::INTERNAL_SERVER_ERROR, "Invalid exit Status")
|
125
|
+
else
|
126
|
+
@tour.res.end_content(@tour_id)
|
127
|
+
end
|
128
|
+
rescue IOError => e
|
129
|
+
BayLog.error_e(e)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,81 @@
|
|
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
|
+
module Baykit
|
7
|
+
module BayServer
|
8
|
+
module Docker
|
9
|
+
module Cgi
|
10
|
+
class CgiStdErrYacht < Baykit::BayServer::WaterCraft::Yacht
|
11
|
+
|
12
|
+
include Baykit::BayServer::Agent
|
13
|
+
include Baykit::BayServer::Util
|
14
|
+
|
15
|
+
attr :tour
|
16
|
+
attr :tour_id
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super
|
20
|
+
reset()
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s()
|
24
|
+
return "CGIErrYat##{@yacht_id}/#{@object_id} tour=#{@tour} id=#{@tour_id}";
|
25
|
+
end
|
26
|
+
|
27
|
+
######################################################
|
28
|
+
# implements Reusable
|
29
|
+
######################################################
|
30
|
+
|
31
|
+
def reset()
|
32
|
+
@tour = nil
|
33
|
+
@tour_id = 0
|
34
|
+
end
|
35
|
+
|
36
|
+
######################################################
|
37
|
+
# implements Yacht
|
38
|
+
######################################################
|
39
|
+
|
40
|
+
def notify_read(buf, adr)
|
41
|
+
|
42
|
+
BayLog.debug("%s CGI StdErr %d bytesd", self, buf.length)
|
43
|
+
if(buf.length() > 0)
|
44
|
+
BayLog.error("CGI Stderr: %s", buf)
|
45
|
+
end
|
46
|
+
|
47
|
+
return NextSocketAction::CONTINUE;
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def notify_eof()
|
52
|
+
BayLog.debug("%s CGI StdErr: EOF\\(^o^)/", self)
|
53
|
+
return NextSocketAction::CLOSE
|
54
|
+
end
|
55
|
+
|
56
|
+
def notify_close()
|
57
|
+
BayLog.debug("%s CGI StdErr: notifyClose", self)
|
58
|
+
@tour.req.content_handler.std_err_closed()
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_timeout(duration)
|
62
|
+
BayLog.warn("%s invalid timeout check", self)
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
|
66
|
+
######################################################
|
67
|
+
# Custom methods
|
68
|
+
######################################################
|
69
|
+
|
70
|
+
def init(tur)
|
71
|
+
init_yacht()
|
72
|
+
@tour = tur
|
73
|
+
@tour_id = tur.tour_id
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
@@ -0,0 +1,158 @@
|
|
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
|
+
module Baykit
|
7
|
+
module BayServer
|
8
|
+
module Docker
|
9
|
+
module Cgi
|
10
|
+
class CgiStdOutYacht < Baykit::BayServer::WaterCraft::Yacht
|
11
|
+
|
12
|
+
include Baykit::BayServer::Agent
|
13
|
+
include Baykit::BayServer::Util
|
14
|
+
|
15
|
+
attr :file_wrote_len
|
16
|
+
|
17
|
+
attr :tour
|
18
|
+
attr :tour_id
|
19
|
+
|
20
|
+
attr :remain
|
21
|
+
attr :header_reading
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
super
|
25
|
+
reset()
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s()
|
29
|
+
return "CGIYat##{@yacht_id}/#{@object_id} tour=#{@tour} id=#{@tour_id}";
|
30
|
+
end
|
31
|
+
|
32
|
+
######################################################
|
33
|
+
# implements Reusable
|
34
|
+
######################################################
|
35
|
+
|
36
|
+
def reset()
|
37
|
+
@file_wrote_len = 0
|
38
|
+
@tour = nil
|
39
|
+
@tour_id = 0
|
40
|
+
@header_reading = true
|
41
|
+
@remain = ""
|
42
|
+
end
|
43
|
+
|
44
|
+
######################################################
|
45
|
+
# implements Yacht
|
46
|
+
######################################################
|
47
|
+
|
48
|
+
def notify_read(buf, adr)
|
49
|
+
@file_wrote_len += buf.length
|
50
|
+
BayLog.trace("%s read file %d bytes: total=%d", self, buf.length, @file_wrote_len)
|
51
|
+
|
52
|
+
pos = 0
|
53
|
+
if @header_reading
|
54
|
+
|
55
|
+
while true
|
56
|
+
p = buf.index("\n", pos)
|
57
|
+
|
58
|
+
#BayLog.debug("pos: %d", pos)
|
59
|
+
|
60
|
+
if p == nil
|
61
|
+
break
|
62
|
+
end
|
63
|
+
|
64
|
+
line = buf[pos .. p]
|
65
|
+
pos = p + 1
|
66
|
+
|
67
|
+
if @remain.length > 0
|
68
|
+
line = @remain + line
|
69
|
+
end
|
70
|
+
@remain = ""
|
71
|
+
|
72
|
+
line = line.strip()
|
73
|
+
|
74
|
+
# if line is empty ("\r\n")
|
75
|
+
# finish header reading.
|
76
|
+
if StringUtil.empty?(line)
|
77
|
+
@header_reading = false
|
78
|
+
@tour.res.send_headers(@tour_id)
|
79
|
+
break
|
80
|
+
else
|
81
|
+
if BayServer.harbor.trace_header()
|
82
|
+
BayLog.info("%s CGI: res header line: %s", tour, line);
|
83
|
+
end
|
84
|
+
|
85
|
+
sep_pos = line.index(':')
|
86
|
+
if sep_pos != nil
|
87
|
+
key = line[0 .. sep_pos - 1].strip()
|
88
|
+
val = line[sep_pos + 1 .. -1].strip()
|
89
|
+
|
90
|
+
if key.downcase() == "status"
|
91
|
+
begin
|
92
|
+
val = val.split(" ")[0]
|
93
|
+
@tour.res.headers.status = val.to_i()
|
94
|
+
rescue => e
|
95
|
+
BayLog.error_e(e)
|
96
|
+
end
|
97
|
+
else
|
98
|
+
@tour.res.headers.add(key, val);
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
available = true
|
106
|
+
|
107
|
+
if @header_reading
|
108
|
+
@remain += buf[pos .. -1]
|
109
|
+
else
|
110
|
+
if buf.length - pos > 0
|
111
|
+
available = @tour.res.send_content(@tour_id, buf, pos, buf.length - pos);
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if available
|
116
|
+
return NextSocketAction::CONTINUE;
|
117
|
+
else
|
118
|
+
return NextSocketAction::SUSPEND;
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
def notify_eof()
|
124
|
+
BayLog.debug("%s CGI StdOut: EOF(^o^)", self)
|
125
|
+
return NextSocketAction::CLOSE
|
126
|
+
end
|
127
|
+
|
128
|
+
def notify_close()
|
129
|
+
BayLog.debug("%s CGI StdOut: notifyClose", self)
|
130
|
+
@tour.req.content_handler.std_out_closed()
|
131
|
+
end
|
132
|
+
|
133
|
+
def check_timeout(duration)
|
134
|
+
BayLog.warn("%s invalid timeout check", self)
|
135
|
+
return false
|
136
|
+
end
|
137
|
+
|
138
|
+
######################################################
|
139
|
+
# Custom methods
|
140
|
+
######################################################
|
141
|
+
|
142
|
+
def init(tur, valve)
|
143
|
+
init_yacht()
|
144
|
+
@tour = tur
|
145
|
+
@tour_id = tur.tour_id
|
146
|
+
tur.res.set_consume_listener do |len, resume|
|
147
|
+
if resume
|
148
|
+
valve.open_valve();
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'baykit/bayserver/train/train'
|
2
|
+
require 'baykit/bayserver/tours/req_content_handler'
|
3
|
+
|
4
|
+
require 'baykit/bayserver/util/string_util'
|
5
|
+
require 'baykit/bayserver/util/http_status'
|
6
|
+
|
7
|
+
module Baykit
|
8
|
+
module BayServer
|
9
|
+
module Docker
|
10
|
+
module Cgi
|
11
|
+
class CgiTrain < Baykit::BayServer::Train::Train
|
12
|
+
include Baykit::BayServer::Tours::ReqContentHandler # implements
|
13
|
+
|
14
|
+
include Baykit::BayServer::Agent
|
15
|
+
include Baykit::BayServer::Train
|
16
|
+
include Baykit::BayServer::Tours
|
17
|
+
include Baykit::BayServer::Util
|
18
|
+
|
19
|
+
READ_CHUNK_SIZE = 8192
|
20
|
+
|
21
|
+
attr :cgi_docker
|
22
|
+
attr :env
|
23
|
+
attr :available
|
24
|
+
attr :lock
|
25
|
+
attr :pid
|
26
|
+
attr :std_in
|
27
|
+
attr :std_out
|
28
|
+
attr :std_err
|
29
|
+
|
30
|
+
def initialize(cgi_docker, tur)
|
31
|
+
super(tur)
|
32
|
+
@cgi_docker = cgi_docker
|
33
|
+
end
|
34
|
+
|
35
|
+
def start_tour(env)
|
36
|
+
@env = env
|
37
|
+
@available = false
|
38
|
+
@lock = Mutex.new()
|
39
|
+
|
40
|
+
@std_in = IO.pipe()
|
41
|
+
@std_out = IO.pipe()
|
42
|
+
@std_err = IO.pipe()
|
43
|
+
@std_in[1].set_encoding("ASCII-8BIT")
|
44
|
+
@std_out[0].set_encoding("ASCII-8BIT")
|
45
|
+
@std_err[0].set_encoding("ASCII-8BIT")
|
46
|
+
|
47
|
+
command = @cgi_docker.create_command(@env)
|
48
|
+
BayLog.debug("%s Spawn: %s", @tour, command)
|
49
|
+
@pid = Process.spawn(@env, command, :in => @std_in[0], :out => @std_out[1], :err => @std_err[1])
|
50
|
+
@std_in[0].close()
|
51
|
+
@std_out[1].close()
|
52
|
+
@std_err[1].close()
|
53
|
+
BayLog.debug("#{@tour} PID: #{pid}")
|
54
|
+
|
55
|
+
@tour.req.set_content_handler(self)
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def depart
|
60
|
+
|
61
|
+
begin
|
62
|
+
|
63
|
+
###############
|
64
|
+
# Handle StdOut
|
65
|
+
HttpUtil.parse_message_headers(@std_out[0], @tour.res.headers)
|
66
|
+
|
67
|
+
if BayServer.harbor.trace_header?
|
68
|
+
@tour.res.headers.names.each do |name|
|
69
|
+
@tour.res.headers.values(name).each do |value|
|
70
|
+
BayLog.info("%s CGI: resHeader: %s=%s", @tour, name, value)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
status = @tour.res.headers.get("Status")
|
76
|
+
#BayLog.debug "Headers: #{@tours.res.headers.headers}"
|
77
|
+
#BayLog.debug "Status: #{status}"
|
78
|
+
if !StringUtil.empty?(status)
|
79
|
+
pos = status.index(" ")
|
80
|
+
if pos
|
81
|
+
code = status[0, pos].to_i
|
82
|
+
else
|
83
|
+
code = status.to_i
|
84
|
+
end
|
85
|
+
@tour.res.headers.status = code
|
86
|
+
end
|
87
|
+
|
88
|
+
@tour.res.set_consume_listener do |len, resume|
|
89
|
+
if resume
|
90
|
+
@available = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
@tour.res.send_headers(@tour_id)
|
95
|
+
|
96
|
+
#BayLog.info("Reading STDOUT")
|
97
|
+
while true
|
98
|
+
buf = StringUtil.alloc(READ_CHUNK_SIZE)
|
99
|
+
c = std_out[0].read(READ_CHUNK_SIZE, buf)
|
100
|
+
if !c
|
101
|
+
break
|
102
|
+
end
|
103
|
+
|
104
|
+
BayLog.trace("%s CGITrain: read stdout bytes: len=%d", @tour, buf.length)
|
105
|
+
@available = @tour.res.send_content(@tour_id, buf, 0, buf.length)
|
106
|
+
while !@available
|
107
|
+
sleep(0.1)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#BayLog.info("Reading STDERR")
|
112
|
+
###############
|
113
|
+
# Handle StdErr
|
114
|
+
###############
|
115
|
+
while true
|
116
|
+
buf = StringUtil.alloc(READ_CHUNK_SIZE)
|
117
|
+
c = std_err[0].read(READ_CHUNK_SIZE, buf)
|
118
|
+
if !c
|
119
|
+
break
|
120
|
+
end
|
121
|
+
|
122
|
+
BayLog.warn("%s CGITrain: read stderr bytes: %d", @tour, buf.length)
|
123
|
+
BayLog.warn(buf)
|
124
|
+
end
|
125
|
+
|
126
|
+
@tour.res.end_content @tour_id
|
127
|
+
|
128
|
+
rescue HttpException => e
|
129
|
+
raise e
|
130
|
+
rescue => e
|
131
|
+
BayLog.error("%s CGITrain: Catch error: %s", @tour, e)
|
132
|
+
BayLog.error_e(e)
|
133
|
+
raise HttpException.new(HttpStatus::INTERNAL_SERVER_ERROR, "CGI error")
|
134
|
+
ensure
|
135
|
+
begin
|
136
|
+
BayLog.debug("%s CGITrain: waiting process end", @tour)
|
137
|
+
Process.wait(@pid)
|
138
|
+
close_pipes()
|
139
|
+
|
140
|
+
BayLog.debug("%s CGITrain: process ended", @tour)
|
141
|
+
rescue => e
|
142
|
+
BayLog.error_e(e)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def on_read_content(tur, buf, start, len)
|
148
|
+
BayLog.info("%s CGITrain:onReadContent: len=%d", tur, len)
|
149
|
+
|
150
|
+
wrote_len = @std_in[1].write(buf[start, len])
|
151
|
+
BayLog.info("%s CGITrain:onReadContent: wrote=%d", tur, wrote_len)
|
152
|
+
tur.req.consumed(Tour::TOUR_ID_NOCHECK, len)
|
153
|
+
end
|
154
|
+
|
155
|
+
def on_end_content(tur)
|
156
|
+
BayLog.trace("%s CGITrain:endContent", tur)
|
157
|
+
|
158
|
+
if !TrainRunner.post(self)
|
159
|
+
raise HttpException.new(HttpStatus::SERVICE_UNAVAILABLE, "TrainRunner is busy")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def on_abort(tur)
|
164
|
+
BayLog.debug("%s CGITrain:abort", tur)
|
165
|
+
close_pipes()
|
166
|
+
|
167
|
+
BayLog.debug("%s KILL PROCESS!: %d", tur, @pid)
|
168
|
+
Process.kill('KILL', @pid)
|
169
|
+
|
170
|
+
return false # not aborted immediately
|
171
|
+
end
|
172
|
+
|
173
|
+
def close_pipes()
|
174
|
+
@std_in[1].close()
|
175
|
+
@std_out[0].close()
|
176
|
+
@std_err[0].close()
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'baykit/bayserver/bcf/package'
|
2
|
+
require 'baykit/bayserver/docker/cgi/cgi_docker'
|
3
|
+
|
4
|
+
module Baykit
|
5
|
+
module BayServer
|
6
|
+
module Docker
|
7
|
+
module Cgi
|
8
|
+
class PhpCgiDocker < Baykit::BayServer::Docker::Cgi::CgiDocker
|
9
|
+
include Baykit::BayServer::Util
|
10
|
+
|
11
|
+
ENV_PHP_SELF = "PHP_SELF"
|
12
|
+
ENV_REDIRECT_STATUS = "REDIRECT_STATUS"
|
13
|
+
|
14
|
+
######################################################
|
15
|
+
# Implements Docker
|
16
|
+
######################################################
|
17
|
+
|
18
|
+
def init(elm, parent)
|
19
|
+
super
|
20
|
+
|
21
|
+
if @interpreter == nil
|
22
|
+
@interpreter = "php-cgi";
|
23
|
+
end
|
24
|
+
|
25
|
+
BayLog.debug("PHP interpreter: " + interpreter)
|
26
|
+
end
|
27
|
+
|
28
|
+
######################################################
|
29
|
+
# Override CgiDocker
|
30
|
+
######################################################
|
31
|
+
|
32
|
+
def create_command(env)
|
33
|
+
env[ENV_PHP_SELF] = env[CgiUtil::SCRIPT_NAME]
|
34
|
+
env[ENV_REDIRECT_STATUS] = 200.to_s
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bayserver-docker-cgi
|
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/cgi/cgi_docker.rb
|
34
|
+
- lib/baykit/bayserver/docker/cgi/cgi_message.rb
|
35
|
+
- lib/baykit/bayserver/docker/cgi/cgi_req_content_handler.rb
|
36
|
+
- lib/baykit/bayserver/docker/cgi/cgi_std_err_yacht.rb
|
37
|
+
- lib/baykit/bayserver/docker/cgi/cgi_std_out_yacht.rb
|
38
|
+
- lib/baykit/bayserver/docker/cgi/cgi_train.rb
|
39
|
+
- lib/baykit/bayserver/docker/cgi/php_cgi_docker.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: []
|