mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
Support configuring the puma server to use SSL
This commit is contained in:
parent
bbec20f91d
commit
170bc99d68
6 changed files with 123 additions and 8 deletions
|
@ -61,10 +61,14 @@ module Capybara
|
||||||
|
|
||||||
attr_reader :app, :port, :host
|
attr_reader :app, :port, :host
|
||||||
|
|
||||||
def initialize(app, port = Capybara.server_port, host = Capybara.server_host, server_errors = Capybara.server_errors)
|
def initialize(app, *deprecated_options, port: Capybara.server_port, host: Capybara.server_host, reportable_errors: Capybara.server_errors)
|
||||||
|
warn "Positional arguments, other than the application, to Server#new are deprecated, please use keyword arguments" unless deprecated_options.empty?
|
||||||
@app = app
|
@app = app
|
||||||
@server_thread = nil # suppress warnings
|
@server_thread = nil # suppress warnings
|
||||||
@host, @port, @server_errors = host, port, server_errors
|
@host = deprecated_options[1] || host
|
||||||
|
@reportable_errors = deprecated_options[2] || reportable_errors
|
||||||
|
@using_ssl = false
|
||||||
|
@port = deprecated_options[0] || port
|
||||||
@port ||= Capybara::Server.ports[port_key]
|
@port ||= Capybara::Server.ports[port_key]
|
||||||
@port ||= find_available_port(host)
|
@port ||= find_available_port(host)
|
||||||
end
|
end
|
||||||
|
@ -77,10 +81,23 @@ module Capybara
|
||||||
middleware.error
|
middleware.error
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def using_ssl?
|
||||||
|
@using_ssl
|
||||||
|
end
|
||||||
|
|
||||||
def responsive?
|
def responsive?
|
||||||
return false if @server_thread && @server_thread.join(0)
|
return false if @server_thread && @server_thread.join(0)
|
||||||
|
|
||||||
res = Net::HTTP.start(host, port) { |http| http.get('/__identify__') }
|
begin
|
||||||
|
res = if !@using_ssl
|
||||||
|
http_connect
|
||||||
|
else
|
||||||
|
https_connect
|
||||||
|
end
|
||||||
|
rescue EOFError, Net::ReadTimeout
|
||||||
|
res = https_connect
|
||||||
|
@using_ssl = true
|
||||||
|
end
|
||||||
|
|
||||||
if res.is_a?(Net::HTTPSuccess) or res.is_a?(Net::HTTPRedirection)
|
if res.is_a?(Net::HTTPSuccess) or res.is_a?(Net::HTTPRedirection)
|
||||||
return res.body == app.object_id.to_s
|
return res.body == app.object_id.to_s
|
||||||
|
@ -121,8 +138,16 @@ module Capybara
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def http_connect
|
||||||
|
Net::HTTP.start(host, port, read_timeout: 2) { |http| http.get('/__identify__') }
|
||||||
|
end
|
||||||
|
|
||||||
|
def https_connect
|
||||||
|
Net::HTTP.start(host, port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |http| http.get('/__identify__') }
|
||||||
|
end
|
||||||
|
|
||||||
def middleware
|
def middleware
|
||||||
@middleware ||= Middleware.new(app, @server_errors)
|
@middleware ||= Middleware.new(app, @reportable_errors)
|
||||||
end
|
end
|
||||||
|
|
||||||
def port_key
|
def port_key
|
||||||
|
|
|
@ -84,7 +84,7 @@ module Capybara
|
||||||
yield config
|
yield config
|
||||||
end
|
end
|
||||||
@server = if config.run_server and @app and driver.needs_server?
|
@server = if config.run_server and @app and driver.needs_server?
|
||||||
Capybara::Server.new(@app, config.server_port, config.server_host, config.server_errors).boot
|
Capybara::Server.new(@app, port: config.server_port, host: config.server_host, reportable_errors: config.server_errors).boot
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
@ -249,7 +249,7 @@ module Capybara
|
||||||
visit_uri = ::Addressable::URI.parse(visit_uri.to_s)
|
visit_uri = ::Addressable::URI.parse(visit_uri.to_s)
|
||||||
|
|
||||||
uri_base = if @server
|
uri_base = if @server
|
||||||
::Addressable::URI.parse(config.app_host || "http://#{@server.host}:#{@server.port}")
|
::Addressable::URI.parse(config.app_host || "http#{'s' if @server.using_ssl?}://#{@server.host}:#{@server.port}")
|
||||||
else
|
else
|
||||||
config.app_host && ::Addressable::URI.parse(config.app_host)
|
config.app_host && ::Addressable::URI.parse(config.app_host)
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,7 +43,7 @@ RSpec.describe Capybara do
|
||||||
|
|
||||||
it "should default to a proc that calls run_default_server" do
|
it "should default to a proc that calls run_default_server" do
|
||||||
mock_app = Object.new
|
mock_app = Object.new
|
||||||
allow(Capybara).to receive(:run_default_server)
|
allow(Capybara).to receive(:run_default_server).and_return(true)
|
||||||
Capybara.server.call(mock_app, 8000)
|
Capybara.server.call(mock_app, 8000)
|
||||||
expect(Capybara).to have_received(:run_default_server).with(mock_app, 8000)
|
expect(Capybara).to have_received(:run_default_server).with(mock_app, 8000)
|
||||||
end
|
end
|
||||||
|
|
25
spec/fixtures/certificate.pem
vendored
Normal file
25
spec/fixtures/certificate.pem
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEITCCAwmgAwIBAgIJALROkwd1gZHQMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV
|
||||||
|
BAYTAlVTMQswCQYDVQQIEwJDQTERMA8GA1UEChMIQ2FweWJhcmExFjAUBgNVBAMT
|
||||||
|
DWNhcHliYXJhLnRlc3QxITAfBgkqhkiG9w0BCQEWEnR3YWxwb2xlQGdtYWlsLmNv
|
||||||
|
bTAeFw0xODA1MDEyMDI5NDVaFw0yODA0MjgyMDI5NDVaMGgxCzAJBgNVBAYTAlVT
|
||||||
|
MQswCQYDVQQIEwJDQTERMA8GA1UEChMIQ2FweWJhcmExFjAUBgNVBAMTDWNhcHli
|
||||||
|
YXJhLnRlc3QxITAfBgkqhkiG9w0BCQEWEnR3YWxwb2xlQGdtYWlsLmNvbTCCASIw
|
||||||
|
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL7icqMv9uApxRXlcIQ3hSEfmULk
|
||||||
|
7CLT1aUAjEmTiqy8TkFqOeSuA3elnbVBhOW+emrb1uUyje20LvEOHbqYYw90ezlV
|
||||||
|
jqNWUapawqjxb+q7KVNpA5uDCtOHIC/1Z1kxQ+yZP/8St4SvnLGUMsUhu0h+ywJa
|
||||||
|
iGZ2xy8wdfjABUiUImRESdNkT7Xs0wxQGY0/FZ4K5Sec4kroOuvdxKKhyf5Js5xS
|
||||||
|
NRv2tXSMWlKHbYEvYzsVtFgv/4GjqN4wVvbfJmsS8thcyrSYSMN7eE0R6dcbJaLM
|
||||||
|
P/GTiw669zPJP164K84QoabLClgwyG+7mqjm7jutq9qXipwyrGsf/WR5fkUCAwEA
|
||||||
|
AaOBzTCByjAdBgNVHQ4EFgQU4ut9c0oB2OGMlN/nvn0Y7twBzJowgZoGA1UdIwSB
|
||||||
|
kjCBj4AU4ut9c0oB2OGMlN/nvn0Y7twBzJqhbKRqMGgxCzAJBgNVBAYTAlVTMQsw
|
||||||
|
CQYDVQQIEwJDQTERMA8GA1UEChMIQ2FweWJhcmExFjAUBgNVBAMTDWNhcHliYXJh
|
||||||
|
LnRlc3QxITAfBgkqhkiG9w0BCQEWEnR3YWxwb2xlQGdtYWlsLmNvbYIJALROkwd1
|
||||||
|
gZHQMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAANtqdDrdehBt20s
|
||||||
|
IVOsVzOp+tJI8pn6G62WJcZWGsvLLfx6Y6eJSP24r5NW4v39cqCgE76J2znzKxeo
|
||||||
|
VIShAJ1SLodR0GwzFGsl3TVKVoce6gBWZNXgkZyJTNqKGWeme8CH1EG3TqYlcybt
|
||||||
|
EXWLQ6wKndD+uHJIfqUy7HfaUv+TghJGLkv8QYqcAWILQko4xqZ1NULDQ2uhjxei
|
||||||
|
oaQlK9teHlVaH87dONesAg3f5rh9j6nvzGiC/T8ycdEhn/DxJMxRS2+mVZqKkk7U
|
||||||
|
60+e9Foc6qTW8UaMShIFYMspoRnr9baBxzxh9V9LZznwqVTf3vuEIck2l2j2KL/R
|
||||||
|
SOBenCM=
|
||||||
|
-----END CERTIFICATE-----
|
27
spec/fixtures/key.pem
vendored
Normal file
27
spec/fixtures/key.pem
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEAvuJyoy/24CnFFeVwhDeFIR+ZQuTsItPVpQCMSZOKrLxOQWo5
|
||||||
|
5K4Dd6WdtUGE5b56atvW5TKN7bQu8Q4duphjD3R7OVWOo1ZRqlrCqPFv6rspU2kD
|
||||||
|
m4MK04cgL/VnWTFD7Jk//xK3hK+csZQyxSG7SH7LAlqIZnbHLzB1+MAFSJQiZERJ
|
||||||
|
02RPtezTDFAZjT8VngrlJ5ziSug6693EoqHJ/kmznFI1G/a1dIxaUodtgS9jOxW0
|
||||||
|
WC//gaOo3jBW9t8maxLy2FzKtJhIw3t4TRHp1xslosw/8ZOLDrr3M8k/XrgrzhCh
|
||||||
|
pssKWDDIb7uaqObuO62r2peKnDKsax/9ZHl+RQIDAQABAoIBABhZepYmgC+IJIPu
|
||||||
|
iLPVAT6AcWR/H0AyFYa+0yZvk7kFLFZb3pa1O+v/TGbavMEx0xvef0Mtd71ixrop
|
||||||
|
OtGarshB65Ycu91KHZDFkx9J7STcSyFAvB0SUkc5bXmwrEZMaoW75tX65T4fyLU+
|
||||||
|
WlubOfC9e9gJBG1NqYrze5kHpaTkR8pBaSxECns5y2HLaMvs1t1kK7snqtGHFRAb
|
||||||
|
deAUl0ONENaO6PF797yM3bsIEgnljdKvaVP3kYq/eAzH4jyw+qG/xq0bZ+nalJzM
|
||||||
|
IL7xRSR/Yak7WZ3QUh99t3dng/z3De4yvhBLq/mc2mIVvt7aERPo/aDG4SrmQ9Jw
|
||||||
|
f1GUT+ECgYEA+i96w2zPHkq0djuuhNaa/R0vybD9hVCdB7enQ8skBzQAQyhp9X9W
|
||||||
|
by38VAbFRVIMrzdfbvwSFrE3Nd9BvyLWl16G+MVu+hq0jhM9p44a62vXvfgQmfFh
|
||||||
|
iXyGkzCTufeLEzOFnP8S+ezacodK1hbQTjllUndn6NUhXcbfozTPfx8CgYEAw1Il
|
||||||
|
xqfU7NkVX6UP/FvTx9aBKqwrD8YOPn9nj26Q45zVbmHJZZIvywlsMDCiJ6JJawEa
|
||||||
|
GSkiZTDpypEvS/2UtLEY0zfbSbQGkBTnagHIFAuVh0AD1EP+kCcnrxA5Vjr8v0WE
|
||||||
|
B0HBfMgoZxa8rmHMpPhrlCCo1ectRgu+dgzEKhsCgYAQ17lwBpc69tSHUSVClCAD
|
||||||
|
AkABWAT5QKARsO91xOs8AOgznTjk6hmrinD+RyZosEliUlv+YMHm/S82VT1b3MCN
|
||||||
|
mDOF8+SwubOGDQ2NhieRycTQaS7U7kcetl9o8VBAqMWYGVPZaeKhKKzcIPeMyiRj
|
||||||
|
38FOd/Nq3U5NveG4XwnJCQKBgGrzmnfTAsbGf+uliMFYzviIPqZNLC8w9i/Gt8BU
|
||||||
|
fMYF5ODSbuNNTxpQiItCtigZtzX+nnnUil76j6o6IbnsmvbuWneeCFetWkKfD7B+
|
||||||
|
VT6UsUYkCXS73rK0nghATAUpu6hIumj22qonN+hrDNo390UGOnIcCBdIxQOr/pjJ
|
||||||
|
mMitAoGAB3tFzlzZHpCE38IqdHL7CKIML9cYJSOm07nFIEUAKN2bUHGsvMH/tMS1
|
||||||
|
I3hyeHxMmYCrOLn7xLqiOVgRjbYS9JiQVdDojqeSvvnLCtY9/lHWi50pqbPfwyfK
|
||||||
|
Og6QoFyxjBEsoSilc6dai58VTO6ufhoJXbXX9PcIl7le4dVPnzE=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
|
@ -51,7 +51,7 @@ RSpec.describe Capybara::Server do
|
||||||
|
|
||||||
it "should use given port" do
|
it "should use given port" do
|
||||||
@app = proc { |_env| [200, {}, ["Hello Server!"]] }
|
@app = proc { |_env| [200, {}, ["Hello Server!"]] }
|
||||||
@server = Capybara::Server.new(@app, 22790).boot
|
@server = Capybara::Server.new(@app, port: 22790).boot
|
||||||
|
|
||||||
@res = Net::HTTP.start(@server.host, 22790) { |http| http.get('/') }
|
@res = Net::HTTP.start(@server.host, 22790) { |http| http.get('/') }
|
||||||
expect(@res.body).to include('Hello Server')
|
expect(@res.body).to include('Hello Server')
|
||||||
|
@ -73,6 +73,28 @@ RSpec.describe Capybara::Server do
|
||||||
expect(@res2.body).to include('Hello Second Server')
|
expect(@res2.body).to include('Hello Second Server')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should support SSL" do
|
||||||
|
begin
|
||||||
|
key = File.join(Dir.pwd, "spec", "fixtures", "key.pem")
|
||||||
|
cert = File.join(Dir.pwd, "spec", "fixtures", "certificate.pem")
|
||||||
|
Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
|
||||||
|
app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
|
||||||
|
server = Capybara::Server.new(app).boot
|
||||||
|
|
||||||
|
expect do
|
||||||
|
Net::HTTP.start(server.host, server.port) { |http| http.get('/__idntify__') }
|
||||||
|
end.to raise_error(EOFError)
|
||||||
|
|
||||||
|
res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
|
||||||
|
https.get('/')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(res.body).to include('Hello SSL Server!')
|
||||||
|
ensure
|
||||||
|
Capybara.server = :default
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "When Capybara.reuse_server is true" do
|
context "When Capybara.reuse_server is true" do
|
||||||
before do
|
before do
|
||||||
@old_reuse_server = Capybara.reuse_server
|
@old_reuse_server = Capybara.reuse_server
|
||||||
|
@ -193,6 +215,22 @@ RSpec.describe Capybara::Server do
|
||||||
expect(server.responsive?).to eq false
|
expect(server.responsive?).to eq false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
[EOFError, Net::ReadTimeout].each do |err|
|
||||||
|
it "should attempt an HTTPS connection if HTTP connection returns #{err}" do
|
||||||
|
app = -> { [200, {}, ['Hello, world']] }
|
||||||
|
ordered_errors = [Errno::ECONNREFUSED, err]
|
||||||
|
# allow(Net::HTTP).to receive(:start).with(anything, anything, hash_excluding(:use_ssl)).and_yield { raise Errno::ECONNREFUSED }
|
||||||
|
allow(Net::HTTP).to receive(:start).with(anything, anything, hash_excluding(:use_ssl)) do
|
||||||
|
raise ordered_errors.shift
|
||||||
|
end
|
||||||
|
response = Net::HTTPSuccess.allocate
|
||||||
|
allow(response).to receive(:body).and_return app.object_id.to_s
|
||||||
|
allow(Net::HTTP).to receive(:start).with(anything, anything, hash_including(use_ssl: true)).and_return(response).once
|
||||||
|
Capybara::Server.new(app).boot
|
||||||
|
expect(Net::HTTP).to have_received(:start).exactly(3).times
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def start_request(server, wait_time)
|
def start_request(server, wait_time)
|
||||||
# Start request, but don't wait for it to finish
|
# Start request, but don't wait for it to finish
|
||||||
socket = TCPSocket.new(server.host, server.port)
|
socket = TCPSocket.new(server.host, server.port)
|
||||||
|
|
Loading…
Reference in a new issue