Skip to content

Commit

Permalink
Merge pull request bblimke#356 from vid-io/feature/http-gem-support
Browse files Browse the repository at this point in the history
HTTP Gem support
  • Loading branch information
bblimke committed Jan 16, 2014
2 parents 1095cde + fcb2472 commit e0f9382
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Supported HTTP libraries
* Curb (currently only Curb::Easy)
* Typhoeus (currently only Typhoeus::Hydra)
* Excon
* HTTP Gem

Supported Ruby Interpreters
---------------------------
Expand Down
1 change: 1 addition & 0 deletions lib/webmock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
require 'webmock/http_lib_adapters/http_lib_adapter_registry'
require 'webmock/http_lib_adapters/http_lib_adapter'
require 'webmock/http_lib_adapters/net_http'
require 'webmock/http_lib_adapters/http_gem_adapter'
require 'webmock/http_lib_adapters/httpclient_adapter'
require 'webmock/http_lib_adapters/patron_adapter'
require 'webmock/http_lib_adapters/curb_adapter'
Expand Down
170 changes: 170 additions & 0 deletions lib/webmock/http_lib_adapters/http_gem_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
begin
require "http"
rescue LoadError
# HTTP gem not found
end


if defined?(HTTP::Client)
module WebMock
module HttpLibAdapters
class HttpGemAdapter < HttpLibAdapter

adapter_for :http_gem


def self.enable!
::HTTP.enable_webmock!
end


def self.disable!
::HTTP.disable_webmock!
end

end
end
end


module HTTP
class Request

def webmock_signature
::WebMock::RequestSignature.new(method, uri.to_s, {
:headers => headers,
:body => body
})
end

end


class Response

def to_webmock
webmock_response = ::WebMock::Response.new

webmock_response.status = [status, reason]
webmock_response.body = body
webmock_response.headers = headers

webmock_response
end


def self.from_webmock(webmock_response)
status = webmock_response.status.first
headers = webmock_response.headers || {}
body = webmock_response.body

new(status, "1.1", headers, body)
end

end


class WebMockPerform

def initialize request, &perform
@request = request
@perform = perform
end


def exec
replay || perform || halt
end


def request_signature
unless @request_signature
@request_signature = @request.webmock_signature
register_request(@request_signature)
end

@request_signature
end


protected


def response_for_request(signature)
::WebMock::StubRegistry.instance.response_for_request(signature)
end


def register_request(signature)
::WebMock::RequestRegistry.instance.requested_signatures.put(signature)
end


def replay
webmock_response = response_for_request(request_signature)

return unless webmock_response

raise Errno::ETIMEDOUT if webmock_response.should_timeout
webmock_response.raise_error_if_any

invoke_callbacks(webmock_response, :real_request => false)
::HTTP::Response.from_webmock webmock_response
end


def perform
return unless ::WebMock.net_connect_allowed?(request_signature.uri)
response = @perform.call
invoke_callbacks(response.to_webmock, :real_request => true)
response
end


def halt
raise ::WebMock::NetConnectNotAllowedError.new request_signature
end


def invoke_callbacks webmock_response, options = {}
::WebMock::CallbackRegistry.invoke_callbacks(
options.merge({ :lib => :http_gem }),
request_signature,
webmock_response
)
end

end


class Client

alias :__perform__ :perform

def perform request, options
return __perform__(request, options) unless ::HTTP.webmock_enabled?
WebMockPerform.new(request) { __perform__(request, options) }.exec
end

end


class << self

def enable_webmock!
@webmock_enabled = true
end


def disable_webmock!
@webmock_enabled = false
end


def webmock_enabled?
@webmock_enabled
end

end
end
end
54 changes: 54 additions & 0 deletions spec/acceptance/http_gem/http_gem_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# encoding: utf-8

require "spec_helper"
require "acceptance/webmock_shared"
require "acceptance/http_gem/http_gem_spec_helper"

describe "HTTP Gem" do

include HttpGemSpecHelper


include_examples "with WebMock", :no_status_message


context "when not following redirects" do

let(:response) { http_request(:get, "http://example.com") }
let(:headers) { response.headers }

it "stops on first request" do
stub_simple_request("example.com", 302, "Location" => "www.example.com")
stub_simple_request("www.example.com")

expect(headers).to include "Host" => "example.com"
end

end


context "when following redirects" do

let(:response) { http_request(:get, "http://example.com", :follow => true) }
let(:headers) { response.headers }


it "returns response of destination" do
stub_simple_request("example.com", 302, "Location" => "www.example.com")
stub_simple_request("www.example.com")

expect(headers).to include "Host" => "www.example.com"
end


it "works with more than one redirect" do
stub_simple_request("example.com", 302, "Location" => "www.example.com")
stub_simple_request("www.example.com", 302, "Location" => "blog.example.com")
stub_simple_request("blog.example.com")

expect(headers).to include "Host" => "blog.example.com"
end

end

end
52 changes: 52 additions & 0 deletions spec/acceptance/http_gem/http_gem_spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require "ostruct"


module HttpGemSpecHelper

def http_request(method, uri, options = {}, &block)
response = HTTP.request(method, normalize_uri(uri), options).response

OpenStruct.new({
:body => response.body,
:headers => normalize_headers(response.headers),
:status => response.status.to_s,
:message => response.reason
})
end


def normalize_uri(uri)
Addressable::URI.heuristic_parse(uri).normalize.to_s
end


def normalize_headers headers
WebMock::Util::Headers.normalize_headers(Hash[headers.map { |k, v|
[k, v.is_a?(Array) ? v.join(", ") : v]
}])
end


def stub_simple_request host, status = 200, headers = {}
stub_request(:any, host).to_return({
:status => status,
:headers => headers.merge({ "Host" => host })
})
end


def client_timeout_exception_class
Errno::ETIMEDOUT
end


def connection_refused_exception_class
Errno::ECONNREFUSED
end


def http_library
:http_gem
end

end
1 change: 1 addition & 0 deletions webmock.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Gem::Specification.new do |s|
s.add_dependency 'crack', '>=0.3.2'

s.add_development_dependency 'rspec', '~> 2.10'
s.add_development_dependency 'http', '>= 0.5.0'
s.add_development_dependency 'httpclient', '>= 2.2.4'
s.add_development_dependency 'patron', '>= 0.4.18' unless RUBY_PLATFORM =~ /java/
s.add_development_dependency 'em-http-request', '>= 1.0.2'
Expand Down

0 comments on commit e0f9382

Please sign in to comment.