Skip to content

Commit

Permalink
Added support for Excon
Browse files Browse the repository at this point in the history
  • Loading branch information
dim committed May 9, 2013
1 parent 8fe9358 commit 41270d6
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 1 deletion.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ gem "httpclient", "~> 2.3", :require => false
gem "curb", "~> 0.8", :require => false, :platforms => :ruby
gem 'em-http-request', :require => false, :platforms => [:ruby, :jruby]
gem 'em-synchrony', :require => false, :platforms => [:ruby, :jruby]
gem 'excon', "~> 0.21.0", :require => false, :platforms => [:ruby, :jruby]
1 change: 1 addition & 0 deletions lib/httpi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

require "httpi/adapter/httpclient"
require "httpi/adapter/curb"
require "httpi/adapter/excon"
require "httpi/adapter/net_http"
require "httpi/adapter/em_http"
require "httpi/adapter/rack"
Expand Down
74 changes: 74 additions & 0 deletions lib/httpi/adapter/excon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
require "httpi/adapter/base"
require "httpi/response"

module HTTPI
module Adapter

# = HTTPI::Adapter::Excon
#
# Adapter for the Excon client.
# https://github.com/geemus/excon
class Excon < Base

register :excon, :deps => %w(excon)

def initialize(request)
@request = request
@client = ::Excon::Connection.new client_opts
end

attr_reader :client

# Executes arbitrary HTTP requests.
# @see HTTPI.request
def request(method)
respond_with @client.send(method)
rescue ::Excon::Errors::SocketError => e
case e.message
when /verify certificate/
raise SSLError
else
$!.extend ConnectionError
end
raise
end

private

def client_opts
url = @request.url
ssl = @request.auth.ssl

opts = {
host: url.host,
path: url.path,
port: url.port.to_s,
query: url.query,
scheme: url.scheme,
headers: @request.headers,
body: @request.body
}

opts[:user], opts[:password] = *@request.auth.credentials if @request.auth.basic?
opts[:connect_timeout] = @request.open_timeout if @request.open_timeout
opts[:read_timeout] = @request.read_timeout if @request.read_timeout
opts[:response_block] = @request.on_body if @request.on_body
opts[:proxy] = @request.proxy if @request.proxy

if ssl.verify_mode == :peer
opts[:ssl_verify_peer] = true
opts[:ssl_ca_file] = ssl.ca_cert_file if ssl.ca_cert_file
opts[:client_cert] = ssl.cert if ssl.cert
opts[:client_key] = ssl.cert_key if ssl.cert_key
end

opts
end

def respond_with(response)
Response.new response.status, response.headers, response.body
end

end
end
end
241 changes: 241 additions & 0 deletions spec/httpi/adapter/excon_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
require "spec_helper"
require "integration/support/server"

describe HTTPI::Adapter::Excon do

subject(:adapter) { :excon }

context "http requests" do
before :all do
@server = IntegrationServer.run
end

after :all do
@server.stop
end

it "sends and receives HTTP headers" do
request = HTTPI::Request.new(@server.url + "x-header")
request.headers["X-Header"] = "HTTPI"

response = HTTPI.get(request, adapter)
response.body.should include("HTTPI")
end

it "executes GET requests" do
response = HTTPI.get(@server.url, adapter)
response.body.should eq("get")
response.headers["Content-Type"].should eq("text/plain")
end

it "executes POST requests" do
response = HTTPI.post(@server.url, "<some>xml</some>", adapter)
response.body.should eq("post")
response.headers["Content-Type"].should eq("text/plain")
end

it "executes HEAD requests" do
response = HTTPI.head(@server.url, adapter)
response.code.should == 200
response.headers["Content-Type"].should eq("text/plain")
end

it "executes PUT requests" do
response = HTTPI.put(@server.url, "<some>xml</some>", adapter)
response.body.should eq("put")
response.headers["Content-Type"].should eq("text/plain")
end

it "executes DELETE requests" do
response = HTTPI.delete(@server.url, adapter)
response.body.should eq("delete")
response.headers["Content-Type"].should eq("text/plain")
end

it "supports basic authentication" do
request = HTTPI::Request.new(@server.url + "basic-auth")
request.auth.basic("admin", "secret")

response = HTTPI.get(request, adapter)
response.body.should eq("basic-auth")
end

it "supports ntlm authentication" do
request = HTTPI::Request.new(@server.url + "ntlm-auth")
request.auth.ntlm("tester", "vReqSoafRe5O")

response = HTTPI.get(request, adapter)
response.body.should eq("ntlm-auth")
end
end

# it does not support digest auth

if RUBY_PLATFORM =~ /java/
pending "Puma Server complains: SSL not supported on JRuby"
else
context "https requests" do
before :all do
@server = IntegrationServer.run(:ssl => true)
end
after :all do
@server.stop
end

# it does not raise when no certificate was set up
it "works when set up properly" do
request = HTTPI::Request.new(@server.url)
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file

response = HTTPI.get(request, adapter)
expect(response.body).to eq("get")
end
end
end

end


__END__

describe "#request(:get)" do
it "should return a valid HTTPI::Response" do
stub_request(:get, request.url.to_s).to_return(basic_response)
adapter.request(:get).should match_response(:body => Fixture.xml)
end
end

describe "#request(:post)" do
it "should return a valid HTTPI::Response" do
request.body = Fixture.xml
stub_request(:post, request.url.to_s).with(:body => request.body).to_return(basic_response)

adapter.request(:post).should match_response(:body => Fixture.xml)
end
end

describe "#request(:head)" do
it "should return a valid HTTPI::Response" do
stub_request(:head, request.url.to_s).to_return(basic_response)
adapter.request(:head).should match_response(:body => Fixture.xml)
end
end

describe "#request(:put)" do
it "should return a valid HTTPI::Response" do
request.url = "http://example.com"
request.headers = { "Accept-encoding" => "utf-8" }
request.body = Fixture.xml

stub_request(:put, request.url.to_s).with(:body => request.body).to_return(basic_response)

adapter.request(:put).should match_response(:body => Fixture.xml)
end
end

describe "#request(:delete)" do
it "should return a valid HTTPI::Response" do
stub_request(:delete, request.url.to_s).to_return(basic_response)
adapter.request(:delete).should match_response(:body => Fixture.xml)
end
end

describe "#request(:custom)" do
it "raises a NotSupportedError" do
expect { adapter.request(:custom) }.
to raise_error(HTTPI::NotSupportedError, "Net::HTTP does not support custom HTTP methods")
end
end

describe "settings:" do
before { stub_request(:get, request.url.to_s) }

describe "use_ssl" do
it "should be set to false for non-SSL requests" do
net_http.expects(:use_ssl=).with(false)
adapter.request(:get)
end

it "should be set to true for SSL requests" do
request.ssl = true

net_http.expects(:use_ssl=).with(true)
adapter.request(:get)
end
end

describe "open_timeout" do
it "should not be set if not specified" do
net_http.expects(:open_timeout=).never
adapter.request(:get)
end

it "should be set if specified" do
request.open_timeout = 30

net_http.expects(:open_timeout=).with(30)
adapter.request(:get)
end
end

describe "read_timeout" do
it "should not be set if not specified" do
net_http.expects(:read_timeout=).never
adapter.request(:get)
end

it "should be set if specified" do
request.read_timeout = 30

net_http.expects(:read_timeout=).with(30)
adapter.request(:get)
end
end

describe "basic_auth" do
it "should be set for HTTP basic auth" do
request.auth.basic "username", "password"

stub_request(:get, "http://username:[email protected]")
Net::HTTP::Get.any_instance.expects(:basic_auth).with(*request.auth.credentials)
adapter.request(:get)
end
end

context "(for SSL client auth)" do
before do
request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
end

it "key, cert and verify_mode should be set" do
net_http.expects(:cert=).with(request.auth.ssl.cert)
net_http.expects(:key=).with(request.auth.ssl.cert_key)
net_http.expects(:verify_mode=).with(request.auth.ssl.openssl_verify_mode)

adapter.request(:get)
end

it "should set the client_ca if specified" do
request.auth.ssl.ca_cert_file = "spec/fixtures/client_cert.pem"
net_http.expects(:ca_file=).with(request.auth.ssl.ca_cert_file)

adapter.request(:get)
end

it 'should set the ssl_version if specified' do
request.auth.ssl.ssl_version = :SSLv3
net_http.expects(:ssl_version=).with(request.auth.ssl.ssl_version)

adapter.request(:get)
end
end
end

def basic_request
request = HTTPI::Request.new "http://example.com"
yield request if block_given?
request
end

end
3 changes: 2 additions & 1 deletion spec/httpi/httpi_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@
:curb => lambda { Curl::Easy },
:net_http => lambda { Net::HTTP },
:em_http => lambda { EventMachine::HttpConnection },
:rack => lambda { Rack::MockRequest }
:rack => lambda { Rack::MockRequest },
:excon => lambda { Excon::Connection }
}

context "using #{adapter}" do
Expand Down

0 comments on commit 41270d6

Please sign in to comment.