manticore 0.4.2-java → 0.4.3-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 +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
|