manticore 0.6.0-java → 0.6.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +2 -0
- data/lib/manticore/client.rb +25 -9
- data/lib/manticore/response.rb +17 -4
- data/lib/manticore/version.rb +1 -1
- data/spec/manticore/client_spec.rb +48 -4
- data/spec/manticore/response_spec.rb +12 -0
- data/spec/spec_helper.rb +12 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1e6b7d1ea5d4bb60011c89d4b3e7b10abff3b42
|
4
|
+
data.tar.gz: db35b3f276b9f5040cee58407a16858f291435d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8a1d7749fd671e7f44970067dd67899d5485de989c320baa39ab6f05df886e34148a3ccdd05ec7513792138314d4d37421509a5a7fd6b47231c30f2f862acec
|
7
|
+
data.tar.gz: f83f8a304ad9c12d94c3b8fd8b5914fded62083a6b90ed61a67e80aa754683ec69fa122e802377f250cc6eaa40f79a09930bb482d5c337cabce3bc799271945c
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
### v0.6.1 (pending)
|
4
4
|
|
5
|
+
* 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)
|
6
|
+
|
5
7
|
### v0.6.0
|
6
8
|
|
7
9
|
* Dependent jars are now vendored, but managed with jar-dependencies. This solves issues installing manticore on platforms that have out-of-date root certs, and simplifies the install process.
|
data/lib/manticore/client.rb
CHANGED
@@ -446,6 +446,7 @@ module Manticore
|
|
446
446
|
end
|
447
447
|
|
448
448
|
def uri_from_url_and_options(url, options)
|
449
|
+
url = url.to_s if url.is_a?(URI)
|
449
450
|
builder = URIBuilder.new(url)
|
450
451
|
pairs = struct_to_name_value_pairs(options[:query])
|
451
452
|
builder.add_parameters pairs unless pairs.empty?
|
@@ -486,11 +487,18 @@ module Manticore
|
|
486
487
|
req.set_config config.build
|
487
488
|
end
|
488
489
|
|
489
|
-
|
490
|
-
options[:headers].each {|k, v| req[k] = v } if options.key?(:headers)
|
491
|
-
|
490
|
+
headers = []
|
492
491
|
# Support keepalive on HTTP/1.0 connections
|
493
|
-
|
492
|
+
headers.push BasicHeader.new("Connection", "Keep-Alive") if @keepalive
|
493
|
+
|
494
|
+
if options.key?(:headers)
|
495
|
+
options[:headers].each do |k, v|
|
496
|
+
Array(v).each do |_v|
|
497
|
+
headers.push BasicHeader.new(k, _v)
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
req.set_headers headers.to_java(BasicHeader) unless headers.empty?
|
494
502
|
|
495
503
|
context = HttpClientContext.new
|
496
504
|
proxy_user = req_options[:proxy].is_a?(Hash) && (req_options[:proxy][:user] || req_options[:proxy][:username])
|
@@ -529,7 +537,17 @@ module Manticore
|
|
529
537
|
|
530
538
|
def auth_from_options(req, options, context)
|
531
539
|
proxy = options.fetch(:proxy, {})
|
532
|
-
|
540
|
+
|
541
|
+
proxy_user, proxy_pass = if proxy.is_a?(String)
|
542
|
+
proxy_uri = URI.parse(proxy)
|
543
|
+
[proxy_uri.user, proxy_uri.password]
|
544
|
+
else
|
545
|
+
[(proxy[:user] || proxy[:username]),
|
546
|
+
(proxy[:pass] || proxy[:password])]
|
547
|
+
end
|
548
|
+
|
549
|
+
|
550
|
+
if options[:auth] || proxy_user
|
533
551
|
provider = BasicCredentialsProvider.new
|
534
552
|
if options[:auth]
|
535
553
|
username = options[:auth][:user] || options[:auth][:username]
|
@@ -547,10 +565,8 @@ module Manticore
|
|
547
565
|
end
|
548
566
|
end
|
549
567
|
|
550
|
-
if
|
551
|
-
|
552
|
-
password = proxy[:pass] || proxy[:password]
|
553
|
-
provider.set_credentials AuthScope.new(get_proxy_host(proxy)), UsernamePasswordCredentials.new(username, password)
|
568
|
+
if proxy_user
|
569
|
+
provider.set_credentials AuthScope.new(get_proxy_host(proxy)), UsernamePasswordCredentials.new(proxy_user, proxy_pass)
|
554
570
|
end
|
555
571
|
context.set_credentials_provider(provider)
|
556
572
|
end
|
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
|
@@ -140,10 +140,14 @@ module Manticore
|
|
140
140
|
end
|
141
141
|
|
142
142
|
# Return the value of a single response header. Will call the request if it has not been called yet.
|
143
|
+
# If the header was returned with multiple values, will only return the first value. If you need to get
|
144
|
+
# multiple values, use response#headers[lowercase_key]
|
143
145
|
#
|
144
|
-
# @
|
146
|
+
# @param key [String] Case-insensitive header key
|
147
|
+
# @return [String] Value of the header, or nil if not present
|
145
148
|
def [](key)
|
146
|
-
headers[key.downcase]
|
149
|
+
v = headers[key.downcase]
|
150
|
+
v.is_a?(Array) ? v.first : v
|
147
151
|
end
|
148
152
|
|
149
153
|
# Return the response code from this request as an integer. Will call the request if it has not been called yet.
|
@@ -246,7 +250,16 @@ module Manticore
|
|
246
250
|
@response = response
|
247
251
|
@code = response.get_status_line.get_status_code
|
248
252
|
@message = response.get_status_line.get_reason_phrase
|
249
|
-
@headers =
|
253
|
+
@headers = response.get_all_headers.each_with_object({}) do |h, o|
|
254
|
+
key = h.get_name.downcase
|
255
|
+
if o.key?(key)
|
256
|
+
o[key] = Array(o[key]) unless o[key].is_a?(Array)
|
257
|
+
o[key].push h.get_value
|
258
|
+
else
|
259
|
+
o[key] = h.get_value
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
250
263
|
@callback_result = @handlers[:success].call(self)
|
251
264
|
nil
|
252
265
|
end
|
data/lib/manticore/version.rb
CHANGED
@@ -24,6 +24,12 @@ describe Manticore::Client do
|
|
24
24
|
expect(json["headers"]["X-Custom-Header"]).to eq "Blaznotts"
|
25
25
|
end
|
26
26
|
|
27
|
+
it "accepts repeated header values" do
|
28
|
+
response = client.get(local_server, headers: {"X-Custom-Header" => ["Whizzles", "Blaznotts"]})
|
29
|
+
json = JSON.load(response.body)
|
30
|
+
expect(json["headers"]["X-Custom-Header"].sort).to eq ["Blaznotts", "Whizzles"]
|
31
|
+
end
|
32
|
+
|
27
33
|
it "enables compression" do
|
28
34
|
response = client.get(local_server)
|
29
35
|
json = JSON.load(response.body)
|
@@ -46,6 +52,35 @@ describe Manticore::Client do
|
|
46
52
|
expect(j["uri"]["port"]).to eq 55441
|
47
53
|
end
|
48
54
|
|
55
|
+
context "via an authenticated proxy" do
|
56
|
+
let(:proxy) { "http://localhost:55442" }
|
57
|
+
let(:auth) { nil }
|
58
|
+
let(:req) { client.get(local_server("/authproxy"), proxy: proxy, auth: auth) }
|
59
|
+
let(:j) { JSON.parse req.body }
|
60
|
+
|
61
|
+
context "with authentication as a hash" do
|
62
|
+
let(:auth) { {user: "user", pass: "pass"} }
|
63
|
+
|
64
|
+
it "proxies" do
|
65
|
+
expect(j["server_port"]).to eq 55442
|
66
|
+
expect(j["uri"]["port"]).to eq 55441
|
67
|
+
expect(j["headers"]["Proxy-Authorization"]).to eq "Basic dXNlcjpwYXNz"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "with authentication as a string" do
|
72
|
+
let(:proxy) { "http://user:pass@localhost:55442"}
|
73
|
+
|
74
|
+
it "proxies" do
|
75
|
+
expect(j["server_port"]).to eq 55442
|
76
|
+
expect(j["uri"]["port"]).to eq 55441
|
77
|
+
expect(j["headers"]["Proxy-Authorization"]).to eq "Basic dXNlcjpwYXNz"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
it "proxies with authentication as a hash" do
|
82
|
+
end
|
83
|
+
|
49
84
|
describe "with a custom user agent" do
|
50
85
|
let(:client) { Manticore::Client.new user_agent: "test-agent/1.0" }
|
51
86
|
|
@@ -368,6 +403,11 @@ describe Manticore::Client do
|
|
368
403
|
expect(JSON.load(response.body)["method"]).to eq "GET"
|
369
404
|
end
|
370
405
|
|
406
|
+
it "works with a URI object" do
|
407
|
+
response = client.get(URI.parse local_server)
|
408
|
+
expect(JSON.load(response.body)["method"]).to eq "GET"
|
409
|
+
end
|
410
|
+
|
371
411
|
it "send a query" do
|
372
412
|
response = client.get local_server, query: {foo: "bar"}
|
373
413
|
expect(CGI.parse(JSON.load(response.body)["uri"]["query"])["foo"]).to eq ["bar"]
|
@@ -438,10 +478,10 @@ describe Manticore::Client do
|
|
438
478
|
end
|
439
479
|
|
440
480
|
it "sends an arbitrary entity" do
|
441
|
-
f = open(__FILE__, "r").to_inputstream
|
481
|
+
f = open(File.expand_path(File.join(__FILE__, "..", "..", "spec_helper.rb")), "r").to_inputstream
|
442
482
|
multipart_entity = MultipartEntityBuilder.create.add_text_body("foo", "bar").add_binary_body("whatever", f , ContentType::TEXT_PLAIN, __FILE__)
|
443
483
|
response = client.post(local_server, entity: multipart_entity.build)
|
444
|
-
expect(response.body).to match "
|
484
|
+
expect(response.body).to match "RSpec.configure"
|
445
485
|
end
|
446
486
|
end
|
447
487
|
|
@@ -664,7 +704,7 @@ describe Manticore::Client do
|
|
664
704
|
"Hello!"
|
665
705
|
].join("\n"))
|
666
706
|
client.close
|
667
|
-
rescue
|
707
|
+
rescue IOError => e
|
668
708
|
end
|
669
709
|
end
|
670
710
|
end
|
@@ -714,7 +754,11 @@ describe Manticore::Client do
|
|
714
754
|
|
715
755
|
after do
|
716
756
|
Thread.kill @server
|
717
|
-
|
757
|
+
begin
|
758
|
+
@socket.close
|
759
|
+
rescue IOError
|
760
|
+
# pass
|
761
|
+
end
|
718
762
|
end
|
719
763
|
end
|
720
764
|
|
@@ -12,6 +12,18 @@ describe Manticore::Response do
|
|
12
12
|
expect(subject["Content-Type"]).to eq "text/plain"
|
13
13
|
end
|
14
14
|
|
15
|
+
context "when a response contains repeated headers" do
|
16
|
+
subject { client.get( local_server "/repeated_headers") }
|
17
|
+
|
18
|
+
it "returns an array of values for headers with multiple occurrances" do
|
19
|
+
expect(subject.headers["link"]).to eq ["foo", "bar"]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns only the first value when using response#[]" do
|
23
|
+
expect(subject["Link"]).to eq "foo"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
15
27
|
it "reads the body" do
|
16
28
|
expect(subject.body).to match "Manticore"
|
17
29
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -15,6 +15,7 @@ PORT = 55441
|
|
15
15
|
def local_server(path = "/", port = PORT)
|
16
16
|
URI.join("http://localhost:#{port}", path).to_s
|
17
17
|
end
|
18
|
+
Thread.abort_on_exception = true
|
18
19
|
|
19
20
|
def read_nonblock(socket)
|
20
21
|
buffer = ""
|
@@ -32,7 +33,7 @@ end
|
|
32
33
|
def start_server(port = PORT)
|
33
34
|
@servers ||= {}
|
34
35
|
@servers[port] = Thread.new {
|
35
|
-
Net::HTTP::Server.run(port: port, log:
|
36
|
+
Net::HTTP::Server.run(port: port, log: open("/dev/null", "a")) do |request, stream|
|
36
37
|
|
37
38
|
query = Rack::Utils.parse_query(request[:uri][:query].to_s)
|
38
39
|
if query["sleep"]
|
@@ -64,9 +65,19 @@ def start_server(port = PORT)
|
|
64
65
|
elsif request[:uri][:path] == "/proxy"
|
65
66
|
payload = JSON.dump(request.merge(server_port: port))
|
66
67
|
[200, {'Content-Type' => content_type, "Content-Length" => payload.length}, [payload]]
|
68
|
+
elsif request[:uri][:path] == "/authproxy"
|
69
|
+
payload = JSON.dump(request.merge(server_port: port))
|
70
|
+
if request[:headers]["Proxy-Authorization"] == "Basic dXNlcjpwYXNz"
|
71
|
+
[200, {'Content-Type' => content_type, "Content-Length" => payload.length}, [payload]]
|
72
|
+
else
|
73
|
+
[407, {'Proxy-Authenticate' => 'Basic realm="localhost'}, [payload]]
|
74
|
+
end
|
67
75
|
elsif request[:uri][:path] == "/keepalive"
|
68
76
|
payload = JSON.dump(request.merge(server_port: port))
|
69
77
|
[200, {'Content-Type' => content_type, "Content-Length" => payload.length, "Keep-Alive" => "timeout=60"}, [payload]]
|
78
|
+
elsif request[:uri][:path] == "/repeated_headers"
|
79
|
+
payload = JSON.dump(request.merge(server_port: port))
|
80
|
+
[200, {'Link' => ["foo", "bar"]}, [payload]]
|
70
81
|
elsif request[:headers]["X-Redirect"] && request[:uri][:path] != request[:headers]["X-Redirect"]
|
71
82
|
[301, {"Location" => local_server( request[:headers]["X-Redirect"] )}, [""]]
|
72
83
|
else
|
@@ -75,7 +86,6 @@ def start_server(port = PORT)
|
|
75
86
|
io = Zlib::GzipWriter.new(out, 2)
|
76
87
|
|
77
88
|
request[:body] = Base64.encode64(request[:body]) if request[:headers]["X-Base64"]
|
78
|
-
|
79
89
|
io.write JSON.dump(request)
|
80
90
|
io.close
|
81
91
|
payload = out.string
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: manticore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Chris Heald
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,7 +122,7 @@ requirements:
|
|
122
122
|
- jar commons-codec:commons-codec, '~> 1.9'
|
123
123
|
- jar org.apache.httpcomponents:httpcore, '~> 4.4.4'
|
124
124
|
rubyforge_project:
|
125
|
-
rubygems_version: 2.4
|
125
|
+
rubygems_version: 2.6.4
|
126
126
|
signing_key:
|
127
127
|
specification_version: 4
|
128
128
|
summary: Manticore is an HTTP client built on the Apache HttpCore components
|