44require 'proxy/signal_handler'
55require 'proxy/log_buffer/trace_decorator'
66require 'thread'
7+ require 'rack'
8+ require 'webrick'
79
810module Proxy
911 class Launcher
@@ -13,18 +15,30 @@ class Launcher
1315
1416 def initialize ( settings = SETTINGS )
1517 @settings = settings
18+ @settings . http_server_type = Proxy ::SETTINGS . http_server_type . to_sym
19+ if @settings . http_server_type == :puma
20+ begin
21+ require 'puma'
22+ require 'rack/handler/puma'
23+ require 'puma-patch'
24+ rescue LoadError
25+ logger . warn 'Puma was requested but not installed, falling back to webrick'
26+ @settings . http_server_type = :webrick
27+ end
28+ end
29+ @servers = [ ]
1630 end
1731
1832 def pid_path
19- settings . daemon_pid
33+ @ settings. daemon_pid
2034 end
2135
2236 def http_enabled?
23- !settings . http_port . nil?
37+ !@ settings. http_port . nil?
2438 end
2539
2640 def https_enabled?
27- settings . ssl_private_key && settings . ssl_certificate && settings . ssl_ca_file
41+ @ settings. ssl_private_key && @ settings. ssl_certificate && @ settings. ssl_ca_file
2842 end
2943
3044 def plugins
@@ -47,7 +61,7 @@ def http_app(http_port, plugins = http_plugins)
4761
4862 {
4963 :app => app ,
50- :server => :webrick ,
64+ :server => @settings . http_server_type ,
5165 :DoNotListen => true ,
5266 :Port => http_port , # only being used to correctly log http port being used
5367 :Logger => ::Proxy ::LogBuffer ::TraceDecorator . instance ,
@@ -74,8 +88,8 @@ def https_app(https_port, plugins = https_plugins)
7488 ssl_options |= OpenSSL ::SSL ::OP_NO_SSLv3 if defined? ( OpenSSL ::SSL ::OP_NO_SSLv3 )
7589 ssl_options |= OpenSSL ::SSL ::OP_NO_TLSv1 if defined? ( OpenSSL ::SSL ::OP_NO_TLSv1 )
7690
77- if Proxy :: SETTINGS . tls_disabled_versions
78- Proxy :: SETTINGS . tls_disabled_versions . each do |version |
91+ if @settings . tls_disabled_versions
92+ @settings . tls_disabled_versions . each do |version |
7993 constant = OpenSSL ::SSL . const_get ( "OP_NO_TLSv#{ version . to_s . tr ( '.' , '_' ) } " ) rescue nil
8094
8195 if constant
@@ -87,21 +101,31 @@ def https_app(https_port, plugins = https_plugins)
87101 end
88102 end
89103
90- {
104+ app_details = {
91105 :app => app ,
92- :server => :webrick ,
106+ :server => @settings . http_server_type ,
93107 :DoNotListen => true ,
94108 :Port => https_port , # only being used to correctly log https port being used
95109 :Logger => ::Proxy ::LogBuffer ::Decorator . instance ,
96110 :ServerSoftware => "foreman-proxy/#{ Proxy ::VERSION } " ,
97111 :SSLEnable => true ,
98112 :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 ,
113+ :SSLCACertificateFile => @settings . ssl_ca_file ,
102114 :SSLOptions => ssl_options ,
103115 :daemonize => false
104116 }
117+ case @settings . http_server_type
118+ when :webrick
119+ app_details [ :SSLPrivateKey ] = load_ssl_private_key ( @settings . ssl_private_key )
120+ app_details [ :SSLCertificate ] = load_ssl_certificate ( @settings . ssl_certificate )
121+ when :puma
122+ app_details [ :SSLArgs ] = {
123+ :ca => @settings . ssl_ca_file ,
124+ :key => @settings . ssl_private_key ,
125+ :cert => @settings . ssl_certificate
126+ }
127+ end
128+ app_details
105129 end
106130
107131 def load_ssl_private_key ( path )
@@ -149,34 +173,90 @@ def write_pid
149173 retry
150174 end
151175
152- def webrick_server ( app , addresses , port )
176+ def add_puma_server ( app , address , port , conn_type )
177+ logger . debug "Launching Puma listener at #{ address } port #{ port } "
178+ if conn_type == :ssl
179+ require 'cgi'
180+ query_list = app [ :SSLArgs ] . to_a . map do |x |
181+ "#{ CGI ::escape ( x [ 0 ] . to_s ) } =#{ CGI ::escape ( x [ 1 ] ) } "
182+ end
183+ host = "ssl://#{ address } /?#{ query_list . join ( '&' ) } "
184+ else
185+ host = address
186+ end
187+ logger . debug "Host URL: #{ host } "
188+ # the following lines are from lib/rack/handler/puma.rb#run
189+ options = { Verbose : true , Port : port , Host : host }
190+ conf = Rack ::Handler ::Puma . config ( app [ :app ] , options )
191+ events = ::Puma ::Events . new ( ::Proxy ::LogBuffer ::Decorator . instance , ::Proxy ::LogBuffer ::Decorator . instance )
192+ launcher = ::Puma ::Launcher . new ( conf , :events => events )
193+ @servers << launcher
194+ launcher . run
195+ end
196+
197+ def add_webrick_server ( app , addresses , port )
153198 server = ::WEBrick ::HTTPServer . new ( app )
154- addresses . each { |a | server . listen ( a , port ) }
155- server . mount "/" , Rack ::Handler ::WEBrick , app [ :app ]
199+ addresses . each do |address |
200+ logger . debug "Launching Webrick listener at #{ address } port #{ port } "
201+ server . listen ( address , port )
202+ end
203+ server . mount '/' , Rack ::Handler ::WEBrick , app [ :app ]
156204 server
157205 end
158206
207+ def add_threaded_server ( server_name , conn_type , app , addresses , port )
208+ result = [ ]
209+ case server_name
210+ when :webrick
211+ result << Thread . new do
212+ @servers << add_webrick_server ( app , addresses , port ) . start
213+ end
214+ when :puma
215+ addresses . map { |a | a == '*' ? [ '0.0.0.0' , '[::1]' ] : a } . flatten . each do |address |
216+ result << Thread . new do
217+ add_puma_server ( app , address , port , conn_type )
218+ end
219+ end
220+ end
221+ result
222+ end
223+
159224 def launch
160225 raise Exception . new ( "Both http and https are disabled, unable to start." ) unless http_enabled? || https_enabled?
161226
162- if settings . daemon
227+ if @ settings. daemon
163228 check_pid
164229 Process . daemon
165230 write_pid
166231 end
167232
168233 ::Proxy ::PluginInitializer . new ( ::Proxy ::Plugins . instance ) . initialize_plugins
169234
170- http_app = http_app ( settings . http_port )
171- https_app = https_app ( settings . https_port )
172- install_webrick_callback! ( http_app , https_app )
173-
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?
235+ http_app = http_app ( @settings . http_port )
236+ https_app = https_app ( @settings . https_port )
237+ install_http_server_callback! ( http_app , https_app )
238+
239+ http_server_name = @settings . http_server_type
240+ https_server_name = @settings . http_server_type
241+ threads = [ ]
242+ if https_app
243+ threads += add_threaded_server ( https_server_name ,
244+ :ssl ,
245+ https_app ,
246+ @settings . bind_host ,
247+ @settings . https_port )
248+ end
176249
177- Proxy ::SignalHandler . install_traps
250+ if http_app
251+ threads += add_threaded_server ( http_server_name ,
252+ :tcp ,
253+ http_app ,
254+ @settings . bind_host ,
255+ @settings . http_port )
256+ end
178257
179- ( t1 || t2 ) . join
258+ Proxy ::SignalHandler . install_traps ( @servers )
259+ threads . each ( &:join )
180260 rescue SignalException => e
181261 logger . debug ( "Caught #{ e } . Exiting" )
182262 raise
@@ -189,19 +269,19 @@ def launch
189269 exit ( 1 )
190270 end
191271
192- def install_webrick_callback !( *apps )
272+ def install_http_server_callback !( *apps )
193273 apps . compact!
194274
195- # track how many webrick apps are still starting up
196- @pending_webrick = apps . size
197- @pending_webrick_lock = Mutex . new
275+ # track how many apps are still starting up
276+ @pending_server = apps . size
277+ @pending_server_lock = Mutex . new
198278
199279 apps . each do |app |
200280 # add a callback to each server, decrementing the pending counter
201281 app [ :StartCallback ] = lambda do
202- @pending_webrick_lock . synchronize do
203- @pending_webrick -= 1
204- launched ( apps ) if @pending_webrick . zero?
282+ @pending_server_lock . synchronize do
283+ @pending_server -= 1
284+ launched ( apps ) if @pending_server . zero?
205285 end
206286 end
207287 end
0 commit comments