rsense-server 0.5.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/.gitignore +23 -0
- data/Gemfile +14 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +1 -0
- data/README.md +51 -0
- data/Rakefile +9 -0
- data/bin/_rsense.rb +115 -0
- data/config/puma.rb +2 -0
- data/lib/rsense/server/code.rb +38 -0
- data/lib/rsense/server/command/completion_result.rb +11 -0
- data/lib/rsense/server/command/special_meth.rb +18 -0
- data/lib/rsense/server/command/type_inference_method.rb +24 -0
- data/lib/rsense/server/command.rb +239 -0
- data/lib/rsense/server/config.rb +70 -0
- data/lib/rsense/server/gem_path.rb +18 -0
- data/lib/rsense/server/listeners/find_definition_event_listener.rb +91 -0
- data/lib/rsense/server/listeners/where_event_listener.rb +39 -0
- data/lib/rsense/server/load_path.rb +62 -0
- data/lib/rsense/server/options.rb +85 -0
- data/lib/rsense/server/parser.rb +17 -0
- data/lib/rsense/server/path_info.rb +17 -0
- data/lib/rsense/server/project.rb +24 -0
- data/lib/rsense/server/version.rb +5 -0
- data/lib/rsense/server.rb +18 -0
- data/rsense-server.gemspec +35 -0
- data/spec/fixtures/config_fixture/.rsense +4 -0
- data/spec/fixtures/deeply/nested/thing.rb +0 -0
- data/spec/fixtures/find_def_sample.json +10 -0
- data/spec/fixtures/sample.json +10 -0
- data/spec/fixtures/test_gem/.gitignore +22 -0
- data/spec/fixtures/test_gem/Gemfile +4 -0
- data/spec/fixtures/test_gem/LICENSE.txt +22 -0
- data/spec/fixtures/test_gem/README.md +29 -0
- data/spec/fixtures/test_gem/Rakefile +2 -0
- data/spec/fixtures/test_gem/lib/sample/version.rb +3 -0
- data/spec/fixtures/test_gem/lib/sample.rb +16 -0
- data/spec/fixtures/test_gem/sample.gemspec +23 -0
- data/spec/fixtures/test_gem/test.json +10 -0
- data/spec/rsense/server/code_spec.rb +44 -0
- data/spec/rsense/server/command/special_meth_spec.rb +23 -0
- data/spec/rsense/server/command_spec.rb +108 -0
- data/spec/rsense/server/config_spec.rb +27 -0
- data/spec/rsense/server/gem_path_spec.rb +16 -0
- data/spec/rsense/server/load_path_spec.rb +63 -0
- data/spec/rsense/server/options_spec.rb +33 -0
- data/spec/rsense/server/path_info_spec.rb +11 -0
- data/spec/rsense/server/project_spec.rb +18 -0
- data/spec/rsense/server_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/vendor/gems/puma-2.8.2-java/COPYING +55 -0
- data/vendor/gems/puma-2.8.2-java/DEPLOYMENT.md +92 -0
- data/vendor/gems/puma-2.8.2-java/Gemfile +17 -0
- data/vendor/gems/puma-2.8.2-java/History.txt +532 -0
- data/vendor/gems/puma-2.8.2-java/LICENSE +26 -0
- data/vendor/gems/puma-2.8.2-java/Manifest.txt +68 -0
- data/vendor/gems/puma-2.8.2-java/README.md +251 -0
- data/vendor/gems/puma-2.8.2-java/Rakefile +158 -0
- data/vendor/gems/puma-2.8.2-java/bin/puma +10 -0
- data/vendor/gems/puma-2.8.2-java/bin/puma-wild +17 -0
- data/vendor/gems/puma-2.8.2-java/bin/pumactl +12 -0
- data/vendor/gems/puma-2.8.2-java/docs/config.md +0 -0
- data/vendor/gems/puma-2.8.2-java/docs/nginx.md +80 -0
- data/vendor/gems/puma-2.8.2-java/docs/signals.md +42 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/PumaHttp11Service.java +17 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/ext_help.h +15 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/extconf.rb +8 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser.c +1225 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser.h +64 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser.java.rl +161 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser.rl +146 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser_common.rl +54 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/io_buffer.c +155 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/mini_ssl.c +195 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/org/jruby/puma/Http11.java +225 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/org/jruby/puma/Http11Parser.java +488 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/org/jruby/puma/MiniSSL.java +289 -0
- data/vendor/gems/puma-2.8.2-java/ext/puma_http11/puma_http11.c +491 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/accept_nonblock.rb +23 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/app/status.rb +59 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/binder.rb +298 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/capistrano.rb +86 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/cli.rb +587 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/client.rb +289 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/cluster.rb +389 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/compat.rb +18 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/configuration.rb +377 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/const.rb +165 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/control_cli.rb +251 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/daemon_ext.rb +25 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/delegation.rb +11 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/detect.rb +4 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/events.rb +130 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/io_buffer.rb +7 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/java_io_buffer.rb +45 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/jruby_restart.rb +83 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/minissl.rb +148 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/null_io.rb +34 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/puma_http11.jar +0 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/rack_default.rb +7 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/rack_patch.rb +45 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/reactor.rb +183 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/runner.rb +146 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/server.rb +801 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/single.rb +102 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/tcp_logger.rb +32 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/thread_pool.rb +185 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma/util.rb +9 -0
- data/vendor/gems/puma-2.8.2-java/lib/puma.rb +14 -0
- data/vendor/gems/puma-2.8.2-java/lib/rack/handler/puma.rb +66 -0
- data/vendor/gems/puma-2.8.2-java/puma.gemspec +55 -0
- data/vendor/gems/puma-2.8.2-java/test/test_app_status.rb +92 -0
- data/vendor/gems/puma-2.8.2-java/test/test_cli.rb +173 -0
- data/vendor/gems/puma-2.8.2-java/test/test_config.rb +26 -0
- data/vendor/gems/puma-2.8.2-java/test/test_http10.rb +27 -0
- data/vendor/gems/puma-2.8.2-java/test/test_http11.rb +144 -0
- data/vendor/gems/puma-2.8.2-java/test/test_integration.rb +165 -0
- data/vendor/gems/puma-2.8.2-java/test/test_iobuffer.rb +38 -0
- data/vendor/gems/puma-2.8.2-java/test/test_minissl.rb +25 -0
- data/vendor/gems/puma-2.8.2-java/test/test_null_io.rb +31 -0
- data/vendor/gems/puma-2.8.2-java/test/test_persistent.rb +238 -0
- data/vendor/gems/puma-2.8.2-java/test/test_puma_server.rb +323 -0
- data/vendor/gems/puma-2.8.2-java/test/test_rack_handler.rb +10 -0
- data/vendor/gems/puma-2.8.2-java/test/test_rack_server.rb +141 -0
- data/vendor/gems/puma-2.8.2-java/test/test_tcp_rack.rb +42 -0
- data/vendor/gems/puma-2.8.2-java/test/test_thread_pool.rb +156 -0
- data/vendor/gems/puma-2.8.2-java/test/test_unix_socket.rb +39 -0
- data/vendor/gems/puma-2.8.2-java/test/test_ws.rb +89 -0
- data/vendor/gems/puma-2.8.2-java/tools/jungle/README.md +9 -0
- data/vendor/gems/puma-2.8.2-java/tools/jungle/init.d/README.md +54 -0
- data/vendor/gems/puma-2.8.2-java/tools/jungle/init.d/puma +332 -0
- data/vendor/gems/puma-2.8.2-java/tools/jungle/init.d/run-puma +3 -0
- data/vendor/gems/puma-2.8.2-java/tools/jungle/upstart/README.md +61 -0
- data/vendor/gems/puma-2.8.2-java/tools/jungle/upstart/puma-manager.conf +31 -0
- data/vendor/gems/puma-2.8.2-java/tools/jungle/upstart/puma.conf +63 -0
- data/vendor/gems/puma-2.8.2-java/tools/trickletest.rb +45 -0
- metadata +389 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
require 'optparse'
|
|
2
|
+
require 'puma/const'
|
|
3
|
+
require 'puma/configuration'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require 'uri'
|
|
6
|
+
require 'socket'
|
|
7
|
+
module Puma
|
|
8
|
+
class ControlCLI
|
|
9
|
+
|
|
10
|
+
COMMANDS = %w{halt restart phased-restart start stats status stop}
|
|
11
|
+
|
|
12
|
+
def is_windows?
|
|
13
|
+
RUBY_PLATFORM =~ /(win|w)32$/ ? true : false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
|
17
|
+
@argv = argv
|
|
18
|
+
@stdout = stdout
|
|
19
|
+
@stderr = stderr
|
|
20
|
+
@options = {}
|
|
21
|
+
|
|
22
|
+
opts = OptionParser.new do |o|
|
|
23
|
+
o.banner = "Usage: pumactl (-p PID | -P pidfile | -S status_file | -C url -T token | -F config.rb) (#{COMMANDS.join("|")})"
|
|
24
|
+
|
|
25
|
+
o.on "-S", "--state PATH", "Where the state file to use is" do |arg|
|
|
26
|
+
@options[:state] = arg
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
o.on "-Q", "--quiet", "Not display messages" do |arg|
|
|
30
|
+
@options[:quiet_flag] = true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
o.on "-P", "--pidfile PATH", "Pid file" do |arg|
|
|
34
|
+
@options[:pidfile] = arg
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
o.on "-p", "--pid PID", "Pid" do |arg|
|
|
38
|
+
@options[:pid] = arg.to_i
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
o.on "-C", "--control-url URL", "The bind url to use for the control server" do |arg|
|
|
42
|
+
@options[:control_url] = arg
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
o.on "-T", "--control-token TOKEN", "The token to use as authentication for the control server" do |arg|
|
|
46
|
+
@options[:control_auth_token] = arg
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
o.on "-F", "--config-file PATH", "Puma config script" do |arg|
|
|
50
|
+
@options[:config_file] = arg
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
o.on_tail("-H", "--help", "Show this message") do
|
|
54
|
+
@stdout.puts o
|
|
55
|
+
exit
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
o.on_tail("-V", "--version", "Show version") do
|
|
59
|
+
puts Const::PUMA_VERSION
|
|
60
|
+
exit
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
opts.order!(argv) { |a| opts.terminate a }
|
|
65
|
+
|
|
66
|
+
command = argv.shift
|
|
67
|
+
@options[:command] = command if command
|
|
68
|
+
|
|
69
|
+
Puma::Configuration.new(@options).load if @options[:config_file]
|
|
70
|
+
|
|
71
|
+
# check present of command
|
|
72
|
+
unless @options[:command]
|
|
73
|
+
raise "Available commands: #{COMMANDS.join(", ")}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
unless COMMANDS.include? @options[:command]
|
|
77
|
+
raise "Invalid command: #{@options[:command]}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
rescue => e
|
|
81
|
+
@stdout.puts e.message
|
|
82
|
+
exit 1
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def message(msg)
|
|
86
|
+
@stdout.puts msg unless @options[:quiet_flag]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def prepare_configuration
|
|
90
|
+
if @options.has_key? :state
|
|
91
|
+
unless File.exist? @options[:state]
|
|
92
|
+
raise "Status file not found: #{@options[:state]}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
status = YAML.load File.read(@options[:state])
|
|
96
|
+
|
|
97
|
+
if status.kind_of?(Hash) && status.has_key?("config")
|
|
98
|
+
|
|
99
|
+
conf = status["config"]
|
|
100
|
+
|
|
101
|
+
# get control_url
|
|
102
|
+
if url = conf.options[:control_url]
|
|
103
|
+
@options[:control_url] = url
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# get control_auth_token
|
|
107
|
+
if token = conf.options[:control_auth_token]
|
|
108
|
+
@options[:control_auth_token] = token
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# get pid
|
|
112
|
+
@options[:pid] = status["pid"].to_i
|
|
113
|
+
else
|
|
114
|
+
raise "Invalid status file: #{@options[:state]}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
elsif @options.has_key? :pidfile
|
|
118
|
+
# get pid from pid_file
|
|
119
|
+
@options[:pid] = File.open(@options[:pidfile]).gets.to_i
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def send_request
|
|
124
|
+
uri = URI.parse @options[:control_url]
|
|
125
|
+
|
|
126
|
+
# create server object by scheme
|
|
127
|
+
@server = case uri.scheme
|
|
128
|
+
when "tcp"
|
|
129
|
+
TCPSocket.new uri.host, uri.port
|
|
130
|
+
when "unix"
|
|
131
|
+
UNIXSocket.new "#{uri.host}#{uri.path}"
|
|
132
|
+
else
|
|
133
|
+
raise "Invalid scheme: #{uri.scheme}"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
if @options[:command] == "status"
|
|
137
|
+
message "Puma is started"
|
|
138
|
+
else
|
|
139
|
+
url = "/#{@options[:command]}"
|
|
140
|
+
|
|
141
|
+
if @options.has_key?(:control_auth_token)
|
|
142
|
+
url = url + "?token=#{@options[:control_auth_token]}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
@server << "GET #{url} HTTP/1.0\r\n\r\n"
|
|
146
|
+
|
|
147
|
+
unless data = @server.read
|
|
148
|
+
raise "Server closed connection before responding"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
response = data.split("\r\n")
|
|
152
|
+
|
|
153
|
+
if response.empty?
|
|
154
|
+
raise "Server sent empty response"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
(@http,@code,@message) = response.first.split(" ",3)
|
|
158
|
+
|
|
159
|
+
if @code == "403"
|
|
160
|
+
raise "Unauthorized access to server (wrong auth token)"
|
|
161
|
+
elsif @code == "404"
|
|
162
|
+
raise "Command error: #{response.last}"
|
|
163
|
+
elsif @code != "200"
|
|
164
|
+
raise "Bad response from server: #{@code}"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
message "Command #{@options[:command]} sent success"
|
|
168
|
+
message response.last if @options[:command] == "stats"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
@server.close
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def send_signal
|
|
175
|
+
unless pid = @options[:pid]
|
|
176
|
+
raise "Neither pid nor control url available"
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
begin
|
|
180
|
+
Process.getpgid pid
|
|
181
|
+
rescue SystemCallError
|
|
182
|
+
if @options[:command] == "restart"
|
|
183
|
+
@options.delete(:command)
|
|
184
|
+
start
|
|
185
|
+
else
|
|
186
|
+
raise "No pid '#{pid}' found"
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
case @options[:command]
|
|
191
|
+
when "restart"
|
|
192
|
+
Process.kill "SIGUSR2", pid
|
|
193
|
+
|
|
194
|
+
when "halt"
|
|
195
|
+
Process.kill "QUIT", pid
|
|
196
|
+
|
|
197
|
+
when "stop"
|
|
198
|
+
Process.kill "SIGTERM", pid
|
|
199
|
+
|
|
200
|
+
when "stats"
|
|
201
|
+
puts "Stats not available via pid only"
|
|
202
|
+
return
|
|
203
|
+
|
|
204
|
+
when "phased-restart"
|
|
205
|
+
Process.kill "SIGUSR1", pid
|
|
206
|
+
|
|
207
|
+
else
|
|
208
|
+
message "Puma is started"
|
|
209
|
+
return
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
message "Command #{@options[:command]} sent success"
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def run
|
|
216
|
+
start if @options[:command] == "start"
|
|
217
|
+
|
|
218
|
+
prepare_configuration
|
|
219
|
+
|
|
220
|
+
if is_windows?
|
|
221
|
+
send_request
|
|
222
|
+
else
|
|
223
|
+
@options.has_key?(:control_url) ? send_request : send_signal
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
rescue => e
|
|
227
|
+
message e.message
|
|
228
|
+
exit 1
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
private
|
|
232
|
+
def start
|
|
233
|
+
require 'puma/cli'
|
|
234
|
+
|
|
235
|
+
run_args = @argv
|
|
236
|
+
|
|
237
|
+
if path = @options[:state]
|
|
238
|
+
run_args = ["-S", path] + run_args
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
if path = @options[:config_file]
|
|
242
|
+
run_args = ["-C", path] + run_args
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
events = Puma::Events.new @stdout, @stderr
|
|
246
|
+
|
|
247
|
+
cli = Puma::CLI.new run_args, events
|
|
248
|
+
cli.run
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Process
|
|
2
|
+
|
|
3
|
+
# This overrides the default version because it is broken if it
|
|
4
|
+
# exists.
|
|
5
|
+
|
|
6
|
+
def self.daemon(nochdir=false, noclose=false)
|
|
7
|
+
exit if fork # Parent exits, child continues.
|
|
8
|
+
|
|
9
|
+
Process.setsid # Become session leader.
|
|
10
|
+
|
|
11
|
+
exit if fork # Zap session leader. See [1].
|
|
12
|
+
|
|
13
|
+
Dir.chdir "/" unless nochdir # Release old working directory.
|
|
14
|
+
|
|
15
|
+
if !noclose
|
|
16
|
+
STDIN.reopen File.open("/dev/null", "r")
|
|
17
|
+
|
|
18
|
+
null_out = File.open "/dev/null", "w"
|
|
19
|
+
STDOUT.reopen null_out
|
|
20
|
+
STDERR.reopen null_out
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
0
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
require 'puma/const'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
|
|
4
|
+
module Puma
|
|
5
|
+
# The default implement of an event sink object used by Server
|
|
6
|
+
# for when certain kinds of events occur in the life of the server.
|
|
7
|
+
#
|
|
8
|
+
# The methods available are the events that the Server fires.
|
|
9
|
+
#
|
|
10
|
+
class Events
|
|
11
|
+
|
|
12
|
+
include Const
|
|
13
|
+
|
|
14
|
+
# Create an Events object that prints to +stdout+ and +stderr+.
|
|
15
|
+
#
|
|
16
|
+
def initialize(stdout, stderr)
|
|
17
|
+
@stdout = stdout
|
|
18
|
+
@stderr = stderr
|
|
19
|
+
|
|
20
|
+
@stdout.sync = true
|
|
21
|
+
@stderr.sync = true
|
|
22
|
+
|
|
23
|
+
@debug = ENV.key? 'PUMA_DEBUG'
|
|
24
|
+
|
|
25
|
+
@on_booted = []
|
|
26
|
+
|
|
27
|
+
@hooks = Hash.new { |h,k| h[k] = [] }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
attr_reader :stdout, :stderr
|
|
31
|
+
|
|
32
|
+
# Fire callbacks for the named hook
|
|
33
|
+
#
|
|
34
|
+
def fire(hook, *args)
|
|
35
|
+
@hooks[hook].each { |t| t.call(*args) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Register a callbock for a given hook
|
|
39
|
+
#
|
|
40
|
+
def register(hook, obj=nil, &blk)
|
|
41
|
+
if obj and blk
|
|
42
|
+
raise "Specify either an object or a block, not both"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
h = obj || blk
|
|
46
|
+
|
|
47
|
+
@hooks[hook] << h
|
|
48
|
+
|
|
49
|
+
h
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Write +str+ to +@stdout+
|
|
53
|
+
#
|
|
54
|
+
def log(str)
|
|
55
|
+
@stdout.puts str
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def write(str)
|
|
59
|
+
@stdout.write str
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def debug(str)
|
|
63
|
+
log("% #{str}") if @debug
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Write +str+ to +@stderr+
|
|
67
|
+
#
|
|
68
|
+
def error(str)
|
|
69
|
+
@stderr.puts "ERROR: #{str}"
|
|
70
|
+
exit 1
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# An HTTP parse error has occured.
|
|
74
|
+
# +server+ is the Server object, +env+ the request, and +error+ a
|
|
75
|
+
# parsing exception.
|
|
76
|
+
#
|
|
77
|
+
def parse_error(server, env, error)
|
|
78
|
+
@stderr.puts "#{Time.now}: HTTP parse error, malformed request (#{env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR]}): #{error.inspect}"
|
|
79
|
+
@stderr.puts "#{Time.now}: ENV: #{env.inspect}\n---\n"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# An unknown error has occured.
|
|
83
|
+
# +server+ is the Server object, +env+ the request, +error+ an exception
|
|
84
|
+
# object, and +kind+ some additional info.
|
|
85
|
+
#
|
|
86
|
+
def unknown_error(server, error, kind="Unknown")
|
|
87
|
+
if error.respond_to? :render
|
|
88
|
+
error.render "#{Time.now}: #{kind} error", @stderr
|
|
89
|
+
else
|
|
90
|
+
@stderr.puts "#{Time.now}: #{kind} error: #{error.inspect}"
|
|
91
|
+
@stderr.puts error.backtrace.join("\n")
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def on_booted(&b)
|
|
96
|
+
@on_booted << b
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def fire_on_booted!
|
|
100
|
+
@on_booted.each { |b| b.call }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
DEFAULT = new(STDOUT, STDERR)
|
|
104
|
+
|
|
105
|
+
# Returns an Events object which writes it's status to 2 StringIO
|
|
106
|
+
# objects.
|
|
107
|
+
#
|
|
108
|
+
def self.strings
|
|
109
|
+
Events.new StringIO.new, StringIO.new
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def self.stdio
|
|
113
|
+
Events.new $stdout, $stderr
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
class PidEvents < Events
|
|
118
|
+
def log(str)
|
|
119
|
+
super "[#{$$}] #{str}"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def write(str)
|
|
123
|
+
super "[#{$$}] #{str}"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def error(str)
|
|
127
|
+
super "[#{$$}] #{str}"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'java'
|
|
2
|
+
|
|
3
|
+
# Conservative native JRuby/Java implementation of IOBuffer
|
|
4
|
+
# backed by a ByteArrayOutputStream and conversion between
|
|
5
|
+
# Ruby String and Java bytes
|
|
6
|
+
module Puma
|
|
7
|
+
class JavaIOBuffer < java.io.ByteArrayOutputStream
|
|
8
|
+
field_reader :buf
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class IOBuffer
|
|
12
|
+
BUF_DEFAULT_SIZE = 4096
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@buf = JavaIOBuffer.new(BUF_DEFAULT_SIZE)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def reset
|
|
19
|
+
@buf.reset
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def <<(str)
|
|
23
|
+
bytes = str.to_java_bytes
|
|
24
|
+
@buf.write(bytes, 0, bytes.length)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def append(*strs)
|
|
28
|
+
strs.each { |s| self << s; }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
String.from_java_bytes @buf.to_byte_array
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
alias_method :to_str, :to_s
|
|
36
|
+
|
|
37
|
+
def used
|
|
38
|
+
@buf.size
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def capacity
|
|
42
|
+
@buf.buf.length
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'ffi'
|
|
2
|
+
|
|
3
|
+
module Puma
|
|
4
|
+
module JRubyRestart
|
|
5
|
+
extend FFI::Library
|
|
6
|
+
ffi_lib 'c'
|
|
7
|
+
|
|
8
|
+
attach_function :execlp, [:string, :varargs], :int
|
|
9
|
+
attach_function :chdir, [:string], :int
|
|
10
|
+
attach_function :fork, [], :int
|
|
11
|
+
attach_function :exit, [:int], :void
|
|
12
|
+
attach_function :setsid, [], :int
|
|
13
|
+
|
|
14
|
+
def self.chdir_exec(dir, argv)
|
|
15
|
+
chdir(dir)
|
|
16
|
+
cmd = argv.first
|
|
17
|
+
argv = ([:string] * argv.size).zip(argv).flatten
|
|
18
|
+
argv << :string
|
|
19
|
+
argv << nil
|
|
20
|
+
execlp(cmd, *argv)
|
|
21
|
+
raise SystemCallError.new(FFI.errno)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
PermKey = 'PUMA_DAEMON_PERM'
|
|
25
|
+
RestartKey = 'PUMA_DAEMON_RESTART'
|
|
26
|
+
|
|
27
|
+
# Called to tell things "Your now always in daemon mode,
|
|
28
|
+
# don't try to reenter it."
|
|
29
|
+
#
|
|
30
|
+
def self.perm_daemonize
|
|
31
|
+
ENV[PermKey] = "1"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.daemon?
|
|
35
|
+
ENV.key?(PermKey) || ENV.key?(RestartKey)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.daemon_init
|
|
39
|
+
return true if ENV.key?(PermKey)
|
|
40
|
+
|
|
41
|
+
return false unless ENV.key? RestartKey
|
|
42
|
+
|
|
43
|
+
master = ENV[RestartKey]
|
|
44
|
+
|
|
45
|
+
# In case the master disappears early
|
|
46
|
+
begin
|
|
47
|
+
Process.kill "SIGUSR2", master.to_i
|
|
48
|
+
rescue SystemCallError => e
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
ENV[RestartKey] = ""
|
|
52
|
+
|
|
53
|
+
setsid
|
|
54
|
+
|
|
55
|
+
null = File.open "/dev/null", "w+"
|
|
56
|
+
STDIN.reopen null
|
|
57
|
+
STDOUT.reopen null
|
|
58
|
+
STDERR.reopen null
|
|
59
|
+
|
|
60
|
+
true
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.daemon_start(dir, argv)
|
|
64
|
+
ENV['PUMA_DAEMON_RESTART'] = Process.pid.to_s
|
|
65
|
+
|
|
66
|
+
if k = ENV['PUMA_JRUBY_DAEMON_OPTS']
|
|
67
|
+
ENV['JRUBY_OPTS'] = k
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
cmd = argv.first
|
|
71
|
+
argv = ([:string] * argv.size).zip(argv).flatten
|
|
72
|
+
argv << :string
|
|
73
|
+
argv << nil
|
|
74
|
+
|
|
75
|
+
chdir(dir)
|
|
76
|
+
ret = fork
|
|
77
|
+
return ret if ret != 0
|
|
78
|
+
execlp(cmd, *argv)
|
|
79
|
+
raise SystemCallError.new(FFI.errno)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
module Puma
|
|
2
|
+
module MiniSSL
|
|
3
|
+
class Socket
|
|
4
|
+
def initialize(socket, engine)
|
|
5
|
+
@socket = socket
|
|
6
|
+
@engine = engine
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def to_io
|
|
10
|
+
@socket
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def readpartial(size)
|
|
14
|
+
while true
|
|
15
|
+
output = @engine.read
|
|
16
|
+
return output if output
|
|
17
|
+
|
|
18
|
+
data = @socket.readpartial(size)
|
|
19
|
+
@engine.inject(data)
|
|
20
|
+
output = @engine.read
|
|
21
|
+
|
|
22
|
+
return output if output
|
|
23
|
+
|
|
24
|
+
while neg_data = @engine.extract
|
|
25
|
+
@socket.write neg_data
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def engine_read_all
|
|
31
|
+
output = @engine.read
|
|
32
|
+
while output and additional_output = @engine.read
|
|
33
|
+
output << additional_output
|
|
34
|
+
end
|
|
35
|
+
output
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def read_nonblock(size)
|
|
39
|
+
while true
|
|
40
|
+
output = engine_read_all
|
|
41
|
+
return output if output
|
|
42
|
+
|
|
43
|
+
data = @socket.read_nonblock(size)
|
|
44
|
+
|
|
45
|
+
@engine.inject(data)
|
|
46
|
+
output = engine_read_all
|
|
47
|
+
|
|
48
|
+
return output if output
|
|
49
|
+
|
|
50
|
+
while neg_data = @engine.extract
|
|
51
|
+
@socket.write neg_data
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def write(data)
|
|
57
|
+
need = data.bytesize
|
|
58
|
+
|
|
59
|
+
while true
|
|
60
|
+
wrote = @engine.write data
|
|
61
|
+
enc = @engine.extract
|
|
62
|
+
|
|
63
|
+
while enc
|
|
64
|
+
@socket.write enc
|
|
65
|
+
enc = @engine.extract
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
need -= wrote
|
|
69
|
+
|
|
70
|
+
return data.bytesize if need == 0
|
|
71
|
+
|
|
72
|
+
data = data[need..-1]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
alias_method :syswrite, :write
|
|
77
|
+
|
|
78
|
+
def flush
|
|
79
|
+
@socket.flush
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def close
|
|
83
|
+
@socket.close
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def peeraddr
|
|
87
|
+
@socket.peeraddr
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class Context
|
|
92
|
+
attr_accessor :verify_mode
|
|
93
|
+
|
|
94
|
+
attr_reader :key
|
|
95
|
+
attr_reader :cert
|
|
96
|
+
|
|
97
|
+
def key=(key)
|
|
98
|
+
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
|
|
99
|
+
@key = key
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def cert=(cert)
|
|
103
|
+
raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
|
|
104
|
+
@cert = cert
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
VERIFY_NONE = 0
|
|
109
|
+
VERIFY_PEER = 1
|
|
110
|
+
|
|
111
|
+
#if defined?(JRUBY_VERSION)
|
|
112
|
+
#class Engine
|
|
113
|
+
#def self.server(key, cert)
|
|
114
|
+
#new(key, cert)
|
|
115
|
+
#end
|
|
116
|
+
#end
|
|
117
|
+
#end
|
|
118
|
+
|
|
119
|
+
class Server
|
|
120
|
+
def initialize(socket, ctx)
|
|
121
|
+
@socket = socket
|
|
122
|
+
@ctx = ctx
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def to_io
|
|
126
|
+
@socket
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def accept
|
|
130
|
+
io = @socket.accept
|
|
131
|
+
engine = Engine.server @ctx.key, @ctx.cert
|
|
132
|
+
|
|
133
|
+
Socket.new io, engine
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def accept_nonblock
|
|
137
|
+
io = @socket.accept_nonblock
|
|
138
|
+
engine = Engine.server @ctx.key, @ctx.cert
|
|
139
|
+
|
|
140
|
+
Socket.new io, engine
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def close
|
|
144
|
+
@socket.close
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|