httpi 2.4.1 → 2.4.2
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
- data/.travis.yml +6 -5
- data/CHANGELOG.md +14 -0
- data/Gemfile +1 -1
- data/httpi.gemspec +2 -0
- data/lib/httpi.rb +4 -4
- data/lib/httpi/adapter/curb.rb +1 -0
- data/lib/httpi/adapter/excon.rb +6 -3
- data/lib/httpi/adapter/httpclient.rb +11 -4
- data/lib/httpi/adapter/net_http.rb +27 -13
- data/lib/httpi/adapter/rack.rb +13 -6
- data/lib/httpi/auth/ssl.rb +8 -2
- data/lib/httpi/request.rb +11 -4
- data/lib/httpi/response.rb +2 -0
- data/lib/httpi/version.rb +1 -1
- data/spec/httpi/adapter/curb_spec.rb +6 -3
- data/spec/httpi/adapter/excon_spec.rb +29 -1
- data/spec/httpi/adapter/httpclient_spec.rb +14 -4
- data/spec/httpi/adapter/net_http_spec.rb +57 -0
- data/spec/httpi/adapter/rack_spec.rb +6 -8
- data/spec/httpi/auth/ssl_spec.rb +1 -1
- data/spec/httpi/httpi_spec.rb +14 -0
- data/spec/httpi/request_spec.rb +5 -0
- data/spec/integration/support/application.rb +1 -0
- metadata +31 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b00e0eb6313b47ac5eb3be9f3330bac10a9321b7
|
4
|
+
data.tar.gz: b49e8aaba759e1384bae07bf825b17f511c809ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3a31c1b2ac5ebbb82336104e64130f3f214462838175c7d966677c5e1cb03b77273d80b0282e9a1a032ea38b963215974a29777223c0da287d7755418b1b05a
|
7
|
+
data.tar.gz: 1c9baad44d8900f1bad06e9c991079300541476dded64e9bd44468a77552fc8d1143c6abe1d6e1ef42c11adf6427ed1d4241f02f9538fccb820e83b985bafc1a
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
### 2.4.2
|
2
|
+
|
3
|
+
* Feature: [#165](https://github.com/savonrb/httpi/pull/165) Extended net_http adapter ssl options with cert_store and ca_path
|
4
|
+
* Improvement: [#166](https://github.com/savonrb/httpi/pull/166) fix some warnings
|
5
|
+
* Feature: [#167](https://github.com/savonrb/httpi/pull/167) adds missing support for cert password
|
6
|
+
* Feature: [#163](https://github.com/savonrb/httpi/pull/163) Support HTTP Basic auth in Rack adapter
|
7
|
+
* Fix: [#162](https://github.com/savonrb/httpi/pull/162) fixing excon adapter to pass client_cert and key as strings instead of objects
|
8
|
+
* Fix: [#160](https://github.com/savonrb/httpi/pull/160) httpclient adapter now accepts NTLM auth
|
9
|
+
* Improvement: [#158](https://github.com/savonrb/httpi/pull/158) Limit the maximum of redirects to prevent infinite redirects
|
10
|
+
* Improvement: [#153](https://github.com/savonrb/httpi/pull/153) Dynamically determine methods Net::HTTP supports
|
11
|
+
* Improvement: [#155](https://github.com/savonrb/httpi/pull/155) Enable socks proxy server specification
|
12
|
+
* Improvement: [#151](https://github.com/savonrb/httpi/pull/151) Fix excon verify mode
|
13
|
+
* Fix: [#149](https://github.com/savonrb/httpi/pull/149) Ensure that header exists before accessing it
|
14
|
+
|
1
15
|
### 2.4.1
|
2
16
|
|
3
17
|
* Fix: [#147](https://github.com/savonrb/httpi/pull/147) Fix call Curb client "SSL peer certificate or SSH remote key was not OK" bug
|
data/Gemfile
CHANGED
@@ -8,7 +8,7 @@ gem 'httpclient', '~> 2.3', :require => false
|
|
8
8
|
gem 'curb', '~> 0.8', :require => false, :platforms => :ruby
|
9
9
|
gem 'em-http-request', :require => false, :platforms => [:ruby, :jruby]
|
10
10
|
gem 'em-synchrony', :require => false, :platforms => [:ruby, :jruby]
|
11
|
-
gem 'excon', '~> 0.21
|
11
|
+
gem 'excon', '~> 0.21', :require => false, :platforms => [:ruby, :jruby]
|
12
12
|
gem 'net-http-persistent', '~> 2.8', :require => false
|
13
13
|
gem 'http', :require => false
|
14
14
|
|
data/httpi.gemspec
CHANGED
@@ -17,12 +17,14 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.license = 'MIT'
|
18
18
|
|
19
19
|
s.add_dependency 'rack'
|
20
|
+
s.add_dependency 'socksify'
|
20
21
|
|
21
22
|
s.add_development_dependency 'rubyntlm', '~> 0.3.2'
|
22
23
|
s.add_development_dependency 'rake', '~> 10.0'
|
23
24
|
s.add_development_dependency 'rspec', '~> 2.14'
|
24
25
|
s.add_development_dependency 'mocha', '~> 0.13'
|
25
26
|
s.add_development_dependency 'puma', '~> 2.3.2'
|
27
|
+
s.add_development_dependency 'webmock'
|
26
28
|
|
27
29
|
s.files = `git ls-files`.split("\n")
|
28
30
|
s.require_path = 'lib'
|
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
|
data/lib/httpi/adapter/curb.rb
CHANGED
@@ -114,6 +114,7 @@ module HTTPI
|
|
114
114
|
# Send client-side certificate regardless of state of SSL verify mode
|
115
115
|
@client.cert_key = ssl.cert_key_file
|
116
116
|
@client.cert = ssl.cert_file
|
117
|
+
@client.certpassword = ssl.cert_key_password
|
117
118
|
|
118
119
|
@client.ssl_verify_peer = ssl.verify_mode == :peer
|
119
120
|
end
|
data/lib/httpi/adapter/excon.rb
CHANGED
@@ -61,11 +61,14 @@ module HTTPI
|
|
61
61
|
opts[:response_block] = @request.on_body if @request.on_body
|
62
62
|
opts[:proxy] = @request.proxy if @request.proxy
|
63
63
|
|
64
|
-
|
64
|
+
case ssl.verify_mode
|
65
|
+
when :peer
|
65
66
|
opts[:ssl_verify_peer] = true
|
66
67
|
opts[:ssl_ca_file] = ssl.ca_cert_file if ssl.ca_cert_file
|
67
|
-
opts[:
|
68
|
-
opts[:
|
68
|
+
opts[:certificate] = ssl.cert.to_pem if ssl.cert
|
69
|
+
opts[:private_key] = ssl.cert_key.to_pem if ssl.cert_key
|
70
|
+
when :none
|
71
|
+
opts[:ssl_verify_peer] = false
|
69
72
|
end
|
70
73
|
|
71
74
|
opts[:ssl_version] = ssl.ssl_version if ssl.ssl_version
|
@@ -36,11 +36,8 @@ module HTTPI
|
|
36
36
|
def setup_client
|
37
37
|
basic_setup
|
38
38
|
|
39
|
-
if @request.auth.ntlm?
|
40
|
-
raise NotSupportedError, "HTTPClient adapter does not support NTLM authentication"
|
41
|
-
end
|
42
|
-
|
43
39
|
setup_auth if @request.auth.http?
|
40
|
+
setup_ntlm_auth if @request.auth.ntlm?
|
44
41
|
setup_ssl_auth if @request.auth.ssl? || @request.ssl?
|
45
42
|
end
|
46
43
|
|
@@ -54,6 +51,16 @@ module HTTPI
|
|
54
51
|
@client.set_auth @request.url, *@request.auth.credentials
|
55
52
|
end
|
56
53
|
|
54
|
+
def setup_ntlm_auth
|
55
|
+
username, password, domain = @request.auth.credentials
|
56
|
+
|
57
|
+
unless domain.nil?
|
58
|
+
username = "#{domain.upcase}\\#{username}"
|
59
|
+
end
|
60
|
+
|
61
|
+
@client.set_auth @request.url, username, password
|
62
|
+
end
|
63
|
+
|
57
64
|
def setup_ssl_auth
|
58
65
|
ssl = @request.auth.ssl
|
59
66
|
|
@@ -4,6 +4,8 @@ require "httpi/adapter/base"
|
|
4
4
|
require "httpi/response"
|
5
5
|
require 'kconv'
|
6
6
|
require 'socket'
|
7
|
+
require "socksify"
|
8
|
+
require 'socksify/http'
|
7
9
|
|
8
10
|
module HTTPI
|
9
11
|
module Adapter
|
@@ -17,7 +19,6 @@ module HTTPI
|
|
17
19
|
register :net_http, :deps => %w(net/https)
|
18
20
|
def initialize(request)
|
19
21
|
check_net_ntlm_version!
|
20
|
-
|
21
22
|
@request = request
|
22
23
|
@client = create_client
|
23
24
|
end
|
@@ -27,8 +28,12 @@ module HTTPI
|
|
27
28
|
# Executes arbitrary HTTP requests.
|
28
29
|
# @see HTTPI.request
|
29
30
|
def request(method)
|
30
|
-
|
31
|
-
|
31
|
+
# Determine if Net::HTTP supports the method using reflection
|
32
|
+
unless Net::HTTP.const_defined?(:"#{method.to_s.capitalize}") &&
|
33
|
+
Net::HTTP.const_get(:"#{method.to_s.capitalize}").class == Class
|
34
|
+
|
35
|
+
raise NotSupportedError, "Net::HTTP does not support "\
|
36
|
+
"#{method.to_s.upcase}"
|
32
37
|
end
|
33
38
|
do_request(method) do |http, http_request|
|
34
39
|
http_request.body = @request.body
|
@@ -67,7 +72,11 @@ module HTTPI
|
|
67
72
|
|
68
73
|
def create_client
|
69
74
|
proxy_url = @request.proxy || URI("")
|
70
|
-
|
75
|
+
if URI(proxy_url).scheme == 'socks'
|
76
|
+
proxy =Net::HTTP.SOCKSProxy(proxy_url.host, proxy_url.port)
|
77
|
+
else
|
78
|
+
proxy = Net::HTTP::Proxy(proxy_url.host, proxy_url.port, proxy_url.user, proxy_url.password)
|
79
|
+
end
|
71
80
|
proxy.new(@request.url.host, @request.url.port)
|
72
81
|
end
|
73
82
|
|
@@ -92,9 +101,9 @@ module HTTPI
|
|
92
101
|
|
93
102
|
# first figure out if we should use NTLM or Negotiate
|
94
103
|
nego_auth_response = respond_with(requester.call(http, request_client(:head)))
|
95
|
-
if nego_auth_response.headers['www-authenticate'].include?
|
104
|
+
if nego_auth_response.headers['www-authenticate'] && nego_auth_response.headers['www-authenticate'].include?('Negotiate')
|
96
105
|
auth_method = 'Negotiate'
|
97
|
-
elsif nego_auth_response.headers['www-authenticate'].include?
|
106
|
+
elsif nego_auth_response.headers['www-authenticate'] && nego_auth_response.headers['www-authenticate'].include?('NTLM')
|
98
107
|
auth_method = 'NTLM'
|
99
108
|
else
|
100
109
|
auth_method = 'NTLM'
|
@@ -150,6 +159,8 @@ module HTTPI
|
|
150
159
|
if @request.auth.ssl?
|
151
160
|
unless ssl.verify_mode == :none
|
152
161
|
@client.ca_file = ssl.ca_cert_file if ssl.ca_cert_file
|
162
|
+
@client.ca_path = ssl.ca_cert_path if ssl.ca_cert_path
|
163
|
+
@client.cert_store = ssl_cert_store(ssl)
|
153
164
|
end
|
154
165
|
|
155
166
|
# Send client-side certificate regardless of state of SSL verify mode
|
@@ -162,14 +173,17 @@ module HTTPI
|
|
162
173
|
@client.ssl_version = ssl.ssl_version if ssl.ssl_version
|
163
174
|
end
|
164
175
|
|
176
|
+
def ssl_cert_store(ssl)
|
177
|
+
return ssl.cert_store if ssl.cert_store
|
178
|
+
|
179
|
+
# Use the default cert store by default, i.e. system ca certs
|
180
|
+
cert_store = OpenSSL::X509::Store.new
|
181
|
+
cert_store.set_default_paths
|
182
|
+
cert_store
|
183
|
+
end
|
184
|
+
|
165
185
|
def request_client(type)
|
166
|
-
request_class =
|
167
|
-
when :get then Net::HTTP::Get
|
168
|
-
when :post then Net::HTTP::Post
|
169
|
-
when :head then Net::HTTP::Head
|
170
|
-
when :put then Net::HTTP::Put
|
171
|
-
when :delete then Net::HTTP::Delete
|
172
|
-
end
|
186
|
+
request_class = Net::HTTP.const_get(:"#{type.to_s.capitalize}")
|
173
187
|
|
174
188
|
request_client = request_class.new @request.url.request_uri, @request.headers
|
175
189
|
request_client.basic_auth(*@request.auth.credentials) if @request.auth.basic?
|
data/lib/httpi/adapter/rack.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'base64'
|
1
2
|
require 'httpi/adapter/base'
|
2
3
|
require 'httpi/response'
|
3
4
|
|
@@ -61,17 +62,18 @@ module HTTPI
|
|
61
62
|
raise NotSupportedError, "Rack adapter does not support custom HTTP methods"
|
62
63
|
end
|
63
64
|
|
64
|
-
env = {}
|
65
|
-
@request.headers.each do |header, value|
|
66
|
-
env["HTTP_#{header.gsub('-', '_').upcase}"] = value
|
67
|
-
end
|
68
|
-
|
69
65
|
if @request.proxy
|
70
66
|
raise NotSupportedError, "Rack adapter does not support proxying"
|
71
67
|
end
|
72
68
|
|
73
69
|
if @request.auth.http?
|
74
|
-
|
70
|
+
if @request.auth.basic?
|
71
|
+
basic_auth = @request.auth.basic.join(':')
|
72
|
+
encoded = Base64.encode64(basic_auth).gsub('\n', '')
|
73
|
+
@request.headers['Authorization'] = "Basic #{encoded}"
|
74
|
+
else
|
75
|
+
raise NotSupportedError, "Rack adapter does not support HTTP #{@request.auth.type} auth"
|
76
|
+
end
|
75
77
|
end
|
76
78
|
|
77
79
|
if @request.auth.ssl?
|
@@ -82,6 +84,11 @@ module HTTPI
|
|
82
84
|
raise NotSupportedError, "Rack adapter does not support response streaming"
|
83
85
|
end
|
84
86
|
|
87
|
+
env = {}
|
88
|
+
@request.headers.each do |header, value|
|
89
|
+
env["HTTP_#{header.gsub('-', '_').upcase}"] = value
|
90
|
+
end
|
91
|
+
|
85
92
|
response = @client.request(method.to_s.upcase, @request.url.to_s,
|
86
93
|
{ :fatal => true, :input => @request.body.to_s }.merge(env))
|
87
94
|
|
data/lib/httpi/auth/ssl.rb
CHANGED
@@ -10,7 +10,7 @@ module HTTPI
|
|
10
10
|
|
11
11
|
VERIFY_MODES = [:none, :peer, :fail_if_no_peer_cert, :client_once]
|
12
12
|
CERT_TYPES = [:pem, :der]
|
13
|
-
SSL_VERSIONS = OpenSSL::SSL::SSLContext::METHODS.reject { |method| method.match
|
13
|
+
SSL_VERSIONS = OpenSSL::SSL::SSLContext::METHODS.reject { |method| method.match(/server|client/) }.sort.reverse
|
14
14
|
|
15
15
|
# Returns whether SSL configuration is present.
|
16
16
|
def present?
|
@@ -31,6 +31,12 @@ module HTTPI
|
|
31
31
|
# Accessor for the cacert file to validate SSL certificates.
|
32
32
|
attr_accessor :ca_cert_file
|
33
33
|
|
34
|
+
# Accessor for the ca_path to validate SSL certificates.
|
35
|
+
attr_accessor :ca_cert_path
|
36
|
+
|
37
|
+
# ertificate store holds trusted CA certificates used to verify peer certificates.
|
38
|
+
attr_accessor :cert_store
|
39
|
+
|
34
40
|
# Returns the cert type to validate SSL certificates PEM|DER.
|
35
41
|
def cert_type
|
36
42
|
@cert_type ||= :pem
|
@@ -63,7 +69,7 @@ module HTTPI
|
|
63
69
|
|
64
70
|
# Returns the SSL version number. Defaults to <tt>nil</tt> (auto-negotiate).
|
65
71
|
def ssl_version
|
66
|
-
@ssl_version
|
72
|
+
@ssl_version ||= nil
|
67
73
|
end
|
68
74
|
|
69
75
|
# Sets the SSL version number. Expects one of <tt>HTTPI::Auth::SSL::SSL_VERSIONS</tt>.
|
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, :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.
|
@@ -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
@@ -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
|
@@ -257,8 +257,8 @@ unless RUBY_PLATFORM =~ /java/
|
|
257
257
|
end
|
258
258
|
|
259
259
|
it 'to 2 when ssl_version is specified as SSLv2/SSLv23' do
|
260
|
-
version = OpenSSL::SSL::SSLContext::METHODS.reject { |method| method.match
|
261
|
-
version = version.select { |method| method.to_s.match
|
260
|
+
version = OpenSSL::SSL::SSLContext::METHODS.reject { |method| method.match(/server|client/) }
|
261
|
+
version = version.select { |method| method.to_s.match(/SSLv2|SSLv23/) }.first
|
262
262
|
request.auth.ssl.ssl_version = version
|
263
263
|
curb.expects(:ssl_version=).with(2)
|
264
264
|
|
@@ -279,6 +279,7 @@ unless RUBY_PLATFORM =~ /java/
|
|
279
279
|
request = HTTPI::Request.new("http://example.com")
|
280
280
|
request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
|
281
281
|
request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
|
282
|
+
request.auth.ssl.cert_key_password = 'example'
|
282
283
|
request
|
283
284
|
end
|
284
285
|
|
@@ -287,6 +288,7 @@ unless RUBY_PLATFORM =~ /java/
|
|
287
288
|
curb.expects(:ssl_verify_host=).with(0) # avoid "SSL peer certificate" error
|
288
289
|
curb.expects(:cert_key=).with(request.auth.ssl.cert_key_file)
|
289
290
|
curb.expects(:cert=).with(request.auth.ssl.cert_file)
|
291
|
+
curb.expects(:certpassword=).with(request.auth.ssl.cert_key_password)
|
290
292
|
|
291
293
|
adapter.request(:get)
|
292
294
|
end
|
@@ -294,6 +296,7 @@ unless RUBY_PLATFORM =~ /java/
|
|
294
296
|
it "cert_key, cert and ssl_verify_peer should be set" do
|
295
297
|
curb.expects(:cert_key=).with(request.auth.ssl.cert_key_file)
|
296
298
|
curb.expects(:cert=).with(request.auth.ssl.cert_file)
|
299
|
+
curb.expects(:certpassword=).with(request.auth.ssl.cert_key_password)
|
297
300
|
curb.expects(:ssl_verify_peer=).with(true)
|
298
301
|
curb.expects(:certtype=).with(request.auth.ssl.cert_type.to_s.upcase)
|
299
302
|
|
@@ -67,6 +67,13 @@ describe HTTPI::Adapter::Excon do
|
|
67
67
|
expect { HTTPI.get(request, adapter) }.
|
68
68
|
to raise_error(HTTPI::NotSupportedError, /does not support NTLM authentication/)
|
69
69
|
end
|
70
|
+
|
71
|
+
it "supports disabling verify mode" do
|
72
|
+
request = HTTPI::Request.new(@server.url)
|
73
|
+
request.auth.ssl.verify_mode = :none
|
74
|
+
adapter_class = HTTPI::Adapter.load(adapter).new(request)
|
75
|
+
expect(adapter_class.client.data[:ssl_verify_peer]).to eq(false)
|
76
|
+
end
|
70
77
|
end
|
71
78
|
|
72
79
|
# it does not support digest auth
|
@@ -83,9 +90,30 @@ describe HTTPI::Adapter::Excon do
|
|
83
90
|
end
|
84
91
|
|
85
92
|
# it does not raise when no certificate was set up
|
86
|
-
it "works when
|
93
|
+
it "works when no client cert is specified" do
|
94
|
+
request = HTTPI::Request.new(@server.url)
|
95
|
+
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
96
|
+
|
97
|
+
response = HTTPI.get(request, adapter)
|
98
|
+
expect(response.body).to eq("get")
|
99
|
+
end
|
100
|
+
|
101
|
+
it "works with client cert and key provided as file path" do
|
102
|
+
request = HTTPI::Request.new(@server.url)
|
103
|
+
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
104
|
+
request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
|
105
|
+
request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
|
106
|
+
|
107
|
+
response = HTTPI.get(request, adapter)
|
108
|
+
expect(response.body).to eq("get")
|
109
|
+
end
|
110
|
+
|
111
|
+
it "works with client cert and key set directly" do
|
87
112
|
request = HTTPI::Request.new(@server.url)
|
113
|
+
|
88
114
|
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
115
|
+
request.auth.ssl.cert = OpenSSL::X509::Certificate.new File.open("spec/fixtures/client_cert.pem").read
|
116
|
+
request.auth.ssl.cert_key = OpenSSL::PKey.read File.open("spec/fixtures/client_key.pem").read
|
89
117
|
|
90
118
|
response = HTTPI.get(request, adapter)
|
91
119
|
expect(response.body).to eq("get")
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
require "httpi/adapter/httpclient"
|
3
3
|
require "httpi/request"
|
4
|
+
require "integration/support/server"
|
4
5
|
|
5
6
|
HTTPI::Adapter.load_adapter(:httpclient)
|
6
7
|
|
@@ -10,6 +11,14 @@ describe HTTPI::Adapter::HTTPClient do
|
|
10
11
|
let(:ssl_config) { HTTPClient::SSLConfig.any_instance }
|
11
12
|
let(:request) { HTTPI::Request.new("http://example.com") }
|
12
13
|
|
14
|
+
before :all do
|
15
|
+
@server = IntegrationServer.run
|
16
|
+
end
|
17
|
+
|
18
|
+
after :all do
|
19
|
+
@server.stop
|
20
|
+
end
|
21
|
+
|
13
22
|
describe "#request(:get)" do
|
14
23
|
it "returns a valid HTTPI::Response" do
|
15
24
|
httpclient_expects(:get)
|
@@ -174,11 +183,12 @@ describe HTTPI::Adapter::HTTPClient do
|
|
174
183
|
end
|
175
184
|
end
|
176
185
|
|
177
|
-
it "
|
178
|
-
request.
|
186
|
+
it "supports NTLM authentication" do
|
187
|
+
request = HTTPI::Request.new(@server.url + "ntlm-auth")
|
179
188
|
|
180
|
-
|
181
|
-
|
189
|
+
request.auth.ntlm("tester", "vReqSoafRe5O")
|
190
|
+
response = HTTPI.get(request, :httpclient)
|
191
|
+
expect(response.body).to eq("ntlm-auth")
|
182
192
|
end
|
183
193
|
|
184
194
|
def httpclient_expects(method)
|
@@ -14,6 +14,22 @@ describe HTTPI::Adapter::NetHTTP do
|
|
14
14
|
@server.stop
|
15
15
|
end
|
16
16
|
|
17
|
+
context 'when socks is specified' do
|
18
|
+
|
19
|
+
let(:socks_client) { mock('socks_client') }
|
20
|
+
let(:request){HTTPI::Request.new(@server.url)}
|
21
|
+
|
22
|
+
it 'uses Net::HTTP.SOCKSProxy as client' do
|
23
|
+
socks_client.expects(:new).with(URI(@server.url).host, URI(@server.url).port).returns(:socks_client_instance)
|
24
|
+
Net::HTTP.expects(:SOCKSProxy).with('localhost', 8080).returns socks_client
|
25
|
+
|
26
|
+
request.proxy = 'socks://localhost:8080'
|
27
|
+
adapter = HTTPI::Adapter::NetHTTP.new(request)
|
28
|
+
|
29
|
+
expect(adapter.client).to eq(:socks_client_instance)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
17
33
|
it "sends and receives HTTP headers" do
|
18
34
|
request = HTTPI::Request.new(@server.url + "x-header")
|
19
35
|
request.headers["X-Header"] = "HTTPI"
|
@@ -52,6 +68,36 @@ describe HTTPI::Adapter::NetHTTP do
|
|
52
68
|
expect(response.headers["Content-Type"]).to eq("text/plain")
|
53
69
|
end
|
54
70
|
|
71
|
+
context "supports custom methods supported by Net::HTTP" do
|
72
|
+
let(:request) do
|
73
|
+
HTTPI::Request.new(@server.url).tap do|r|
|
74
|
+
r.body = request_body if request_body
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
let(:request_body) { nil }
|
79
|
+
|
80
|
+
let(:response) { HTTPI.request(http_method, request, adapter) }
|
81
|
+
|
82
|
+
shared_examples_for 'any supported custom method' do
|
83
|
+
specify { response.body.should eq http_method.to_s }
|
84
|
+
specify { response.headers["Content-Type"].should eq('text/plain') }
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'PATCH' do
|
88
|
+
let(:http_method) { :patch }
|
89
|
+
let(:request_body) { "<some>xml</some>" }
|
90
|
+
|
91
|
+
it_behaves_like 'any supported custom method'
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'UNSUPPORTED method' do
|
95
|
+
let(:http_method) { :unsupported }
|
96
|
+
|
97
|
+
specify { expect { response }.to raise_error HTTPI::NotSupportedError }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
55
101
|
it "supports basic authentication" do
|
56
102
|
request = HTTPI::Request.new(@server.url + "basic-auth")
|
57
103
|
request.auth.basic("admin", "secret")
|
@@ -85,6 +131,17 @@ describe HTTPI::Adapter::NetHTTP do
|
|
85
131
|
expect { HTTPI.get(request, adapter) }.
|
86
132
|
to raise_error(HTTPI::NotSupportedError, /Net::NTLM is not available/)
|
87
133
|
end
|
134
|
+
|
135
|
+
it "does not crash when authenticate header is missing (on second request)" do
|
136
|
+
request = HTTPI::Request.new(@server.url + 'ntlm-auth')
|
137
|
+
request.auth.ntlm("tester", "vReqSoafRe5O")
|
138
|
+
|
139
|
+
expect { HTTPI.get(request, adapter) }.
|
140
|
+
to_not raise_error
|
141
|
+
|
142
|
+
expect { HTTPI.get(request, adapter) }.
|
143
|
+
to_not raise_error
|
144
|
+
end
|
88
145
|
end
|
89
146
|
|
90
147
|
# it does not support digest auth
|
@@ -82,14 +82,12 @@ describe HTTPI::Adapter::NetHTTP do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
describe "
|
86
|
-
|
87
|
-
request.
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
expect { client.request(:get) }.
|
92
|
-
to raise_error(HTTPI::NotSupportedError, "Rack adapter does not support HTTP auth")
|
85
|
+
describe "basic auth" do
|
86
|
+
it "is supported" do
|
87
|
+
request = HTTPI::Request.new(@url + "basic-auth")
|
88
|
+
request.auth.basic("admin", "secret")
|
89
|
+
response = HTTPI.get(request, adapter)
|
90
|
+
expect(response.body).to eq("basic-auth")
|
93
91
|
end
|
94
92
|
end
|
95
93
|
|
data/spec/httpi/auth/ssl_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require "httpi/auth/ssl"
|
|
3
3
|
|
4
4
|
describe HTTPI::Auth::SSL do
|
5
5
|
before(:all) do
|
6
|
-
@ssl_versions = OpenSSL::SSL::SSLContext::METHODS.reject { |method| method.match
|
6
|
+
@ssl_versions = OpenSSL::SSL::SSLContext::METHODS.reject { |method| method.match(/server|client/) }.sort.reverse
|
7
7
|
end
|
8
8
|
|
9
9
|
describe "VERIFY_MODES" do
|
data/spec/httpi/httpi_spec.rb
CHANGED
@@ -269,6 +269,20 @@ describe HTTPI do
|
|
269
269
|
|
270
270
|
client.request(:custom, request, :httpclient)
|
271
271
|
end
|
272
|
+
|
273
|
+
it 'follows redirects at maximum of the redirect limit' do
|
274
|
+
request.follow_redirect = true
|
275
|
+
request.redirect_limit = 2
|
276
|
+
redirect_location = 'http://foo.bar'
|
277
|
+
|
278
|
+
redirect = HTTPI::Response.new(302, {'location' => redirect_location}, 'Moved')
|
279
|
+
response = HTTPI::Response.new(200, {}, 'success')
|
280
|
+
|
281
|
+
httpclient.any_instance.expects(:request).times(2).with(:custom).returns(redirect, response)
|
282
|
+
request.expects(:url=).with(URI.parse(redirect_location))
|
283
|
+
|
284
|
+
client.request(:custom, request, :httpclient)
|
285
|
+
end
|
272
286
|
end
|
273
287
|
|
274
288
|
HTTPI::REQUEST_METHODS.each do |method|
|
data/spec/httpi/request_spec.rb
CHANGED
@@ -108,6 +108,11 @@ describe HTTPI::Request do
|
|
108
108
|
expect(request.proxy).to eq(URI("http://proxy.example.com"))
|
109
109
|
end
|
110
110
|
|
111
|
+
it 'also accepts the socks URL to use as a String' do
|
112
|
+
request.proxy ="socks://socks.example.com"
|
113
|
+
expect(request.proxy).to eq(URI("socks://socks.example.com"))
|
114
|
+
end
|
115
|
+
|
111
116
|
it "also accepts a URI object" do
|
112
117
|
request.proxy = URI("http://proxy.example.com")
|
113
118
|
expect(request.proxy).to eq(URI("http://proxy.example.com"))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Harrington
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-04-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -25,6 +25,20 @@ dependencies:
|
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: socksify
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: rubyntlm
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,6 +109,20 @@ dependencies:
|
|
95
109
|
- - "~>"
|
96
110
|
- !ruby/object:Gem::Version
|
97
111
|
version: 2.3.2
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: webmock
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
98
126
|
description: Common interface for Ruby's HTTP libraries
|
99
127
|
email: me@rubiii.com
|
100
128
|
executables: []
|
@@ -190,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
218
|
version: '0'
|
191
219
|
requirements: []
|
192
220
|
rubyforge_project: httpi
|
193
|
-
rubygems_version: 2.
|
221
|
+
rubygems_version: 2.5.1
|
194
222
|
signing_key:
|
195
223
|
specification_version: 4
|
196
224
|
summary: Common interface for Ruby's HTTP libraries
|