manticore 0.6.0-java → 0.7.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 +5 -5
- data/.gitlab-ci.yml +42 -0
- data/.travis.yml +8 -10
- data/CHANGELOG.md +18 -1
- data/Gemfile +4 -2
- data/README.md +3 -1
- data/Rakefile +14 -12
- data/ext/manticore/org/manticore/Manticore.java +13 -4
- data/lib/faraday/adapter/manticore.rb +11 -15
- data/lib/manticore.rb +10 -10
- data/lib/manticore/client.rb +102 -76
- data/lib/manticore/client/proxies.rb +3 -1
- data/lib/manticore/cookie.rb +12 -12
- data/lib/manticore/facade.rb +2 -2
- data/lib/manticore/java_extensions.rb +1 -1
- data/lib/manticore/response.rb +48 -30
- data/lib/manticore/stubbed_response.rb +6 -5
- data/lib/manticore/version.rb +1 -1
- data/lib/manticore_jars.rb +6 -6
- data/lib/org/manticore/manticore-ext.jar +0 -0
- data/manticore.gemspec +4 -2
- data/spec/manticore/client_proxy_spec.rb +5 -4
- data/spec/manticore/client_spec.rb +177 -69
- data/spec/manticore/cookie_spec.rb +9 -10
- data/spec/manticore/facade_spec.rb +6 -6
- data/spec/manticore/response_spec.rb +22 -11
- data/spec/manticore/stubbed_response_spec.rb +5 -5
- data/spec/spec_helper.rb +51 -28
- metadata +28 -14
@@ -9,6 +9,7 @@ module Manticore
|
|
9
9
|
def async
|
10
10
|
AsyncProxy.new(self)
|
11
11
|
end
|
12
|
+
|
12
13
|
alias_method :parallel, :async
|
13
14
|
alias_method :batch, :async
|
14
15
|
|
@@ -20,6 +21,7 @@ module Manticore
|
|
20
21
|
|
21
22
|
class BaseProxy
|
22
23
|
include ProxiesInterface
|
24
|
+
|
23
25
|
def initialize(client)
|
24
26
|
@client = client
|
25
27
|
end
|
@@ -55,4 +57,4 @@ module Manticore
|
|
55
57
|
end
|
56
58
|
end
|
57
59
|
end
|
58
|
-
end
|
60
|
+
end
|
data/lib/manticore/cookie.rb
CHANGED
@@ -36,7 +36,7 @@ module Manticore
|
|
36
36
|
value: cookie.get_value,
|
37
37
|
secure: cookie.is_secure,
|
38
38
|
persistent: cookie.is_persistent,
|
39
|
-
spec_version: cookie.get_version
|
39
|
+
spec_version: cookie.get_version,
|
40
40
|
)
|
41
41
|
end
|
42
42
|
|
@@ -63,16 +63,16 @@ module Manticore
|
|
63
63
|
attr_reader :comment, :comment_url, :domain, :expires, :name, :path, :ports, :value, :spec_version
|
64
64
|
|
65
65
|
def initialize(args)
|
66
|
-
@comment
|
67
|
-
@comment_url
|
68
|
-
@domain
|
69
|
-
@expires
|
70
|
-
@name
|
71
|
-
@path
|
72
|
-
@ports
|
73
|
-
@value
|
74
|
-
@secure
|
75
|
-
@persistent
|
66
|
+
@comment = args.fetch(:comment, nil)
|
67
|
+
@comment_url = args.fetch(:comment_url, nil)
|
68
|
+
@domain = args.fetch(:domain, nil)
|
69
|
+
@expires = args.fetch(:expires, nil)
|
70
|
+
@name = args.fetch(:name, nil)
|
71
|
+
@path = args.fetch(:path, nil)
|
72
|
+
@ports = args.fetch(:ports, nil)
|
73
|
+
@value = args.fetch(:value, nil)
|
74
|
+
@secure = args.fetch(:secure, nil)
|
75
|
+
@persistent = args.fetch(:persistent, nil)
|
76
76
|
@spec_version = args.fetch(:spec_version, nil)
|
77
77
|
end
|
78
78
|
|
@@ -104,4 +104,4 @@ module Manticore
|
|
104
104
|
!@persistent
|
105
105
|
end
|
106
106
|
end
|
107
|
-
end
|
107
|
+
end
|
data/lib/manticore/facade.rb
CHANGED
@@ -4,7 +4,7 @@ class Java::OrgApacheHttpClientMethods::HttpRequestBase
|
|
4
4
|
|
5
5
|
# Provides an easy way to get the request headers from any request
|
6
6
|
def headers
|
7
|
-
Hash[*get_all_headers.flat_map {|h| [h.name, h.value] }]
|
7
|
+
Hash[*get_all_headers.flat_map { |h| [h.name, h.value] }]
|
8
8
|
end
|
9
9
|
|
10
10
|
# Get a single request header
|
data/lib/manticore/response.rb
CHANGED
@@ -3,7 +3,7 @@ module Manticore
|
|
3
3
|
# as a Ruby proxy for HTTPClient responses.
|
4
4
|
#
|
5
5
|
# @!attribute [r] headers
|
6
|
-
# @return [Hash] Headers from this response
|
6
|
+
# @return [Hash] Headers from this response. If a header is given more than once in a response, the value is an array of values. Otherwise, it is the header value.
|
7
7
|
# @!attribute [r] code
|
8
8
|
# @return [Integer] Response code from this response
|
9
9
|
# @!attribute [r] context
|
@@ -15,7 +15,7 @@ module Manticore
|
|
15
15
|
include_package "org.apache.http.util"
|
16
16
|
include_package "org.apache.http.protocol"
|
17
17
|
java_import "org.apache.http.client.protocol.HttpClientContext"
|
18
|
-
java_import
|
18
|
+
java_import "java.util.concurrent.Callable"
|
19
19
|
|
20
20
|
include ResponseHandler
|
21
21
|
include Callable
|
@@ -29,14 +29,14 @@ module Manticore
|
|
29
29
|
# @param request [HttpRequestBase] The underlying request object
|
30
30
|
# @param context [HttpContext] The underlying HttpContext
|
31
31
|
def initialize(client, request, context, &block)
|
32
|
-
@client
|
32
|
+
@client = client
|
33
33
|
@request = request
|
34
34
|
@context = context
|
35
35
|
@handlers = {
|
36
|
-
success:
|
37
|
-
failure:
|
38
|
-
cancelled: Proc.new {},
|
39
|
-
complete:
|
36
|
+
success: block || Proc.new { |resp| resp.body },
|
37
|
+
failure: Proc.new { |ex| raise ex },
|
38
|
+
cancelled: Proc.new { },
|
39
|
+
complete: [],
|
40
40
|
}
|
41
41
|
end
|
42
42
|
|
@@ -91,9 +91,9 @@ module Manticore
|
|
91
91
|
def final_url
|
92
92
|
call_once
|
93
93
|
last_request = context.get_attribute ExecutionContext.HTTP_REQUEST
|
94
|
-
last_host
|
95
|
-
host
|
96
|
-
url
|
94
|
+
last_host = context.get_attribute ExecutionContext.HTTP_TARGET_HOST
|
95
|
+
host = last_host.to_uri
|
96
|
+
url = last_request.get_uri
|
97
97
|
URI.join(host, url.to_s)
|
98
98
|
end
|
99
99
|
|
@@ -115,15 +115,16 @@ module Manticore
|
|
115
115
|
def body(&block)
|
116
116
|
call_once
|
117
117
|
@body ||= begin
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
118
|
+
if entity = @response.get_entity
|
119
|
+
EntityConverter.new.read_entity(entity, &block)
|
120
|
+
end
|
121
|
+
rescue Java::JavaIo::IOException, Java::JavaNet::SocketException, IOError => e
|
122
|
+
raise StreamClosedException.new("Could not read from stream: #{e.message}")
|
123
|
+
# ensure
|
124
|
+
# @request.release_connection
|
125
|
+
end
|
126
126
|
end
|
127
|
+
|
127
128
|
alias_method :read_body, :body
|
128
129
|
|
129
130
|
# Returns true if this response has been called (requested and populated) yet
|
@@ -140,10 +141,14 @@ module Manticore
|
|
140
141
|
end
|
141
142
|
|
142
143
|
# Return the value of a single response header. Will call the request if it has not been called yet.
|
144
|
+
# If the header was returned with multiple values, will only return the first value. If you need to get
|
145
|
+
# multiple values, use response#headers[lowercase_key]
|
143
146
|
#
|
144
|
-
# @
|
147
|
+
# @param key [String] Case-insensitive header key
|
148
|
+
# @return [String] Value of the header, or nil if not present
|
145
149
|
def [](key)
|
146
|
-
headers[key.downcase]
|
150
|
+
v = headers[key.downcase]
|
151
|
+
v.is_a?(Array) ? v.first : v
|
147
152
|
end
|
148
153
|
|
149
154
|
# Return the response code from this request as an integer. Will call the request if it has not been called yet.
|
@@ -192,6 +197,7 @@ module Manticore
|
|
192
197
|
@handlers[:success] = block
|
193
198
|
self
|
194
199
|
end
|
200
|
+
|
195
201
|
alias_method :success, :on_success
|
196
202
|
|
197
203
|
# Set handler for failure responses
|
@@ -202,8 +208,9 @@ module Manticore
|
|
202
208
|
@handlers[:failure] = block
|
203
209
|
self
|
204
210
|
end
|
211
|
+
|
205
212
|
alias_method :failure, :on_failure
|
206
|
-
alias_method :fail,
|
213
|
+
alias_method :fail, :on_failure
|
207
214
|
|
208
215
|
# Set handler for cancelled requests. NB: Not actually used right now?
|
209
216
|
# @param block Proc which will be invoked on a on a cancelled response.
|
@@ -213,8 +220,9 @@ module Manticore
|
|
213
220
|
@handlers[:cancelled] = block
|
214
221
|
self
|
215
222
|
end
|
216
|
-
|
217
|
-
alias_method :
|
223
|
+
|
224
|
+
alias_method :cancelled, :on_cancelled
|
225
|
+
alias_method :cancellation, :on_cancelled
|
218
226
|
alias_method :on_cancellation, :on_cancelled
|
219
227
|
|
220
228
|
# Set handler for completed requests
|
@@ -225,8 +233,9 @@ module Manticore
|
|
225
233
|
@handlers[:complete] = Array(@handlers[:complete]).compact + [block]
|
226
234
|
self
|
227
235
|
end
|
228
|
-
|
229
|
-
alias_method :
|
236
|
+
|
237
|
+
alias_method :complete, :on_complete
|
238
|
+
alias_method :completed, :on_complete
|
230
239
|
alias_method :on_completed, :on_complete
|
231
240
|
|
232
241
|
def times_retried
|
@@ -243,10 +252,19 @@ module Manticore
|
|
243
252
|
# Implementation of {http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/ResponseHandler.html#handleResponse(org.apache.http.HttpResponse) ResponseHandler#handleResponse}
|
244
253
|
# @param response [Response] The underlying Java Response object
|
245
254
|
def handleResponse(response)
|
246
|
-
@response
|
247
|
-
@code
|
248
|
-
@message
|
249
|
-
@headers
|
255
|
+
@response = response
|
256
|
+
@code = response.get_status_line.get_status_code
|
257
|
+
@message = response.get_status_line.get_reason_phrase
|
258
|
+
@headers = response.get_all_headers.each_with_object({}) do |h, o|
|
259
|
+
key = h.get_name.downcase
|
260
|
+
if o.key?(key)
|
261
|
+
o[key] = Array(o[key]) unless o[key].is_a?(Array)
|
262
|
+
o[key].push h.get_value
|
263
|
+
else
|
264
|
+
o[key] = h.get_value
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
250
268
|
@callback_result = @handlers[:success].call(self)
|
251
269
|
nil
|
252
270
|
end
|
@@ -261,7 +279,7 @@ module Manticore
|
|
261
279
|
end
|
262
280
|
|
263
281
|
def execute_complete
|
264
|
-
@handlers[:complete].each {|h| h.call(self) }
|
282
|
+
@handlers[:complete].each { |h| h.call(self) }
|
265
283
|
end
|
266
284
|
end
|
267
285
|
end
|
@@ -33,12 +33,12 @@ module Manticore
|
|
33
33
|
# @return [Manticore::StubbedResponse] self
|
34
34
|
def stub(stubs)
|
35
35
|
if stubs.key? :cookies
|
36
|
-
stubs[:cookies].keys.each {|key| stubs[:cookies][key] = Array(stubs[:cookies][key]) }
|
36
|
+
stubs[:cookies].keys.each { |key| stubs[:cookies][key] = Array(stubs[:cookies][key]) }
|
37
37
|
end
|
38
38
|
stubs[:code] ||= 200
|
39
39
|
|
40
40
|
stubs[:headers] ||= {}
|
41
|
-
stubs[:headers] = Hash[*stubs[:headers].flat_map {|k, v| [k.downcase, v] }]
|
41
|
+
stubs[:headers] = Hash[*stubs[:headers].flat_map { |k, v| [k.downcase, v] }]
|
42
42
|
stubs[:headers]["content-length"] ||= stubs[:body].length.to_s if stubs.key?(:body)
|
43
43
|
|
44
44
|
@stubs = stubs
|
@@ -69,6 +69,7 @@ module Manticore
|
|
69
69
|
@body
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
72
73
|
alias_method :read_body, :body
|
73
74
|
|
74
75
|
# Returns the stubbed cookies of this response. This is the union of cookies from the `:cookies`
|
@@ -82,8 +83,8 @@ module Manticore
|
|
82
83
|
|
83
84
|
def handleResponse(response)
|
84
85
|
raise response[:raises] if response.key?(:raises)
|
85
|
-
@body
|
86
|
-
@code
|
86
|
+
@body = response[:body]
|
87
|
+
@code = response[:code]
|
87
88
|
@headers = response[:headers]
|
88
89
|
@cookies = response[:cookies]
|
89
90
|
Array(@headers["set-cookie"]).each do |cookie|
|
@@ -99,4 +100,4 @@ module Manticore
|
|
99
100
|
call unless @called
|
100
101
|
end
|
101
102
|
end
|
102
|
-
end
|
103
|
+
end
|
data/lib/manticore/version.rb
CHANGED
data/lib/manticore_jars.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# this is a generated file, to avoid over-writing it just delete this comment
|
2
|
-
require
|
2
|
+
require "jar_dependencies"
|
3
3
|
|
4
|
-
require_jar(
|
5
|
-
require_jar(
|
6
|
-
require_jar(
|
7
|
-
require_jar(
|
8
|
-
require_jar(
|
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")
|
Binary file
|
data/manticore.gemspec
CHANGED
@@ -25,9 +25,11 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.cert_chain = ['gem-public_cert.pem']
|
26
26
|
end
|
27
27
|
|
28
|
-
spec.
|
28
|
+
spec.add_dependency "openssl_pkcs8_pure"
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler"
|
29
31
|
spec.add_development_dependency "rake"
|
30
|
-
spec.add_development_dependency "jar-dependencies"
|
32
|
+
spec.add_development_dependency "jar-dependencies", "~> 0.4.1"
|
31
33
|
|
32
34
|
spec.requirements << "jar org.apache.httpcomponents:httpclient, '~> 4.5.0'"
|
33
35
|
spec.requirements << "jar org.apache.httpcomponents:httpmime, '~> 4.5.0'"
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
2
3
|
describe Manticore::Client do
|
3
4
|
let(:client) { Manticore::Client.new }
|
4
5
|
|
@@ -29,7 +30,7 @@ describe Manticore::Client do
|
|
29
30
|
stub.async.get(local_server)
|
30
31
|
stub.async.get(local_server)
|
31
32
|
|
32
|
-
expect(
|
33
|
+
expect(client.execute!.map(&:class)).to eq [Manticore::StubbedResponse, Manticore::StubbedResponse]
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -58,7 +59,7 @@ describe Manticore::Client do
|
|
58
59
|
end
|
59
60
|
|
60
61
|
it "can chain handlers" do
|
61
|
-
client.async.get("http://localhost:55441/").on_success {|r| r.code }
|
62
|
+
client.async.get("http://localhost:55441/").on_success { |r| r.code }
|
62
63
|
expect(client.execute!.map(&:callback_result)).to eq [200]
|
63
64
|
end
|
64
65
|
end
|
@@ -95,4 +96,4 @@ describe Manticore::Client do
|
|
95
96
|
end
|
96
97
|
end
|
97
98
|
end
|
98
|
-
end
|
99
|
+
end
|
@@ -1,11 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
2
|
+
require "spec_helper"
|
3
3
|
|
4
|
-
java_import
|
5
|
-
java_import
|
4
|
+
java_import "org.apache.http.entity.mime.MultipartEntityBuilder"
|
5
|
+
java_import "org.apache.http.entity.ContentType"
|
6
6
|
|
7
7
|
describe Manticore::Client do
|
8
|
-
|
9
8
|
let(:client) { Manticore::Client.new }
|
10
9
|
|
11
10
|
it "fetches a URL and return a response" do
|
@@ -24,6 +23,12 @@ describe Manticore::Client do
|
|
24
23
|
expect(json["headers"]["X-Custom-Header"]).to eq "Blaznotts"
|
25
24
|
end
|
26
25
|
|
26
|
+
it "accepts repeated header values" do
|
27
|
+
response = client.get(local_server, headers: {"X-Custom-Header" => ["Whizzles", "Blaznotts"]})
|
28
|
+
json = JSON.load(response.body)
|
29
|
+
expect(json["headers"]["X-Custom-Header"].sort).to eq ["Blaznotts", "Whizzles"]
|
30
|
+
end
|
31
|
+
|
27
32
|
it "enables compression" do
|
28
33
|
response = client.get(local_server)
|
29
34
|
json = JSON.load(response.body)
|
@@ -46,6 +51,39 @@ describe Manticore::Client do
|
|
46
51
|
expect(j["uri"]["port"]).to eq 55441
|
47
52
|
end
|
48
53
|
|
54
|
+
it "automatically decodes application/JSON as UTF-8" do
|
55
|
+
j = JSON.parse client.get(local_server("/json_utf8")).body
|
56
|
+
expect(j["last_name"]).to eq "Töger"
|
57
|
+
end
|
58
|
+
|
59
|
+
context "via an authenticated proxy" do
|
60
|
+
let(:proxy) { "http://localhost:55442" }
|
61
|
+
let(:auth) { nil }
|
62
|
+
let(:j) { JSON.parse req.body }
|
63
|
+
|
64
|
+
context "with authentication as a hash" do
|
65
|
+
let(:auth) { {user: "user", pass: "pass"} }
|
66
|
+
let(:req) { client.get(local_server("/authproxy"), proxy: proxy, auth: auth) }
|
67
|
+
|
68
|
+
it "proxies" do
|
69
|
+
expect(j["server_port"]).to eq 55442
|
70
|
+
expect(j["uri"]["port"]).to eq 55441
|
71
|
+
expect(j["headers"]["Proxy-Authorization"]).to eq "Basic dXNlcjpwYXNz"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "with authentication as a string" do
|
76
|
+
let(:proxy) { "http://user:pass@localhost:55442" }
|
77
|
+
let(:req) { client.get(local_server("/authproxy"), proxy: proxy) }
|
78
|
+
|
79
|
+
it "proxies" do
|
80
|
+
expect(j["server_port"]).to eq 55442
|
81
|
+
expect(j["uri"]["port"]).to eq 55441
|
82
|
+
expect(j["headers"]["Proxy-Authorization"]).to eq "Basic dXNlcjpwYXNz"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
49
87
|
describe "with a custom user agent" do
|
50
88
|
let(:client) { Manticore::Client.new user_agent: "test-agent/1.0" }
|
51
89
|
|
@@ -74,17 +112,21 @@ describe Manticore::Client do
|
|
74
112
|
end
|
75
113
|
end
|
76
114
|
|
77
|
-
describe
|
78
|
-
describe
|
79
|
-
context
|
115
|
+
describe "ssl settings" do
|
116
|
+
describe "verify" do
|
117
|
+
context "default" do
|
80
118
|
let(:client) { Manticore::Client.new }
|
81
119
|
|
82
120
|
it "breaks on SSL validation errors" do
|
83
121
|
expect { client.get("https://localhost:55444/").call }.to raise_exception(Manticore::ClientProtocolException)
|
84
122
|
end
|
123
|
+
|
124
|
+
it "breaks on SSL expiry errors" do
|
125
|
+
expect { client.get("https://localhost:55446/").call }.to raise_exception(Manticore::ClientProtocolException)
|
126
|
+
end
|
85
127
|
end
|
86
128
|
|
87
|
-
context
|
129
|
+
context "when on and no trust store is given" do
|
88
130
|
let(:client) { Manticore::Client.new :ssl => {:verify => :strict} }
|
89
131
|
|
90
132
|
it "breaks on SSL validation errors" do
|
@@ -92,7 +134,7 @@ describe Manticore::Client do
|
|
92
134
|
end
|
93
135
|
end
|
94
136
|
|
95
|
-
context
|
137
|
+
context "when on and custom trust store is given" do
|
96
138
|
let(:client) { Manticore::Client.new :ssl => {verify: :strict, truststore: File.expand_path("../../ssl/truststore.jks", __FILE__), truststore_password: "test123"} }
|
97
139
|
|
98
140
|
it "verifies the request and succeed" do
|
@@ -108,7 +150,7 @@ describe Manticore::Client do
|
|
108
150
|
end
|
109
151
|
end
|
110
152
|
|
111
|
-
context
|
153
|
+
context "when on and custom trust store is given with the wrong password" do
|
112
154
|
let(:client) { Manticore::Client.new :ssl => {verify: :strict, truststore: File.expand_path("../../ssl/truststore.jks", __FILE__), truststore_password: "wrongpass"} }
|
113
155
|
|
114
156
|
it "fails to load the keystore" do
|
@@ -116,22 +158,58 @@ describe Manticore::Client do
|
|
116
158
|
end
|
117
159
|
end
|
118
160
|
|
119
|
-
context
|
120
|
-
let(:client) { Manticore::Client.new :ssl => {verify: :strict, ca_file: File.expand_path("../../ssl/root-ca.crt", __FILE__)
|
161
|
+
context "when ca_file is given" do
|
162
|
+
let(:client) { Manticore::Client.new :ssl => {verify: :strict, ca_file: File.expand_path("../../ssl/root-ca.crt", __FILE__)} }
|
121
163
|
|
122
164
|
it "verifies the request and succeed" do
|
123
165
|
expect { client.get("https://localhost:55444/").body }.to_not raise_exception
|
124
166
|
end
|
125
167
|
end
|
126
168
|
|
127
|
-
context
|
128
|
-
let(:client) {
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
169
|
+
context "when client_cert and client_key are given as file paths" do
|
170
|
+
let(:client) {
|
171
|
+
Manticore::Client.new(
|
172
|
+
:ssl => {
|
173
|
+
verify: :strict,
|
174
|
+
ca_file: File.expand_path("../../ssl/root-ca.crt", __FILE__),
|
175
|
+
client_cert: File.expand_path("../../ssl/client.crt", __FILE__),
|
176
|
+
client_key: File.expand_path("../../ssl/client.key", __FILE__),
|
177
|
+
},
|
178
|
+
)
|
179
|
+
}
|
180
|
+
|
181
|
+
it "successfully auths requests" do
|
182
|
+
expect(client.get("https://localhost:55445/").body).to match("hello")
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "when client_cert and client_key are given as OpenSSL::X509::Certificate" do
|
187
|
+
let(:client) {
|
188
|
+
Manticore::Client.new(
|
189
|
+
:ssl => {
|
190
|
+
verify: :strict,
|
191
|
+
ca_file: File.expand_path("../../ssl/root-ca.crt", __FILE__),
|
192
|
+
client_cert: OpenSSL::X509::Certificate.new(File.read(File.expand_path("../../ssl/client.crt", __FILE__))),
|
193
|
+
client_key: OpenSSL::PKey::RSA.new(File.read(File.expand_path("../../ssl/client.key", __FILE__))),
|
194
|
+
},
|
195
|
+
)
|
196
|
+
}
|
197
|
+
|
198
|
+
it "successfully auths requests" do
|
199
|
+
expect(client.get("https://localhost:55445/").body).to match("hello")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
context "when client_cert and client_key are given as strings" do
|
204
|
+
let(:client) {
|
205
|
+
Manticore::Client.new(
|
206
|
+
:ssl => {
|
207
|
+
verify: :strict,
|
208
|
+
ca_file: File.expand_path("../../ssl/root-ca.crt", __FILE__),
|
209
|
+
client_cert: File.read(File.expand_path("../../ssl/client.crt", __FILE__)),
|
210
|
+
client_key: File.read(File.expand_path("../../ssl/client.key", __FILE__)),
|
211
|
+
},
|
212
|
+
)
|
135
213
|
}
|
136
214
|
|
137
215
|
it "successfully auths requests" do
|
@@ -139,12 +217,16 @@ describe Manticore::Client do
|
|
139
217
|
end
|
140
218
|
end
|
141
219
|
|
142
|
-
context
|
143
|
-
let(:client) { Manticore::Client.new :ssl => {:verify => :
|
220
|
+
context "when off" do
|
221
|
+
let(:client) { Manticore::Client.new :ssl => {:verify => :disable} }
|
144
222
|
|
145
223
|
it "does not break on SSL validation errors" do
|
146
224
|
expect { client.get("https://localhost:55444/").body }.to_not raise_exception
|
147
225
|
end
|
226
|
+
|
227
|
+
it "does not break on expired SSL certificates" do
|
228
|
+
expect { client.get("https://localhost:55446/").body }.to_not raise_exception
|
229
|
+
end
|
148
230
|
end
|
149
231
|
|
150
232
|
context "against a server that verifies clients" do
|
@@ -155,7 +237,7 @@ describe Manticore::Client do
|
|
155
237
|
truststore_password: "test123",
|
156
238
|
keystore: File.expand_path("../../ssl/client.p12", __FILE__),
|
157
239
|
keystore_password: "test123",
|
158
|
-
verify: :strict
|
240
|
+
verify: :strict,
|
159
241
|
}
|
160
242
|
Manticore::Client.new :ssl => options
|
161
243
|
}
|
@@ -170,7 +252,7 @@ describe Manticore::Client do
|
|
170
252
|
options = {
|
171
253
|
truststore: File.expand_path("../../ssl/truststore.jks", __FILE__),
|
172
254
|
truststore_password: "test123",
|
173
|
-
verify: :strict
|
255
|
+
verify: :strict,
|
174
256
|
}
|
175
257
|
Manticore::Client.new :ssl => options
|
176
258
|
}
|
@@ -206,40 +288,39 @@ describe Manticore::Client do
|
|
206
288
|
expect(subject).to receive(:call).once.and_call_original
|
207
289
|
end
|
208
290
|
|
209
|
-
specify { expect { subject.body }.to change
|
210
|
-
specify { expect { subject.headers }.to change
|
291
|
+
specify { expect { subject.body }.to change { subject.called? } }
|
292
|
+
specify { expect { subject.headers }.to change { subject.called? } }
|
211
293
|
specify { expect { subject.final_url }.to change { subject.called? } }
|
212
|
-
specify { expect { subject.code }.to change
|
213
|
-
specify { expect { subject.length }.to change
|
214
|
-
specify { expect { subject.cookies }.to change
|
294
|
+
specify { expect { subject.code }.to change { subject.called? } }
|
295
|
+
specify { expect { subject.length }.to change { subject.called? } }
|
296
|
+
specify { expect { subject.cookies }.to change { subject.called? } }
|
215
297
|
end
|
216
298
|
|
217
299
|
it "automatically calls synchronous requests that pass a handler block" do
|
218
|
-
req = client.get(local_server) {|r| }
|
300
|
+
req = client.get(local_server) { |r| }
|
219
301
|
expect(req).to be_called
|
220
302
|
end
|
221
303
|
|
222
304
|
it "does not call asynchronous requests even if a block is passed" do
|
223
|
-
req = client.async.get(local_server) {|r| }
|
305
|
+
req = client.async.get(local_server) { |r| }
|
224
306
|
expect(req).to_not be_called
|
225
307
|
end
|
226
308
|
|
227
309
|
it "does not call asynchronous requests when on_success is passed" do
|
228
|
-
req = client.async.get(local_server).on_success {|r| }
|
310
|
+
req = client.async.get(local_server).on_success { |r| }
|
229
311
|
expect(req).to_not be_called
|
230
312
|
end
|
231
313
|
|
232
314
|
it "calls async requests on client execution" do
|
233
|
-
req = client.async.get(local_server).on_success {|r| }
|
315
|
+
req = client.async.get(local_server).on_success { |r| }
|
234
316
|
expect { client.execute! }.to change { req.called? }.from(false).to(true)
|
235
317
|
end
|
236
318
|
|
237
|
-
|
238
319
|
describe "with a bad port number" do
|
239
320
|
it "returns a Manticore::InvalidArgumentException" do
|
240
321
|
failure = nil
|
241
322
|
client.async.get(local_server("/", 65536)).
|
242
|
-
on_failure {|f| failure = f }
|
323
|
+
on_failure { |f| failure = f }
|
243
324
|
client.execute!
|
244
325
|
expect(failure).to be_a(Manticore::InvalidArgumentException)
|
245
326
|
end
|
@@ -251,7 +332,7 @@ describe Manticore::Client do
|
|
251
332
|
# I'm not crazy about reaching into the client via instance_variable_get here, but it works.
|
252
333
|
expect(client.instance_variable_get("@client")).to receive(:execute).and_raise(StandardError.new("Uh oh"))
|
253
334
|
client.async.get(local_server).
|
254
|
-
on_failure {|f| failure = f }
|
335
|
+
on_failure { |f| failure = f }
|
255
336
|
client.execute!
|
256
337
|
expect(failure).to be_a(StandardError)
|
257
338
|
end
|
@@ -368,6 +449,11 @@ describe Manticore::Client do
|
|
368
449
|
expect(JSON.load(response.body)["method"]).to eq "GET"
|
369
450
|
end
|
370
451
|
|
452
|
+
it "works with a URI object" do
|
453
|
+
response = client.get(URI.parse local_server)
|
454
|
+
expect(JSON.load(response.body)["method"]).to eq "GET"
|
455
|
+
end
|
456
|
+
|
371
457
|
it "send a query" do
|
372
458
|
response = client.get local_server, query: {foo: "bar"}
|
373
459
|
expect(CGI.parse(JSON.load(response.body)["uri"]["query"])["foo"]).to eq ["bar"]
|
@@ -438,10 +524,10 @@ describe Manticore::Client do
|
|
438
524
|
end
|
439
525
|
|
440
526
|
it "sends an arbitrary entity" do
|
441
|
-
f = open(__FILE__, "r").to_inputstream
|
442
|
-
multipart_entity = MultipartEntityBuilder.create.add_text_body("foo", "bar").add_binary_body("whatever", f
|
527
|
+
f = open(File.expand_path(File.join(__FILE__, "..", "..", "spec_helper.rb")), "r").to_inputstream
|
528
|
+
multipart_entity = MultipartEntityBuilder.create.add_text_body("foo", "bar").add_binary_body("whatever", f, ContentType::TEXT_PLAIN, __FILE__)
|
443
529
|
response = client.post(local_server, entity: multipart_entity.build)
|
444
|
-
expect(response.body).to match "
|
530
|
+
expect(response.body).to match "RSpec.configure"
|
445
531
|
end
|
446
532
|
end
|
447
533
|
|
@@ -477,7 +563,7 @@ describe Manticore::Client do
|
|
477
563
|
describe "#head" do
|
478
564
|
it "works" do
|
479
565
|
response = client.head(local_server)
|
480
|
-
expect(
|
566
|
+
expect(response.body).to be_nil
|
481
567
|
end
|
482
568
|
end
|
483
569
|
|
@@ -510,8 +596,8 @@ describe Manticore::Client do
|
|
510
596
|
futures = [55441, 55442].map do |port|
|
511
597
|
client.async.get("http://localhost:#{port}/?sleep=1").
|
512
598
|
on_success do |response|
|
513
|
-
|
514
|
-
|
599
|
+
Time.now.to_f
|
600
|
+
end
|
515
601
|
end
|
516
602
|
|
517
603
|
client.execute!
|
@@ -522,7 +608,7 @@ describe Manticore::Client do
|
|
522
608
|
it "returns the results of the handler blocks" do
|
523
609
|
[55441, 55442].each do |port|
|
524
610
|
client.async.get("http://localhost:#{port}/").
|
525
|
-
on_success {|response, request| "Result" }
|
611
|
+
on_success { |response, request| "Result" }
|
526
612
|
end
|
527
613
|
|
528
614
|
expect(client.execute!.map(&:callback_result)).to eq ["Result", "Result"]
|
@@ -532,7 +618,7 @@ describe Manticore::Client do
|
|
532
618
|
describe "#clear_pending" do
|
533
619
|
it "removes pending requests" do
|
534
620
|
ran = false
|
535
|
-
client.async.get("http://google.com").on_success {|r| ran = true }
|
621
|
+
client.async.get("http://google.com").on_success { |r| ran = true }
|
536
622
|
client.clear_pending
|
537
623
|
expect(client.execute!).to be_empty
|
538
624
|
expect(ran).to be false
|
@@ -563,25 +649,25 @@ describe Manticore::Client do
|
|
563
649
|
end
|
564
650
|
end
|
565
651
|
|
566
|
-
context
|
652
|
+
context "stubbing" do
|
567
653
|
it "only the provided URLs" do
|
568
654
|
client.stub local_server, body: "body"
|
569
|
-
client.async.get(local_server).on_success {|r| expect(r).to be_a Manticore::StubbedResponse }
|
570
|
-
client.async.get(local_server("/other")).on_success {|r| expect(r).to_not be_a Manticore::StubbedResponse }
|
655
|
+
client.async.get(local_server).on_success { |r| expect(r).to be_a Manticore::StubbedResponse }
|
656
|
+
client.async.get(local_server("/other")).on_success { |r| expect(r).to_not be_a Manticore::StubbedResponse }
|
571
657
|
client.execute!
|
572
658
|
end
|
573
659
|
|
574
660
|
it "by regex matching" do
|
575
661
|
client.stub %r{#{local_server("/foo")}}, body: "body"
|
576
|
-
client.async.get(local_server("/foo")).on_success {|r| expect(r).to be_a Manticore::StubbedResponse }
|
577
|
-
client.async.get(local_server("/bar")).on_success {|r| expect(r).to_not be_a Manticore::StubbedResponse }
|
662
|
+
client.async.get(local_server("/foo")).on_success { |r| expect(r).to be_a Manticore::StubbedResponse }
|
663
|
+
client.async.get(local_server("/bar")).on_success { |r| expect(r).to_not be_a Manticore::StubbedResponse }
|
578
664
|
client.execute!
|
579
665
|
end
|
580
666
|
|
581
667
|
it "strictly matches string stubs" do
|
582
668
|
client.stub local_server("/foo"), body: "body"
|
583
|
-
client.async.get(local_server("/foo")).on_success {|r| expect(r).to be_a Manticore::StubbedResponse }
|
584
|
-
client.async.get(local_server("/other")).on_success {|r| expect(r).to_not be_a Manticore::StubbedResponse }
|
669
|
+
client.async.get(local_server("/foo")).on_success { |r| expect(r).to be_a Manticore::StubbedResponse }
|
670
|
+
client.async.get(local_server("/other")).on_success { |r| expect(r).to_not be_a Manticore::StubbedResponse }
|
585
671
|
client.execute!
|
586
672
|
end
|
587
673
|
|
@@ -613,10 +699,9 @@ describe Manticore::Client do
|
|
613
699
|
describe "keepalive" do
|
614
700
|
let(:url) { "http://www.facebook.com/" }
|
615
701
|
|
616
|
-
|
617
702
|
context "with keepalive" do
|
618
703
|
it "adds the Connection: Keep-Alive header for http/1.0" do
|
619
|
-
expect(
|
704
|
+
expect(client.get(url).request["Connection"]).to eq "Keep-Alive"
|
620
705
|
end
|
621
706
|
|
622
707
|
let(:client) { Manticore::Client.new keepalive: true, pool_max: 1 }
|
@@ -634,7 +719,7 @@ describe Manticore::Client do
|
|
634
719
|
let(:client) { Manticore::Client.new keepalive: false, pool_max: 1 }
|
635
720
|
|
636
721
|
it "does not add the Connection: Keep-Alive header for http/1.0" do
|
637
|
-
expect(
|
722
|
+
expect(client.get(url).request["Connection"]).to be_nil
|
638
723
|
end
|
639
724
|
|
640
725
|
it "closes the connection after a request" do
|
@@ -649,35 +734,54 @@ describe Manticore::Client do
|
|
649
734
|
end
|
650
735
|
|
651
736
|
context "with a misbehaving endpoint" do
|
737
|
+
let(:port) do
|
738
|
+
p = 4000
|
739
|
+
server = nil
|
740
|
+
begin
|
741
|
+
server = TCPServer.new p
|
742
|
+
rescue Errno::EADDRINUSE
|
743
|
+
p += 1
|
744
|
+
retry
|
745
|
+
ensure
|
746
|
+
server.close
|
747
|
+
end
|
748
|
+
p
|
749
|
+
end
|
750
|
+
|
652
751
|
before do
|
653
|
-
@socket = TCPServer.new
|
752
|
+
@socket = TCPServer.new port
|
654
753
|
@server = Thread.new do
|
655
754
|
loop do
|
656
|
-
client = @socket.accept
|
657
755
|
begin
|
756
|
+
client = @socket.accept
|
658
757
|
client.puts([
|
659
758
|
"HTTP/1.1 200 OK",
|
660
759
|
"Keep-Alive: timeout=3000",
|
661
760
|
"Connection: Keep-Alive",
|
662
761
|
"Content-Length: 6",
|
663
762
|
"",
|
664
|
-
"Hello!"
|
763
|
+
"Hello!",
|
665
764
|
].join("\n"))
|
666
765
|
client.close
|
667
|
-
rescue
|
766
|
+
rescue IOError => e
|
767
|
+
break
|
668
768
|
end
|
669
769
|
end
|
670
770
|
end
|
671
771
|
end
|
672
772
|
|
773
|
+
after do
|
774
|
+
@server.kill
|
775
|
+
end
|
776
|
+
|
673
777
|
let(:client) { Manticore::Client.new keepalive: true, pool_max: 1 }
|
674
778
|
|
675
779
|
it "retries 3 times by default" do
|
676
780
|
# The first time, reply with keepalive, then close the connection
|
677
781
|
# The second connection should succeed
|
678
782
|
|
679
|
-
request1 = client.get("http://localhost
|
680
|
-
request2 = client.get("http://localhost
|
783
|
+
request1 = client.get("http://localhost:#{port}/")
|
784
|
+
request2 = client.get("http://localhost:#{port}/")
|
681
785
|
expect { request1.call }.to_not raise_exception
|
682
786
|
expect { request2.call }.to_not raise_exception
|
683
787
|
|
@@ -691,8 +795,8 @@ describe Manticore::Client do
|
|
691
795
|
it "retries 0 times and fail on the second request" do
|
692
796
|
# The first time, reply with keepalive, then close the connection
|
693
797
|
# The second connection should succeed
|
694
|
-
expect { client.get("http://localhost
|
695
|
-
expect { client.get("http://localhost
|
798
|
+
expect { client.get("http://localhost:#{port}/").call }.to_not raise_exception
|
799
|
+
expect { client.get("http://localhost:#{port}/").call }.to raise_exception(Manticore::SocketException)
|
696
800
|
end
|
697
801
|
end
|
698
802
|
|
@@ -702,8 +806,8 @@ describe Manticore::Client do
|
|
702
806
|
it "succeeds without any retries" do
|
703
807
|
# The first time, reply with keepalive, then close the connection
|
704
808
|
# The second connection should succeed
|
705
|
-
request1 = client.get("http://localhost
|
706
|
-
request2 = client.get("http://localhost
|
809
|
+
request1 = client.get("http://localhost:#{port}/")
|
810
|
+
request2 = client.get("http://localhost:#{port}/")
|
707
811
|
expect { request1.call }.to_not raise_exception
|
708
812
|
expect { request2.call }.to_not raise_exception
|
709
813
|
|
@@ -714,7 +818,11 @@ describe Manticore::Client do
|
|
714
818
|
|
715
819
|
after do
|
716
820
|
Thread.kill @server
|
717
|
-
|
821
|
+
begin
|
822
|
+
@socket.close
|
823
|
+
rescue IOError
|
824
|
+
# pass
|
825
|
+
end
|
718
826
|
end
|
719
827
|
end
|
720
828
|
|
@@ -771,15 +879,15 @@ describe Manticore::Client do
|
|
771
879
|
|
772
880
|
describe "background" do
|
773
881
|
it "returns a response" do
|
774
|
-
expect(
|
882
|
+
expect(client.background.get(local_server)).to be_a Manticore::Response
|
775
883
|
end
|
776
884
|
|
777
885
|
it "has the background flag set" do
|
778
|
-
expect(
|
886
|
+
expect(client.background.get(local_server).background).to eq true
|
779
887
|
end
|
780
888
|
|
781
889
|
it "returns a future when called" do
|
782
|
-
expect(
|
890
|
+
expect(client.background.get(local_server).call).to be_a Java::JavaUtilConcurrent::FutureTask
|
783
891
|
end
|
784
892
|
|
785
893
|
it "evaluates immediately when given a block" do
|
@@ -798,7 +906,7 @@ describe Manticore::Client do
|
|
798
906
|
java_import "java.util.concurrent.TimeUnit"
|
799
907
|
host = URI.parse(uri).host
|
800
908
|
pool = client.instance_variable_get("@pool")
|
801
|
-
req = pool.requestConnection(Java::OrgApacheHttpConnRouting::HttpRoute.new(
|
909
|
+
req = pool.requestConnection(Java::OrgApacheHttpConnRouting::HttpRoute.new(Java::OrgApacheHttp::HttpHost.new(host)), nil)
|
802
910
|
conn = req.get(3, TimeUnit::SECONDS)
|
803
911
|
begin
|
804
912
|
yield conn
|