httpi 2.4.2 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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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
- W0d+jECBVYECn8wCStxfoFcQQRhlGrsOn05379cD8e1odMOJAkEA3o/7CsgXqahG
8
- 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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-----