httpi 2.4.1 → 3.0.0
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 +5 -5
- data/.github/workflows/development.yml +48 -0
- data/CHANGELOG.md +45 -0
- data/Gemfile +10 -5
- data/README.md +20 -16
- data/Rakefile +5 -3
- data/UPDATING.md +7 -0
- data/httpi.gemspec +6 -7
- data/lib/httpi/adapter/curb.rb +8 -2
- data/lib/httpi/adapter/em_http.rb +5 -4
- data/lib/httpi/adapter/excon.rb +17 -5
- data/lib/httpi/adapter/http.rb +15 -2
- data/lib/httpi/adapter/httpclient.rb +16 -4
- data/lib/httpi/adapter/net_http.rb +42 -16
- data/lib/httpi/adapter/net_http_persistent.rb +6 -2
- data/lib/httpi/adapter/rack.rb +13 -6
- data/lib/httpi/auth/ssl.rb +68 -3
- data/lib/httpi/logger.rb +6 -1
- data/lib/httpi/request.rb +12 -5
- data/lib/httpi/response.rb +2 -0
- data/lib/httpi/version.rb +1 -1
- data/lib/httpi.rb +4 -4
- data/spec/fixtures/client_cert.pem +18 -14
- data/spec/fixtures/client_key.pem +25 -13
- data/spec/httpi/adapter/curb_spec.rb +36 -10
- data/spec/httpi/adapter/em_http_spec.rb +23 -21
- data/spec/httpi/adapter/excon_spec.rb +28 -90
- data/spec/httpi/adapter/http_spec.rb +23 -96
- data/spec/httpi/adapter/httpclient_spec.rb +46 -4
- data/spec/httpi/adapter/net_http_persistent_spec.rb +31 -81
- data/spec/httpi/adapter/net_http_spec.rb +39 -99
- data/spec/httpi/adapter/rack_spec.rb +6 -8
- data/spec/httpi/auth/ssl_spec.rb +49 -1
- data/spec/httpi/httpi_spec.rb +16 -4
- data/spec/httpi/request_spec.rb +5 -0
- data/spec/integration/curb_spec.rb +20 -0
- data/spec/integration/em_http_spec.rb +19 -2
- data/spec/integration/excon_spec.rb +174 -0
- data/spec/integration/fixtures/ca_all.pem +17 -42
- data/spec/integration/fixtures/server.cert +17 -17
- data/spec/integration/fixtures/server.key +25 -13
- data/spec/integration/http_spec.rb +156 -0
- data/spec/integration/httpclient_spec.rb +20 -0
- data/spec/integration/net_http_persistent_spec.rb +34 -2
- data/spec/integration/net_http_spec.rb +144 -1
- data/spec/integration/support/application.rb +4 -2
- data/spec/integration/support/server.rb +1 -2
- data/spec/spec_helper.rb +0 -2
- metadata +31 -29
- data/.travis.yml +0 -8
data/lib/httpi/auth/ssl.rb
CHANGED
@@ -10,11 +10,22 @@ module HTTPI
|
|
10
10
|
|
11
11
|
VERIFY_MODES = [:none, :peer, :fail_if_no_peer_cert, :client_once]
|
12
12
|
CERT_TYPES = [:pem, :der]
|
13
|
-
|
13
|
+
|
14
|
+
# Fix for
|
15
|
+
# httpi/auth/ssl.rb:13: warning: constant OpenSSL::SSL::SSLContext::METHODS is deprecated
|
16
|
+
ssl_context = OpenSSL::SSL::SSLContext
|
17
|
+
SSL_VERSIONS = if ssl_context.const_defined? :METHODS_MAP
|
18
|
+
ssl_context.const_get(:METHODS_MAP).keys
|
19
|
+
else
|
20
|
+
ssl_context::METHODS.reject { |method| method.match(/server|client/) }
|
21
|
+
end.sort.reverse
|
22
|
+
|
23
|
+
# Returns OpenSSL::SSL::*_VERSION values for min_version and max_version
|
24
|
+
MIN_MAX_VERSIONS = OpenSSL::SSL.constants.select{|constant| constant =~/_VERSION$/}.map{|version| version.to_s.gsub(/_VERSION$/,'').to_sym}.reverse
|
14
25
|
|
15
26
|
# Returns whether SSL configuration is present.
|
16
27
|
def present?
|
17
|
-
(verify_mode == :none) || (cert && cert_key) || ca_cert_file
|
28
|
+
(verify_mode == :none) || (cert && cert_key) || ca_cert_file || ciphers
|
18
29
|
rescue TypeError, Errno::ENOENT
|
19
30
|
false
|
20
31
|
end
|
@@ -31,6 +42,30 @@ module HTTPI
|
|
31
42
|
# Accessor for the cacert file to validate SSL certificates.
|
32
43
|
attr_accessor :ca_cert_file
|
33
44
|
|
45
|
+
# Accessor for the ca_path to validate SSL certificates.
|
46
|
+
attr_accessor :ca_cert_path
|
47
|
+
|
48
|
+
# Certificate store holds trusted CA certificates used to verify peer certificates.
|
49
|
+
attr_accessor :cert_store
|
50
|
+
|
51
|
+
# Accessor for the SSL ciphers list.
|
52
|
+
attr_reader :ciphers
|
53
|
+
|
54
|
+
# Sets the available symmetric algorithms for encryption and decryption.
|
55
|
+
# @see OpenSSL::SSL::SSLContext#ciphers
|
56
|
+
# @example
|
57
|
+
# ssl.ciphers = "cipher1:cipher2:..."
|
58
|
+
# ssl.ciphers = [name, ...]
|
59
|
+
# ssl.ciphers = [[name, version, bits, alg_bits], ...]
|
60
|
+
def ciphers=(ciphers)
|
61
|
+
@ciphers =
|
62
|
+
if ciphers
|
63
|
+
context = OpenSSL::SSL::SSLContext.new
|
64
|
+
context.ciphers = ciphers
|
65
|
+
context.ciphers.map(&:first)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
34
69
|
# Returns the cert type to validate SSL certificates PEM|DER.
|
35
70
|
def cert_type
|
36
71
|
@cert_type ||= :pem
|
@@ -63,7 +98,7 @@ module HTTPI
|
|
63
98
|
|
64
99
|
# Returns the SSL version number. Defaults to <tt>nil</tt> (auto-negotiate).
|
65
100
|
def ssl_version
|
66
|
-
@ssl_version
|
101
|
+
@ssl_version ||= nil
|
67
102
|
end
|
68
103
|
|
69
104
|
# Sets the SSL version number. Expects one of <tt>HTTPI::Auth::SSL::SSL_VERSIONS</tt>.
|
@@ -76,6 +111,36 @@ module HTTPI
|
|
76
111
|
@ssl_version = version
|
77
112
|
end
|
78
113
|
|
114
|
+
# Returns the SSL min_version number. Defaults to <tt>nil</tt> (auto-negotiate).
|
115
|
+
def min_version
|
116
|
+
@min_version ||= nil
|
117
|
+
end
|
118
|
+
|
119
|
+
# Sets the SSL min_version number. Expects one of <tt>HTTPI::Auth::SSL::MIN_MAX_VERSIONS</tt>.
|
120
|
+
def min_version=(version)
|
121
|
+
unless MIN_MAX_VERSIONS.include? version
|
122
|
+
raise ArgumentError, "Invalid SSL min_version #{version.inspect}\n" +
|
123
|
+
"Please specify one of #{MIN_MAX_VERSIONS.inspect}"
|
124
|
+
end
|
125
|
+
|
126
|
+
@min_version = version
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns the SSL min_version number. Defaults to <tt>nil</tt> (auto-negotiate).
|
130
|
+
def max_version
|
131
|
+
@max_version ||= nil
|
132
|
+
end
|
133
|
+
|
134
|
+
# Sets the SSL min_version number. Expects one of <tt>HTTPI::Auth::SSL::MIN_MAX_VERSIONS</tt>.
|
135
|
+
def max_version=(version)
|
136
|
+
unless MIN_MAX_VERSIONS.include? version
|
137
|
+
raise ArgumentError, "Invalid SSL max_version #{version.inspect}\n" +
|
138
|
+
"Please specify one of #{MIN_MAX_VERSIONS.inspect}"
|
139
|
+
end
|
140
|
+
|
141
|
+
@max_version = version
|
142
|
+
end
|
143
|
+
|
79
144
|
# Returns an <tt>OpenSSL::X509::Certificate</tt> for the +cert_file+.
|
80
145
|
def cert
|
81
146
|
@cert ||= (OpenSSL::X509::Certificate.new File.read(cert_file) if cert_file)
|
data/lib/httpi/logger.rb
CHANGED
@@ -43,8 +43,13 @@ module HTTPI
|
|
43
43
|
protected
|
44
44
|
|
45
45
|
def log_request(method, request, adapter)
|
46
|
-
log("HTTPI #{method.to_s.upcase} request to #{request.url.host} (#{adapter})")
|
46
|
+
log("HTTPI #{request_ssl_info(request)} #{method.to_s.upcase} request to #{request.url.host} (#{adapter})")
|
47
47
|
end
|
48
48
|
|
49
|
+
def request_ssl_info(request)
|
50
|
+
if request.auth && request.auth.ssl
|
51
|
+
"#{request.auth.ssl.ssl_version}/#{request.auth.ssl.verify_mode}"
|
52
|
+
end
|
53
|
+
end
|
49
54
|
end
|
50
55
|
end
|
data/lib/httpi/request.rb
CHANGED
@@ -11,7 +11,7 @@ module HTTPI
|
|
11
11
|
class Request
|
12
12
|
|
13
13
|
# Available attribute writers.
|
14
|
-
ATTRIBUTES = [:url, :proxy, :headers, :body, :open_timeout, :read_timeout, :follow_redirect, :query]
|
14
|
+
ATTRIBUTES = [:url, :proxy, :headers, :body, :open_timeout, :read_timeout, :write_timeout, :follow_redirect, :redirect_limit, :query]
|
15
15
|
|
16
16
|
# Accepts a Hash of +args+ to mass assign attributes and authentication credentials.
|
17
17
|
def initialize(args = {})
|
@@ -56,8 +56,7 @@ module HTTPI
|
|
56
56
|
|
57
57
|
# Returns whether to use SSL.
|
58
58
|
def ssl?
|
59
|
-
|
60
|
-
!!(url.to_s =~ /^https/)
|
59
|
+
@ssl ||= !!(url.to_s =~ /^https/)
|
61
60
|
end
|
62
61
|
|
63
62
|
# Sets whether to use SSL.
|
@@ -91,7 +90,7 @@ module HTTPI
|
|
91
90
|
headers["Cookie"] = cookies if cookies
|
92
91
|
end
|
93
92
|
|
94
|
-
attr_accessor :open_timeout, :read_timeout
|
93
|
+
attr_accessor :open_timeout, :read_timeout, :write_timeout
|
95
94
|
attr_reader :body
|
96
95
|
|
97
96
|
# Sets a body request given a String or a Hash.
|
@@ -102,6 +101,7 @@ module HTTPI
|
|
102
101
|
# Sets the block to be called while processing the response. The block
|
103
102
|
# accepts a single parameter - the chunked response body.
|
104
103
|
def on_body(&block)
|
104
|
+
@on_body ||= nil
|
105
105
|
if block_given? then
|
106
106
|
@on_body = block
|
107
107
|
end
|
@@ -130,6 +130,13 @@ module HTTPI
|
|
130
130
|
@follow_redirect ||= false
|
131
131
|
end
|
132
132
|
|
133
|
+
attr_writer :redirect_limit
|
134
|
+
|
135
|
+
# Returns how many redirects should be followed - defaults to 3 if not set.
|
136
|
+
def redirect_limit
|
137
|
+
@redirect_limit ||= 3
|
138
|
+
end
|
139
|
+
|
133
140
|
private
|
134
141
|
|
135
142
|
# Stores the cookies from past requests.
|
@@ -139,7 +146,7 @@ module HTTPI
|
|
139
146
|
|
140
147
|
# Expects a +url+, validates its validity and returns a +URI+ object.
|
141
148
|
def normalize_url!(url)
|
142
|
-
raise ArgumentError, "Invalid URL: #{url}" unless url.to_s =~ /^http/
|
149
|
+
raise ArgumentError, "Invalid URL: #{url}" unless url.to_s =~ /^http|socks/
|
143
150
|
url.kind_of?(URI) ? url : URI(url)
|
144
151
|
end
|
145
152
|
|
data/lib/httpi/response.rb
CHANGED
@@ -44,12 +44,14 @@ module HTTPI
|
|
44
44
|
|
45
45
|
# Returns any DIME attachments.
|
46
46
|
def attachments
|
47
|
+
@body ||= nil
|
47
48
|
decode_body unless @body
|
48
49
|
@attachments ||= []
|
49
50
|
end
|
50
51
|
|
51
52
|
# Returns the HTTP response body.
|
52
53
|
def body
|
54
|
+
@body ||= nil
|
53
55
|
decode_body unless @body
|
54
56
|
@body
|
55
57
|
end
|
data/lib/httpi/version.rb
CHANGED
data/lib/httpi.rb
CHANGED
@@ -103,7 +103,7 @@ module HTTPI
|
|
103
103
|
class << self
|
104
104
|
|
105
105
|
def query_builder
|
106
|
-
@query_builder
|
106
|
+
@query_builder ||= HTTPI::QueryBuilder::Flat
|
107
107
|
end
|
108
108
|
|
109
109
|
def query_builder=(builder)
|
@@ -152,7 +152,7 @@ module HTTPI
|
|
152
152
|
end
|
153
153
|
|
154
154
|
# Executes an HTTP request for the given +method+.
|
155
|
-
def request(method, request, adapter = nil)
|
155
|
+
def request(method, request, adapter = nil, redirects = 0)
|
156
156
|
adapter_class = load_adapter(adapter, request)
|
157
157
|
|
158
158
|
yield adapter_class.client if block_given?
|
@@ -160,10 +160,10 @@ module HTTPI
|
|
160
160
|
|
161
161
|
response = adapter_class.request(method)
|
162
162
|
|
163
|
-
if response &&
|
163
|
+
if response && HTTPI::Response::RedirectResponseCodes.member?(response.code) && request.follow_redirect? && redirects < request.redirect_limit
|
164
164
|
request.url = URI.join(request.url, response.headers['location'])
|
165
165
|
log("Following redirect: '#{request.url}'.")
|
166
|
-
return request(method, request, adapter)
|
166
|
+
return request(method, request, adapter, redirects + 1)
|
167
167
|
end
|
168
168
|
|
169
169
|
response
|
@@ -1,16 +1,20 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
2
|
+
MIIDVTCCAj2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQKDBhEZXZl
|
3
|
+
bG9wbWVudC9DTj1sb2NhbGhvc3QwHhcNMTgwODEwMDAzMTQzWhcNMjgwODA3MDAz
|
4
|
+
MTQzWjAjMSEwHwYDVQQKDBhEZXZlbG9wbWVudC9DTj1sb2NhbGhvc3QwggEiMA0G
|
5
|
+
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDbU3vifU9omTx5T6ECuYnvryr4iWPP
|
6
|
+
A4sXhduO8aD3IdA8zHlPtZnmh0liE30nAY00xKa4Eisxs9/UgUoHlEb5nCtYs6Od
|
7
|
+
9pjiuyry2G5lBHIhLlVNTbReRKfjhr3ewUxcnQN0xiynjfsUMbzoVI1ZsGDWZ9gF
|
8
|
+
4DHg3Accee3+/BNBDTWixYXh64D9YI1Tj/3fC1I2taUp32jdLXE9mbCByQlk5EZf
|
9
|
+
BZUWx868FtwwzU3ymbq2uQQtTl5a0QHqLUwb0nkdewoRvaZJFkopI+1tgy0Hs+pY
|
10
|
+
QM99vQWS7ViM5qbVYtPil/4VVWJbx/kQi/To4/Q8TxYbIRkoeJSOq9U3AgMBAAGj
|
11
|
+
gZMwgZAwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU4W1eb4Zc4NOpBe8UXcmIzLHB
|
12
|
+
FFQwSwYDVR0jBEQwQoAU4W1eb4Zc4NOpBe8UXcmIzLHBFFShJ6QlMCMxITAfBgNV
|
13
|
+
BAoMGERldmVsb3BtZW50L0NOPWxvY2FsaG9zdIIBATAUBgNVHREEDTALgglsb2Nh
|
14
|
+
bGhvc3QwDQYJKoZIhvcNAQELBQADggEBAM7oYR6eVIascNLhgfJFboVernRl137Y
|
15
|
+
7hyjBQTSleMame/VN1MwMscUYpen8rFu9lUviKe9fxV/7OqNR4vvZ83ttbb+CxJ7
|
16
|
+
3mwoQHufjrGcxsWUKrmtJsXAGZpGJFw7ygnKDAfDPKWSKYeUuQ417AutPWSvhWqa
|
17
|
+
LEohhNCeHJj/+3U2vj2g2rvy0AASeMff9IMz/lpPZ2bjJQjlITXXPvswB2/uZSRT
|
18
|
+
KWEifqfo03/nTjhzN7dz2hXEeZHroCq6FZa1R6smYVM79TORFWiKfdKtjXI8wQQ2
|
19
|
+
BhVJpWQB2yw9d/4Q7x2EPjJEPiVoRLW0vF8uxr++14nhVkSpYJCSNAw=
|
16
20
|
-----END CERTIFICATE-----
|
@@ -1,15 +1,27 @@
|
|
1
1
|
-----BEGIN RSA PRIVATE KEY-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
2
|
+
MIIEpAIBAAKCAQEA21N74n1PaJk8eU+hArmJ768q+IljzwOLF4XbjvGg9yHQPMx5
|
3
|
+
T7WZ5odJYhN9JwGNNMSmuBIrMbPf1IFKB5RG+ZwrWLOjnfaY4rsq8thuZQRyIS5V
|
4
|
+
TU20XkSn44a93sFMXJ0DdMYsp437FDG86FSNWbBg1mfYBeAx4NwHHHnt/vwTQQ01
|
5
|
+
osWF4euA/WCNU4/93wtSNrWlKd9o3S1xPZmwgckJZORGXwWVFsfOvBbcMM1N8pm6
|
6
|
+
trkELU5eWtEB6i1MG9J5HXsKEb2mSRZKKSPtbYMtB7PqWEDPfb0Fku1YjOam1WLT
|
7
|
+
4pf+FVViW8f5EIv06OP0PE8WGyEZKHiUjqvVNwIDAQABAoIBAQCbixNaxt/gIHyg
|
8
|
+
0/YuRoMqdqIU7OrZz3t/TTEuqPItEc/qrmCCRRpGQT+rzIJ/fTw1ZhmOhWQYtaZR
|
9
|
+
wPdNdLz5HOYo3A13Y4F9mpuU6iUwgvylx4Q7dJYsHKisVcymA5QyQjBHSpw0oB6m
|
10
|
+
bbe5VO2B4/JpW+/6CsuU2rY4XciJgc+MDitqxgZOfMK8xcOiQ4EDa1OxL3TeZcYQ
|
11
|
+
F5yUc39DhIDV03O/AFYnMZUMUQFNpSAyktms6YUL1JhwozcCaXB/da8TVRrLz1pl
|
12
|
+
Cj3p2VgzHKa40NVCjXc2nvPCYRMF0yD0Jm9fRJPsCkVS3wtGgqQW+rwum1p/UPTr
|
13
|
+
6x0MGd7RAoGBAPbxwBLiPyRnLy+9qgu2fS0JwXcG/6d6bhUrWS4hjzoggKyDz8Jg
|
14
|
+
4KByXxnJVigZ8qlkynZKfb3FMuAPNxHxFhK5qPDNxV2UsdnR6RbDc9Sba8mBmzhl
|
15
|
+
vvJSH7Nf7B0ws7sTzecXkh3BkaP5rhPycOxdLJs705p4RUALkDW7hn1NAoGBAONe
|
16
|
+
dfmO49s2y1Ye2XrRCmGqfVa0n4pFmQajgputc4BPkf3XudtH365O0QEwt54Nw3dQ
|
17
|
+
IvFzq/f0XVhkw4Coo38WZ4nTctbW/ZkVvKJnk2DJE1ubNJvw1wHzwz848BVT/b4Z
|
18
|
+
VplqNDPvWmEmGFzrLeOwPZfDcglDxaCpjF7q0GqTAoGAcEOjUHJuxjvqpceR4NVL
|
19
|
+
vwfqXhRecWMlXJZiaqhzFrfkB4m9D98+/3I/bdesRXrWaNAbgv+GfpmB8X65SHzT
|
20
|
+
zht9hEvn6A1LdX0KfIDKzeMCc49qY49N6ZgQNVnsW7DiZLAyMVbz5Hc1oNhHnWXg
|
21
|
+
lHQfbUsbfeQjh2Q6YVMpZxkCgYAmC2pGJciup46CjIrraAsKqJJsbbC8XETsvXNf
|
22
|
+
RTisYaQWC4DH1lDxQ7LpNhOjWL46Oqh+KlK+HJ956PJlltI0s7UDdOQkWrj4YpC7
|
23
|
+
xAT/DuY0T9YPuc7gPr+O1qIlj3ZH1smMxh6SChzfYJZ3BcsZ7CWCPWvZbQOmjHg2
|
24
|
+
cagKDQKBgQCjuICU3aElEXyGwPCEazVakgcuAuiAAjECQrHrbSVPaTDu6Cumupkw
|
25
|
+
50ypk/qJ3DegEumpufwLg37A9yFogkkHBI9Sw0PVjzXM0iWJsHceLTHWUgJBWcl3
|
26
|
+
5Sl/AacXbUHz4NMqARNVrfR3DP33Z/YXJ4bpsVswEjD51jPwwluwyA==
|
15
27
|
-----END RSA PRIVATE KEY-----
|
@@ -20,7 +20,7 @@ unless RUBY_PLATFORM =~ /java/
|
|
20
20
|
it "supports ntlm authentication" do
|
21
21
|
request = HTTPI::Request.new(@server.url + "ntlm-auth")
|
22
22
|
adapter = HTTPI::Adapter::Curb.new(request)
|
23
|
-
|
23
|
+
|
24
24
|
request.auth.ntlm("tester", "vReqSoafRe5O")
|
25
25
|
expect(adapter.request(:get).body).to eq("ntlm-auth")
|
26
26
|
end
|
@@ -146,29 +146,36 @@ unless RUBY_PLATFORM =~ /java/
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
149
|
-
describe "
|
149
|
+
describe "timeout_ms" do
|
150
150
|
it "is not set unless it's specified" do
|
151
|
-
curb.expects(:
|
151
|
+
curb.expects(:timeout_ms=).never
|
152
152
|
adapter.request(:get)
|
153
153
|
end
|
154
154
|
|
155
|
-
it "is set if specified" do
|
155
|
+
it "is set if specified read_timeout" do
|
156
156
|
request.read_timeout = 30
|
157
|
-
curb.expects(:
|
157
|
+
curb.expects(:timeout_ms=).with(30_000)
|
158
|
+
|
159
|
+
adapter.request(:get)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "is set if specified write_timeout" do
|
163
|
+
request.write_timeout = 30
|
164
|
+
curb.expects(:timeout_ms=).with(30_000)
|
158
165
|
|
159
166
|
adapter.request(:get)
|
160
167
|
end
|
161
168
|
end
|
162
169
|
|
163
|
-
describe "
|
170
|
+
describe "connect_timeout_ms" do
|
164
171
|
it "is not set unless it's specified" do
|
165
|
-
curb.expects(:
|
172
|
+
curb.expects(:connect_timeout_ms=).never
|
166
173
|
adapter.request(:get)
|
167
174
|
end
|
168
175
|
|
169
176
|
it "is set if specified" do
|
170
177
|
request.open_timeout = 30
|
171
|
-
curb.expects(:
|
178
|
+
curb.expects(:connect_timeout_ms=).with(30_000)
|
172
179
|
|
173
180
|
adapter.request(:get)
|
174
181
|
end
|
@@ -243,6 +250,13 @@ unless RUBY_PLATFORM =~ /java/
|
|
243
250
|
request
|
244
251
|
end
|
245
252
|
|
253
|
+
it 'sets ssl_cipher_list' do
|
254
|
+
request.auth.ssl.ciphers = ["AES128"]
|
255
|
+
curb.expects(:set).with(any_parameters).at_least(1)
|
256
|
+
curb.expects(:set).with(:ssl_cipher_list, anything)
|
257
|
+
adapter.request(:get)
|
258
|
+
end
|
259
|
+
|
246
260
|
context 'sets ssl_version' do
|
247
261
|
it 'defaults to nil when no ssl_version is specified' do
|
248
262
|
curb.expects(:ssl_version=).with(nil)
|
@@ -257,8 +271,7 @@ unless RUBY_PLATFORM =~ /java/
|
|
257
271
|
end
|
258
272
|
|
259
273
|
it 'to 2 when ssl_version is specified as SSLv2/SSLv23' do
|
260
|
-
version =
|
261
|
-
version = version.select { |method| method.to_s.match /SSLv2|SSLv23/ }.first
|
274
|
+
version = HTTPI::Auth::SSL::SSL_VERSIONS.select { |method| method.to_s.match(/SSLv2|SSLv23/) }.first
|
262
275
|
request.auth.ssl.ssl_version = version
|
263
276
|
curb.expects(:ssl_version=).with(2)
|
264
277
|
|
@@ -272,6 +285,16 @@ unless RUBY_PLATFORM =~ /java/
|
|
272
285
|
adapter.request(:get)
|
273
286
|
end
|
274
287
|
end
|
288
|
+
it 'raises error when min_version not nil' do
|
289
|
+
request.auth.ssl.min_version = :TLS1_2
|
290
|
+
expect{ adapter.request(:get) }.
|
291
|
+
to raise_error(HTTPI::NotSupportedError, 'Curb adapter does not support #min_version or #max_version. Please, use #ssl_version instead.')
|
292
|
+
end
|
293
|
+
it 'raises error when max_version not nil' do
|
294
|
+
request.auth.ssl.max_version = :TLS1_2
|
295
|
+
expect{ adapter.request(:get) }.
|
296
|
+
to raise_error(HTTPI::NotSupportedError, 'Curb adapter does not support #min_version or #max_version. Please, use #ssl_version instead.')
|
297
|
+
end
|
275
298
|
end
|
276
299
|
|
277
300
|
context "(for SSL client auth)" do
|
@@ -279,6 +302,7 @@ unless RUBY_PLATFORM =~ /java/
|
|
279
302
|
request = HTTPI::Request.new("http://example.com")
|
280
303
|
request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
|
281
304
|
request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
|
305
|
+
request.auth.ssl.cert_key_password = 'example'
|
282
306
|
request
|
283
307
|
end
|
284
308
|
|
@@ -287,6 +311,7 @@ unless RUBY_PLATFORM =~ /java/
|
|
287
311
|
curb.expects(:ssl_verify_host=).with(0) # avoid "SSL peer certificate" error
|
288
312
|
curb.expects(:cert_key=).with(request.auth.ssl.cert_key_file)
|
289
313
|
curb.expects(:cert=).with(request.auth.ssl.cert_file)
|
314
|
+
curb.expects(:certpassword=).with(request.auth.ssl.cert_key_password)
|
290
315
|
|
291
316
|
adapter.request(:get)
|
292
317
|
end
|
@@ -294,6 +319,7 @@ unless RUBY_PLATFORM =~ /java/
|
|
294
319
|
it "cert_key, cert and ssl_verify_peer should be set" do
|
295
320
|
curb.expects(:cert_key=).with(request.auth.ssl.cert_key_file)
|
296
321
|
curb.expects(:cert=).with(request.auth.ssl.cert_file)
|
322
|
+
curb.expects(:certpassword=).with(request.auth.ssl.cert_key_password)
|
297
323
|
curb.expects(:ssl_verify_peer=).with(true)
|
298
324
|
curb.expects(:certtype=).with(request.auth.ssl.cert_type.to_s.upcase)
|
299
325
|
|
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
require "httpi/adapter/em_http"
|
3
3
|
require "httpi/request"
|
4
4
|
|
5
|
-
|
5
|
+
unless RUBY_PLATFORM =~ /java/
|
6
6
|
HTTPI::Adapter.load_adapter(:em_http)
|
7
7
|
|
8
8
|
describe HTTPI::Adapter::EmHttpRequest do
|
@@ -89,15 +89,12 @@ begin
|
|
89
89
|
end
|
90
90
|
|
91
91
|
it "sets host, port and authorization" do
|
92
|
-
url =
|
93
|
-
|
92
|
+
url = "http://example.com:80"
|
94
93
|
connection_options = {
|
95
|
-
:
|
96
|
-
|
97
|
-
|
98
|
-
:
|
99
|
-
:port => 443,
|
100
|
-
:authorization => ['username', 'password']
|
94
|
+
:proxy => {
|
95
|
+
:host => "proxy-host.com",
|
96
|
+
:port => 443,
|
97
|
+
:authorization => ["username", "password"]
|
101
98
|
}
|
102
99
|
}
|
103
100
|
|
@@ -111,8 +108,8 @@ begin
|
|
111
108
|
it "is passed as a connection option" do
|
112
109
|
request.open_timeout = 30
|
113
110
|
|
114
|
-
url =
|
115
|
-
connection_options = { :
|
111
|
+
url = "http://example.com:80"
|
112
|
+
connection_options = { connect_timeout: 30 }
|
116
113
|
|
117
114
|
EventMachine::HttpRequest.expects(:new).with(url, connection_options)
|
118
115
|
|
@@ -121,11 +118,22 @@ begin
|
|
121
118
|
end
|
122
119
|
|
123
120
|
describe "receive_timeout" do
|
124
|
-
it "is passed as a connection option" do
|
121
|
+
it "is passed as a connection option (when read_timeout specified)" do
|
125
122
|
request.read_timeout = 60
|
126
123
|
|
127
|
-
url =
|
128
|
-
connection_options = { :
|
124
|
+
url = "http://example.com:80"
|
125
|
+
connection_options = { inactivity_timeout: 60 }
|
126
|
+
|
127
|
+
EventMachine::HttpRequest.expects(:new).with(url, connection_options)
|
128
|
+
|
129
|
+
adapter
|
130
|
+
end
|
131
|
+
|
132
|
+
it "is passed as a connection option (when write_timeout specified)" do
|
133
|
+
request.write_timeout = 60
|
134
|
+
|
135
|
+
url = "http://example.com:80"
|
136
|
+
connection_options = { inactivity_timeout: 60 }
|
129
137
|
|
130
138
|
EventMachine::HttpRequest.expects(:new).with(url, connection_options)
|
131
139
|
|
@@ -142,7 +150,7 @@ begin
|
|
142
150
|
|
143
151
|
it "raises an error for HTTP digest auth" do
|
144
152
|
request.auth.digest "username", "password"
|
145
|
-
expect { adapter.request(:get) }.to raise_error
|
153
|
+
expect { adapter.request(:get) }.to raise_error HTTPI::NotSupportedError
|
146
154
|
end
|
147
155
|
end
|
148
156
|
|
@@ -169,10 +177,4 @@ begin
|
|
169
177
|
end
|
170
178
|
|
171
179
|
end
|
172
|
-
rescue LoadError => e
|
173
|
-
if e.message =~ /fiber/
|
174
|
-
warn "LoadError: #{e.message} (EventMachine requires fibers)"
|
175
|
-
else
|
176
|
-
raise e
|
177
|
-
end
|
178
180
|
end
|
@@ -1,96 +1,34 @@
|
|
1
1
|
require "spec_helper"
|
2
|
-
require "
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
it "executes GET requests" do
|
26
|
-
response = HTTPI.get(@server.url, adapter)
|
27
|
-
expect(response.body).to eq("get")
|
28
|
-
expect(response.headers["Content-Type"]).to eq("text/plain")
|
29
|
-
end
|
30
|
-
|
31
|
-
it "executes POST requests" do
|
32
|
-
response = HTTPI.post(@server.url, "<some>xml</some>", adapter)
|
33
|
-
expect(response.body).to eq("post")
|
34
|
-
expect(response.headers["Content-Type"]).to eq("text/plain")
|
35
|
-
end
|
36
|
-
|
37
|
-
it "executes HEAD requests" do
|
38
|
-
response = HTTPI.head(@server.url, adapter)
|
39
|
-
expect(response.code).to eq(200)
|
40
|
-
expect(response.headers["Content-Type"]).to eq("text/plain")
|
41
|
-
end
|
42
|
-
|
43
|
-
it "executes PUT requests" do
|
44
|
-
response = HTTPI.put(@server.url, "<some>xml</some>", adapter)
|
45
|
-
expect(response.body).to eq("put")
|
46
|
-
expect(response.headers["Content-Type"]).to eq("text/plain")
|
47
|
-
end
|
48
|
-
|
49
|
-
it "executes DELETE requests" do
|
50
|
-
response = HTTPI.delete(@server.url, adapter)
|
51
|
-
expect(response.body).to eq("delete")
|
52
|
-
expect(response.headers["Content-Type"]).to eq("text/plain")
|
53
|
-
end
|
54
|
-
|
55
|
-
it "supports basic authentication" do
|
56
|
-
request = HTTPI::Request.new(@server.url + "basic-auth")
|
57
|
-
request.auth.basic("admin", "secret")
|
58
|
-
|
59
|
-
response = HTTPI.get(request, adapter)
|
60
|
-
expect(response.body).to eq("basic-auth")
|
61
|
-
end
|
62
|
-
|
63
|
-
it "does not support ntlm authentication" do
|
64
|
-
request = HTTPI::Request.new(@server.url + "ntlm-auth")
|
65
|
-
request.auth.ntlm("tester", "vReqSoafRe5O")
|
66
|
-
|
67
|
-
expect { HTTPI.get(request, adapter) }.
|
68
|
-
to raise_error(HTTPI::NotSupportedError, /does not support NTLM authentication/)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# it does not support digest auth
|
73
|
-
|
74
|
-
if RUBY_PLATFORM =~ /java/
|
75
|
-
pending "Puma Server complains: SSL not supported on JRuby"
|
76
|
-
else
|
77
|
-
context "https requests" do
|
78
|
-
before :all do
|
79
|
-
@server = IntegrationServer.run(:ssl => true)
|
2
|
+
require "httpi/adapter/excon"
|
3
|
+
require "httpi/request"
|
4
|
+
|
5
|
+
begin
|
6
|
+
HTTPI::Adapter.load_adapter(:excon)
|
7
|
+
|
8
|
+
describe HTTPI::Adapter::Excon do
|
9
|
+
let(:adapter) { HTTPI::Adapter::Excon.new(request) }
|
10
|
+
let(:request) { HTTPI::Request.new("http://example.com") }
|
11
|
+
|
12
|
+
describe "settings" do
|
13
|
+
describe "connect_timeout, read_timeout, write_timeout" do
|
14
|
+
it "are passed as connection options" do
|
15
|
+
request.open_timeout = 30
|
16
|
+
request.read_timeout = 40
|
17
|
+
request.write_timeout = 50
|
18
|
+
|
19
|
+
expect(adapter.client.data).to include(
|
20
|
+
connect_timeout: 30,
|
21
|
+
read_timeout: 40,
|
22
|
+
write_timeout: 50
|
23
|
+
)
|
24
|
+
end
|
80
25
|
end
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
it "works when set up properly" do
|
87
|
-
request = HTTPI::Request.new(@server.url)
|
88
|
-
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
89
|
-
|
90
|
-
response = HTTPI.get(request, adapter)
|
91
|
-
expect(response.body).to eq("get")
|
26
|
+
describe "host, hostname" do
|
27
|
+
it "both are set" do
|
28
|
+
Excon.expects(:display_warning).never
|
29
|
+
expect(adapter.client.data).to include(host: 'example.com', hostname: 'example.com')
|
30
|
+
end
|
92
31
|
end
|
93
32
|
end
|
94
33
|
end
|
95
|
-
|
96
34
|
end
|