diff --git a/Rakefile b/Rakefile index 350da80d..4764d9c9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,4 +1,5 @@ require 'date' +require 'openssl' require 'rake/testtask' task :default => :test @@ -26,6 +27,23 @@ def replace_header(head, header_name) head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"} end +# Adapted from WEBrick::Utils. Skips cert extensions so it +# can be used as a CA bundle +def create_self_signed_cert(bits, cn, comment) + rsa = OpenSSL::PKey::RSA.new(bits) + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 1 + name = OpenSSL::X509::Name.new(cn) + cert.subject = name + cert.issuer = name + cert.not_before = Time.now + cert.not_after = Time.now + (365*24*60*60) + cert.public_key = rsa.public_key + cert.sign(rsa, OpenSSL::Digest::SHA1.new) + return [cert, rsa] +end + ## standard tasks desc "Run all tests" @@ -33,6 +51,13 @@ task :test do exec 'script/test' end +desc "Generate certificates for SSL tests" +task :'test:generate_certs' do + cert, key = create_self_signed_cert(1024, [['CN', 'localhost']], 'Faraday Test CA') + File.open('faraday.cert.crt', 'w') {|f| f.puts(cert.to_s) } + File.open('faraday.cert.key', 'w') {|f| f.puts(key) } +end + desc "Open an irb session preloaded with this library" task :console do sh "irb -rubygems -r ./lib/#{name}.rb" diff --git a/lib/faraday/adapter/rack.rb b/lib/faraday/adapter/rack.rb index ce2faf20..0d214648 100644 --- a/lib/faraday/adapter/rack.rb +++ b/lib/faraday/adapter/rack.rb @@ -29,7 +29,8 @@ module Faraday super rack_env = { :method => env[:method], - :input => env[:body].respond_to?(:read) ? env[:body].read : env[:body] + :input => env[:body].respond_to?(:read) ? env[:body].read : env[:body], + 'rack.url_scheme' => env[:url].scheme } env[:request_headers].each do |name, value| diff --git a/test/adapters/integration.rb b/test/adapters/integration.rb index df68efc3..ceb974d0 100644 --- a/test/adapters/integration.rb +++ b/test/adapters/integration.rb @@ -9,7 +9,9 @@ module Adapters module Integration def self.apply(base, *extras) if base.live_server? - ([:Common] + extras).each {|name| base.send(:include, self.const_get(name)) } + modules = [:Common] + modules << :SSL if base.live_server.scheme == 'https' + modules.concat(extras).each {|name| base.send(:include, self.const_get(name)) } yield if block_given? elsif !defined? @warned warn "Warning: Not running integration tests against a live server." @@ -59,6 +61,12 @@ module Adapters end end + module SSL + def test_ssl_secure + assert_equal "true", get('ssl').body + end + end + module Common extend Forwardable def_delegators :create_connection, :get, :head, :put, :post, :patch, :delete, :run_request @@ -184,7 +192,10 @@ module Adapters end server = self.class.live_server - url = 'http://%s:%d' % [server.host, server.port] + url = '%s://%s:%d' % [server.scheme, server.host, server.port] + + options[:ssl] ||= {} + options[:ssl][:ca_file] ||= File.expand_path('../../../faraday.cert.crt', __FILE__) Faraday::Connection.new(url, options, &builder_block).tap do |conn| conn.headers['X-Faraday-Adapter'] = adapter.to_s diff --git a/test/live_server.rb b/test/live_server.rb index 3e5b2562..a5ead452 100644 --- a/test/live_server.rb +++ b/test/live_server.rb @@ -50,6 +50,10 @@ class LiveServer < Sinatra::Base status 204 # no content end + get '/ssl' do + request.secure?.to_s + end + error do |e| "#{e.class}\n#{e.to_s}\n#{e.backtrace.join("\n")}" end @@ -57,5 +61,25 @@ end end if $0 == __FILE__ - Faraday::LiveServer.run! + options = { + :Port => Faraday::LiveServer.port + } + + if (ENV['LIVE'] || '').index('https') == 0 + require 'webrick/https' + + key = OpenSSL::PKey::RSA.new(File.open(File.expand_path("../../faraday.cert.key", __FILE__)).read) + cert = OpenSSL::X509::Certificate.new(File.open(File.expand_path("../../faraday.cert.crt", __FILE__)).read) + options = { + :SSLEnable => true, + :SSLPrivateKey => key, + :SSLCertificate => cert, + :SSLVerifyClient => OpenSSL::SSL::VERIFY_PEER + }.merge(options) + end + + Rack::Handler::WEBrick.run(Faraday::LiveServer, options) do |server| + [:INT, :TERM].each { |sig| trap(sig) { server.stop } } + end end +