From 937c86b6ab72954fb84e04aa7ea533ec3f4adea5 Mon Sep 17 00:00:00 2001 From: Jan van der Pas Date: Fri, 23 Oct 2020 21:12:45 +0200 Subject: [PATCH] Replace the Net::HTTP adapter by a separate gem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Net::HTTP adapter is extracted into its own gem. The idea behind this change is to create an ecosystem of different packages that you can use with Faraday, so that Faraday doesn’t have to ship with the packages itself. For now all the Net::HTTP tests are still in place to verify that everything is working correctly. --- faraday.gemspec | 1 + lib/faraday.rb | 2 + lib/faraday/adapter.rb | 1 - lib/faraday/adapter/net_http.rb | 219 --------------------- lib/faraday/adapter/net_http_persistent.rb | 1 + lib/faraday/autoload.rb | 1 - 6 files changed, 4 insertions(+), 221 deletions(-) delete mode 100644 lib/faraday/adapter/net_http.rb diff --git a/faraday.gemspec b/faraday.gemspec index 66e45ed84..d205ce048 100644 --- a/faraday.gemspec +++ b/faraday.gemspec @@ -20,6 +20,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'multipart-post', '>= 1.2', '< 3' spec.add_dependency 'ruby2_keywords' + spec.add_dependency 'faraday-net_http', '~> 0.0.5' # Includes `examples` and `spec` to allow external adapter gems to run Faraday unit and integration tests spec.files = Dir['CHANGELOG.md', '{examples,lib,spec}/**/*', 'LICENSE.md', 'Rakefile', 'README.md'] diff --git a/lib/faraday.rb b/lib/faraday.rb index 1c0ba84af..8100c2e97 100644 --- a/lib/faraday.rb +++ b/lib/faraday.rb @@ -6,6 +6,8 @@ require 'faraday/middleware_registry' require 'faraday/dependency_loader' +require 'faraday/net_http' + # This is the main namespace for Faraday. # # It provides methods to create {Connection} objects, and HTTP-related diff --git a/lib/faraday/adapter.rb b/lib/faraday/adapter.rb index 7bd6bcea0..395786691 100644 --- a/lib/faraday/adapter.rb +++ b/lib/faraday/adapter.rb @@ -11,7 +11,6 @@ class Adapter register_middleware File.expand_path('adapter', __dir__), test: [:Test, 'test'], - net_http: [:NetHttp, 'net_http'], net_http_persistent: [ :NetHttpPersistent, 'net_http_persistent' diff --git a/lib/faraday/adapter/net_http.rb b/lib/faraday/adapter/net_http.rb deleted file mode 100644 index e0a037297..000000000 --- a/lib/faraday/adapter/net_http.rb +++ /dev/null @@ -1,219 +0,0 @@ -# frozen_string_literal: true - -begin - require 'net/https' -rescue LoadError - warn 'Warning: no such file to load -- net/https. ' \ - 'Make sure openssl is installed if you want ssl support' - require 'net/http' -end -require 'zlib' - -module Faraday - class Adapter - # Net::HTTP adapter. - class NetHttp < Faraday::Adapter - exceptions = [ - IOError, - Errno::EADDRNOTAVAIL, - Errno::ECONNABORTED, - Errno::ECONNREFUSED, - Errno::ECONNRESET, - Errno::EHOSTUNREACH, - Errno::EINVAL, - Errno::ENETUNREACH, - Errno::EPIPE, - Net::HTTPBadResponse, - Net::HTTPHeaderSyntaxError, - Net::ProtocolError, - SocketError, - Zlib::GzipFile::Error - ] - - if defined?(::OpenSSL::SSL::SSLError) - exceptions << ::OpenSSL::SSL::SSLError - end - exceptions << ::Net::OpenTimeout if defined?(::Net::OpenTimeout) - - NET_HTTP_EXCEPTIONS = exceptions.freeze - - def initialize(app = nil, opts = {}, &block) - @ssl_cert_store = nil - super(app, opts, &block) - end - - def build_connection(env) - net_http_connection(env).tap do |http| - if http.respond_to?(:use_ssl=) - http.use_ssl = env[:url].scheme == 'https' - end - configure_ssl(http, env[:ssl]) - configure_request(http, env[:request]) - end - end - - def net_http_connection(env) - klass = if (proxy = env[:request][:proxy]) - Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port, - proxy[:user], proxy[:password]) - else - Net::HTTP - end - port = env[:url].port || (env[:url].scheme == 'https' ? 443 : 80) - klass.new(env[:url].hostname, port) - end - - def call(env) - super - http_response = connection(env) do |http| - begin - perform_request(http, env) - rescue *NET_HTTP_EXCEPTIONS => e - if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError) - raise Faraday::SSLError, e - end - - raise Faraday::ConnectionFailed, e - end - end - - save_response(env, http_response.code.to_i, - http_response.body || +'', nil, - http_response.message) do |response_headers| - http_response.each_header do |key, value| - response_headers[key] = value - end - end - - @app.call env - rescue Timeout::Error, Errno::ETIMEDOUT => e - raise Faraday::TimeoutError, e - end - - private - - def create_request(env) - request = Net::HTTPGenericRequest.new \ - env[:method].to_s.upcase, # request method - !!env[:body], # is there request body - env[:method] != :head, # is there response body - env[:url].request_uri, # request uri path - env[:request_headers] # request headers - - if env[:body].respond_to?(:read) - request.body_stream = env[:body] - else - request.body = env[:body] - end - request - end - - def perform_request(http, env) - if env[:request].stream_response? - size = 0 - yielded = false - http_response = request_with_wrapped_block(http, env) do |chunk| - if chunk.bytesize.positive? || size.positive? - yielded = true - size += chunk.bytesize - env[:request].on_data.call(chunk, size) - end - end - env[:request].on_data.call(+'', 0) unless yielded - # Net::HTTP returns something, - # but it's not meaningful according to the docs. - http_response.body = nil - http_response - else - request_with_wrapped_block(http, env) - end - end - - def request_with_wrapped_block(http, env, &block) - if (env[:method] == :get) && !env[:body] - # prefer `get` to `request` because the former handles gzip (ruby 1.9) - request_via_get_method(http, env, &block) - else - request_via_request_method(http, env, &block) - end - end - - def request_via_get_method(http, env, &block) - # Must use Net::HTTP#start and pass it a block otherwise the server's - # TCP socket does not close correctly. - http.start do |opened_http| - opened_http.get env[:url].request_uri, env[:request_headers], &block - end - end - - def request_via_request_method(http, env, &block) - # Must use Net::HTTP#start and pass it a block otherwise the server's - # TCP socket does not close correctly. - http.start do |opened_http| - if block_given? - opened_http.request create_request(env) do |response| - response.read_body(&block) - end - else - opened_http.request create_request(env) - end - end - end - - def configure_ssl(http, ssl) - return unless ssl - - http.verify_mode = ssl_verify_mode(ssl) - http.cert_store = ssl_cert_store(ssl) - - http.cert = ssl[:client_cert] if ssl[:client_cert] - http.key = ssl[:client_key] if ssl[:client_key] - http.ca_file = ssl[:ca_file] if ssl[:ca_file] - http.ca_path = ssl[:ca_path] if ssl[:ca_path] - http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] - http.ssl_version = ssl[:version] if ssl[:version] - http.min_version = ssl[:min_version] if ssl[:min_version] - http.max_version = ssl[:max_version] if ssl[:max_version] - end - - def configure_request(http, req) - if (sec = request_timeout(:read, req)) - http.read_timeout = sec - end - - if (sec = http.respond_to?(:write_timeout=) && - request_timeout(:write, req)) - http.write_timeout = sec - end - - if (sec = request_timeout(:open, req)) - http.open_timeout = sec - end - - # Only set if Net::Http supports it, since Ruby 2.5. - http.max_retries = 0 if http.respond_to?(:max_retries=) - - @config_block&.call(http) - end - - def ssl_cert_store(ssl) - return ssl[:cert_store] if ssl[:cert_store] - - @ssl_cert_store ||= begin - # Use the default cert store by default, i.e. system ca certs - OpenSSL::X509::Store.new.tap(&:set_default_paths) - end - end - - def ssl_verify_mode(ssl) - ssl[:verify_mode] || begin - if ssl.fetch(:verify, true) - OpenSSL::SSL::VERIFY_PEER - else - OpenSSL::SSL::VERIFY_NONE - end - end - end - end - end -end diff --git a/lib/faraday/adapter/net_http_persistent.rb b/lib/faraday/adapter/net_http_persistent.rb index ff20c2567..573bff4ba 100644 --- a/lib/faraday/adapter/net_http_persistent.rb +++ b/lib/faraday/adapter/net_http_persistent.rb @@ -5,6 +5,7 @@ class Adapter # Net::HTTP::Persistent adapter. class NetHttpPersistent < NetHttp dependency 'net/http/persistent' + dependency 'net/http/persistent' private diff --git a/lib/faraday/autoload.rb b/lib/faraday/autoload.rb index ecf4052de..61b93ac13 100644 --- a/lib/faraday/autoload.rb +++ b/lib/faraday/autoload.rb @@ -58,7 +58,6 @@ def all_loaded_constants class Adapter extend AutoloadHelper autoload_all 'faraday/adapter', - NetHttp: 'net_http', NetHttpPersistent: 'net_http_persistent', EMSynchrony: 'em_synchrony', EMHttp: 'em_http',