active_utils 2.2.3 → 3.0.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.travis.yml +13 -3
- data/Gemfile +1 -1
- data/Gemfile.activesupport32 +4 -0
- data/Gemfile.activesupport40 +4 -0
- data/Gemfile.activesupport41 +4 -0
- data/Gemfile.activesupport42 +4 -0
- data/active_utils.gemspec +2 -1
- data/lib/active_utils/common/connection.rb +3 -169
- data/lib/active_utils/common/country.rb +3 -329
- data/lib/active_utils/common/currency_code.rb +3 -49
- data/lib/active_utils/common/error.rb +3 -28
- data/lib/active_utils/common/network_connection_retries.rb +3 -72
- data/lib/active_utils/common/post_data.rb +3 -23
- data/lib/active_utils/common/posts_data.rb +3 -76
- data/lib/active_utils/common/requires_parameters.rb +3 -15
- data/lib/active_utils/common/utils.rb +3 -19
- data/lib/active_utils/common/validateable.rb +3 -80
- data/lib/active_utils/common/version.rb +4 -0
- data/lib/active_utils/connection.rb +170 -0
- data/lib/active_utils/country.rb +330 -0
- data/lib/active_utils/currency_code.rb +51 -0
- data/lib/active_utils/error.rb +29 -0
- data/lib/active_utils/network_connection_retries.rb +78 -0
- data/lib/active_utils/post_data.rb +24 -0
- data/lib/active_utils/posts_data.rb +78 -0
- data/lib/active_utils/requires_parameters.rb +16 -0
- data/lib/active_utils/utils.rb +20 -0
- data/lib/active_utils/validateable.rb +81 -0
- data/lib/active_utils/version.rb +1 -1
- data/lib/active_utils.rb +21 -16
- data/test/test_helper.rb +15 -4
- data/test/unit/connection_test.rb +15 -15
- data/test/unit/network_connection_retries_test.rb +62 -11
- data/test/unit/post_data_test.rb +6 -6
- data/test/unit/posts_data_test.rb +4 -4
- data/test/unit/utils_test.rb +1 -1
- data/test/unit/validateable_test.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +35 -6
- metadata.gz.sig +0 -0
|
@@ -1,50 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
class InvalidCurrencyCodeError < StandardError
|
|
3
|
-
end
|
|
1
|
+
require "active_utils/active_merchant_shim"
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"AED", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD",
|
|
8
|
-
"BND", "BOB", "BRL", "BSD", "BTN", "BWP", "BYR", "BZD", "CAD", "CHF", "CLP", "CNY", "COP", "CRC",
|
|
9
|
-
"CZK", "DKK", "DOP", "DZD", "EGP", "ETB", "EUR", "FJD", "GBP", "GEL", "GHS", "GMD", "GTQ", "GYD",
|
|
10
|
-
"HKD", "HNL", "HRK", "HUF", "IDR", "ILS", "INR", "ISK", "JEP", "JMD", "JOD", "JPY", "KES", "KGS",
|
|
11
|
-
"KHR", "KRW", "KWD", "KYD", "KZT", "LBP", "LKR", "LTL", "LVL", "MAD", "MDL", "MGA", "MKD", "MMK",
|
|
12
|
-
"MNT", "MOP", "MUR", "MVR", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR",
|
|
13
|
-
"PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SCR", "SEK",
|
|
14
|
-
"SGD", "STD", "SYP", "THB", "TND", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "VEF",
|
|
15
|
-
"VND", "VUV", "WST", "XAF", "XCD", "XOF", "XPF", "ZAR", "ZMW"
|
|
16
|
-
]
|
|
17
|
-
|
|
18
|
-
NON_ISO_TO_ISO = {
|
|
19
|
-
"ARN" => "ARS",
|
|
20
|
-
"AZM" => "AZN",
|
|
21
|
-
"CHP" => "CLP",
|
|
22
|
-
"DHS" => "AED",
|
|
23
|
-
"ECD" => "XCD",
|
|
24
|
-
"GHC" => "GHS",
|
|
25
|
-
"JAD" => "JMD",
|
|
26
|
-
"JYE" => "JPY",
|
|
27
|
-
"KUD" => "KWD",
|
|
28
|
-
"MZM" => "MZN",
|
|
29
|
-
"NTD" => "TWD",
|
|
30
|
-
"NMP" => "MXN",
|
|
31
|
-
"RDD" => "DOP",
|
|
32
|
-
"RMB" => "CNY",
|
|
33
|
-
"SFR" => "CHF",
|
|
34
|
-
"SID" => "SGD",
|
|
35
|
-
"UKL" => "GBP",
|
|
36
|
-
"WON" => "KRW"
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
def self.standardize(code)
|
|
40
|
-
code = code.upcase unless code.nil?
|
|
41
|
-
|
|
42
|
-
return code if is_iso?(code)
|
|
43
|
-
NON_ISO_TO_ISO[code] || raise(InvalidCurrencyCodeError, "#{code} is not an ISO currency, nor can it be converted to one.")
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def self.is_iso?(code)
|
|
47
|
-
ISO_CURRENCIES.include? code
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
3
|
+
ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
|
|
4
|
+
require "active_utils/currency_code"
|
|
@@ -1,29 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
class ActiveMerchantError < StandardError #:nodoc:
|
|
3
|
-
end
|
|
1
|
+
require "active_utils/active_merchant_shim"
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class RetriableConnectionError < ConnectionError # :nodoc:
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
class ResponseError < ActiveMerchantError # :nodoc:
|
|
12
|
-
attr_reader :response
|
|
13
|
-
|
|
14
|
-
def initialize(response, message = nil)
|
|
15
|
-
@response = response
|
|
16
|
-
@message = message
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def to_s
|
|
20
|
-
"Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
class ClientCertificateError < ActiveMerchantError # :nodoc
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
class InvalidResponseError < ActiveMerchantError # :nodoc
|
|
28
|
-
end
|
|
29
|
-
end
|
|
3
|
+
ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
|
|
4
|
+
require "active_utils/error"
|
|
@@ -1,73 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
module NetworkConnectionRetries
|
|
3
|
-
DEFAULT_RETRIES = 3
|
|
4
|
-
DEFAULT_CONNECTION_ERRORS = {
|
|
5
|
-
EOFError => "The remote server dropped the connection",
|
|
6
|
-
Errno::ECONNRESET => "The remote server reset the connection",
|
|
7
|
-
Timeout::Error => "The connection to the remote server timed out",
|
|
8
|
-
Errno::ETIMEDOUT => "The connection to the remote server timed out",
|
|
9
|
-
SocketError => "The connection to the remote server could not be established",
|
|
10
|
-
OpenSSL::SSL::SSLError => "The SSL connection to the remote server could not be established"
|
|
11
|
-
}
|
|
1
|
+
require "active_utils/active_merchant_shim"
|
|
12
2
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def retry_exceptions(options={})
|
|
18
|
-
connection_errors = DEFAULT_CONNECTION_ERRORS.merge(options[:connection_exceptions] || {})
|
|
19
|
-
|
|
20
|
-
retry_network_exceptions(options) do
|
|
21
|
-
begin
|
|
22
|
-
yield
|
|
23
|
-
rescue Errno::ECONNREFUSED => e
|
|
24
|
-
raise ActiveMerchant::RetriableConnectionError, "The remote server refused the connection"
|
|
25
|
-
rescue OpenSSL::X509::CertificateError => e
|
|
26
|
-
NetworkConnectionRetries.log(options[:logger], :error, e.message, options[:tag])
|
|
27
|
-
raise ActiveMerchant::ClientCertificateError, "The remote server did not accept the provided SSL certificate"
|
|
28
|
-
rescue Zlib::BufError => e
|
|
29
|
-
raise ActiveMerchant::InvalidResponseError, "The remote server replied with an invalid response"
|
|
30
|
-
rescue *connection_errors.keys => e
|
|
31
|
-
raise ActiveMerchant::ConnectionError, connection_errors[e.class]
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
def retry_network_exceptions(options = {})
|
|
39
|
-
initial_retries = options[:max_retries] || DEFAULT_RETRIES
|
|
40
|
-
retries = initial_retries
|
|
41
|
-
request_start = nil
|
|
42
|
-
|
|
43
|
-
begin
|
|
44
|
-
request_start = Time.now.to_f
|
|
45
|
-
result = yield
|
|
46
|
-
log_with_retry_details(options[:logger], initial_retries-retries + 1, Time.now.to_f - request_start, "success", options[:tag])
|
|
47
|
-
result
|
|
48
|
-
rescue ActiveMerchant::RetriableConnectionError => e
|
|
49
|
-
retries -= 1
|
|
50
|
-
|
|
51
|
-
log_with_retry_details(options[:logger], initial_retries-retries, Time.now.to_f - request_start, e.message, options[:tag])
|
|
52
|
-
retry unless retries.zero?
|
|
53
|
-
raise ActiveMerchant::ConnectionError, e.message
|
|
54
|
-
rescue ActiveMerchant::ConnectionError, ActiveMerchant::InvalidResponseError => e
|
|
55
|
-
retries -= 1
|
|
56
|
-
log_with_retry_details(options[:logger], initial_retries-retries, Time.now.to_f - request_start, e.message, options[:tag])
|
|
57
|
-
retry if (options[:retry_safe] || retry_safe) && !retries.zero?
|
|
58
|
-
raise
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def self.log(logger, level, message, tag=nil)
|
|
63
|
-
tag ||= self.class.to_s
|
|
64
|
-
message = "[#{tag}] #{message}"
|
|
65
|
-
logger.send(level, message) if logger
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
def log_with_retry_details(logger, attempts, time, message, tag)
|
|
70
|
-
NetworkConnectionRetries.log(logger, :info, "connection_attempt=%d connection_request_time=%.4fs connection_msg=\"%s\"" % [attempts, time, message], tag)
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
3
|
+
ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
|
|
4
|
+
require "active_utils/network_connection_retries"
|
|
@@ -1,24 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "active_utils/active_merchant_shim"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class_attribute :required_fields, :instance_writer => false
|
|
6
|
-
self.required_fields = []
|
|
7
|
-
|
|
8
|
-
def []=(key, value)
|
|
9
|
-
return if value.blank? && !required?(key)
|
|
10
|
-
super
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def to_post_data
|
|
14
|
-
collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
alias_method :to_s, :to_post_data
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
def required?(key)
|
|
21
|
-
required_fields.include?(key)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
3
|
+
ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
|
|
4
|
+
require "active_utils/post_data"
|
|
@@ -1,77 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
module PostsData #:nodoc:
|
|
1
|
+
require "active_utils/active_merchant_shim"
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
base.ssl_strict = true
|
|
7
|
-
|
|
8
|
-
base.superclass_delegating_accessor :ssl_version
|
|
9
|
-
base.ssl_version = nil
|
|
10
|
-
|
|
11
|
-
base.class_attribute :retry_safe
|
|
12
|
-
base.retry_safe = false
|
|
13
|
-
|
|
14
|
-
base.superclass_delegating_accessor :open_timeout
|
|
15
|
-
base.open_timeout = 60
|
|
16
|
-
|
|
17
|
-
base.superclass_delegating_accessor :read_timeout
|
|
18
|
-
base.read_timeout = 60
|
|
19
|
-
|
|
20
|
-
base.superclass_delegating_accessor :max_retries
|
|
21
|
-
base.max_retries = Connection::MAX_RETRIES
|
|
22
|
-
|
|
23
|
-
base.superclass_delegating_accessor :logger
|
|
24
|
-
base.superclass_delegating_accessor :wiredump_device
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def ssl_get(endpoint, headers={})
|
|
28
|
-
ssl_request(:get, endpoint, nil, headers)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def ssl_post(endpoint, data, headers = {})
|
|
32
|
-
ssl_request(:post, endpoint, data, headers)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def ssl_request(method, endpoint, data, headers)
|
|
36
|
-
handle_response(raw_ssl_request(method, endpoint, data, headers))
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def raw_ssl_request(method, endpoint, data, headers = {})
|
|
40
|
-
logger.warn "#{self.class} using ssl_strict=false, which is insecure" if logger unless ssl_strict
|
|
41
|
-
|
|
42
|
-
connection = new_connection(endpoint)
|
|
43
|
-
connection.open_timeout = open_timeout
|
|
44
|
-
connection.read_timeout = read_timeout
|
|
45
|
-
connection.retry_safe = retry_safe
|
|
46
|
-
connection.verify_peer = ssl_strict
|
|
47
|
-
connection.ssl_version = ssl_version
|
|
48
|
-
connection.logger = logger
|
|
49
|
-
connection.max_retries = max_retries
|
|
50
|
-
connection.tag = self.class.name
|
|
51
|
-
connection.wiredump_device = wiredump_device
|
|
52
|
-
|
|
53
|
-
connection.pem = @options[:pem] if @options
|
|
54
|
-
connection.pem_password = @options[:pem_password] if @options
|
|
55
|
-
|
|
56
|
-
connection.ignore_http_status = @options[:ignore_http_status] if @options
|
|
57
|
-
|
|
58
|
-
connection.request(method, data, headers)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
private
|
|
62
|
-
|
|
63
|
-
def new_connection(endpoint)
|
|
64
|
-
Connection.new(endpoint)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def handle_response(response)
|
|
68
|
-
case response.code.to_i
|
|
69
|
-
when 200...300
|
|
70
|
-
response.body
|
|
71
|
-
else
|
|
72
|
-
raise ResponseError.new(response)
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
end
|
|
77
|
-
end
|
|
3
|
+
ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
|
|
4
|
+
require "active_utils/posts_data"
|
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
module RequiresParameters #:nodoc:
|
|
3
|
-
def requires!(hash, *params)
|
|
4
|
-
params.each do |param|
|
|
5
|
-
if param.is_a?(Array)
|
|
6
|
-
raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash.has_key?(param.first)
|
|
1
|
+
require "active_utils/active_merchant_shim"
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
else
|
|
11
|
-
raise ArgumentError.new("Missing required parameter: #{param}") unless hash.has_key?(param)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
3
|
+
ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
|
|
4
|
+
require "active_utils/requires_parameters"
|
|
@@ -1,20 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "active_utils/active_merchant_shim"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def generate_unique_id
|
|
6
|
-
SecureRandom.hex(16)
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
module_function :generate_unique_id
|
|
10
|
-
|
|
11
|
-
def deprecated(message)
|
|
12
|
-
warning = Kernel.caller[1] + message
|
|
13
|
-
if respond_to?(:logger) && logger.present?
|
|
14
|
-
logger.warn(warning)
|
|
15
|
-
else
|
|
16
|
-
warn(warning)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
3
|
+
ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
|
|
4
|
+
require "active_utils/utils"
|
|
@@ -1,81 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
module Validateable #:nodoc:
|
|
3
|
-
def valid?
|
|
4
|
-
errors.clear
|
|
1
|
+
require "active_utils/active_merchant_shim"
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
errors.empty?
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def initialize(attributes = {})
|
|
13
|
-
self.attributes = attributes
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def errors
|
|
17
|
-
@errors ||= Errors.new(self)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def attributes=(attributes)
|
|
23
|
-
unless attributes.nil?
|
|
24
|
-
for key, value in attributes
|
|
25
|
-
send("#{key}=", value )
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# This hash keeps the errors of the object
|
|
31
|
-
class Errors < HashWithIndifferentAccess
|
|
32
|
-
|
|
33
|
-
def initialize(base)
|
|
34
|
-
super() { |h, k| h[k] = [] ; h[k] }
|
|
35
|
-
@base = base
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def count
|
|
39
|
-
size
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def empty?
|
|
43
|
-
all? { |k, v| v && v.empty? }
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# returns a specific fields error message.
|
|
47
|
-
# if more than one error is available we will only return the first. If no error is available
|
|
48
|
-
# we return an empty string
|
|
49
|
-
def on(field)
|
|
50
|
-
self[field].to_a.first
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def add(field, error)
|
|
54
|
-
self[field] << error
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def add_to_base(error)
|
|
58
|
-
add(:base, error)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def each_full
|
|
62
|
-
full_messages.each { |msg| yield msg }
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def full_messages
|
|
66
|
-
result = []
|
|
67
|
-
|
|
68
|
-
self.each do |key, messages|
|
|
69
|
-
next if messages.blank?
|
|
70
|
-
if key == 'base'
|
|
71
|
-
result << "#{messages.first}"
|
|
72
|
-
else
|
|
73
|
-
result << "#{key.to_s.humanize} #{messages.first}"
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
result
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
3
|
+
ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
|
|
4
|
+
require "active_utils/validateable"
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'net/https'
|
|
4
|
+
require 'benchmark'
|
|
5
|
+
|
|
6
|
+
module ActiveUtils
|
|
7
|
+
class Connection
|
|
8
|
+
include NetworkConnectionRetries
|
|
9
|
+
|
|
10
|
+
MAX_RETRIES = 3
|
|
11
|
+
OPEN_TIMEOUT = 60
|
|
12
|
+
READ_TIMEOUT = 60
|
|
13
|
+
VERIFY_PEER = true
|
|
14
|
+
CA_FILE = (File.dirname(__FILE__) + '/../../certs/cacert.pem')
|
|
15
|
+
CA_PATH = nil
|
|
16
|
+
RETRY_SAFE = false
|
|
17
|
+
RUBY_184_POST_HEADERS = { "Content-Type" => "application/x-www-form-urlencoded" }
|
|
18
|
+
|
|
19
|
+
attr_accessor :endpoint
|
|
20
|
+
attr_accessor :open_timeout
|
|
21
|
+
attr_accessor :read_timeout
|
|
22
|
+
attr_accessor :verify_peer
|
|
23
|
+
attr_accessor :ssl_version
|
|
24
|
+
attr_accessor :ca_file
|
|
25
|
+
attr_accessor :ca_path
|
|
26
|
+
attr_accessor :retry_safe
|
|
27
|
+
attr_accessor :pem
|
|
28
|
+
attr_accessor :pem_password
|
|
29
|
+
attr_accessor :wiredump_device
|
|
30
|
+
attr_accessor :logger
|
|
31
|
+
attr_accessor :tag
|
|
32
|
+
attr_accessor :ignore_http_status
|
|
33
|
+
attr_accessor :max_retries
|
|
34
|
+
attr_accessor :proxy_address
|
|
35
|
+
attr_accessor :proxy_port
|
|
36
|
+
|
|
37
|
+
def initialize(endpoint)
|
|
38
|
+
@endpoint = endpoint.is_a?(URI) ? endpoint : URI.parse(endpoint)
|
|
39
|
+
@open_timeout = OPEN_TIMEOUT
|
|
40
|
+
@read_timeout = READ_TIMEOUT
|
|
41
|
+
@retry_safe = RETRY_SAFE
|
|
42
|
+
@verify_peer = VERIFY_PEER
|
|
43
|
+
@ca_file = CA_FILE
|
|
44
|
+
@ca_path = CA_PATH
|
|
45
|
+
@max_retries = MAX_RETRIES
|
|
46
|
+
@ignore_http_status = false
|
|
47
|
+
@ssl_version = nil
|
|
48
|
+
@proxy_address = nil
|
|
49
|
+
@proxy_port = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def request(method, body, headers = {})
|
|
53
|
+
request_start = Time.now.to_f
|
|
54
|
+
|
|
55
|
+
retry_exceptions(:max_retries => max_retries, :logger => logger, :tag => tag) do
|
|
56
|
+
begin
|
|
57
|
+
info "connection_http_method=#{method.to_s.upcase} connection_uri=#{endpoint}", tag
|
|
58
|
+
|
|
59
|
+
result = nil
|
|
60
|
+
|
|
61
|
+
realtime = Benchmark.realtime do
|
|
62
|
+
result = case method
|
|
63
|
+
when :get
|
|
64
|
+
raise ArgumentError, "GET requests do not support a request body" if body
|
|
65
|
+
http.get(endpoint.request_uri, headers)
|
|
66
|
+
when :post
|
|
67
|
+
debug body
|
|
68
|
+
http.post(endpoint.request_uri, body, RUBY_184_POST_HEADERS.merge(headers))
|
|
69
|
+
when :put
|
|
70
|
+
debug body
|
|
71
|
+
http.put(endpoint.request_uri, body, headers)
|
|
72
|
+
when :delete
|
|
73
|
+
# It's kind of ambiguous whether the RFC allows bodies
|
|
74
|
+
# for DELETE requests. But Net::HTTP's delete method
|
|
75
|
+
# very unambiguously does not.
|
|
76
|
+
raise ArgumentError, "DELETE requests do not support a request body" if body
|
|
77
|
+
http.delete(endpoint.request_uri, headers)
|
|
78
|
+
else
|
|
79
|
+
raise ArgumentError, "Unsupported request method #{method.to_s.upcase}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
info "--> %d %s (%d %.4fs)" % [result.code, result.message, result.body ? result.body.length : 0, realtime], tag
|
|
84
|
+
debug result.body
|
|
85
|
+
result
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
ensure
|
|
90
|
+
info "connection_request_total_time=%.4fs" % [Time.now.to_f - request_start], tag
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
def http
|
|
95
|
+
http = Net::HTTP.new(endpoint.host, endpoint.port, proxy_address, proxy_port)
|
|
96
|
+
configure_debugging(http)
|
|
97
|
+
configure_timeouts(http)
|
|
98
|
+
configure_ssl(http)
|
|
99
|
+
configure_cert(http)
|
|
100
|
+
http
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def configure_debugging(http)
|
|
104
|
+
http.set_debug_output(wiredump_device)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def configure_timeouts(http)
|
|
108
|
+
http.open_timeout = open_timeout
|
|
109
|
+
http.read_timeout = read_timeout
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def configure_ssl(http)
|
|
113
|
+
return unless endpoint.scheme == "https"
|
|
114
|
+
|
|
115
|
+
http.use_ssl = true
|
|
116
|
+
http.ssl_version = ssl_version if ssl_version
|
|
117
|
+
|
|
118
|
+
if verify_peer
|
|
119
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
120
|
+
http.ca_file = ca_file
|
|
121
|
+
http.ca_path = ca_path
|
|
122
|
+
else
|
|
123
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def configure_cert(http)
|
|
129
|
+
return if pem.blank?
|
|
130
|
+
|
|
131
|
+
http.cert = OpenSSL::X509::Certificate.new(pem)
|
|
132
|
+
|
|
133
|
+
if pem_password
|
|
134
|
+
http.key = OpenSSL::PKey::RSA.new(pem, pem_password)
|
|
135
|
+
else
|
|
136
|
+
http.key = OpenSSL::PKey::RSA.new(pem)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def handle_response(response)
|
|
141
|
+
if @ignore_http_status then
|
|
142
|
+
return response.body
|
|
143
|
+
else
|
|
144
|
+
case response.code.to_i
|
|
145
|
+
when 200...300
|
|
146
|
+
response.body
|
|
147
|
+
else
|
|
148
|
+
raise ResponseError.new(response)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def debug(message, tag = nil)
|
|
154
|
+
log(:debug, message, tag)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def info(message, tag = nil)
|
|
158
|
+
log(:info, message, tag)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def error(message, tag = nil)
|
|
162
|
+
log(:error, message, tag)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def log(level, message, tag)
|
|
166
|
+
message = "[#{tag}] #{message}" if tag
|
|
167
|
+
logger.send(level, message) if logger
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|