bayserver-docker-terminal 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/terminal/fully_hijackers_yacht.rb +155 -0
- data/lib/baykit/bayserver/docker/terminal/hijacked_data_sender.rb +170 -0
- data/lib/baykit/bayserver/docker/terminal/hijackers_yacht.rb +106 -0
- data/lib/baykit/bayserver/docker/terminal/terminal_docker.rb +204 -0
- data/lib/baykit/bayserver/docker/terminal/terminal_train.rb +209 -0
- data/lib/rack/handler/bayserver.rb +66 -0
- data/lib/rack/handler/terminal.rb +17 -0
- metadata +63 -0
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
|
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: []
|