httpi 2.4.2 → 2.5.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.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/development.yml +48 -0
  3. data/CHANGELOG.md +27 -0
  4. data/Gemfile +9 -4
  5. data/README.md +4 -9
  6. data/Rakefile +5 -3
  7. data/httpi.gemspec +5 -5
  8. data/lib/httpi/adapter/curb.rb +7 -2
  9. data/lib/httpi/adapter/em_http.rb +5 -4
  10. data/lib/httpi/adapter/excon.rb +11 -2
  11. data/lib/httpi/adapter/http.rb +15 -2
  12. data/lib/httpi/adapter/httpclient.rb +5 -0
  13. data/lib/httpi/adapter/net_http.rb +17 -3
  14. data/lib/httpi/adapter/net_http_persistent.rb +6 -2
  15. data/lib/httpi/auth/ssl.rb +62 -3
  16. data/lib/httpi/logger.rb +6 -1
  17. data/lib/httpi/request.rb +2 -2
  18. data/lib/httpi/version.rb +1 -1
  19. data/spec/fixtures/client_cert.pem +18 -14
  20. data/spec/fixtures/client_key.pem +25 -13
  21. data/spec/httpi/adapter/curb_spec.rb +32 -9
  22. data/spec/httpi/adapter/em_http_spec.rb +23 -21
  23. data/spec/httpi/adapter/excon_spec.rb +28 -118
  24. data/spec/httpi/adapter/http_spec.rb +23 -96
  25. data/spec/httpi/adapter/httpclient_spec.rb +32 -0
  26. data/spec/httpi/adapter/net_http_persistent_spec.rb +31 -81
  27. data/spec/httpi/adapter/net_http_spec.rb +37 -154
  28. data/spec/httpi/auth/ssl_spec.rb +49 -1
  29. data/spec/httpi/httpi_spec.rb +2 -4
  30. data/spec/integration/curb_spec.rb +20 -0
  31. data/spec/integration/em_http_spec.rb +19 -2
  32. data/spec/integration/excon_spec.rb +174 -0
  33. data/spec/integration/fixtures/ca_all.pem +17 -42
  34. data/spec/integration/fixtures/server.cert +17 -17
  35. data/spec/integration/fixtures/server.key +25 -13
  36. data/spec/integration/http_spec.rb +156 -0
  37. data/spec/integration/httpclient_spec.rb +20 -0
  38. data/spec/integration/net_http_persistent_spec.rb +34 -2
  39. data/spec/integration/net_http_spec.rb +136 -1
  40. data/spec/integration/support/application.rb +3 -2
  41. data/spec/integration/support/server.rb +1 -2
  42. data/spec/spec_helper.rb +0 -2
  43. metadata +16 -15
  44. data/.travis.yml +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b00e0eb6313b47ac5eb3be9f3330bac10a9321b7
4
- data.tar.gz: b49e8aaba759e1384bae07bf825b17f511c809ec
2
+ SHA256:
3
+ metadata.gz: 2c921690b77440f26fa4da9bac58ed74d16440e9df7d180be606e1c21460dfbb
4
+ data.tar.gz: d95e355e1925d7cb78622fc6188cc761eedec15e30ad9bd93b565937873d86c6
5
5
  SHA512:
6
- metadata.gz: b3a31c1b2ac5ebbb82336104e64130f3f214462838175c7d966677c5e1cb03b77273d80b0282e9a1a032ea38b963215974a29777223c0da287d7755418b1b05a
7
- data.tar.gz: 1c9baad44d8900f1bad06e9c991079300541476dded64e9bd44468a77552fc8d1143c6abe1d6e1ef42c11adf6427ed1d4241f02f9538fccb820e83b985bafc1a
6
+ metadata.gz: '09c5e6e4bf5242de2f9472123c94ca3f17a3fd60e816886cf7402d4d977d45e2cc8be98e3d6a4ac2c7d16b68af8cef58a016d4b1b4aa443bfca92bde6f7232ce'
7
+ data.tar.gz: ba7d999bc0d771365a4c647df38419f7ba2ee22f3d06c33dd660645aad999d7529d1ce8036b9d2d24994098fcdf2f415df2b533b4c68c5c1a483b0e25862629a
@@ -0,0 +1,48 @@
1
+ name: Development
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ name: ${{matrix.ruby}} on ${{matrix.os}}
8
+ runs-on: ${{matrix.os}}-latest
9
+ continue-on-error: ${{matrix.experimental}}
10
+
11
+ strategy:
12
+ matrix:
13
+ os:
14
+ - ubuntu
15
+
16
+ ruby:
17
+ - "2.6"
18
+ - "2.7"
19
+ - "3.0"
20
+
21
+ experimental: [false]
22
+ env: [""]
23
+
24
+ include:
25
+ - os: ubuntu
26
+ ruby: truffleruby
27
+ experimental: true
28
+ - os: ubuntu
29
+ ruby: jruby
30
+ experimental: true
31
+ - os: ubuntu
32
+ ruby: head
33
+ experimental: true
34
+
35
+ steps:
36
+ - uses: actions/checkout@v2
37
+
38
+ - name: Install dependencies
39
+ run: sudo apt-get install libcurl4-openssl-dev
40
+
41
+ - uses: ruby/setup-ruby@v1
42
+ with:
43
+ ruby-version: ${{matrix.ruby}}
44
+ bundler-cache: true
45
+
46
+ - name: Run tests
47
+ timeout-minutes: 5
48
+ run: ${{matrix.env}} bundle exec rspec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ ### 2.5.0 (2021-10-05)
2
+
3
+ * Feature: [#214](https://github.com/savonrb/httpi/pull/214) Add SSL ciphers configuration
4
+ * Improvement: [#227](https://github.com/savonrb/httpi/pull/227) Use GitHub Actions as CI. Require at least Ruby v2.3.
5
+
6
+ ### 2.4.5
7
+
8
+ * Improvement: [#209](https://github.com/savonrb/httpi/pull/209) Drop Travis CI support for Ruby < 2.3.0 and jruby.
9
+ * Feature: [#208](https://github.com/savonrb/httpi/pull/208) Add SSL min/max_version configuration for supporting adapters
10
+ * Improvement: [#206](https://github.com/savonrb/httpi/pull/206) Support for net-http-persistent v3
11
+ * Improvement: [#204](https://github.com/savonrb/httpi/pull/204) Avoid excon warning
12
+
13
+ ### 2.4.4
14
+
15
+ * Improvement: [#197](https://github.com/savonrb/httpi/pull/197) Add support for new write timeout option to all adapters
16
+ * Fix: [#196](https://github.com/savonrb/httpi/pull/196) Fix httpi adapters support for read/open timeout
17
+ * Improvement: [Remove references to broken site](https://github.com/savonrb/httpi/commit/345e5e2b1a4376a7be769f67088a431895de09ad)
18
+ * Fix: [#190](https://github.com/savonrb/httpi/pull/190) Don't convert port to string on Excon adapter
19
+
20
+ ### 2.4.3
21
+
22
+ * Fix: [#171](https://github.com/savonrb/httpi/pull/171) bug with rubyntlm v0.6.0
23
+ * Fix: [#181](https://github.com/savonrb/httpi/pull/181) excon and http adapters
24
+ * Feature: [#183](https://github.com/savonrb/httpi/pull/183) Logging ssl information of a request
25
+ * Fix: [#187](https://github.com/savonrb/httpi/pull/187) only require ntlm if ntlm auth was requested
26
+
27
+
1
28
  ### 2.4.2
2
29
 
3
30
  * Feature: [#165](https://github.com/savonrb/httpi/pull/165) Extended net_http adapter ssl options with cert_store and ca_path
data/Gemfile CHANGED
@@ -3,15 +3,20 @@ gemspec
3
3
 
4
4
  gem 'jruby-openssl', :platforms => :jruby
5
5
 
6
+ gem 'public_suffix', '~> 4.0'
7
+
6
8
  # http clients
7
9
  gem 'httpclient', '~> 2.3', :require => false
8
- gem 'curb', '~> 0.8', :require => false, :platforms => :ruby
9
- gem 'em-http-request', :require => false, :platforms => [:ruby, :jruby]
10
+ gem 'curb', '~> 0.8', :require => false, :platforms => [:ruby]
11
+ gem 'em-http-request', :require => false, :platforms => [:ruby]
10
12
  gem 'em-synchrony', :require => false, :platforms => [:ruby, :jruby]
11
13
  gem 'excon', '~> 0.21', :require => false, :platforms => [:ruby, :jruby]
12
- gem 'net-http-persistent', '~> 2.8', :require => false
14
+ gem 'net-http-persistent', '~> 4.0', :require => false
13
15
  gem 'http', :require => false
14
16
 
17
+ # adapter extensions
18
+ gem 'rack'
19
+ gem 'socksify'
20
+
15
21
  # coverage
16
22
  gem 'simplecov', :require => false
17
- gem 'coveralls', :require => false
data/README.md CHANGED
@@ -2,18 +2,14 @@
2
2
 
3
3
  A common interface for Ruby's HTTP libraries.
4
4
 
5
- [Documentation](http://httpirb.com) | [RDoc](http://rubydoc.info/gems/httpi) |
5
+ [Documentation](https://www.rubydoc.info/gems/httpi) |
6
6
  [Mailing list](https://groups.google.com/forum/#!forum/httpirb)
7
7
 
8
- [![Build Status](https://secure.travis-ci.org/savonrb/httpi.png?branch=master)](http://travis-ci.org/savonrb/httpi)
9
- [![Gem Version](https://badge.fury.io/rb/httpi.png)](http://badge.fury.io/rb/httpi)
10
- [![Code Climate](https://codeclimate.com/github/savonrb/httpi.png)](https://codeclimate.com/github/savonrb/httpi)
11
- [![Coverage Status](https://coveralls.io/repos/savonrb/httpi/badge.png?branch=master)](https://coveralls.io/r/savonrb/httpi)
12
-
8
+ [![Development](https://github.com/savonrb/httpi/actions/workflows/development.yml/badge.svg)](https://github.com/savonrb/httpi/actions/workflows/development.yml)
13
9
 
14
10
  ## Installation
15
11
 
16
- HTTPI is available through [Rubygems](http://rubygems.org/gems/httpi) and can be installed via:
12
+ HTTPI is available through [Rubygems](https://rubygems.org/gems/httpi) and can be installed via:
17
13
 
18
14
  ```
19
15
  $ gem install httpi
@@ -28,7 +24,6 @@ gem 'httpi', '~> 2.1.0'
28
24
 
29
25
  ## Usage example
30
26
 
31
-
32
27
  ``` ruby
33
28
  require "httpi"
34
29
 
@@ -52,4 +47,4 @@ HTTPI.request(:custom, request)
52
47
 
53
48
  ## Documentation
54
49
 
55
- Continue reading at [httpirb.com](http://httpirb.com)
50
+ Continue reading at https://www.rubydoc.info/gems/httpi
data/Rakefile CHANGED
@@ -10,7 +10,9 @@ RSpec::Core::RakeTask.new "spec_integration" do |t|
10
10
  t.pattern = "spec/integration/*_spec.rb"
11
11
  end
12
12
 
13
- task :default => :spec
14
-
15
13
  desc "Run RSpec code and integration examples"
16
- task :ci => [:spec, :spec_integration]
14
+ RSpec::Core::RakeTask.new "ci" do |t|
15
+ t.pattern = "spec/{httpi,integration}/**/*_spec.rb"
16
+ end
17
+
18
+ task :default => :spec
data/httpi.gemspec CHANGED
@@ -11,19 +11,19 @@ Gem::Specification.new do |s|
11
11
  s.homepage = "http://github.com/savonrb/#{s.name}"
12
12
  s.summary = "Common interface for Ruby's HTTP libraries"
13
13
  s.description = s.summary
14
- s.required_ruby_version = '>= 1.9.2'
15
14
 
16
- s.rubyforge_project = s.name
15
+ s.required_ruby_version = '>= 2.3'
16
+
17
17
  s.license = 'MIT'
18
18
 
19
19
  s.add_dependency 'rack'
20
20
  s.add_dependency 'socksify'
21
21
 
22
22
  s.add_development_dependency 'rubyntlm', '~> 0.3.2'
23
- s.add_development_dependency 'rake', '~> 10.0'
24
- s.add_development_dependency 'rspec', '~> 2.14'
23
+ s.add_development_dependency 'rake', '~> 13.0'
24
+ s.add_development_dependency 'rspec', '~> 3.5'
25
25
  s.add_development_dependency 'mocha', '~> 0.13'
26
- s.add_development_dependency 'puma', '~> 2.3.2'
26
+ s.add_development_dependency 'puma', '~> 5.0'
27
27
  s.add_development_dependency 'webmock'
28
28
 
29
29
  s.files = `git ls-files`.split("\n")
@@ -72,8 +72,9 @@ module HTTPI
72
72
  def basic_setup
73
73
  @client.url = @request.url.to_s
74
74
  @client.proxy_url = @request.proxy.to_s if @request.proxy
75
- @client.timeout = @request.read_timeout if @request.read_timeout
76
- @client.connect_timeout = @request.open_timeout if @request.open_timeout
75
+ read_or_write_timeout = @request.read_timeout || @request.write_timeout
76
+ @client.timeout_ms = read_or_write_timeout * 1000 if read_or_write_timeout
77
+ @client.connect_timeout_ms = @request.open_timeout * 1000 if @request.open_timeout
77
78
  @client.headers = @request.headers.to_hash
78
79
  @client.verbose = false
79
80
  # cURL workaround
@@ -115,6 +116,7 @@ module HTTPI
115
116
  @client.cert_key = ssl.cert_key_file
116
117
  @client.cert = ssl.cert_file
117
118
  @client.certpassword = ssl.cert_key_password
119
+ @client.set(:ssl_cipher_list, ssl.ciphers.join(':')) if ssl.ciphers
118
120
 
119
121
  @client.ssl_verify_peer = ssl.verify_mode == :peer
120
122
  end
@@ -127,6 +129,9 @@ module HTTPI
127
129
  when :SSLv23 then 2
128
130
  when :SSLv3 then 3
129
131
  end
132
+ if ssl.min_version || ssl.max_version
133
+ raise NotSupportedError, 'Curb adapter does not support #min_version or #max_version. Please, use #ssl_version instead.'
134
+ end
130
135
  end
131
136
 
132
137
  def respond_with(client)
@@ -69,10 +69,11 @@ module HTTPI
69
69
  end
70
70
 
71
71
  def connection_options
72
- options = {
73
- :connect_timeout => @request.open_timeout,
74
- :inactivity_timeout => @request.read_timeout
75
- }
72
+ options = {}
73
+
74
+ read_or_write_timeout = @request.read_timeout || @request.write_timeout
75
+ options[:inactivity_timeout] = read_or_write_timeout if read_or_write_timeout
76
+ options[:connect_timeout] = @request.open_timeout if @request.open_timeout
76
77
 
77
78
  options[:proxy] = proxy_options if @request.proxy
78
79
 
@@ -41,8 +41,9 @@ module HTTPI
41
41
 
42
42
  opts = {
43
43
  :host => url.host,
44
+ :hostname => url.hostname,
44
45
  :path => url.path,
45
- :port => url.port.to_s,
46
+ :port => url.port,
46
47
  :query => url.query,
47
48
  :scheme => url.scheme,
48
49
  :headers => @request.headers,
@@ -58,6 +59,7 @@ module HTTPI
58
59
  opts[:user], opts[:password] = *@request.auth.credentials if @request.auth.basic?
59
60
  opts[:connect_timeout] = @request.open_timeout if @request.open_timeout
60
61
  opts[:read_timeout] = @request.read_timeout if @request.read_timeout
62
+ opts[:write_timeout] = @request.write_timeout if @request.write_timeout
61
63
  opts[:response_block] = @request.on_body if @request.on_body
62
64
  opts[:proxy] = @request.proxy if @request.proxy
63
65
 
@@ -71,13 +73,20 @@ module HTTPI
71
73
  opts[:ssl_verify_peer] = false
72
74
  end
73
75
 
76
+ opts[:ciphers] = ssl.ciphers if ssl.ciphers
74
77
  opts[:ssl_version] = ssl.ssl_version if ssl.ssl_version
78
+ opts[:ssl_min_version] = ssl.min_version if ssl.min_version
79
+ opts[:ssl_max_version] = ssl.max_version if ssl.max_version
75
80
 
76
81
  opts
77
82
  end
78
83
 
79
84
  def respond_with(response)
80
- Response.new response.status, response.headers, response.body
85
+ headers = response.headers.dup
86
+ if (cookies = response.data[:cookies]) && !cookies.empty?
87
+ headers["Set-Cookie"] = cookies
88
+ end
89
+ Response.new response.status, headers, response.body
81
90
  end
82
91
 
83
92
  end
@@ -32,9 +32,13 @@ module HTTPI
32
32
  unless ::HTTP::Request::METHODS.include? method
33
33
  raise NotSupportedError, "http.rb does not support custom HTTP methods"
34
34
  end
35
- response = @client.send(method, @request.url, :body => @request.body)
35
+ response = begin
36
+ @client.send(method, @request.url, :body => @request.body)
37
+ rescue OpenSSL::SSL::SSLError
38
+ raise SSLError
39
+ end
36
40
 
37
- Response.new(response.code, response.headers, response.body.to_s)
41
+ Response.new(response.code, response.headers.to_h, response.body.to_s)
38
42
  end
39
43
 
40
44
  private
@@ -54,7 +58,10 @@ module HTTPI
54
58
  context.cert = @request.auth.ssl.cert
55
59
  context.key = @request.auth.ssl.cert_key
56
60
  context.ssl_version = @request.auth.ssl.ssl_version if @request.auth.ssl.ssl_version != nil
61
+ context.min_version = @request.auth.ssl.min_version if @request.auth.ssl.min_version != nil
62
+ context.max_version = @request.auth.ssl.max_version if @request.auth.ssl.max_version != nil
57
63
  context.verify_mode = @request.auth.ssl.openssl_verify_mode
64
+ context.ciphers = @request.auth.ssl.ciphers if @request.auth.ssl.ciphers
58
65
 
59
66
  client = ::HTTP::Client.new(:ssl_context => context)
60
67
  else
@@ -69,6 +76,12 @@ module HTTPI
69
76
  client = client.via(@request.proxy.host, @request.proxy.port, @request.proxy.user, @request.proxy.password)
70
77
  end
71
78
 
79
+ timeouts = {}
80
+ timeouts[:connect] = @request.open_timeout if @request.open_timeout
81
+ timeouts[:read] = @request.read_timeout if @request.read_timeout
82
+ timeouts[:write] = @request.write_timeout if @request.write_timeout
83
+ client = client.timeout(timeouts) if timeouts.any?
84
+
72
85
  client.headers(@request.headers)
73
86
  end
74
87
  end
@@ -45,6 +45,7 @@ module HTTPI
45
45
  @client.proxy = @request.proxy if @request.proxy
46
46
  @client.connect_timeout = @request.open_timeout if @request.open_timeout
47
47
  @client.receive_timeout = @request.read_timeout if @request.read_timeout
48
+ @client.send_timeout = @request.write_timeout if @request.write_timeout
48
49
  end
49
50
 
50
51
  def setup_auth
@@ -72,11 +73,15 @@ module HTTPI
72
73
  # Send client-side certificate regardless of state of SSL verify mode
73
74
  @client.ssl_config.client_cert = ssl.cert
74
75
  @client.ssl_config.client_key = ssl.cert_key
76
+ @client.ssl_config.ciphers = ssl.ciphers if ssl.ciphers
75
77
 
76
78
  @client.ssl_config.verify_mode = ssl.openssl_verify_mode
77
79
  end
78
80
 
79
81
  @client.ssl_config.ssl_version = ssl.ssl_version.to_s if ssl.ssl_version
82
+ if ssl.min_version || ssl.max_version
83
+ raise NotSupportedError, 'Httpclient adapter does not support #min_version or #max_version. Please, use #ssl_version instead'
84
+ end
80
85
  end
81
86
 
82
87
  def respond_with(response)
@@ -18,7 +18,7 @@ module HTTPI
18
18
 
19
19
  register :net_http, :deps => %w(net/https)
20
20
  def initialize(request)
21
- check_net_ntlm_version!
21
+ check_net_ntlm_version! if request.auth.ntlm?
22
22
  @request = request
23
23
  @client = create_client
24
24
  end
@@ -55,11 +55,15 @@ module HTTPI
55
55
  end
56
56
 
57
57
  private
58
+ def ntlm_version
59
+ Net::NTLM::VERSION::STRING
60
+ end
61
+
58
62
  def check_net_ntlm_version!
59
63
  begin
60
64
  require 'net/ntlm'
61
- require 'net/ntlm/version' unless Net::NTLM.const_defined?(:VERSION)
62
- unless Net::NTLM::VERSION::STRING >= '0.3.2'
65
+ require 'net/ntlm/version' unless Net::NTLM.const_defined?(:VERSION, false)
66
+ unless ntlm_version >= '0.3.2'
63
67
  raise ArgumentError, 'Invalid version of rubyntlm. Please use v0.3.2+.'
64
68
  end
65
69
  rescue LoadError
@@ -151,6 +155,13 @@ module HTTPI
151
155
  @client.use_ssl = @request.ssl?
152
156
  @client.open_timeout = @request.open_timeout if @request.open_timeout
153
157
  @client.read_timeout = @request.read_timeout if @request.read_timeout
158
+ if @request.write_timeout
159
+ if @client.respond_to?(:write_timeout=) # Expected to appear in Ruby 2.6
160
+ @client.write_timeout = @request.write_timeout
161
+ else
162
+ raise NotSupportedError, "Net::HTTP supports write_timeout starting from Ruby 2.6"
163
+ end
164
+ end
154
165
  end
155
166
 
156
167
  def setup_ssl_auth
@@ -166,11 +177,14 @@ module HTTPI
166
177
  # Send client-side certificate regardless of state of SSL verify mode
167
178
  @client.key = ssl.cert_key
168
179
  @client.cert = ssl.cert
180
+ @client.ciphers = ssl.ciphers if ssl.ciphers
169
181
 
170
182
  @client.verify_mode = ssl.openssl_verify_mode
171
183
  end
172
184
 
173
185
  @client.ssl_version = ssl.ssl_version if ssl.ssl_version
186
+ @client.min_version = ssl.min_version if ssl.min_version
187
+ @client.max_version = ssl.max_version if ssl.max_version
174
188
  end
175
189
 
176
190
  def ssl_cert_store(ssl)
@@ -12,7 +12,11 @@ module HTTPI
12
12
  private
13
13
 
14
14
  def create_client
15
- Net::HTTP::Persistent.new thread_key
15
+ if Gem::Version.new(Net::HTTP::Persistent::VERSION) >= Gem::Version.new('3.0.0')
16
+ Net::HTTP::Persistent.new name: thread_key
17
+ else
18
+ Net::HTTP::Persistent.new thread_key
19
+ end
16
20
  end
17
21
 
18
22
  def perform(http, http_request, &on_body)
@@ -32,12 +36,12 @@ module HTTPI
32
36
 
33
37
  @client.open_timeout = @request.open_timeout if @request.open_timeout
34
38
  @client.read_timeout = @request.read_timeout if @request.read_timeout
39
+ raise NotSupportedError, "Net::HTTP::Persistent does not support write_timeout" if @request.write_timeout
35
40
  end
36
41
 
37
42
  def thread_key
38
43
  @request.url.host.split(/\W/).reject{|p|p == ""}.join('-')
39
44
  end
40
-
41
45
  end
42
46
  end
43
47
  end
@@ -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
- SSL_VERSIONS = OpenSSL::SSL::SSLContext::METHODS.reject { |method| method.match(/server|client/) }.sort.reverse
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
@@ -34,9 +45,27 @@ module HTTPI
34
45
  # Accessor for the ca_path to validate SSL certificates.
35
46
  attr_accessor :ca_cert_path
36
47
 
37
- # ertificate store holds trusted CA certificates used to verify peer certificates.
48
+ # Certificate store holds trusted CA certificates used to verify peer certificates.
38
49
  attr_accessor :cert_store
39
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
+
40
69
  # Returns the cert type to validate SSL certificates PEM|DER.
41
70
  def cert_type
42
71
  @cert_type ||= :pem
@@ -82,6 +111,36 @@ module HTTPI
82
111
  @ssl_version = version
83
112
  end
84
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
+
85
144
  # Returns an <tt>OpenSSL::X509::Certificate</tt> for the +cert_file+.
86
145
  def cert
87
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, :redirect_limit, :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 = {})
@@ -90,7 +90,7 @@ module HTTPI
90
90
  headers["Cookie"] = cookies if cookies
91
91
  end
92
92
 
93
- attr_accessor :open_timeout, :read_timeout
93
+ attr_accessor :open_timeout, :read_timeout, :write_timeout
94
94
  attr_reader :body
95
95
 
96
96
  # Sets a body request given a String or a Hash.
data/lib/httpi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module HTTPI
2
- VERSION = '2.4.2'
2
+ VERSION = '2.5.0'
3
3
  end
@@ -1,16 +1,20 @@
1
1
  -----BEGIN CERTIFICATE-----
2
- MIICbTCCAdYCCQDC4v8d04615DANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJE
3
- RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzEOMAwGA1UEChMF
4
- aHR0cGkxFDASBgNVBAMTC2V4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFt
5
- cGxlQGV4YW1wbGUuY29tMB4XDTEwMTAxNTE4NTg0N1oXDTExMTAxNTE4NTg0N1ow
6
- ezELMAkGA1UEBhMCREUxEDAOBgNVBAgTB0hhbWJ1cmcxEDAOBgNVBAcTB0hhbWJ1
7
- cmcxDjAMBgNVBAoTBWh0dHBpMRQwEgYDVQQDEwtleGFtcGxlLmNvbTEiMCAGCSqG
8
- SIb3DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB
9
- jQAwgYkCgYEAvJiaojIFQAbFczXkBmjxpxra9LbQm0VIESFSl8uBSjmG/gmCBwKg
10
- 8O94P3tAjDNClC+fEqBLE37KH4qe76yw7upgRruP5jQzUEL1yCaVtA/DoqgaCxZy
11
- 7VhB2A3f71Zw6kQPt3BOME68fnGsTX65x9XAawCGzGmJSk/Z6wvml1MCAwEAATAN
12
- BgkqhkiG9w0BAQUFAAOBgQCxOyni9LOKf17vUKVG8Y4TBzRYwm8/hlEdVEU3JKG0
13
- /aCCwIJLHl+z+3L4r81IN3+YKrHilqx9K0emboJbBRQklYsv/AE+J44Bq3llRiro
14
- 0e5zwH61jb1j+kxhcxoGiiy8R7hYho24ljuMgFGqtK3kZSP/t9tBLLVp+ItWQ6xX
15
- 5g==
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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- qEa8zpfF0TmhQ0oWN75Cq709gfVVBfx/bVcCQHan1HN/Ef6FlKqKjxQGQXYwEfQa
11
- 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
- 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
- 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
- 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
15
27
  -----END RSA PRIVATE KEY-----