This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Jan van der Pas
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Faraday Net::HTTP adapter
|
||||
|
||||
This gem is a [Faraday][faraday] adapter for the [Net::HTTP][net-http] library. Faraday is an HTTP client library that provides a common interface over many adapters. Every adapter is defined into it's own gem. This gem defines the adapter for `Net::HTTP` the HTTP library that's included into the standard library of Ruby.
|
||||
|
||||
## Installation
|
||||
|
||||
Add this line to your application's Gemfile:
|
||||
|
||||
```ruby
|
||||
gem 'faraday-net_http'
|
||||
```
|
||||
|
||||
And then execute:
|
||||
|
||||
$ bundle install
|
||||
|
||||
Or install it yourself as:
|
||||
|
||||
$ gem install faraday-net_http
|
||||
|
||||
## Usage
|
||||
|
||||
```ruby
|
||||
conn = Faraday.new(...) do |f|
|
||||
f.adapter :net_http do |http|
|
||||
# yields Net::HTTP
|
||||
http.verify_callback = lambda do |preverify, cert_store|
|
||||
# do something here...
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
||||
|
||||
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](rubygems).
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports and pull requests are welcome on [GitHub][repo].
|
||||
|
||||
## License
|
||||
|
||||
The gem is available as open source under the terms of the [license][license].
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Everyone interacting in the Faraday Net::HTTP adapter project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct][code-of-conduct].
|
||||
|
||||
[faraday]: https://github.com/lostisland/faraday
|
||||
[net-http]: https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html
|
||||
[rubygems]: https://rubygems.org
|
||||
[repo]: https://github.com/lostisland/faraday-net_http
|
||||
[license]: https://github.com/lostisland/faraday-net_http/blob/main/LICENSE.md
|
||||
[code-of-conduct]: https://github.com/lostisland/faraday-net_http/blob/main/CODE_OF_CONDUCT.md
|
||||
@@ -0,0 +1,202 @@
|
||||
# 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
|
||||
class NetHttp < Faraday::Adapter
|
||||
exceptions = [
|
||||
IOError,
|
||||
Errno::EADDRNOTAVAIL,
|
||||
Errno::EALREADY,
|
||||
Errno::ECONNABORTED,
|
||||
Errno::ECONNREFUSED,
|
||||
Errno::ECONNRESET,
|
||||
Errno::EHOSTUNREACH,
|
||||
Errno::EINVAL,
|
||||
Errno::ENETUNREACH,
|
||||
Errno::EPIPE,
|
||||
Net::HTTPBadResponse,
|
||||
Net::HTTPHeaderSyntaxError,
|
||||
Net::ProtocolError,
|
||||
SocketError,
|
||||
Zlib::GzipFile::Error
|
||||
]
|
||||
|
||||
exceptions << ::OpenSSL::SSL::SSLError if defined?(::OpenSSL::SSL::SSLError)
|
||||
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|
|
||||
http.use_ssl = env[:url].scheme == 'https' if http.respond_to?(:use_ssl=)
|
||||
configure_ssl(http, env[:ssl])
|
||||
configure_request(http, env[:request])
|
||||
end
|
||||
end
|
||||
|
||||
def net_http_connection(env)
|
||||
proxy = env[:request][:proxy]
|
||||
port = env[:url].port || (env[:url].scheme == 'https' ? 443 : 80)
|
||||
if proxy
|
||||
Net::HTTP.new(env[:url].hostname, port,
|
||||
proxy[:uri].hostname, proxy[:uri].port,
|
||||
proxy[:user], proxy[:password])
|
||||
else
|
||||
Net::HTTP.new(env[:url].hostname, port, nil)
|
||||
end
|
||||
end
|
||||
|
||||
def call(env)
|
||||
super
|
||||
connection(env) do |http|
|
||||
perform_request(http, env)
|
||||
rescue *NET_HTTP_EXCEPTIONS => e
|
||||
raise Faraday::SSLError, e if defined?(OpenSSL) && e.is_a?(OpenSSL::SSL::SSLError)
|
||||
|
||||
raise Faraday::ConnectionFailed, e
|
||||
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.stream_response?
|
||||
http_response = env.stream_response do |&on_data|
|
||||
request_with_wrapped_block(http, env, &on_data)
|
||||
end
|
||||
http_response.body = nil
|
||||
else
|
||||
http_response = request_with_wrapped_block(http, env)
|
||||
end
|
||||
env.response_body = encoded_body(http_response)
|
||||
env.response.finish(env)
|
||||
http_response
|
||||
end
|
||||
|
||||
def request_with_wrapped_block(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.request create_request(env) do |response|
|
||||
save_http_response(env, response)
|
||||
|
||||
response.read_body(&block) if block_given?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def save_http_response(env, http_response)
|
||||
save_response(
|
||||
env, http_response.code.to_i, nil, nil, http_response.message, finished: false
|
||||
) do |response_headers|
|
||||
http_response.each_header do |key, value|
|
||||
response_headers[key] = value
|
||||
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]
|
||||
http.verify_hostname = ssl[:verify_hostname] if verify_hostname_enabled?(http, ssl)
|
||||
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]
|
||||
|
||||
# Use the default cert store by default, i.e. system ca certs
|
||||
@ssl_cert_store ||= OpenSSL::X509::Store.new.tap(&:set_default_paths)
|
||||
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
|
||||
|
||||
def encoded_body(http_response)
|
||||
body = http_response.body || +''
|
||||
/\bcharset=([^;]+)/.match(http_response['Content-Type']) do |match|
|
||||
content_charset = ::Encoding.find(match[1].strip)
|
||||
body = body.dup if body.frozen?
|
||||
body.force_encoding(content_charset)
|
||||
rescue ArgumentError
|
||||
nil
|
||||
end
|
||||
body
|
||||
end
|
||||
|
||||
def verify_hostname_enabled?(http, ssl)
|
||||
http.respond_to?(:verify_hostname=) && ssl.key?(:verify_hostname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'faraday/adapter/net_http'
|
||||
require 'faraday/net_http/version'
|
||||
|
||||
module Faraday
|
||||
module NetHttp
|
||||
Faraday::Adapter.register_middleware(net_http: Faraday::Adapter::NetHttp)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Faraday
|
||||
module NetHttp
|
||||
VERSION = '3.1.0'
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user