1+ require 'bundler'
12require 'proxy/log'
23require 'proxy/sd_notify'
34require 'proxy/settings'
45require 'proxy/signal_handler'
56require 'proxy/log_buffer/trace_decorator'
67require 'thread'
8+ require 'rack'
9+ require 'webrick'
10+ begin
11+ require 'puma'
12+ require 'rack/handler/puma'
13+ require 'puma_patch'
14+ $HAS_PUMA = true
15+ rescue LoadError
16+ $stderr. puts 'Puma was requested but not installed'
17+ $HAS_PUMA = false
18+ end
719
820module Proxy
921 class Launcher
@@ -13,18 +25,24 @@ class Launcher
1325
1426 def initialize ( settings = SETTINGS )
1527 @settings = settings
28+ @settings . http_server_type = Proxy ::SETTINGS . http_server_type . to_sym
29+ if @settings . http_server_type == :puma && !$HAS_PUMA
30+ logger . warn 'Puma was requested but not installed, falling back to webrick'
31+ @settings . http_server_type = :webrick
32+ end
33+ @servers = [ ]
1634 end
1735
1836 def pid_path
19- settings . daemon_pid
37+ @ settings. daemon_pid
2038 end
2139
2240 def http_enabled?
23- !settings . http_port . nil?
41+ !@ settings. http_port . nil?
2442 end
2543
2644 def https_enabled?
27- settings . ssl_private_key && settings . ssl_certificate && settings . ssl_ca_file
45+ @ settings. ssl_private_key && @ settings. ssl_certificate && @ settings. ssl_ca_file
2846 end
2947
3048 def plugins
@@ -47,7 +65,7 @@ def http_app(http_port, plugins = http_plugins)
4765
4866 {
4967 :app => app ,
50- :server => :webrick ,
68+ :server => @settings . http_server_type ,
5169 :DoNotListen => true ,
5270 :Port => http_port , # only being used to correctly log http port being used
5371 :Logger => ::Proxy ::LogBuffer ::TraceDecorator . instance ,
@@ -74,8 +92,8 @@ def https_app(https_port, plugins = https_plugins)
7492 ssl_options |= OpenSSL ::SSL ::OP_NO_SSLv3 if defined? ( OpenSSL ::SSL ::OP_NO_SSLv3 )
7593 ssl_options |= OpenSSL ::SSL ::OP_NO_TLSv1 if defined? ( OpenSSL ::SSL ::OP_NO_TLSv1 )
7694
77- if Proxy :: SETTINGS . tls_disabled_versions
78- Proxy :: SETTINGS . tls_disabled_versions . each do |version |
95+ if @settings . tls_disabled_versions
96+ @settings . tls_disabled_versions . each do |version |
7997 constant = OpenSSL ::SSL . const_get ( "OP_NO_TLSv#{ version . to_s . gsub ( /\. / , '_' ) } " ) rescue nil
8098
8199 if constant
@@ -87,21 +105,31 @@ def https_app(https_port, plugins = https_plugins)
87105 end
88106 end
89107
90- {
108+ app_details = {
91109 :app => app ,
92- :server => :webrick ,
110+ :server => @settings . http_server_type ,
93111 :DoNotListen => true ,
94112 :Port => https_port , # only being used to correctly log https port being used
95113 :Logger => ::Proxy ::LogBuffer ::Decorator . instance ,
96114 :ServerSoftware => "foreman-proxy/#{ Proxy ::VERSION } " ,
97115 :SSLEnable => true ,
98116 :SSLVerifyClient => OpenSSL ::SSL ::VERIFY_PEER ,
99- :SSLPrivateKey => load_ssl_private_key ( settings . ssl_private_key ) ,
100- :SSLCertificate => load_ssl_certificate ( settings . ssl_certificate ) ,
101- :SSLCACertificateFile => settings . ssl_ca_file ,
117+ :SSLCACertificateFile => @settings . ssl_ca_file ,
102118 :SSLOptions => ssl_options ,
103119 :daemonize => false
104120 }
121+ case @settings . http_server_type
122+ when :webrick
123+ app_details [ :SSLPrivateKey ] = load_ssl_private_key ( @settings . ssl_private_key )
124+ app_details [ :SSLCertificate ] = load_ssl_certificate ( @settings . ssl_certificate )
125+ when :puma
126+ app_details [ :SSLArgs ] = {
127+ :ca => @settings . ssl_ca_file ,
128+ :key => @settings . ssl_private_key ,
129+ :cert => @settings . ssl_certificate
130+ }
131+ end
132+ app_details
105133 end
106134
107135 def load_ssl_private_key ( path )
@@ -149,32 +177,85 @@ def write_pid
149177 retry
150178 end
151179
152- def webrick_server ( app , addresses , port )
180+ def add_puma_server ( app , addresses , port , conn_type )
181+ # IMPORTANT:
182+ # The following code takes only a single host.
183+ # The current reason for it, is that "run" is blocking, and in order to
184+ # add support for more hosts, additional threads requires to be created
185+ address = addresses . first
186+ address = '0.0.0.0' if address == '*'
187+ if conn_type == :ssl
188+ host = "ssl://#{ address } /"
189+ require 'cgi'
190+ query_list = [ ]
191+ app [ :SSLArgs ] . each_pair do |name , value |
192+ query_list << "#{ CGI ::escape ( name . to_s ) } =#{ CGI ::escape ( value ) } "
193+ end
194+ host = "#{ host } ?#{ query_list . join ( '&' ) } "
195+ else
196+ host = address
197+ end
198+ Rack ::Handler ::Puma . run ( app [ :app ] ,
199+ Verbose : true ,
200+ Port : port ,
201+ Host : host
202+ )
203+ end
204+
205+ def add_webrick_server ( app , addresses , port )
153206 server = ::WEBrick ::HTTPServer . new ( app )
154- addresses . each { |a | server . listen ( a , port ) }
155- server . mount "/" , Rack ::Handler ::WEBrick , app [ :app ]
207+ addresses . each { |a | server . listen ( a , port ) }
208+ server . mount '/' , Rack ::Handler ::WEBrick , app [ :app ]
156209 server
157210 end
158211
212+ def add_threaded_server ( server_name , conn_type , app , addresses , port )
213+ case server_name
214+ when :webrick
215+ Thread . new do
216+ @servers << add_webrick_server ( app , addresses , port ) . start
217+ end
218+ when :puma
219+ Thread . new do
220+ add_puma_server ( app , addresses , port , conn_type )
221+ end
222+ end
223+ end
224+
159225 def launch
160226 raise Exception . new ( "Both http and https are disabled, unable to start." ) unless http_enabled? || https_enabled?
161227
162- if settings . daemon
228+ if @ settings. daemon
163229 check_pid
164230 Process . daemon
165231 write_pid
166232 end
167233
168234 ::Proxy ::PluginInitializer . new ( ::Proxy ::Plugins . instance ) . initialize_plugins
169235
170- http_app = http_app ( settings . http_port )
171- https_app = https_app ( settings . https_port )
172- install_webrick_callback! ( http_app , https_app )
236+ http_app = http_app ( @settings . http_port )
237+ https_app = https_app ( @settings . https_port )
238+ install_http_server_callback! ( http_app , https_app )
239+
240+ http_server_name = @settings . http_server_type
241+ https_server_name = @settings . http_server_type
242+ if https_app
243+ t1 = add_threaded_server ( https_server_name ,
244+ :ssl ,
245+ https_app ,
246+ @settings . bind_host ,
247+ @settings . https_port )
248+ end
173249
174- t1 = Thread . new { webrick_server ( https_app , settings . bind_host , settings . https_port ) . start } unless https_app . nil?
175- t2 = Thread . new { webrick_server ( http_app , settings . bind_host , settings . http_port ) . start } unless http_app . nil?
250+ if http_app
251+ t2 = add_threaded_server ( http_server_name ,
252+ :tcp ,
253+ http_app ,
254+ @settings . bind_host ,
255+ @settings . http_port )
256+ end
176257
177- Proxy ::SignalHandler . install_traps
258+ Proxy ::SignalHandler . install_traps ( @servers )
178259
179260 ( t1 || t2 ) . join
180261 rescue SignalException => e
@@ -189,19 +270,19 @@ def launch
189270 exit ( 1 )
190271 end
191272
192- def install_webrick_callback !( *apps )
273+ def install_http_server_callback !( *apps )
193274 apps . compact!
194275
195- # track how many webrick apps are still starting up
196- @pending_webrick = apps . size
197- @pending_webrick_lock = Mutex . new
276+ # track how many apps are still starting up
277+ @pending_server = apps . size
278+ @pending_server_lock = Mutex . new
198279
199280 apps . each do |app |
200281 # add a callback to each server, decrementing the pending counter
201282 app [ :StartCallback ] = lambda do
202- @pending_webrick_lock . synchronize do
203- @pending_webrick -= 1
204- launched ( apps ) if @pending_webrick . zero?
283+ @pending_server_lock . synchronize do
284+ @pending_server -= 1
285+ launched ( apps ) if @pending_server . zero?
205286 end
206287 end
207288 end
0 commit comments