manticore 0.6.3-java → 0.8.0-java

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8b96d1eb1f7f1e5b6885a5f08e24ba394ac9fac0
4
- data.tar.gz: 1ff15070f745905119d536ae7df328ce845990a6
2
+ SHA256:
3
+ metadata.gz: 063b0fd32e3dfbee4335d04293e098e8b1bc054ecd727ff51011e6eef3675c4b
4
+ data.tar.gz: 8a5da3e5e6433d7d57e388069e95393fbc66220f1695ab7b1443f9dc49f84d11
5
5
  SHA512:
6
- metadata.gz: 1f08d3632cbe683ce2456e4cde41d05545bdf5926992067f06f25af1477d9a31bac90d797a88a4f4d4a7a56477afd9f725981958ac3082e501c18199da4875b3
7
- data.tar.gz: d2231b58a53b86bd77af5c2f27f79d9a4ece0d72cffbace8c1a830fefcd33a84f5c710f93d1e55e76637ab48d5966c79f466ee40c911418a59e4ce440576a8c7
6
+ metadata.gz: db22357ef64973e1452bb970dbb2d7a6c960c895db7d0afe1ae96339f414a06dba8c1039b7f5d3d0ce493443317a9d72c7dce04e7c7fbab98704e55e124d2766
7
+ data.tar.gz: 6744d52a35f0e94d23db237b9f364353eeec4bb3667eb35a06620cf16b676e5b49bd76bb12ba7296f6924b2b7ae052cb4f1d443a6f1e87b00d32b9d1af60c507
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,42 @@
1
+ .default: &default
2
+ variables:
3
+ TERM: xterm-256color
4
+ JRUBY_OPTS: --debug
5
+ cache:
6
+ paths:
7
+ - bundler --path vendor/bundle
8
+ - $HOME/.m2
9
+ before_script:
10
+ - apt update && apt install -y git
11
+ - gem install ruby-maven
12
+ - bundle install --path vendor/bundle
13
+ script:
14
+ - bundle exec rake
15
+
16
+ test jruby-9.2:
17
+ <<: *default
18
+ image: jruby:9.2
19
+ artifacts:
20
+ expire_in: 3 days
21
+ paths:
22
+ - coverage
23
+
24
+ test jruby-9.1:
25
+ <<: *default
26
+ image: jruby:9.1
27
+
28
+ test jruby-1.7:
29
+ <<: *default
30
+ image: jruby:1.7
31
+
32
+ pages:
33
+ stage: deploy
34
+ only:
35
+ - master
36
+ artifacts:
37
+ expire_in: 3 days
38
+ paths:
39
+ - public
40
+ script:
41
+ - mkdir -p public
42
+ - mv coverage/ public/coverage/
data/.travis.yml CHANGED
@@ -1,23 +1,22 @@
1
+ dist: trusty # due Oracle JDK
1
2
  language: ruby
2
- sudo: false
3
3
  cache:
4
4
  - bundler
5
5
  - directories:
6
6
  - $HOME/.m2
7
7
  rvm:
8
- - jruby-1.7
9
- - jruby-9.0.5.0
8
+ - jruby-9.2.19.0 # Ruby 2.5
10
9
  jdk:
11
10
  - oraclejdk8
12
- - openjdk7
11
+ - openjdk8
12
+ - openjdk11
13
13
  before_install:
14
- - gem install ruby-maven bundler
15
- - bundle install
14
+ - gem install bundler -v 1.17.3
16
15
  matrix:
17
16
  include:
18
- - rvm: jruby-9.2.0.0
19
- jdk: oraclejdk8
20
17
  - rvm: jruby-head
21
- jdk: oraclejdk8
18
+ jdk: openjdk11
19
+ - rvm: jruby-9.1.17.0 # Ruby 2.3
20
+ jdk: openjdk8
22
21
  allow_failures:
23
22
  - rvm: jruby-head
data/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
+ ### v0.8.0
2
+
3
+ * [feat] restore compat with (legacy) verify: false (#102)
4
+ * Accept untrusted certs when SSL verify is disabled (#100)
5
+ * [deps] update http-client to 4.5.13 (#99)
6
+
7
+ ## v0.7
8
+
9
+ ### v0.7.1
10
+
11
+ * Don't override certificates with same Subject (#93)
12
+ * Set Java cause for ManticoreException types (#96)
13
+ * Fix SSL handshake hang indefinitely (#98)
14
+
15
+ ### v0.7.0
16
+
17
+ * Drop support for JRuby 1.7. It probably still works, but we don't test against it anymore
18
+ * Fix a thread safety issue with regards to adding requests to the parallel execution queue while the client is already processing a queue (#80)
19
+
1
20
  ## v0.6
2
21
 
22
+ ### v0.6.4
23
+
24
+ * client_cert and client_key now take the literal keys as strings, OpenSSL::X509::Certificate/OpenSSL::PKey::Pkey instances, or key file paths. (#77)
25
+ * Reduced unnecessary string copying (!78 - thanks @kares)
26
+
27
+ ### v0.6.2-v0.6.3
28
+
29
+ * Fixed the use of authentication information in proxy URLs (#71)
30
+ * Changed the default encoding to UTF-8 when a response MIME is application/json (#70)
31
+
3
32
  ### v0.6.1
4
33
 
5
34
  * Manticore will accept a URI object (which it calls #to_s on) as an alternate to a String for the URL in client#get(url)
data/Gemfile CHANGED
@@ -8,7 +8,9 @@ group :development, :test do
8
8
  gem "rspec", "~> 3.0"
9
9
  gem "rspec-its"
10
10
  gem "httpclient", "~> 2.3"
11
- gem "rack", "~> 1.5"
11
+ gem "rack", ">= 2.1.4"
12
12
  gem "rake-compiler"
13
13
  gem "gserver"
14
- end
14
+ gem "simplecov"
15
+ gem "json"
16
+ end
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Manticore
2
2
 
3
- [![Build Status](https://travis-ci.org/cheald/manticore.svg?branch=master)](https://travis-ci.org/cheald/manticore)
3
+ **Note**: While I'll continue to maintain the library here, I've moved the canonical copy to Gitlab at https://gitlab.com/cheald/manticore - it is preferred that you submit issues and PRs there.
4
+
5
+ [![Build Status](https://app.travis-ci.com/cheald/manticore.svg?branch=master)](https://app.travis-ci.com/cheald/manticore)
4
6
 
5
7
  Manticore is a fast, robust HTTP client built on the Apache HTTPClient libraries. It is only compatible with JRuby.
6
8
 
@@ -88,7 +90,11 @@ For detailed documentation, see the [full Manticore::Client documentation](http:
88
90
  Rather than using the Facade, you can create your own standalone Client instances. When you create a `Client`, you will pass various parameters that it will use to set up the pool.
89
91
 
90
92
  ```ruby
91
- client = Manticore::Client.new(request_timeout: 5, connect_timeout: 5, socket_timeout: 5, pool_max: 10, pool_max_per_route: 2)
93
+ client = Manticore::Client.new(request_timeout: 5,
94
+ connect_timeout: 5,
95
+ socket_timeout: 5,
96
+ pool_max: 10,
97
+ pool_max_per_route: 2)
92
98
  ```
93
99
 
94
100
  Then, you can make requests from the client. Pooling and route maximum constraints are automatically managed:
@@ -120,11 +126,20 @@ per-route concurrency limits, and other neat things. In general, you should crea
120
126
  To set this up, you might create 2 pools, each configured for the task:
121
127
 
122
128
  ```ruby
123
- general_http_client = Manticore::Client.new connect_timeout: 10, socket_timeout: 10, request_timeout: 10, follow_redirects: true, max_per_route: 2
129
+ general_http_client = Manticore::Client.new(connect_timeout: 10,
130
+ socket_timeout: 10,
131
+ request_timeout: 10,
132
+ follow_redirects: true,
133
+ max_per_route: 2)
124
134
  # With an OpenSSL CA store
125
- proxied_backend_client = Manticore::Client.new proxy: "https://backend.internal:4242", ssl: {ca_file: "my_certs.pem"}
135
+ proxied_backend_client = Manticore::Client.new(proxy: "https://backend.internal:4242",
136
+ ssl: { ca_file: "my_certs.pem" })
126
137
  # Or with a .jks truststore
127
- # proxied_backend_client = Manticore::Client.new proxy: "https://backend.internal:4242", ssl: {truststore: "./truststore.jks", truststore_password: "s3cr3t"}
138
+ proxied_backend_client = Manticore::Client.new(proxy: "https://backend.internal:4242",
139
+ ssl: {
140
+ truststore: "./truststore.jks",
141
+ truststore_password: "s3cr3t"
142
+ })
128
143
  ```
129
144
 
130
145
  This would create 2 separate request pools; the first would be configured with generous timeouts and redirect following, and would use the system
data/Rakefile CHANGED
@@ -36,6 +36,7 @@ task :generate_certs do
36
36
  # Create the CA
37
37
  "#{openssl} genrsa 4096 | #{openssl} pkcs8 -topk8 -nocrypt -out #{root}/root-ca.key",
38
38
  "#{openssl} req -sha256 -x509 -newkey rsa:4096 -nodes -key #{root}/root-ca.key -sha256 -days 365 -out #{root}/root-ca.crt -subj \"/C=US/ST=The Internet/L=The Internet/O=Manticore CA/OU=Manticore/CN=localhost\"",
39
+ "#{openssl} req -sha256 -x509 -newkey rsa:4096 -nodes -key #{root}/root-ca.key -sha256 -days 365 -out #{root}/root-untrusted-ca.crt -subj \"/C=US/ST=The Darknet/L=The Darknet/O=Manticore CA/OU=Manticore/CN=localhost\"",
39
40
 
40
41
  # Create the client CSR, key, and signed cert
41
42
  "#{openssl} genrsa 4096 | #{openssl} pkcs8 -topk8 -nocrypt -out #{root}/client.key",
@@ -48,6 +49,7 @@ task :generate_certs do
48
49
  "#{openssl} req -sha256 -key #{root}/host.key -newkey rsa:4096 -out #{root}/host.csr -subj \"/C=US/ST=The Internet/L=The Internet/O=Manticore Host/OU=Manticore/CN=localhost\"",
49
50
  "#{openssl} x509 -req -in #{root}/host.csr -CA #{root}/root-ca.crt -CAkey #{root}/root-ca.key -CAcreateserial -out #{root}/host.crt -sha256 -days 1",
50
51
  "#{openssl} x509 -req -in #{root}/host.csr -CA #{root}/root-ca.crt -CAkey #{root}/root-ca.key -CAcreateserial -out #{root}/host-expired.crt -sha256 -days -7",
52
+ "#{openssl} x509 -req -in #{root}/host.csr -CA #{root}/root-untrusted-ca.crt -CAkey #{root}/root-ca.key -CAcreateserial -out #{root}/host-untrusted.crt -sha256 -days 1",
51
53
 
52
54
  "#{keytool} -import -file #{root}/root-ca.crt -alias rootCA -keystore #{root}/truststore.jks -noprompt -storepass test123",
53
55
  "#{openssl} pkcs12 -export -clcerts -out #{root}/client.p12 -inkey #{root}/client.key -in #{root}/client.crt -certfile #{root}/root-ca.crt -password pass:test123",
@@ -66,7 +66,7 @@ public class Manticore implements Library {
66
66
 
67
67
  private IRubyObject readWholeEntity(ThreadContext context, HttpEntity entity, Encoding encoding) throws IOException {
68
68
  ByteList bl = new ByteList(EntityUtils.toByteArray(entity), false);
69
- return RubyString.newStringShared(context.getRuntime(), bl, encoding);
69
+ return RubyString.newString(context.getRuntime(), bl, encoding);
70
70
  }
71
71
 
72
72
  private IRubyObject streamEntity(ThreadContext context, HttpEntity entity, Encoding encoding, Block block) throws IOException {
@@ -86,7 +86,7 @@ public class Manticore implements Library {
86
86
  byte[] tmp = new byte[4096];
87
87
  int l;
88
88
  while((l = instream.read(tmp)) != -1) {
89
- block.call( context, RubyString.newString(context.getRuntime(), new ByteList(tmp, 0, l, true), encoding) );
89
+ block.call( context, RubyString.newStringShared(context.getRuntime(), new ByteList(tmp, 0, l, false), encoding) );
90
90
  }
91
91
  } finally {
92
92
  instream.close();
@@ -94,4 +94,4 @@ public class Manticore implements Library {
94
94
  return context.nil;
95
95
  }
96
96
  }
97
- }
97
+ }
@@ -20,17 +20,12 @@ module Faraday
20
20
  ParallelManager.new
21
21
  end
22
22
 
23
- def initialize(app, connection_options = {})
24
- @connection_options = connection_options
25
- super(app)
26
- end
27
-
28
23
  def client(env)
29
24
  @client ||= begin
30
25
  opts = {}
31
26
  if ssl = env[:ssl].to_hash
32
27
  opts[:ssl] = {}
33
- opts[:ssl][:verify] = :disable if ssl[:verify] == false
28
+ opts[:ssl][:verify] = ssl[:verify] unless ssl[:verify].nil?
34
29
  opts[:ssl][:ca_file] = ssl[:ca_file]
35
30
  opts[:ssl][:client_cert] = ssl[:client_cert]
36
31
  opts[:ssl][:client_key] = ssl[:client_key]
@@ -1,6 +1,7 @@
1
1
  require "thread"
2
2
  require "base64"
3
3
  require "weakref"
4
+ require "openssl_pkcs8_pure"
4
5
 
5
6
  module Manticore
6
7
  # @!macro [new] http_method_shared
@@ -68,10 +69,8 @@ module Manticore
68
69
  include_package "org.apache.http.client.config"
69
70
  include_package "org.apache.http.config"
70
71
  include_package "org.apache.http.conn.socket"
71
- include_package "org.apache.http.impl"
72
72
  include_package "org.apache.http.impl.client"
73
73
  include_package "org.apache.http.impl.conn"
74
- include_package "org.apache.http.impl.auth"
75
74
  include_package "org.apache.http.entity"
76
75
  include_package "org.apache.http.message"
77
76
  include_package "org.apache.http.params"
@@ -79,16 +78,21 @@ module Manticore
79
78
  include_package "org.apache.http.auth"
80
79
  include_package "java.util.concurrent"
81
80
  include_package "org.apache.http.client.protocol"
82
- include_package "org.apache.http.conn.ssl"
83
81
  include_package "java.security.cert"
84
82
  include_package "java.security.spec"
85
83
  include_package "java.security"
86
- include_package "org.apache.http.client.utils"
87
84
  java_import "org.apache.http.HttpHost"
88
85
  java_import "javax.net.ssl.SSLContext"
89
86
  java_import "org.manticore.HttpGetWithEntity"
90
87
  java_import "org.manticore.HttpDeleteWithEntity"
91
88
  java_import "org.apache.http.auth.UsernamePasswordCredentials"
89
+ java_import "org.apache.http.conn.ssl.SSLConnectionSocketFactory"
90
+ java_import "org.apache.http.conn.ssl.SSLContextBuilder"
91
+ java_import "org.apache.http.conn.ssl.TrustAllStrategy"
92
+ java_import "org.apache.http.conn.ssl.TrustSelfSignedStrategy"
93
+ java_import "org.apache.http.client.utils.URIBuilder"
94
+ java_import "org.apache.http.impl.DefaultConnectionReuseStrategy"
95
+ java_import "org.apache.http.impl.auth.BasicScheme"
92
96
 
93
97
  # This is a class rather than a proc because the proc holds a closure around
94
98
  # the instance of the Client that creates it.
@@ -169,8 +173,8 @@ module Manticore
169
173
  # @option options [String] ssl[:keystore_password] (nil) Password used for decrypting the client auth key store
170
174
  # @option options [String] ssl[:keystore_type] (nil) Format of the key store, ie "JKS" or "PKCS12". If left nil, the type will be inferred from the keystore filename.
171
175
  # @option options [String] ssl[:ca_file] (nil) OpenSSL-style path to an X.509 certificate to use to validate SSL certificates
172
- # @option options [String] ssl[:client_cert] (nil) OpenSSL-style path to an X.509 certificate to use for client authentication
173
- # @option options [String] ssl[:client_key] (nil) OpenSSL-style path to an RSA key to use for client authentication
176
+ # @option options [String|OpenSSL::X509::Certificate] ssl[:client_cert] (nil) A string containing a base64-encoded X.509 certificate, OR a path to an OpenSSL-style X.509 certificate, OR an instance of OpenSSL::X509::Certificate
177
+ # @option options [String|OpenSSL::PKey::Pkey] ssl[:client_key] (nil) A string containing a base64-encoded RSA key to use for client authentication, OR a path to an OpenSSL-style RSA key, OR an instance of OpenSSL::PKey::PKey
174
178
  # @option options [boolean] ssl[:track_state] (false) Turn on or off connection state tracking. This helps prevent SSL information from leaking across threads, but means that connections
175
179
  # can't be shared across those threads. This should generally be left off unless you know what you're doing.
176
180
  def initialize(options = {})
@@ -200,11 +204,7 @@ module Manticore
200
204
  builder.set_connection_reuse_strategy DefaultConnectionReuseStrategy.new
201
205
  end
202
206
 
203
- socket_config_builder = SocketConfig.custom
204
- socket_config_builder.set_so_timeout(options.fetch(:socket_timeout, DEFAULT_SOCKET_TIMEOUT) * 1000)
205
- socket_config_builder.set_tcp_no_delay(options.fetch(:tcp_no_delay, true))
206
- builder.set_default_socket_config socket_config_builder.build
207
-
207
+ builder.set_default_socket_config socket_config_from_options(options)
208
208
  builder.set_connection_manager pool(options)
209
209
 
210
210
  request_config = RequestConfig.custom
@@ -222,7 +222,7 @@ module Manticore
222
222
  @client = builder.build
223
223
  finalize @client, :close
224
224
  @options = options
225
- @async_requests = []
225
+ @async_requests = Queue.new
226
226
  @stubs = {}
227
227
  end
228
228
 
@@ -333,8 +333,9 @@ module Manticore
333
333
  # @return [Array] An array of the responses from the requests executed.
334
334
  def execute!
335
335
  method = executor.java_method(:submit, [java.util.concurrent.Callable.java_class])
336
- result = @async_requests.map { |r| method.call r }
337
- @async_requests.clear
336
+
337
+ result = []
338
+ result << method.call(@async_requests.pop) until @async_requests.empty?
338
339
  result.map do |future|
339
340
  begin
340
341
  future.get
@@ -385,11 +386,13 @@ module Manticore
385
386
  def pool_builder(options)
386
387
  http_sf = PlainConnectionSocketFactory.new
387
388
 
389
+ # :nocov:
388
390
  if options[:ignore_ssl_validation]
389
391
  $stderr.puts "The options[:ignore_ssl_validation] setting is deprecated in favor of options[:ssl][:verify]"
390
392
  options[:ssl] ||= {}
391
393
  options[:ssl] = {:verify => !options.delete(:ignore_ssl_validation)}.merge(options[:ssl])
392
394
  end
395
+ # :nocov:
393
396
 
394
397
  https_sf = ssl_socket_factory_from_options options.fetch(:ssl, {})
395
398
  registry = RegistryBuilder.create.register("http", http_sf).register("https", https_sf).build
@@ -403,10 +406,19 @@ module Manticore
403
406
  cm.set_validate_after_inactivity options.fetch(:check_connection_timeout, 2_000)
404
407
  cm.set_default_max_per_route options.fetch(:pool_max_per_route, @max_pool_size)
405
408
  cm.set_max_total @max_pool_size
409
+ cm.set_default_socket_config socket_config_from_options(options)
410
+
406
411
  finalize cm, :shutdown
407
412
  end
408
413
  end
409
414
  end
415
+
416
+ def socket_config_from_options(options)
417
+ socket_config_builder = SocketConfig.custom
418
+ socket_config_builder.set_so_timeout(options.fetch(:socket_timeout, DEFAULT_SOCKET_TIMEOUT) * 1000)
419
+ socket_config_builder.set_tcp_no_delay(options.fetch(:tcp_no_delay, true))
420
+ socket_config_builder.build
421
+ end
410
422
 
411
423
  def create_executor_if_needed
412
424
  return @executor if @executor
@@ -506,7 +518,7 @@ module Manticore
506
518
 
507
519
  if @use_cookies == :per_request
508
520
  store = BasicCookieStore.new
509
- context.setAttribute(ClientContext.COOKIE_STORE, store)
521
+ context.setAttribute(ClientContext::COOKIE_STORE, store)
510
522
  end
511
523
 
512
524
  return req, context
@@ -600,11 +612,14 @@ module Manticore
600
612
  def ssl_socket_factory_from_options(ssl_options)
601
613
  trust_store = trust_strategy = nil
602
614
 
603
- verifier = SSLConnectionSocketFactory::STRICT_HOSTNAME_VERIFIER
604
615
  case ssl_options.fetch(:verify, :strict)
605
- when false, :disable, :none
616
+ when false
617
+ trust_store = nil
618
+ trust_strategy = TrustSelfSignedStrategy::INSTANCE
619
+ verifier = SSLConnectionSocketFactory::ALLOW_ALL_HOSTNAME_VERIFIER
620
+ when :disable, :none
606
621
  trust_store = nil
607
- trust_strategy = TrustSelfSignedStrategy.new
622
+ trust_strategy = TrustAllStrategy::INSTANCE
608
623
  verifier = SSLConnectionSocketFactory::ALLOW_ALL_HOSTNAME_VERIFIER
609
624
  when :browser
610
625
  verifier = SSLConnectionSocketFactory::BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
@@ -614,7 +629,7 @@ module Manticore
614
629
  raise "Invalid value for :verify. Valid values are (:all, :browser, :default)"
615
630
  end
616
631
 
617
- context = SSLContexts.custom
632
+ context = SSLContextBuilder.new
618
633
  setup_trust_store ssl_options, context, trust_strategy
619
634
  setup_key_store ssl_options, context
620
635
 
@@ -629,8 +644,8 @@ module Manticore
629
644
  trust_store ||= blank_keystore
630
645
  open(ssl_options[:ca_file]) do |fp|
631
646
  cert_collection = CertificateFactory.get_instance("X509").generate_certificates(fp.to_inputstream).to_a
632
- cert_collection.each do |cert|
633
- trust_store.set_certificate_entry(cert.getSubjectX500Principal.name, cert)
647
+ cert_collection.each_with_index do |cert, i|
648
+ trust_store.set_certificate_entry("#{i}#" + cert.getSubjectX500Principal.name, cert)
634
649
  end
635
650
  end
636
651
  end
@@ -645,39 +660,44 @@ module Manticore
645
660
  keystore_password = (ssl_options[:keystore_password] || "").to_java.toCharArray
646
661
 
647
662
  # Support OpenSSL-style bare X.509 certs with an RSA key
648
- # This is really dumb - we have to b64-decode the key ourselves, and we can only support PKCS8
649
663
  if ssl_options[:client_cert] && ssl_options[:client_key]
650
664
  key_store ||= blank_keystore
651
665
  certs, key = nil, nil
652
- open(ssl_options[:client_cert]) do |fp|
653
- certs = CertificateFactory.get_instance("X509").generate_certificates(fp.to_inputstream).to_array([].to_java(Certificate))
654
- end
666
+
667
+ cert_str = if ssl_options[:client_cert].is_a?(OpenSSL::X509::Certificate)
668
+ ssl_options[:client_cert].to_s
669
+ elsif ssl_options[:client_cert].is_a?(String) && File.exists?(ssl_options[:client_cert])
670
+ File.read(ssl_options[:client_cert])
671
+ else
672
+ ssl_options[:client_cert].to_s
673
+ end
674
+
675
+ cert_stream = java.io.ByteArrayInputStream.new(cert_str.strip.to_java_bytes)
676
+ certs = CertificateFactory.get_instance("X509").generate_certificates(cert_stream).to_array([].to_java(Certificate))
677
+
678
+ key_str = if ssl_options[:client_key].is_a?(OpenSSL::PKey::PKey)
679
+ ssl_options[:client_key].to_pem_pkcs8
680
+ elsif ssl_options[:client_key].is_a?(String) && File.exists?(ssl_options[:client_key])
681
+ File.read(ssl_options[:client_key])
682
+ else
683
+ ssl_options[:client_key].to_s
684
+ end
655
685
 
656
686
  # Add each of the keys in the given keyfile into the keystore.
657
- open(ssl_options[:client_key]) do |fp|
658
- key_parts = fp.read.scan(KEY_EXTRACTION_REGEXP)
659
- key_parts.each do |type, b64key|
660
- body = Base64.decode64 b64key
661
- spec = PKCS8EncodedKeySpec.new(body.to_java_bytes)
662
- type = type.strip
663
- type = "RSA" if type == ""
664
- key = KeyFactory.getInstance(type).generatePrivate(spec)
665
- key_store.set_key_entry("key-#{Digest::SHA1.hexdigest(body)}", key, keystore_password, certs)
666
- end
687
+ key_parts = key_str.scan(KEY_EXTRACTION_REGEXP)
688
+ key_parts.each do |type, b64key|
689
+ body = Base64.decode64 b64key
690
+ spec = PKCS8EncodedKeySpec.new(body.strip.to_java_bytes)
691
+ type = type.strip
692
+ type = "RSA" if type == ""
693
+ key = KeyFactory.getInstance(type).generatePrivate(spec)
694
+ key_store.set_key_entry("key-#{Digest::SHA1.hexdigest(body)}", key, keystore_password, certs)
667
695
  end
668
696
  end
669
697
 
670
698
  context.load_key_material(key_store, keystore_password) if key_store
671
699
  end
672
700
 
673
- def get_trust_store(options)
674
- get_store :truststore, options
675
- end
676
-
677
- def get_key_store(options)
678
- get_store :keystore, options
679
- end
680
-
681
701
  def get_store(prefix, options)
682
702
  KeyStore.get_instance(options[:"#{prefix}_type"] || guess_store_type(options[prefix])).tap do |store|
683
703
  instream = open(options[prefix], "rb").to_inputstream
@@ -11,14 +11,13 @@ module Manticore
11
11
  # @!attribute [r] callback_result
12
12
  # @return Value returned from any given on_success/response block
13
13
  class Response
14
- include_package "org.apache.http.client"
15
- include_package "org.apache.http.util"
16
- include_package "org.apache.http.protocol"
14
+
15
+ java_import "org.apache.http.client.ResponseHandler"
17
16
  java_import "org.apache.http.client.protocol.HttpClientContext"
18
- java_import "java.util.concurrent.Callable"
17
+ java_import "org.apache.http.protocol.ExecutionContext"
19
18
 
20
- include ResponseHandler
21
- include Callable
19
+ include org.apache.http.client.ResponseHandler
20
+ include java.util.concurrent.Callable
22
21
 
23
22
  attr_accessor :background
24
23
  attr_reader :context, :request, :callback_result, :called, :future
@@ -54,15 +53,16 @@ module Manticore
54
53
  ex = Manticore::ConnectTimeout
55
54
  rescue Java::JavaNet::SocketException => e
56
55
  ex = Manticore::SocketException
57
- rescue Java::OrgApacheHttpClient::ClientProtocolException, Java::JavaxNetSsl::SSLHandshakeException, Java::OrgApacheHttpConn::HttpHostConnectException,
58
- Java::OrgApacheHttp::NoHttpResponseException, Java::OrgApacheHttp::ConnectionClosedException => e
56
+ rescue Java::OrgApacheHttpClient::ClientProtocolException, Java::JavaxNetSsl::SSLHandshakeException,
57
+ Java::OrgApacheHttpConn::HttpHostConnectException, Java::OrgApacheHttp::NoHttpResponseException,
58
+ Java::OrgApacheHttp::ConnectionClosedException => e
59
59
  ex = Manticore::ClientProtocolException
60
60
  rescue Java::JavaNet::UnknownHostException => e
61
61
  ex = Manticore::ResolutionFailure
62
62
  rescue Java::JavaLang::IllegalArgumentException => e
63
63
  ex = Manticore::InvalidArgumentException
64
64
  rescue Java::JavaLang::IllegalStateException => e
65
- if e.message.match(/Connection pool shut down/)
65
+ if (e.message || '').index('Connection pool shut down')
66
66
  ex = Manticore::ClientStoppedException
67
67
  else
68
68
  @exception = e
@@ -75,7 +75,7 @@ module Manticore
75
75
 
76
76
  # TODO: If calling async, execute_complete may fail and then silently swallow exceptions. How do we fix that?
77
77
  if ex || @exception
78
- @exception ||= ex.new(e.cause || e.message)
78
+ @exception ||= ex.new(e)
79
79
  @handlers[:failure].call @exception
80
80
  execute_complete
81
81
  nil
@@ -90,8 +90,8 @@ module Manticore
90
90
  # @return [String]
91
91
  def final_url
92
92
  call_once
93
- last_request = context.get_attribute ExecutionContext.HTTP_REQUEST
94
- last_host = context.get_attribute ExecutionContext.HTTP_TARGET_HOST
93
+ last_request = context.get_attribute ExecutionContext::HTTP_REQUEST
94
+ last_host = context.get_attribute ExecutionContext::HTTP_TARGET_HOST
95
95
  host = last_host.to_uri
96
96
  url = last_request.get_uri
97
97
  URI.join(host, url.to_s)
@@ -1,3 +1,3 @@
1
1
  module Manticore
2
- VERSION = "0.6.3"
2
+ VERSION = "0.8.0"
3
3
  end
data/lib/manticore.rb CHANGED
@@ -5,7 +5,11 @@ require "cgi"
5
5
  require_relative "./manticore_jars.rb"
6
6
  require_relative "./org/manticore/manticore-ext"
7
7
 
8
- org.manticore.Manticore.new.load(JRuby.runtime, false)
8
+ if defined? JRuby::Util.load_ext
9
+ JRuby::Util.load_ext 'org.manticore.Manticore'
10
+ else
11
+ org.manticore.Manticore.new.load(JRuby.runtime, false)
12
+ end
9
13
 
10
14
  require_relative "./manticore/version"
11
15
 
@@ -13,7 +17,27 @@ require_relative "./manticore/version"
13
17
  # with the beauty of Ruby.
14
18
  module Manticore
15
19
  # General base class for all Manticore exceptions
16
- class ManticoreException < StandardError; end
20
+ class ManticoreException < StandardError
21
+ def initialize(arg = nil)
22
+ case arg
23
+ when nil
24
+ @_cause = nil
25
+ super()
26
+ when java.lang.Throwable
27
+ @_cause = arg
28
+ super(arg.message)
29
+ else
30
+ @_cause = nil
31
+ super(arg)
32
+ end
33
+ end
34
+
35
+ # @return cause which is likely to be a Java exception
36
+ # @overload Exception#cause
37
+ def cause
38
+ @_cause || super
39
+ end
40
+ end
17
41
 
18
42
  # Exception thrown if you attempt to read from a closed Response stream
19
43
  class StreamClosedException < ManticoreException; end
@@ -1,8 +1,18 @@
1
1
  # this is a generated file, to avoid over-writing it just delete this comment
2
- require "jar_dependencies"
2
+ begin
3
+ require 'jar_dependencies'
4
+ rescue LoadError
5
+ require 'commons-logging/commons-logging/1.2/commons-logging-1.2.jar'
6
+ require 'commons-codec/commons-codec/1.15/commons-codec-1.15.jar'
7
+ require 'org/apache/httpcomponents/httpcore/4.4.14/httpcore-4.4.14.jar'
8
+ require 'org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar'
9
+ require 'org/apache/httpcomponents/httpmime/4.5.13/httpmime-4.5.13.jar'
10
+ end
3
11
 
4
- require_jar("commons-logging", "commons-logging", "1.2")
5
- require_jar("org.apache.httpcomponents", "httpmime", "4.5.2")
6
- require_jar("commons-codec", "commons-codec", "1.10")
7
- require_jar("org.apache.httpcomponents", "httpclient", "4.5.2")
8
- require_jar("org.apache.httpcomponents", "httpcore", "4.4.4")
12
+ if defined? Jars
13
+ require_jar 'commons-logging', 'commons-logging', '1.2'
14
+ require_jar 'commons-codec', 'commons-codec', '1.15'
15
+ require_jar 'org.apache.httpcomponents', 'httpcore', '4.4.14'
16
+ require_jar 'org.apache.httpcomponents', 'httpclient', '4.5.13'
17
+ require_jar 'org.apache.httpcomponents', 'httpmime', '4.5.13'
18
+ end
Binary file
data/manticore.gemspec CHANGED
@@ -19,19 +19,23 @@ Gem::Specification.new do |spec|
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.required_ruby_version = '>= 2.3' # JRuby >= 9.1
23
+
22
24
  private_key = File.expand_path("~/.gemcert/gem-private_key.pem")
23
25
  if File.exists? private_key
24
26
  spec.signing_key = private_key
25
27
  spec.cert_chain = ['gem-public_cert.pem']
26
28
  end
27
29
 
28
- spec.add_development_dependency "bundler", "~> 1.3"
30
+ spec.add_dependency "openssl_pkcs8_pure"
31
+
32
+ spec.add_development_dependency "bundler"
29
33
  spec.add_development_dependency "rake"
30
- spec.add_development_dependency "jar-dependencies"
34
+ spec.add_development_dependency "jar-dependencies", "~> 0.4.1"
31
35
 
32
- spec.requirements << "jar org.apache.httpcomponents:httpclient, '~> 4.5.0'"
33
- spec.requirements << "jar org.apache.httpcomponents:httpmime, '~> 4.5.0'"
36
+ spec.requirements << "jar org.apache.httpcomponents:httpclient, '~> 4.5.13'"
37
+ spec.requirements << "jar org.apache.httpcomponents:httpmime, '~> 4.5.13'"
34
38
  spec.requirements << "jar commons-logging:commons-logging, '~> 1.2'"
35
39
  spec.requirements << "jar commons-codec:commons-codec, '~> 1.9'"
36
- spec.requirements << "jar org.apache.httpcomponents:httpcore, '~> 4.4.4'"
40
+ spec.requirements << "jar org.apache.httpcomponents:httpcore, '~> 4.4.14'"
37
41
  end
@@ -130,7 +130,13 @@ describe Manticore::Client do
130
130
  let(:client) { Manticore::Client.new :ssl => {:verify => :strict} }
131
131
 
132
132
  it "breaks on SSL validation errors" do
133
- expect { client.get("https://localhost:55444/").call }.to raise_exception(Manticore::ClientProtocolException)
133
+ begin
134
+ client.get("https://localhost:55445/").body
135
+ rescue Manticore::ClientProtocolException => e
136
+ expect( e.cause ).to be_a javax.net.ssl.SSLHandshakeException
137
+ else
138
+ fail "exception not raised"
139
+ end
134
140
  end
135
141
  end
136
142
 
@@ -166,7 +172,7 @@ describe Manticore::Client do
166
172
  end
167
173
  end
168
174
 
169
- context "when client_cert and client_key are given" do
175
+ context "when client_cert and client_key are given as file paths" do
170
176
  let(:client) {
171
177
  Manticore::Client.new(
172
178
  :ssl => {
@@ -183,6 +189,40 @@ describe Manticore::Client do
183
189
  end
184
190
  end
185
191
 
192
+ context "when client_cert and client_key are given as OpenSSL::X509::Certificate" do
193
+ let(:client) {
194
+ Manticore::Client.new(
195
+ :ssl => {
196
+ verify: :strict,
197
+ ca_file: File.expand_path("../../ssl/root-ca.crt", __FILE__),
198
+ client_cert: OpenSSL::X509::Certificate.new(File.read(File.expand_path("../../ssl/client.crt", __FILE__))),
199
+ client_key: OpenSSL::PKey::RSA.new(File.read(File.expand_path("../../ssl/client.key", __FILE__))),
200
+ },
201
+ )
202
+ }
203
+
204
+ it "successfully auths requests" do
205
+ expect(client.get("https://localhost:55445/").body).to match("hello")
206
+ end
207
+ end
208
+
209
+ context "when client_cert and client_key are given as strings" do
210
+ let(:client) {
211
+ Manticore::Client.new(
212
+ :ssl => {
213
+ verify: :strict,
214
+ ca_file: File.expand_path("../../ssl/root-ca.crt", __FILE__),
215
+ client_cert: File.read(File.expand_path("../../ssl/client.crt", __FILE__)),
216
+ client_key: File.read(File.expand_path("../../ssl/client.key", __FILE__)),
217
+ },
218
+ )
219
+ }
220
+
221
+ it "successfully auths requests" do
222
+ expect(client.get("https://localhost:55445/").body).to match("hello")
223
+ end
224
+ end
225
+
186
226
  context "when off" do
187
227
  let(:client) { Manticore::Client.new :ssl => {:verify => :disable} }
188
228
 
@@ -193,6 +233,10 @@ describe Manticore::Client do
193
233
  it "does not break on expired SSL certificates" do
194
234
  expect { client.get("https://localhost:55446/").body }.to_not raise_exception
195
235
  end
236
+
237
+ it "does not break on untrusted certificates" do
238
+ expect { client.get("https://localhost:55447/").body }.to_not raise_exception
239
+ end
196
240
  end
197
241
 
198
242
  context "against a server that verifies clients" do
@@ -529,7 +573,7 @@ describe Manticore::Client do
529
573
  describe "#head" do
530
574
  it "works" do
531
575
  response = client.head(local_server)
532
- expect(JSON.load(response.body)).to be_nil
576
+ expect(response.body).to be_nil
533
577
  end
534
578
  end
535
579
 
@@ -730,11 +774,16 @@ describe Manticore::Client do
730
774
  ].join("\n"))
731
775
  client.close
732
776
  rescue IOError => e
777
+ break
733
778
  end
734
779
  end
735
780
  end
736
781
  end
737
782
 
783
+ after do
784
+ @server.kill
785
+ end
786
+
738
787
  let(:client) { Manticore::Client.new keepalive: true, pool_max: 1 }
739
788
 
740
789
  it "retries 3 times by default" do
@@ -791,7 +840,13 @@ describe Manticore::Client do
791
840
  let(:client) { Manticore::Client.new request_timeout: 1, connect_timeout: 1, socket_timeout: 1 }
792
841
 
793
842
  it "times out" do
794
- expect { client.get(local_server "/?sleep=2").body }.to raise_exception(Manticore::SocketTimeout)
843
+ begin
844
+ client.get(local_server "/?sleep=2").body
845
+ rescue Manticore::SocketTimeout => e
846
+ expect( e.cause ).to be_a java.net.SocketTimeoutException
847
+ else
848
+ fail "exception not raised"
849
+ end
795
850
  end
796
851
 
797
852
  it "times out when custom request options are passed" do
@@ -6,7 +6,7 @@ describe Manticore::Response do
6
6
 
7
7
  its(:headers) { is_expected.to be_a Hash }
8
8
  its(:body) { is_expected.to be_a String }
9
- its(:length) { is_expected.to be_a Fixnum }
9
+ its(:length) { is_expected.to be_a Integer }
10
10
 
11
11
  it "provides response header lookup via #[]" do
12
12
  expect(subject["Content-Type"]).to eq "application/json"
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  # encoding: utf-8
2
2
  require "rubygems"
3
3
  require "bundler/setup"
4
+ require "simplecov"
5
+
6
+ SimpleCov.start do
7
+ add_filter "spec/"
8
+ end
9
+
4
10
  require "manticore"
5
11
  require "zlib"
6
12
  require "json"
@@ -145,6 +151,7 @@ RSpec.configure do |c|
145
151
  start_ssl_server 55444
146
152
  start_ssl_server 55445, :SSLVerifyClient => OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT, :SSLCACertificateFile => File.expand_path("../ssl/root-ca.crt", __FILE__)
147
153
  start_ssl_server 55446, cert: File.expand_path("../ssl/host-expired.crt", __FILE__)
154
+ start_ssl_server 55447, cert: File.expand_path("../ssl/host-untrusted.crt", __FILE__), SSLCACertificateFile: File.expand_path("../ssl/root-untrusted-ca.crt", __FILE__)
148
155
 
149
156
  Manticore.disable_httpcomponents_logging!
150
157
  }
metadata CHANGED
@@ -1,36 +1,36 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manticore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.8.0
5
5
  platform: java
6
6
  authors:
7
7
  - Chris Heald
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-28 00:00:00.000000000 Z
11
+ date: 2022-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '1.3'
19
- name: bundler
18
+ version: '0'
19
+ name: openssl_pkcs8_pure
20
20
  prerelease: false
21
- type: :development
21
+ type: :runtime
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.3'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '0'
33
- name: rake
33
+ name: bundler
34
34
  prerelease: false
35
35
  type: :development
36
36
  version_requirements: !ruby/object:Gem::Requirement
@@ -44,7 +44,7 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: '0'
47
- name: jar-dependencies
47
+ name: rake
48
48
  prerelease: false
49
49
  type: :development
50
50
  version_requirements: !ruby/object:Gem::Requirement
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.4.1
61
+ name: jar-dependencies
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.4.1
55
69
  description: Manticore is an HTTP client built on the Apache HttpCore components
56
70
  email:
57
71
  - cheald@mashable.com
@@ -60,6 +74,7 @@ extensions: []
60
74
  extra_rdoc_files: []
61
75
  files:
62
76
  - ".gitignore"
77
+ - ".gitlab-ci.yml"
63
78
  - ".travis.yml"
64
79
  - APACHE-LICENSE-2.0.txt
65
80
  - CHANGELOG.md
@@ -71,7 +86,7 @@ files:
71
86
  - ext/manticore/org/manticore/HttpGetWithEntity.java
72
87
  - ext/manticore/org/manticore/Manticore.java
73
88
  - gem-public_cert.pem
74
- - lib/commons-codec/commons-codec/1.10/commons-codec-1.10.jar
89
+ - lib/commons-codec/commons-codec/1.15/commons-codec-1.15.jar
75
90
  - lib/commons-logging/commons-logging/1.2/commons-logging-1.2.jar
76
91
  - lib/faraday/adapter/manticore.rb
77
92
  - lib/manticore.rb
@@ -84,9 +99,9 @@ files:
84
99
  - lib/manticore/stubbed_response.rb
85
100
  - lib/manticore/version.rb
86
101
  - lib/manticore_jars.rb
87
- - lib/org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar
88
- - lib/org/apache/httpcomponents/httpcore/4.4.4/httpcore-4.4.4.jar
89
- - lib/org/apache/httpcomponents/httpmime/4.5.2/httpmime-4.5.2.jar
102
+ - lib/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar
103
+ - lib/org/apache/httpcomponents/httpcore/4.4.14/httpcore-4.4.14.jar
104
+ - lib/org/apache/httpcomponents/httpmime/4.5.13/httpmime-4.5.13.jar
90
105
  - lib/org/manticore/manticore-ext.jar
91
106
  - manticore.gemspec
92
107
  - spec/manticore/client_proxy_spec.rb
@@ -109,20 +124,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
124
  requirements:
110
125
  - - ">="
111
126
  - !ruby/object:Gem::Version
112
- version: '0'
127
+ version: '2.3'
113
128
  required_rubygems_version: !ruby/object:Gem::Requirement
114
129
  requirements:
115
130
  - - ">="
116
131
  - !ruby/object:Gem::Version
117
132
  version: '0'
118
133
  requirements:
119
- - jar org.apache.httpcomponents:httpclient, '~> 4.5.0'
120
- - jar org.apache.httpcomponents:httpmime, '~> 4.5.0'
134
+ - jar org.apache.httpcomponents:httpclient, '~> 4.5.13'
135
+ - jar org.apache.httpcomponents:httpmime, '~> 4.5.13'
121
136
  - jar commons-logging:commons-logging, '~> 1.2'
122
137
  - jar commons-codec:commons-codec, '~> 1.9'
123
- - jar org.apache.httpcomponents:httpcore, '~> 4.4.4'
124
- rubyforge_project:
125
- rubygems_version: 2.4.8
138
+ - jar org.apache.httpcomponents:httpcore, '~> 4.4.14'
139
+ rubygems_version: 3.1.6
126
140
  signing_key:
127
141
  specification_version: 4
128
142
  summary: Manticore is an HTTP client built on the Apache HttpCore components