manticore 0.4.2-java → 0.4.3-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +15 -2
- data/Gemfile +1 -1
- data/LICENSE.txt +0 -0
- data/README.md +3 -3
- data/Rakefile +0 -0
- data/ext/manticore/org/manticore/Manticore.java +0 -0
- data/lib/faraday/adapter/manticore.rb +11 -1
- data/lib/manticore/client.rb +58 -26
- data/lib/manticore/stubbed_response.rb +9 -5
- data/lib/manticore/version.rb +1 -1
- data/manticore.gemspec +0 -0
- data/spec/manticore/client_proxy_spec.rb +22 -22
- data/spec/manticore/client_spec.rb +152 -148
- data/spec/manticore/cookie_spec.rb +9 -9
- data/spec/manticore/facade_spec.rb +8 -8
- data/spec/manticore/response_spec.rb +16 -16
- data/spec/manticore/stubbed_response_spec.rb +20 -15
- metadata +12 -12
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e663f9b19e305371f23a33ca105cf960255b53a
|
4
|
+
data.tar.gz: 6c0dd62a760f11460cf565949632e8dbfa77d117
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0f65941a497dfa2254d4859bf8528cfc0b299f280a6564556aa3a9f08de4d634a1ef3f488ac467b12ace46a5637a793a65a63ffa290300551019f7b49fd0d1f
|
7
|
+
data.tar.gz: 3e5766be83ff90fc7bab9b5becdc5801156a1fe06ead3f3dd679ee686c8b9c1994ba12c04f7bb450f6758b9d21b21f7e67f41f979b083ce421feecf721b8880e
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,19 @@
|
|
1
|
+
## v0.5
|
2
|
+
|
3
|
+
### v0.5.0 (pending)
|
4
|
+
|
1
5
|
## v0.4
|
2
6
|
|
3
|
-
### v0.4.3
|
7
|
+
### v0.4.3
|
8
|
+
|
9
|
+
* Manticore no longer automatically retries all request types. Only non-idempotent requests will be automatically retried by default.
|
10
|
+
* added the `:retry_non_idempotent` [bool] option, which instructs Manticore to automatically retry all request types, rather than just idempotent request types
|
11
|
+
* .pfx files are automatically recognized as PKCS12 stores
|
12
|
+
* Improved StubbedResponse's mimicry of Response
|
13
|
+
* Minor improvments to the Faraday adapter
|
14
|
+
* Added an option for eager auth, which instructs Manticore to present basic auth credentials on initial request, rather than being challenged for them. You should
|
15
|
+
only use this if you have a specific need for it, as it may be a security concern otherwise.
|
16
|
+
* Manticore now cleans up the stale connection reaper thread at_exit. This may resolve memory leaks in servlet contexts.
|
4
17
|
|
5
18
|
### v0.4.2
|
6
19
|
|
@@ -10,7 +23,7 @@
|
|
10
23
|
|
11
24
|
### v0.4.1
|
12
25
|
|
13
|
-
* Add support for ssl[:ca_file]
|
26
|
+
* Add support for `ssl[:ca_file]`, `ssl[:client_cert]`, and `ssl[:client_key]`, to emulate OpenSSL features in other Ruby HTTP clients
|
14
27
|
* Integrate Faraday adapter for Manticore
|
15
28
|
|
16
29
|
### v0.4.0
|
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Documentation
|
22
22
|
|
23
|
-
Documentation is available [at rubydoc.info](http://rubydoc.info/github/cheald/manticore/master/
|
23
|
+
Documentation is available [at rubydoc.info](http://www.rubydoc.info/github/cheald/manticore/master/Manticore/Client).
|
24
24
|
|
25
25
|
## Performance
|
26
26
|
|
@@ -66,7 +66,7 @@ end
|
|
66
66
|
response_code = MyClient.get("http://www.google.com/").code
|
67
67
|
```
|
68
68
|
|
69
|
-
Mixing the client into a class will create a new
|
69
|
+
Mixing the client into a class will create a new pool. If you want to share a single pool between clients, specify the `shared_pool` option:
|
70
70
|
|
71
71
|
```ruby
|
72
72
|
class MyClient
|
@@ -111,7 +111,7 @@ end
|
|
111
111
|
|
112
112
|
You've seen "pools" mentioned a few times. Manticore creates and configures a [PoolingHttpClientConnectionManager](http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html)
|
113
113
|
which all requests are run through. The advantage here is that configuration and setup is performed once, and this lets clients take advantage of things like keepalive,
|
114
|
-
per-route concurrency limits, and other neat things. In general, you should create one `Manticore::Client` instance
|
114
|
+
per-route concurrency limits, and other neat things. In general, you should create one `Manticore::Client` instance per unique configuration needed. For example, you might have an app that performs 2 functions:
|
115
115
|
|
116
116
|
1. General HTTP requesting from the internet-at-large
|
117
117
|
2. Communication with a backend service over SSL, using a custom trust store
|
data/Rakefile
CHANGED
File without changes
|
File without changes
|
@@ -20,6 +20,11 @@ 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
|
+
|
23
28
|
def client(env)
|
24
29
|
@client ||= begin
|
25
30
|
opts = {}
|
@@ -30,6 +35,11 @@ module Faraday
|
|
30
35
|
opts[:ssl][:client_cert] = ssl[:client_cert]
|
31
36
|
opts[:ssl][:client_key] = ssl[:client_key]
|
32
37
|
end
|
38
|
+
conn_opts = @connection_options.dup
|
39
|
+
if conn_opts.key?(:ssl)
|
40
|
+
(opts[:ssl] ||= {}).merge! conn_opts.delete(:ssl)
|
41
|
+
end
|
42
|
+
opts.merge! conn_opts
|
33
43
|
::Manticore::Client.new(opts)
|
34
44
|
end
|
35
45
|
end
|
@@ -78,7 +88,7 @@ module Faraday
|
|
78
88
|
when ::Manticore::SocketException, ::Java::JavaUtilConcurrent::ExecutionException
|
79
89
|
raise ConnectionFailed, err
|
80
90
|
when ::Manticore::ClientProtocolException
|
81
|
-
raise Faraday::
|
91
|
+
raise Faraday::ClientError, err
|
82
92
|
else
|
83
93
|
raise err
|
84
94
|
end
|
data/lib/manticore/client.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'thread'
|
2
|
+
require 'singleton'
|
2
3
|
require 'base64'
|
3
4
|
|
4
5
|
module Manticore
|
@@ -15,6 +16,12 @@ module Manticore
|
|
15
16
|
# @option options [Integer] request_timeout Request-specific request timeout
|
16
17
|
# @option options [Integer] max_redirects Request-specific maximum redirect limit
|
17
18
|
# @option options [Boolean] follow_redirects Specify whether this request should follow redirects
|
19
|
+
# @option options [Hash] auth Specify authentication for the request
|
20
|
+
# @option options [String] auth[:user] Username to auth with
|
21
|
+
# @option options [String] auth[:password] Password to auth with
|
22
|
+
# @option options [Boolean] auth[:eager] Eagerly offer the Authorization header before the server challenges for it.
|
23
|
+
# You should not use this unless you know you specifically need it, as misuse
|
24
|
+
# of it can leak user credentials.
|
18
25
|
#
|
19
26
|
# @!macro [new] http_request_exceptions
|
20
27
|
# @raise [Manticore::Timeout] on socket, connection, or response timeout
|
@@ -62,6 +69,7 @@ module Manticore
|
|
62
69
|
include_package "org.apache.http.impl"
|
63
70
|
include_package "org.apache.http.impl.client"
|
64
71
|
include_package "org.apache.http.impl.conn"
|
72
|
+
include_package "org.apache.http.impl.auth"
|
65
73
|
include_package "org.apache.http.entity"
|
66
74
|
include_package "org.apache.http.message"
|
67
75
|
include_package "org.apache.http.params"
|
@@ -119,15 +127,15 @@ module Manticore
|
|
119
127
|
# @option options [integer] request_timeout (60) Sets the timeout for a given request. Raises Manticore::Timeout on failure.
|
120
128
|
# @option options [integer] max_redirects (5) Sets the maximum number of redirects to follow.
|
121
129
|
# @option options [integer] automatic_retries (3) Sets the number of times the client will automatically retry failed requests.
|
130
|
+
# @option options [boolean] retry_non_idempotent (false) If true, Manticore will automatically retry failed requests with non-idempotent verbs. Otherwise, it only automatically retries
|
131
|
+
# on GET, HEAD, PUT, DELETE, OPTIONS, and TRACE
|
122
132
|
# @option options [boolean] expect_continue (false) Enable support for HTTP 100
|
123
133
|
# @option options [boolean] stale_check (false) Enable support for stale connection checking. Adds overhead.
|
124
134
|
# @option options [String] proxy Proxy host in form: http://proxy.org:1234
|
125
135
|
# @option options [Hash] proxy Proxy host in form: {host: 'proxy.org'[, port: 80[, scheme: 'http'[, user: 'username@host', password: 'password']]]}
|
126
136
|
# @option options [Hash] proxy Proxy host in form: {url: 'http://proxy.org:1234'[, user: 'username@host', password: 'password']]]}
|
127
137
|
# @option options [URI] proxy Proxy host as a URI object
|
128
|
-
# @option options [Boolean
|
129
|
-
# then connections will be kept alive for this long when Connection: keep-alive
|
130
|
-
# is sent, but no Keep-Alive header is sent.
|
138
|
+
# @option options [Boolean] keepalive (true) Whether to allow connections to be reused. Defaults to true.
|
131
139
|
# @option options [Hash] ssl Hash of options for configuring SSL
|
132
140
|
# @option options [Array<String>] ssl[:protocols] (nil) A list of protocols that Manticore should accept
|
133
141
|
# @option options [Array<String>] ssl[:cipher_suites] (nil) A list of cipher suites that Manticore should accept
|
@@ -155,19 +163,7 @@ module Manticore
|
|
155
163
|
builder.disable_content_compression if options.fetch(:compression, true) == false
|
156
164
|
builder.set_proxy get_proxy_host(options[:proxy]) if options.key?(:proxy)
|
157
165
|
|
158
|
-
builder.set_retry_handler
|
159
|
-
if (executionCount > options.fetch(:automatic_retries, 3))
|
160
|
-
false
|
161
|
-
else
|
162
|
-
case exception
|
163
|
-
when Java::OrgApacheHttp::NoHttpResponseException, Java::JavaNet::SocketException
|
164
|
-
context.setAttribute "retryCount", executionCount
|
165
|
-
true
|
166
|
-
else
|
167
|
-
false
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
166
|
+
builder.set_retry_handler LoggingStandardRetryHandler.new options.fetch(:automatic_retries, 3), options.fetch(:retry_non_idempotent, false)
|
171
167
|
|
172
168
|
# http://hc.apache.org/httpcomponents-client-ga/tutorial/html/advanced.html#stateful_conn
|
173
169
|
# By default this is used to prevent different contexts from accessing SSL data
|
@@ -362,13 +358,7 @@ module Manticore
|
|
362
358
|
cm = pool_builder options
|
363
359
|
cm.set_default_max_per_route options.fetch(:pool_max_per_route, @max_pool_size)
|
364
360
|
cm.set_max_total @max_pool_size
|
365
|
-
|
366
|
-
Thread.new {
|
367
|
-
loop {
|
368
|
-
cm.closeExpiredConnections
|
369
|
-
sleep 5000
|
370
|
-
}
|
371
|
-
}
|
361
|
+
IdleConnectionReaper.instance.monitor(cm)
|
372
362
|
cm
|
373
363
|
end
|
374
364
|
end
|
@@ -468,7 +458,7 @@ module Manticore
|
|
468
458
|
|
469
459
|
context = HttpClientContext.new
|
470
460
|
proxy_user = req_options[:proxy].is_a?(Hash) && (req_options[:proxy][:user] || req_options[:proxy][:username])
|
471
|
-
auth_from_options(req_options, context) if req_options.key?(:auth) || proxy_user
|
461
|
+
auth_from_options(req, req_options, context) if req_options.key?(:auth) || proxy_user
|
472
462
|
|
473
463
|
if @use_cookies == :per_request
|
474
464
|
store = BasicCookieStore.new
|
@@ -501,7 +491,7 @@ module Manticore
|
|
501
491
|
end
|
502
492
|
end
|
503
493
|
|
504
|
-
def auth_from_options(options, context)
|
494
|
+
def auth_from_options(req, options, context)
|
505
495
|
proxy = options.fetch(:proxy, {})
|
506
496
|
if options[:auth] || proxy[:user] || proxy[:username]
|
507
497
|
provider = BasicCredentialsProvider.new
|
@@ -509,6 +499,16 @@ module Manticore
|
|
509
499
|
username = options[:auth][:user] || options[:auth][:username]
|
510
500
|
password = options[:auth][:pass] || options[:auth][:password]
|
511
501
|
provider.set_credentials AuthScope::ANY, UsernamePasswordCredentials.new(username, password)
|
502
|
+
|
503
|
+
if options[:auth][:eager]
|
504
|
+
uri = URI.parse req.uri.to_string
|
505
|
+
target = HttpHost.new(uri.host, uri.port, uri.scheme)
|
506
|
+
scheme = BasicScheme.new
|
507
|
+
|
508
|
+
cache = BasicAuthCache.new
|
509
|
+
cache.put target, scheme
|
510
|
+
context.set_auth_cache cache
|
511
|
+
end
|
512
512
|
end
|
513
513
|
|
514
514
|
if proxy[:user] || proxy[:username]
|
@@ -634,11 +634,43 @@ module Manticore
|
|
634
634
|
end
|
635
635
|
|
636
636
|
def guess_store_type(filename)
|
637
|
-
if filename.end_with?(".p12")
|
637
|
+
if filename.end_with?(".p12") || filename.end_with?(".pfx")
|
638
638
|
"pkcs12"
|
639
639
|
else
|
640
640
|
KeyStore.get_default_type
|
641
641
|
end
|
642
642
|
end
|
643
643
|
end
|
644
|
+
|
645
|
+
class LoggingStandardRetryHandler < Java::OrgApacheHttpImplClient::StandardHttpRequestRetryHandler
|
646
|
+
def retryRequest(exception, executionCount, context)
|
647
|
+
context.setAttribute "retryCount", executionCount
|
648
|
+
super(exception, executionCount, context)
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
class IdleConnectionReaper
|
653
|
+
include Singleton
|
654
|
+
def initialize
|
655
|
+
@mutex = Mutex.new
|
656
|
+
@pools = []
|
657
|
+
@running = Java::JavaUtilConcurrentAtomic::AtomicBoolean.new(true)
|
658
|
+
@thread = Thread.new do
|
659
|
+
while @running.get
|
660
|
+
@mutex.synchronize { @pools.each(&:closeExpiredConnections) }
|
661
|
+
sleep 5000
|
662
|
+
end
|
663
|
+
end
|
664
|
+
at_exit { shutdown }
|
665
|
+
end
|
666
|
+
|
667
|
+
def monitor(pool)
|
668
|
+
@mutex.synchronize { @pools << pool }
|
669
|
+
end
|
670
|
+
|
671
|
+
def shutdown
|
672
|
+
@running.set(false)
|
673
|
+
@thread.wakeup
|
674
|
+
end
|
675
|
+
end
|
644
676
|
end
|
@@ -40,7 +40,7 @@ module Manticore
|
|
40
40
|
|
41
41
|
stubs[:headers] ||= {}
|
42
42
|
stubs[:headers] = Hash[*stubs[:headers].flat_map {|k, v| [k.downcase, v] }]
|
43
|
-
stubs[:headers]["content-length"] = stubs[:body].length if stubs.key?(:body)
|
43
|
+
stubs[:headers]["content-length"] = stubs[:body].length.to_s if stubs.key?(:body)
|
44
44
|
@stubs = stubs
|
45
45
|
|
46
46
|
self
|
@@ -57,13 +57,17 @@ module Manticore
|
|
57
57
|
# @return [String] The final URL
|
58
58
|
def final_url
|
59
59
|
call_once
|
60
|
-
@headers["location"]
|
60
|
+
@headers["location"] || @request.getURI.to_string
|
61
61
|
end
|
62
62
|
|
63
63
|
# Returns the stubbed body of this response.
|
64
|
-
def body
|
64
|
+
def body(&block)
|
65
65
|
call_once
|
66
|
-
|
66
|
+
if block_given?
|
67
|
+
yield body
|
68
|
+
else
|
69
|
+
@body
|
70
|
+
end
|
67
71
|
end
|
68
72
|
alias_method :read_body, :body
|
69
73
|
|
@@ -87,7 +91,7 @@ module Manticore
|
|
87
91
|
@cookies[c.name] ||= []
|
88
92
|
@cookies[c.name] << c
|
89
93
|
end
|
90
|
-
@handlers[:success].call(self)
|
94
|
+
@callback_result = @handlers[:success].call(self)
|
91
95
|
self
|
92
96
|
end
|
93
97
|
|
data/lib/manticore/version.rb
CHANGED
data/manticore.gemspec
CHANGED
File without changes
|
@@ -4,38 +4,38 @@ describe Manticore::Client do
|
|
4
4
|
|
5
5
|
describe Manticore::Client::StubProxy do
|
6
6
|
describe "#respond_with" do
|
7
|
-
it "
|
7
|
+
it "responds with a stubbed response" do
|
8
8
|
client.respond_with(body: "body", code: 200).get(local_server).on_success do |response|
|
9
|
-
response.
|
10
|
-
response.body.
|
11
|
-
response.code.
|
9
|
+
expect(response).to be_a Manticore::StubbedResponse
|
10
|
+
expect(response.body).to eq "body"
|
11
|
+
expect(response.code).to eq 200
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
context "for synchronous requests" do
|
16
|
-
it "
|
16
|
+
it "responds only stub the next subsequent response" do
|
17
17
|
stub = client.respond_with(body: "body", code: 200)
|
18
18
|
|
19
19
|
stub.get(local_server) do |response|
|
20
|
-
response.
|
20
|
+
expect(response).to be_a Manticore::StubbedResponse
|
21
21
|
end
|
22
22
|
|
23
23
|
stub.get(local_server) do |response|
|
24
|
-
response.
|
24
|
+
expect(response).to be_a Manticore::Response
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
context "for synchronous requests" do
|
30
|
-
it "
|
30
|
+
it "responds only stub the next subsequent response" do
|
31
31
|
stub = client.respond_with(body: "body", code: 200)
|
32
32
|
|
33
33
|
stub.async.get(local_server).on_success do |response|
|
34
|
-
response.
|
34
|
+
expect(response).to be_a Manticore::StubbedResponse
|
35
35
|
end
|
36
36
|
|
37
37
|
stub.async.get(local_server).on_success do |response|
|
38
|
-
response.
|
38
|
+
expect(response).to be_a Manticore::Response
|
39
39
|
end
|
40
40
|
|
41
41
|
client.execute!
|
@@ -45,17 +45,17 @@ describe Manticore::Client do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
describe Manticore::Client::AsyncProxy do
|
48
|
-
it "
|
48
|
+
it "does not make a request until execute is called" do
|
49
49
|
anchor = Time.now.to_f
|
50
50
|
client.async.get("http://localhost:55441/?sleep=1.6")
|
51
|
-
(Time.now.to_f - anchor).
|
51
|
+
expect(Time.now.to_f - anchor).to be < 1.0
|
52
52
|
|
53
53
|
anchor = Time.now.to_f
|
54
54
|
client.execute!
|
55
|
-
(Time.now.to_f - anchor).
|
55
|
+
expect(Time.now.to_f - anchor).to be > 1.0
|
56
56
|
end
|
57
57
|
|
58
|
-
it "
|
58
|
+
it "returns the response object, which may then have handlers attached" do
|
59
59
|
response = client.async.get("http://localhost:55441/")
|
60
60
|
success = false
|
61
61
|
response.on_success do
|
@@ -63,29 +63,29 @@ describe Manticore::Client do
|
|
63
63
|
end
|
64
64
|
|
65
65
|
client.execute!
|
66
|
-
success.
|
66
|
+
expect(success).to eq true
|
67
67
|
end
|
68
68
|
|
69
69
|
it "can chain handlers" do
|
70
70
|
client.async.get("http://localhost:55441/").on_success {|r| r.code }
|
71
|
-
client.execute!.map(&:callback_result).
|
71
|
+
expect(client.execute!.map(&:callback_result)).to eq [200]
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
75
|
describe Manticore::Client::BackgroundProxy do
|
76
|
-
it "
|
76
|
+
it "does not block execution" do
|
77
77
|
anchor = Time.now.to_f
|
78
78
|
future = client.background.get("http://localhost:55441/?sleep=1.5")
|
79
|
-
(Time.now.to_f - anchor).
|
79
|
+
expect(Time.now.to_f - anchor).to be < 1.0
|
80
80
|
|
81
81
|
response = future.get
|
82
|
-
(Time.now.to_f - anchor).
|
83
|
-
response.body.
|
82
|
+
expect(Time.now.to_f - anchor).to be > 1.0
|
83
|
+
expect(response.body).to match(/sleep=1.5/)
|
84
84
|
end
|
85
85
|
|
86
|
-
it "
|
86
|
+
it "returns a future" do
|
87
87
|
response = client.background.get("http://localhost:55441/")
|
88
|
-
response.
|
88
|
+
expect(response).to be_a Java::JavaUtilConcurrent::FutureTask
|
89
89
|
response.get
|
90
90
|
end
|
91
91
|
end
|