begin require 'typhoeus' rescue LoadError # typhoeus not found end if defined?(Typhoeus) WebMock::VersionChecker.new('Typhoeus', Typhoeus::VERSION, '0.3.2').check_version! module WebMock module HttpLibAdapters class TyphoeusAdapter < HttpLibAdapter adapter_for :typhoeus def self.enable! @disabled = false add_before_callback add_after_request_callback ::Typhoeus::Config.block_connection = true end def self.disable! @disabled = true remove_after_request_callback remove_before_callback ::Typhoeus::Config.block_connection = false end def self.disabled? !!@disabled end def self.add_before_callback unless Typhoeus.before.include?(BEFORE_CALLBACK) Typhoeus.before << BEFORE_CALLBACK end end def self.remove_before_callback Typhoeus.before.delete_if {|v| v == BEFORE_CALLBACK } end def self.add_after_request_callback unless Typhoeus.on_complete.include?(AFTER_REQUEST_CALLBACK) Typhoeus.on_complete << AFTER_REQUEST_CALLBACK end end def self.remove_after_request_callback Typhoeus.on_complete.delete_if {|v| v == AFTER_REQUEST_CALLBACK } end def self.build_request_signature(req) uri = WebMock::Util::URI.heuristic_parse(req.url) uri.path = uri.normalized_path.gsub("[^:]//","/") headers = req.options[:headers] if req.options[:userpwd] headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.options[:userpwd]) end body = req.options[:body] if body.is_a?(Hash) body = WebMock::Util::QueryMapper.values_to_query(body) end request_signature = WebMock::RequestSignature.new( req.options[:method] || :get, uri.to_s, body: body, headers: headers ) req.instance_variable_set(:@__webmock_request_signature, request_signature) request_signature end def self.build_webmock_response(typhoeus_response) webmock_response = WebMock::Response.new webmock_response.status = [typhoeus_response.code, typhoeus_response.status_message] webmock_response.body = typhoeus_response.body webmock_response.headers = typhoeus_response.headers webmock_response end def self.generate_typhoeus_response(request_signature, webmock_response) response = if webmock_response.should_timeout ::Typhoeus::Response.new( code: 0, status_message: "", body: "", headers: {}, return_code: :operation_timedout ) else ::Typhoeus::Response.new( code: webmock_response.status[0], status_message: webmock_response.status[1], body: webmock_response.body, headers: webmock_response.headers, effective_url: request_signature.uri ) end response.mock = :webmock response end def self.request_hash(request_signature) hash = {} hash[:body] = request_signature.body hash[:headers] = request_signature.headers hash end AFTER_REQUEST_CALLBACK = Proc.new do |response| request = response.request request_signature = request.instance_variable_get(:@__webmock_request_signature) webmock_response = ::WebMock::HttpLibAdapters::TyphoeusAdapter. build_webmock_response(response) if response.mock WebMock::CallbackRegistry.invoke_callbacks( {lib: :typhoeus}, request_signature, webmock_response ) else WebMock::CallbackRegistry.invoke_callbacks( {lib: :typhoeus, real_request: true}, request_signature, webmock_response ) end end BEFORE_CALLBACK = Proc.new do |request| Typhoeus::Expectation.all.delete_if {|e| e.from == :webmock } res = true unless WebMock::HttpLibAdapters::TyphoeusAdapter.disabled? request_signature = ::WebMock::HttpLibAdapters::TyphoeusAdapter.build_request_signature(request) request.block_connection = false; ::WebMock::RequestRegistry.instance.requested_signatures.put(request_signature) if webmock_response = ::WebMock::StubRegistry.instance.response_for_request(request_signature) # ::WebMock::HttpLibAdapters::TyphoeusAdapter.stub_typhoeus(request_signature, webmock_response, self) response = ::WebMock::HttpLibAdapters::TyphoeusAdapter.generate_typhoeus_response(request_signature, webmock_response) if request.respond_to?(:on_headers) request.execute_headers_callbacks(response) end if request.respond_to?(:streaming?) && request.streaming? response.options[:response_body] = "" request.on_body.each { |callback| callback.call(webmock_response.body, response) } end request.finish(response) webmock_response.raise_error_if_any res = false elsif !WebMock.net_connect_allowed?(request_signature.uri) raise WebMock::NetConnectNotAllowedError.new(request_signature) end end res end end end end end