1+ require 'bundler'
12require 'proxy/log'
23require 'proxy/sd_notify'
34require 'proxy/settings'
45require 'proxy/signal_handler'
56require 'thread'
7+ require 'rack'
8+ require 'webrick'
9+ begin
10+ require 'puma'
11+ require 'rack/handler/puma'
12+ require 'puma_patch'
13+ $HAS_PUMA = true
14+ rescue LoadError
15+ $stderr. puts 'Puma was requested but not installed'
16+ $HAS_PUMA = false
17+ end
618
719module Proxy
820 class Launcher
@@ -12,18 +24,23 @@ class Launcher
1224
1325 def initialize ( settings = SETTINGS )
1426 @settings = settings
27+ @settings . http_server_type = Proxy ::SETTINGS . http_server_type . to_sym
28+ if @settings . http_server_type == :puma && !$HAS_PUMA
29+ logger . warn 'Puma was requested but not installed, falling back to webrick'
30+ @settings . http_server_type = :webrick
31+ end
1532 end
1633
1734 def pid_path
18- settings . daemon_pid
35+ @ settings. daemon_pid
1936 end
2037
2138 def http_enabled?
22- !settings . http_port . nil?
39+ !@ settings. http_port . nil?
2340 end
2441
2542 def https_enabled?
26- settings . ssl_private_key && settings . ssl_certificate && settings . ssl_ca_file
43+ @ settings. ssl_private_key && @ settings. ssl_certificate && @ settings. ssl_ca_file
2744 end
2845
2946 def plugins
@@ -46,7 +63,7 @@ def http_app(http_port, plugins = http_plugins)
4663
4764 {
4865 :app => app ,
49- :server => :webrick ,
66+ :server => @settings . http_server_type ,
5067 :DoNotListen => true ,
5168 :Port => http_port , # only being used to correctly log http port being used
5269 :Logger => ::Proxy ::LogBuffer ::Decorator . instance ,
@@ -72,8 +89,8 @@ def https_app(https_port, plugins = https_plugins)
7289 ssl_options |= OpenSSL ::SSL ::OP_NO_SSLv3 if defined? ( OpenSSL ::SSL ::OP_NO_SSLv3 )
7390 ssl_options |= OpenSSL ::SSL ::OP_NO_TLSv1 if defined? ( OpenSSL ::SSL ::OP_NO_TLSv1 )
7491
75- if Proxy :: SETTINGS . tls_disabled_versions
76- Proxy :: SETTINGS . tls_disabled_versions . each do |version |
92+ if @settings . tls_disabled_versions
93+ @settings . tls_disabled_versions . each do |version |
7794 constant = OpenSSL ::SSL . const_get ( "OP_NO_TLSv#{ version . to_s . gsub ( /\. / , '_' ) } " ) rescue nil
7895
7996 if constant
@@ -85,21 +102,31 @@ def https_app(https_port, plugins = https_plugins)
85102 end
86103 end
87104
88- {
105+ app_details = {
89106 :app => app ,
90- :server => :webrick ,
107+ :server => @settings . http_server_type ,
91108 :DoNotListen => true ,
92109 :Port => https_port , # only being used to correctly log https port being used
93110 :Logger => ::Proxy ::LogBuffer ::Decorator . instance ,
94111 :ServerSoftware => "foreman-proxy/#{ Proxy ::VERSION } " ,
95112 :SSLEnable => true ,
96113 :SSLVerifyClient => OpenSSL ::SSL ::VERIFY_PEER ,
97- :SSLPrivateKey => load_ssl_private_key ( settings . ssl_private_key ) ,
98- :SSLCertificate => load_ssl_certificate ( settings . ssl_certificate ) ,
99- :SSLCACertificateFile => settings . ssl_ca_file ,
114+ :SSLCACertificateFile => @settings . ssl_ca_file ,
100115 :SSLOptions => ssl_options ,
101116 :daemonize => false
102117 }
118+ case @settings . http_server_type
119+ when :webrick
120+ app_details [ :SSLPrivateKey ] = load_ssl_private_key ( @settings . ssl_private_key )
121+ app_details [ :SSLCertificate ] = load_ssl_certificate ( @settings . ssl_certificate )
122+ when :puma
123+ app_details [ :SSLArgs ] = {
124+ :ca => @settings . ssl_ca_file ,
125+ :key => @settings . ssl_private_key ,
126+ :cert => @settings . ssl_certificate
127+ }
128+ end
129+ app_details
103130 end
104131
105132 def load_ssl_private_key ( path )
@@ -147,30 +174,83 @@ def write_pid
147174 retry
148175 end
149176
150- def webrick_server ( app , addresses , port )
177+ def add_puma_server ( app , addresses , port , conn_type )
178+ # IMPORTANT:
179+ # The following code takes only a single host.
180+ # The current reason for it, is that "run" is blocking, and in order to
181+ # add support for more hosts, additional threads requires to be created
182+ address = addresses . first
183+ address = '0.0.0.0' if address == '*'
184+ if conn_type == :ssl
185+ host = "ssl://#{ address } /"
186+ require 'cgi'
187+ query_list = [ ]
188+ app [ :SSLArgs ] . each_pair do |name , value |
189+ query_list << "#{ CGI ::escape ( name . to_s ) } =#{ CGI ::escape ( value ) } "
190+ end
191+ host = "#{ host } ?#{ query_list . join ( '&' ) } "
192+ else
193+ host = address
194+ end
195+ Rack ::Handler ::Puma . run ( app [ :app ] ,
196+ Verbose : true ,
197+ Port : port ,
198+ Host : host
199+ )
200+ end
201+
202+ def add_webrick_server ( app , addresses , port )
151203 server = ::WEBrick ::HTTPServer . new ( app )
152- addresses . each { |a | server . listen ( a , port ) }
153- server . mount "/" , Rack ::Handler ::WEBrick , app [ :app ]
204+ addresses . each { |a | server . listen ( a , port ) }
205+ server . mount '/' , Rack ::Handler ::WEBrick , app [ :app ]
154206 server
155207 end
156208
209+ def add_threaded_server ( server_name , conn_type , app , addresses , port )
210+ case server_name
211+ when :webrick
212+ Thread . new do
213+ add_webrick_server ( app , addresses , port ) . start
214+ end
215+ when :puma
216+ Thread . new do
217+ add_puma_server ( app , addresses , port , conn_type )
218+ end
219+ end
220+ end
221+
157222 def launch
158223 raise Exception . new ( "Both http and https are disabled, unable to start." ) unless http_enabled? || https_enabled?
159224
160- if settings . daemon
225+ if @ settings. daemon
161226 check_pid
162227 Process . daemon
163228 write_pid
164229 end
165230
166231 ::Proxy ::PluginInitializer . new ( ::Proxy ::Plugins . instance ) . initialize_plugins
167232
168- http_app = http_app ( settings . http_port )
169- https_app = https_app ( settings . https_port )
170- install_webrick_callback! ( http_app , https_app )
233+ http_app = http_app ( @settings . http_port )
234+ https_app = https_app ( @settings . https_port )
235+ install_http_server_callback! ( http_app , https_app )
236+
237+ http_server_name = @settings . http_server_type
238+ https_server_name = @settings . http_server_type
239+ if https_app
240+ t1 = add_threaded_server ( https_server_name ,
241+ :ssl ,
242+ https_app ,
243+ @settings . bind_host ,
244+ @settings . https_port )
245+ end
171246
172- t1 = Thread . new { webrick_server ( https_app , settings . bind_host , settings . https_port ) . start } unless https_app . nil?
173- t2 = Thread . new { webrick_server ( http_app , settings . bind_host , settings . http_port ) . start } unless http_app . nil?
247+ if http_app
248+ t2 = add_threaded_server ( http_server_name ,
249+ :tcp ,
250+ http_app ,
251+ @settings . bind_host ,
252+ @settings . http_port )
253+ end
174254
175255 Proxy ::SignalHandler . install_traps
176256
@@ -187,19 +267,19 @@ def launch
187267 exit ( 1 )
188268 end
189269
190- def install_webrick_callback !( *apps )
270+ def install_http_server_callback !( *apps )
191271 apps . compact!
192272
193- # track how many webrick apps are still starting up
194- @pending_webrick = apps . size
195- @pending_webrick_lock = Mutex . new
273+ # track how many apps are still starting up
274+ @pending_server = apps . size
275+ @pending_server_lock = Mutex . new
196276
197277 apps . each do |app |
198278 # add a callback to each server, decrementing the pending counter
199279 app [ :StartCallback ] = lambda do
200- @pending_webrick_lock . synchronize do
201- @pending_webrick -= 1
202- launched ( apps ) if @pending_webrick . zero?
280+ @pending_server_lock . synchronize do
281+ @pending_server -= 1
282+ launched ( apps ) if @pending_server . zero?
203283 end
204284 end
205285 end
0 commit comments