httpi 2.4.1 → 2.4.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|