Use HTTPClient instead of Net::HTTP
This commit is contained in:
parent
c102c571e0
commit
e8481dd14d
|
@ -26,5 +26,6 @@ Gem::Specification.new do |spec|
|
||||||
spec.add_runtime_dependency 'hurley', '~> 0.1'
|
spec.add_runtime_dependency 'hurley', '~> 0.1'
|
||||||
spec.add_runtime_dependency 'googleauth', '~> 0.5'
|
spec.add_runtime_dependency 'googleauth', '~> 0.5'
|
||||||
spec.add_runtime_dependency 'thor', '~> 0.19'
|
spec.add_runtime_dependency 'thor', '~> 0.19'
|
||||||
|
spec.add_runtime_dependency 'httpclient', '~> 2.7'
|
||||||
spec.add_runtime_dependency 'memoist', '~> 0.11'
|
spec.add_runtime_dependency 'memoist', '~> 0.11'
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,7 @@ require 'google/apis/core/api_command'
|
||||||
require 'google/apis/core/batch'
|
require 'google/apis/core/batch'
|
||||||
require 'google/apis/core/upload'
|
require 'google/apis/core/upload'
|
||||||
require 'google/apis/core/download'
|
require 'google/apis/core/download'
|
||||||
|
require 'google/apis/core/http_client_adapter'
|
||||||
require 'google/apis/options'
|
require 'google/apis/options'
|
||||||
require 'googleauth'
|
require 'googleauth'
|
||||||
require 'hurley'
|
require 'hurley'
|
||||||
|
@ -291,6 +292,7 @@ module Google
|
||||||
# @return [Hurley::Client]
|
# @return [Hurley::Client]
|
||||||
def new_client
|
def new_client
|
||||||
client = Hurley::Client.new
|
client = Hurley::Client.new
|
||||||
|
client.connection = Google::Apis::Core::HttpClientAdapter.new unless client_options.use_net_http
|
||||||
client.request_options.timeout = request_options.timeout_sec
|
client.request_options.timeout = request_options.timeout_sec
|
||||||
client.request_options.open_timeout = request_options.open_timeout_sec
|
client.request_options.open_timeout = request_options.open_timeout_sec
|
||||||
client.request_options.proxy = client_options.proxy_url
|
client.request_options.proxy = client_options.proxy_url
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
require 'httpclient'
|
||||||
|
require 'hurley'
|
||||||
|
require 'hurley/client'
|
||||||
|
|
||||||
|
module Google
|
||||||
|
module Apis
|
||||||
|
module Core
|
||||||
|
# HTTPClient adapter for Hurley.
|
||||||
|
class HttpClientAdapter
|
||||||
|
|
||||||
|
def call(request)
|
||||||
|
client = ::HTTPClient.new
|
||||||
|
configure_client(client, request)
|
||||||
|
|
||||||
|
begin
|
||||||
|
::Hurley::Response.new(request) do |res|
|
||||||
|
http_res = client.request(request.verb.to_s.upcase, request.url.to_s, nil, request.body_io, request.header.to_hash, false) do |http_res, chunk|
|
||||||
|
copy_response(http_res, res)
|
||||||
|
res.receive_body(chunk)
|
||||||
|
end
|
||||||
|
copy_response(http_res, res)
|
||||||
|
end
|
||||||
|
rescue ::HTTPClient::TimeoutError, Errno::ETIMEDOUT
|
||||||
|
raise ::Hurley::Timeout, $!
|
||||||
|
rescue ::HTTPClient::BadResponseError => err
|
||||||
|
if err.message.include?('status 407')
|
||||||
|
raise ::Hurley::ConnectionFailed, %{407 "Proxy Authentication Required "}
|
||||||
|
else
|
||||||
|
raise Hurley::ClientError, $!
|
||||||
|
end
|
||||||
|
rescue Errno::ECONNREFUSED, EOFError
|
||||||
|
raise ::Hurley::ConnectionFailed, $!
|
||||||
|
rescue => err
|
||||||
|
if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
|
||||||
|
raise Hurley::SSLError, err
|
||||||
|
else
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy_response(http_res, res)
|
||||||
|
unless res.status_code
|
||||||
|
res.status_code = http_res.status.to_i
|
||||||
|
http_res.header.all.each do |(k,v)|
|
||||||
|
res.header[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def configure_client(client, request)
|
||||||
|
client.transparent_gzip_decompression = true
|
||||||
|
if request.options.proxy
|
||||||
|
proxy = request.options.proxy
|
||||||
|
client.proxy = sprintf('%s:%d', proxy.host, proxy.port)
|
||||||
|
if proxy.user && proxy.password
|
||||||
|
client.set_proxy_auth proxy.user, proxy.password
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if request.options.timeout
|
||||||
|
client.connect_timeout = request.options.timeout
|
||||||
|
client.receive_timeout = request.options.timeout
|
||||||
|
client.send_timeout = request.options.timeout
|
||||||
|
end
|
||||||
|
if request.options.open_timeout
|
||||||
|
client.connect_timeout = request.options.open_timeout
|
||||||
|
client.send_timeout = request.options.open_timeout
|
||||||
|
end
|
||||||
|
ssl_config = client.ssl_config
|
||||||
|
ssl_opts = request.ssl_options
|
||||||
|
ssl_config.verify_mode = ssl_opts.openssl_verify_mode
|
||||||
|
ssl_config.cert_store = ssl_opts.openssl_cert_store
|
||||||
|
ssl_config.add_trust_ca ssl_opts.ca_file if ssl_opts.ca_file
|
||||||
|
ssl_config.add_trust_ca ssl_opts.ca_path if ssl_opts.ca_path
|
||||||
|
ssl_config.client_cert = ssl_opts.openssl_client_cert if ssl_opts.openssl_client_cert
|
||||||
|
ssl_config.client_key = ssl_opts.openssl_client_key if ssl_opts.openssl_client_key
|
||||||
|
ssl_config.verify_depth = ssl_opts.verify_depth if ssl_opts.verify_depth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -18,7 +18,8 @@ module Google
|
||||||
ClientOptions = Struct.new(
|
ClientOptions = Struct.new(
|
||||||
:application_name,
|
:application_name,
|
||||||
:application_version,
|
:application_version,
|
||||||
:proxy_url)
|
:proxy_url,
|
||||||
|
:use_net_http)
|
||||||
|
|
||||||
RequestOptions = Struct.new(
|
RequestOptions = Struct.new(
|
||||||
:authorization,
|
:authorization,
|
||||||
|
@ -73,7 +74,8 @@ module Google
|
||||||
new_options
|
new_options
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ClientOptions.default.use_net_http = false
|
||||||
ClientOptions.default.application_name = 'unknown'
|
ClientOptions.default.application_name = 'unknown'
|
||||||
ClientOptions.default.application_version = '0.0.0'
|
ClientOptions.default.application_version = '0.0.0'
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,4 @@ RSpec.describe Google::Apis::RequestOptions do
|
||||||
it 'should allow nil in merge' do
|
it 'should allow nil in merge' do
|
||||||
expect(options.merge(nil)).to be_an_instance_of(Google::Apis::RequestOptions)
|
expect(options.merge(nil)).to be_an_instance_of(Google::Apis::RequestOptions)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should override default options' do
|
|
||||||
Google::Apis::RequestOptions.default.header = 'Content-Length: 50'
|
|
||||||
opts = Google::Apis::RequestOptions.new
|
|
||||||
opts.header = 'Content-Length: 70'
|
|
||||||
expect(options.merge(opts).header).to eq 'Content-Length: 70'
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,7 @@ RSpec.describe Google::Apis::AdsenseV1_4, :if => run_integration_tests? do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should download a report with multiple dimensions' do
|
it 'should download a report with multiple dimensions' do
|
||||||
|
pending "Not enabled for test account"
|
||||||
report = @adsense.generate_report( Date.today.to_s, Date.today.to_s, dimension: ["DATE", "AD_UNIT_NAME"] )
|
report = @adsense.generate_report( Date.today.to_s, Date.today.to_s, dimension: ["DATE", "AD_UNIT_NAME"] )
|
||||||
|
|
||||||
report_header_names = report.headers.map { |h| h.name }
|
report_header_names = report.headers.map { |h| h.name }
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
require 'google/apis/pubsub_v1beta2'
|
require 'google/apis/pubsub_v1'
|
||||||
require 'googleauth'
|
require 'googleauth'
|
||||||
|
|
||||||
Pubsub = Google::Apis::PubsubV1beta2
|
Pubsub = Google::Apis::PubsubV1
|
||||||
|
|
||||||
RSpec.describe Google::Apis::PubsubV1beta2, :if => run_integration_tests? do
|
RSpec.describe Google::Apis::PubsubV1, :if => run_integration_tests? do
|
||||||
|
|
||||||
before(:context) do
|
before(:context) do
|
||||||
WebMock.allow_net_connect!
|
WebMock.allow_net_connect!
|
||||||
|
|
|
@ -87,11 +87,12 @@ end
|
||||||
# Enable retries for tests
|
# Enable retries for tests
|
||||||
Google::Apis::RequestOptions.default.retries = 5
|
Google::Apis::RequestOptions.default.retries = 5
|
||||||
|
|
||||||
|
# Allow testing different adapters
|
||||||
|
Google::Apis::ClientOptions.default.use_net_http = true if ENV['USE_NET_HTTP']
|
||||||
# Temporarily patch WebMock to allow chunked responses for Net::HTTP
|
# Temporarily patch WebMock to allow chunked responses for Net::HTTP
|
||||||
module Net
|
module Net
|
||||||
module WebMockHTTPResponse
|
module WebMockHTTPResponse
|
||||||
def eval_chunk(chunk)
|
def eval_chunk(chunk)
|
||||||
puts chunk.is_a? Exception
|
|
||||||
chunk if chunk.is_a?(String)
|
chunk if chunk.is_a?(String)
|
||||||
chunk.read if chunk.is_a?(IO)
|
chunk.read if chunk.is_a?(IO)
|
||||||
chunk.call if chunk.is_a?(Proc)
|
chunk.call if chunk.is_a?(Proc)
|
||||||
|
@ -121,6 +122,37 @@ module Net
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class WebMockHTTPClient
|
||||||
|
def eval_chunk(chunk)
|
||||||
|
chunk if chunk.is_a?(String)
|
||||||
|
chunk.read if chunk.is_a?(IO)
|
||||||
|
chunk.call if chunk.is_a?(Proc)
|
||||||
|
fail HTTPClient::TimeoutError if chunk == ::Timeout::Error
|
||||||
|
fail chunk if chunk.is_a?(Class)
|
||||||
|
chunk
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_httpclient_response(webmock_response, stream = false, req_header = nil, &block)
|
||||||
|
body = stream ? StringIO.new(webmock_response.body) : webmock_response.body
|
||||||
|
response = HTTP::Message.new_response(body, req_header)
|
||||||
|
response.header.init_response(webmock_response.status[0])
|
||||||
|
response.reason = webmock_response.status[1]
|
||||||
|
webmock_response.headers.to_a.each { |name, value| response.header.set(name, value) }
|
||||||
|
|
||||||
|
raise HTTPClient::TimeoutError if webmock_response.should_timeout
|
||||||
|
webmock_response.raise_error_if_any
|
||||||
|
|
||||||
|
body_parts = Array(webmock_response.body)
|
||||||
|
body_parts.each do |chunk|
|
||||||
|
chunk = eval_chunk(chunk)
|
||||||
|
block.call(response, chunk) if block
|
||||||
|
end
|
||||||
|
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def run_integration_tests?
|
def run_integration_tests?
|
||||||
ENV['GOOGLE_APPLICATION_CREDENTIALS'] && ENV['GOOGLE_PROJECT_ID']
|
ENV['GOOGLE_APPLICATION_CREDENTIALS'] && ENV['GOOGLE_PROJECT_ID']
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue