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.
Files changed (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/Gemfile +14 -0
  4. data/Guardfile +5 -0
  5. data/LICENSE.txt +1 -0
  6. data/README.md +51 -0
  7. data/Rakefile +9 -0
  8. data/bin/_rsense.rb +115 -0
  9. data/config/puma.rb +2 -0
  10. data/lib/rsense/server/code.rb +38 -0
  11. data/lib/rsense/server/command/completion_result.rb +11 -0
  12. data/lib/rsense/server/command/special_meth.rb +18 -0
  13. data/lib/rsense/server/command/type_inference_method.rb +24 -0
  14. data/lib/rsense/server/command.rb +239 -0
  15. data/lib/rsense/server/config.rb +70 -0
  16. data/lib/rsense/server/gem_path.rb +18 -0
  17. data/lib/rsense/server/listeners/find_definition_event_listener.rb +91 -0
  18. data/lib/rsense/server/listeners/where_event_listener.rb +39 -0
  19. data/lib/rsense/server/load_path.rb +62 -0
  20. data/lib/rsense/server/options.rb +85 -0
  21. data/lib/rsense/server/parser.rb +17 -0
  22. data/lib/rsense/server/path_info.rb +17 -0
  23. data/lib/rsense/server/project.rb +24 -0
  24. data/lib/rsense/server/version.rb +5 -0
  25. data/lib/rsense/server.rb +18 -0
  26. data/rsense-server.gemspec +35 -0
  27. data/spec/fixtures/config_fixture/.rsense +4 -0
  28. data/spec/fixtures/deeply/nested/thing.rb +0 -0
  29. data/spec/fixtures/find_def_sample.json +10 -0
  30. data/spec/fixtures/sample.json +10 -0
  31. data/spec/fixtures/test_gem/.gitignore +22 -0
  32. data/spec/fixtures/test_gem/Gemfile +4 -0
  33. data/spec/fixtures/test_gem/LICENSE.txt +22 -0
  34. data/spec/fixtures/test_gem/README.md +29 -0
  35. data/spec/fixtures/test_gem/Rakefile +2 -0
  36. data/spec/fixtures/test_gem/lib/sample/version.rb +3 -0
  37. data/spec/fixtures/test_gem/lib/sample.rb +16 -0
  38. data/spec/fixtures/test_gem/sample.gemspec +23 -0
  39. data/spec/fixtures/test_gem/test.json +10 -0
  40. data/spec/rsense/server/code_spec.rb +44 -0
  41. data/spec/rsense/server/command/special_meth_spec.rb +23 -0
  42. data/spec/rsense/server/command_spec.rb +108 -0
  43. data/spec/rsense/server/config_spec.rb +27 -0
  44. data/spec/rsense/server/gem_path_spec.rb +16 -0
  45. data/spec/rsense/server/load_path_spec.rb +63 -0
  46. data/spec/rsense/server/options_spec.rb +33 -0
  47. data/spec/rsense/server/path_info_spec.rb +11 -0
  48. data/spec/rsense/server/project_spec.rb +18 -0
  49. data/spec/rsense/server_spec.rb +7 -0
  50. data/spec/spec_helper.rb +16 -0
  51. data/vendor/gems/puma-2.8.2-java/COPYING +55 -0
  52. data/vendor/gems/puma-2.8.2-java/DEPLOYMENT.md +92 -0
  53. data/vendor/gems/puma-2.8.2-java/Gemfile +17 -0
  54. data/vendor/gems/puma-2.8.2-java/History.txt +532 -0
  55. data/vendor/gems/puma-2.8.2-java/LICENSE +26 -0
  56. data/vendor/gems/puma-2.8.2-java/Manifest.txt +68 -0
  57. data/vendor/gems/puma-2.8.2-java/README.md +251 -0
  58. data/vendor/gems/puma-2.8.2-java/Rakefile +158 -0
  59. data/vendor/gems/puma-2.8.2-java/bin/puma +10 -0
  60. data/vendor/gems/puma-2.8.2-java/bin/puma-wild +17 -0
  61. data/vendor/gems/puma-2.8.2-java/bin/pumactl +12 -0
  62. data/vendor/gems/puma-2.8.2-java/docs/config.md +0 -0
  63. data/vendor/gems/puma-2.8.2-java/docs/nginx.md +80 -0
  64. data/vendor/gems/puma-2.8.2-java/docs/signals.md +42 -0
  65. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/PumaHttp11Service.java +17 -0
  66. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/ext_help.h +15 -0
  67. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/extconf.rb +8 -0
  68. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser.c +1225 -0
  69. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser.h +64 -0
  70. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser.java.rl +161 -0
  71. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser.rl +146 -0
  72. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/http11_parser_common.rl +54 -0
  73. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/io_buffer.c +155 -0
  74. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/mini_ssl.c +195 -0
  75. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/org/jruby/puma/Http11.java +225 -0
  76. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/org/jruby/puma/Http11Parser.java +488 -0
  77. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/org/jruby/puma/MiniSSL.java +289 -0
  78. data/vendor/gems/puma-2.8.2-java/ext/puma_http11/puma_http11.c +491 -0
  79. data/vendor/gems/puma-2.8.2-java/lib/puma/accept_nonblock.rb +23 -0
  80. data/vendor/gems/puma-2.8.2-java/lib/puma/app/status.rb +59 -0
  81. data/vendor/gems/puma-2.8.2-java/lib/puma/binder.rb +298 -0
  82. data/vendor/gems/puma-2.8.2-java/lib/puma/capistrano.rb +86 -0
  83. data/vendor/gems/puma-2.8.2-java/lib/puma/cli.rb +587 -0
  84. data/vendor/gems/puma-2.8.2-java/lib/puma/client.rb +289 -0
  85. data/vendor/gems/puma-2.8.2-java/lib/puma/cluster.rb +389 -0
  86. data/vendor/gems/puma-2.8.2-java/lib/puma/compat.rb +18 -0
  87. data/vendor/gems/puma-2.8.2-java/lib/puma/configuration.rb +377 -0
  88. data/vendor/gems/puma-2.8.2-java/lib/puma/const.rb +165 -0
  89. data/vendor/gems/puma-2.8.2-java/lib/puma/control_cli.rb +251 -0
  90. data/vendor/gems/puma-2.8.2-java/lib/puma/daemon_ext.rb +25 -0
  91. data/vendor/gems/puma-2.8.2-java/lib/puma/delegation.rb +11 -0
  92. data/vendor/gems/puma-2.8.2-java/lib/puma/detect.rb +4 -0
  93. data/vendor/gems/puma-2.8.2-java/lib/puma/events.rb +130 -0
  94. data/vendor/gems/puma-2.8.2-java/lib/puma/io_buffer.rb +7 -0
  95. data/vendor/gems/puma-2.8.2-java/lib/puma/java_io_buffer.rb +45 -0
  96. data/vendor/gems/puma-2.8.2-java/lib/puma/jruby_restart.rb +83 -0
  97. data/vendor/gems/puma-2.8.2-java/lib/puma/minissl.rb +148 -0
  98. data/vendor/gems/puma-2.8.2-java/lib/puma/null_io.rb +34 -0
  99. data/vendor/gems/puma-2.8.2-java/lib/puma/puma_http11.jar +0 -0
  100. data/vendor/gems/puma-2.8.2-java/lib/puma/rack_default.rb +7 -0
  101. data/vendor/gems/puma-2.8.2-java/lib/puma/rack_patch.rb +45 -0
  102. data/vendor/gems/puma-2.8.2-java/lib/puma/reactor.rb +183 -0
  103. data/vendor/gems/puma-2.8.2-java/lib/puma/runner.rb +146 -0
  104. data/vendor/gems/puma-2.8.2-java/lib/puma/server.rb +801 -0
  105. data/vendor/gems/puma-2.8.2-java/lib/puma/single.rb +102 -0
  106. data/vendor/gems/puma-2.8.2-java/lib/puma/tcp_logger.rb +32 -0
  107. data/vendor/gems/puma-2.8.2-java/lib/puma/thread_pool.rb +185 -0
  108. data/vendor/gems/puma-2.8.2-java/lib/puma/util.rb +9 -0
  109. data/vendor/gems/puma-2.8.2-java/lib/puma.rb +14 -0
  110. data/vendor/gems/puma-2.8.2-java/lib/rack/handler/puma.rb +66 -0
  111. data/vendor/gems/puma-2.8.2-java/puma.gemspec +55 -0
  112. data/vendor/gems/puma-2.8.2-java/test/test_app_status.rb +92 -0
  113. data/vendor/gems/puma-2.8.2-java/test/test_cli.rb +173 -0
  114. data/vendor/gems/puma-2.8.2-java/test/test_config.rb +26 -0
  115. data/vendor/gems/puma-2.8.2-java/test/test_http10.rb +27 -0
  116. data/vendor/gems/puma-2.8.2-java/test/test_http11.rb +144 -0
  117. data/vendor/gems/puma-2.8.2-java/test/test_integration.rb +165 -0
  118. data/vendor/gems/puma-2.8.2-java/test/test_iobuffer.rb +38 -0
  119. data/vendor/gems/puma-2.8.2-java/test/test_minissl.rb +25 -0
  120. data/vendor/gems/puma-2.8.2-java/test/test_null_io.rb +31 -0
  121. data/vendor/gems/puma-2.8.2-java/test/test_persistent.rb +238 -0
  122. data/vendor/gems/puma-2.8.2-java/test/test_puma_server.rb +323 -0
  123. data/vendor/gems/puma-2.8.2-java/test/test_rack_handler.rb +10 -0
  124. data/vendor/gems/puma-2.8.2-java/test/test_rack_server.rb +141 -0
  125. data/vendor/gems/puma-2.8.2-java/test/test_tcp_rack.rb +42 -0
  126. data/vendor/gems/puma-2.8.2-java/test/test_thread_pool.rb +156 -0
  127. data/vendor/gems/puma-2.8.2-java/test/test_unix_socket.rb +39 -0
  128. data/vendor/gems/puma-2.8.2-java/test/test_ws.rb +89 -0
  129. data/vendor/gems/puma-2.8.2-java/tools/jungle/README.md +9 -0
  130. data/vendor/gems/puma-2.8.2-java/tools/jungle/init.d/README.md +54 -0
  131. data/vendor/gems/puma-2.8.2-java/tools/jungle/init.d/puma +332 -0
  132. data/vendor/gems/puma-2.8.2-java/tools/jungle/init.d/run-puma +3 -0
  133. data/vendor/gems/puma-2.8.2-java/tools/jungle/upstart/README.md +61 -0
  134. data/vendor/gems/puma-2.8.2-java/tools/jungle/upstart/puma-manager.conf +31 -0
  135. data/vendor/gems/puma-2.8.2-java/tools/jungle/upstart/puma.conf +63 -0
  136. data/vendor/gems/puma-2.8.2-java/tools/trickletest.rb +45 -0
  137. 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,11 @@
1
+ module Puma
2
+ module Delegation
3
+ def forward(what, who)
4
+ module_eval <<-CODE
5
+ def #{what}(*args, &block)
6
+ #{who}.#{what}(*args, &block)
7
+ end
8
+ CODE
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ module Puma
2
+ IS_JRUBY = defined?(JRUBY_VERSION)
3
+ end
4
+
@@ -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,7 @@
1
+ require 'puma/detect'
2
+
3
+ if Puma::IS_JRUBY
4
+ require 'puma/java_io_buffer'
5
+ else
6
+ require 'puma/puma_http11'
7
+ 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