Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP Gem support #356

Merged
merged 1 commit into from Jan 16, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
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
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
@@ -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
@@ -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
@@ -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
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