manticore 0.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +3 -0
- data/APACHE-LICENSE-2.0.txt +202 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +28 -0
- data/README.md +120 -0
- data/Rakefile +8 -0
- data/lib/jar/commons-logging-1.1.3.jar +0 -0
- data/lib/jar/httpclient-4.3.2.jar +0 -0
- data/lib/jar/httpcore-4.3.1.jar +0 -0
- data/lib/manticore/async_response.rb +80 -0
- data/lib/manticore/client.rb +391 -0
- data/lib/manticore/facade.rb +40 -0
- data/lib/manticore/response.rb +76 -0
- data/lib/manticore/version.rb +3 -0
- data/lib/manticore.rb +27 -0
- data/manticore.gemspec +25 -0
- data/spec/manticore/client_spec.rb +178 -0
- data/spec/manticore/facade_spec.rb +41 -0
- data/spec/manticore/response_spec.rb +29 -0
- data/spec/spec_helper.rb +74 -0
- metadata +111 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Manticore::Client do
|
4
|
+
let(:client) { Manticore::Client.new }
|
5
|
+
|
6
|
+
it "should fetch a URL and return a response" do
|
7
|
+
client.get(local_server).should be_a Manticore::Response
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should resolve redirections" do
|
11
|
+
response = client.get(local_server, headers: {"X-Redirect" => "/foobar"})
|
12
|
+
response.code.should == 200
|
13
|
+
response.final_url.should == URI(local_server("/foobar"))
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should accept custom headers" do
|
17
|
+
response = client.get(local_server, headers: {"X-Custom-Header" => "Blaznotts"})
|
18
|
+
json = JSON.load(response.body)
|
19
|
+
json["headers"]["X-Custom-Header"].should == "Blaznotts"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should enable compression" do
|
23
|
+
response = client.get(local_server)
|
24
|
+
json = JSON.load(response.body)
|
25
|
+
json["headers"].should have_key "Accept-Encoding"
|
26
|
+
json["headers"]["Accept-Encoding"].should match("gzip")
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when compression is disabled" do
|
30
|
+
let(:client) {
|
31
|
+
Manticore::Client.new do |client, request_config|
|
32
|
+
client.disable_content_compression
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
it "should disable compression" do
|
37
|
+
response = client.get(local_server)
|
38
|
+
json = JSON.load(response.body)
|
39
|
+
json["headers"]["Accept-Encoding"].should be_nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#get" do
|
44
|
+
it "should work" do
|
45
|
+
response = client.get(local_server)
|
46
|
+
JSON.load(response.body)["method"].should == "GET"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#post" do
|
51
|
+
it "should work" do
|
52
|
+
response = client.post(local_server)
|
53
|
+
JSON.load(response.body)["method"].should == "POST"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should send a body" do
|
57
|
+
response = client.post(local_server, body: "This is a post body")
|
58
|
+
JSON.load(response.body)["body"].should == "This is a post body"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should send params" do
|
62
|
+
response = client.post(local_server, params: {key: "value"})
|
63
|
+
JSON.load(response.body)["body"].should == "key=value"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#put" do
|
68
|
+
it "should work" do
|
69
|
+
response = client.put(local_server)
|
70
|
+
JSON.load(response.body)["method"].should == "PUT"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should send a body" do
|
74
|
+
response = client.put(local_server, body: "This is a put body")
|
75
|
+
JSON.load(response.body)["body"].should == "This is a put body"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should send params" do
|
79
|
+
response = client.put(local_server, params: {key: "value"})
|
80
|
+
JSON.load(response.body)["body"].should == "key=value"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#head" do
|
85
|
+
it "should work" do
|
86
|
+
response = client.head(local_server)
|
87
|
+
JSON.load(response.body).should be_nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#options" do
|
92
|
+
it "should work" do
|
93
|
+
response = client.options(local_server)
|
94
|
+
JSON.load(response.body)["method"].should == "OPTIONS"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#patch" do
|
99
|
+
it "should work" do
|
100
|
+
response = client.patch(local_server)
|
101
|
+
JSON.load(response.body)["method"].should == "PATCH"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should send a body" do
|
105
|
+
response = client.patch(local_server, body: "This is a patch body")
|
106
|
+
JSON.load(response.body)["body"].should == "This is a patch body"
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should send params" do
|
110
|
+
response = client.patch(local_server, params: {key: "value"})
|
111
|
+
JSON.load(response.body)["body"].should == "key=value"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "async methods" do
|
116
|
+
it "should not make a request until execute is called" do
|
117
|
+
anchor = Time.now.to_f
|
118
|
+
client.async_get("http://localhost:55441/?sleep=0.5")
|
119
|
+
(Time.now.to_f - anchor).should < 0.4
|
120
|
+
|
121
|
+
anchor = Time.now.to_f
|
122
|
+
client.execute!
|
123
|
+
(Time.now.to_f - anchor).should > 0.4
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should return the response object, which may then have handlers attached" do
|
127
|
+
response = client.async_get("http://localhost:55441/")
|
128
|
+
success = false
|
129
|
+
response.on_success do
|
130
|
+
success = true
|
131
|
+
end
|
132
|
+
|
133
|
+
client.execute!
|
134
|
+
success.should == true
|
135
|
+
end
|
136
|
+
|
137
|
+
it "can chain handlers" do
|
138
|
+
client.async_get("http://localhost:55441/").on_success {|r| r.code }
|
139
|
+
client.execute!.should == [200]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "#execute!" do
|
144
|
+
it "should perform multiple concurrent requests" do
|
145
|
+
@times = []
|
146
|
+
[55441, 55442].each do |port|
|
147
|
+
client.async_get("http://localhost:#{port}/?sleep=1") do |request|
|
148
|
+
request.on_success do |response, request|
|
149
|
+
@times << Time.now.to_f
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
client.execute!
|
155
|
+
@times[0].should be_within(0.5).of(@times[1])
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should return the results of the handler blocks" do
|
159
|
+
[55441, 55442].each do |port|
|
160
|
+
client.async_get("http://localhost:#{port}/") do |request|
|
161
|
+
request.on_success {|response, request| "Result" }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
client.execute!.should == ["Result", "Result"]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "#clear_pending" do
|
170
|
+
it "should remove pending requests" do
|
171
|
+
ran = false
|
172
|
+
client.async_get("http://google.com").on_success {|r| ran = true }
|
173
|
+
client.clear_pending
|
174
|
+
client.execute!.should be_empty
|
175
|
+
ran.should be_false
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Manticore::Facade do
|
4
|
+
context "when extended into an arbitrary class" do
|
5
|
+
let(:extended_class) {
|
6
|
+
Class.new do
|
7
|
+
include Manticore::Facade
|
8
|
+
include_http_client
|
9
|
+
end
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:extended_shared_class) {
|
13
|
+
Class.new do
|
14
|
+
include Manticore::Facade
|
15
|
+
include_http_client shared_pool: true
|
16
|
+
end
|
17
|
+
}
|
18
|
+
|
19
|
+
it "should get a response" do
|
20
|
+
result = JSON.parse extended_class.get(local_server).body
|
21
|
+
result["method"].should == "GET"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not use the shared client by default" do
|
25
|
+
extended_class.instance_variable_get("@manticore_facade").object_id.should_not ==
|
26
|
+
Manticore.instance_variable_get("@manticore_facade").object_id
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be able to use the shared client" do
|
30
|
+
extended_shared_class.instance_variable_get("@manticore_facade").object_id.should ==
|
31
|
+
Manticore.instance_variable_get("@manticore_facade").object_id
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "from the default Manticore module" do
|
36
|
+
it "should get a response" do
|
37
|
+
result = JSON.parse Manticore.get(local_server).body
|
38
|
+
result["method"].should == "GET"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Manticore::Response do
|
4
|
+
let(:client) { Manticore::Client.new }
|
5
|
+
subject { client.get( local_server ) }
|
6
|
+
|
7
|
+
its(:headers) { should be_a Hash }
|
8
|
+
its(:body) { should be_a String }
|
9
|
+
its(:length) { should be_a Fixnum }
|
10
|
+
|
11
|
+
it "should read the body" do
|
12
|
+
subject.body.should match "Manticore"
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when the client is invoked with a block" do
|
16
|
+
it "should allow reading the body from a block" do
|
17
|
+
response = client.get(local_server) do |response|
|
18
|
+
response.body.should match 'Manticore'
|
19
|
+
end
|
20
|
+
|
21
|
+
response.body.should match "Manticore"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not read the body implicitly if called with a block" do
|
25
|
+
response = client.get(local_server) {}
|
26
|
+
expect { response.body }.to raise_exception(Manticore::StreamClosedException)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'manticore'
|
4
|
+
require 'zlib'
|
5
|
+
require 'json'
|
6
|
+
require 'rack'
|
7
|
+
|
8
|
+
PORT = 55441
|
9
|
+
|
10
|
+
def local_server(path = "/", port = PORT)
|
11
|
+
URI.join("http://localhost:#{port}", path).to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_nonblock(socket)
|
15
|
+
buffer = ""
|
16
|
+
loop {
|
17
|
+
begin
|
18
|
+
buffer << socket.read_nonblock(4096)
|
19
|
+
rescue Errno::EAGAIN
|
20
|
+
# Resource temporarily unavailable - read would block
|
21
|
+
break
|
22
|
+
end
|
23
|
+
}
|
24
|
+
buffer
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_server(port = PORT)
|
28
|
+
@servers ||= {}
|
29
|
+
@servers[port] = Thread.new {
|
30
|
+
Net::HTTP::Server.run(port: port) do |request, stream|
|
31
|
+
|
32
|
+
query = Rack::Utils.parse_query(request[:uri][:query].to_s)
|
33
|
+
if query["sleep"]
|
34
|
+
sleep(query["sleep"].to_f)
|
35
|
+
end
|
36
|
+
|
37
|
+
if cl = request[:headers]["Content-Length"]
|
38
|
+
request[:body] = read_nonblock stream.socket
|
39
|
+
end
|
40
|
+
|
41
|
+
if request[:headers]["X-Redirect"] && request[:uri][:path] != request[:headers]["X-Redirect"]
|
42
|
+
[301, {"Location" => local_server( request[:headers]["X-Redirect"] )}, [""]]
|
43
|
+
else
|
44
|
+
if request[:headers]["Accept-Encoding"] && request[:headers]["Accept-Encoding"].match("gzip")
|
45
|
+
out = StringIO.new('', "w")
|
46
|
+
io = Zlib::GzipWriter.new(out, 2)
|
47
|
+
io.write JSON.dump(request)
|
48
|
+
io.close
|
49
|
+
payload = out.string
|
50
|
+
[200, {'Content-Type' => "text/plain", 'Content-Encoding' => "gzip", "Content-Length" => payload.length}, [payload]]
|
51
|
+
else
|
52
|
+
payload = JSON.dump(request)
|
53
|
+
[200, {'Content-Type' => "text/plain", "Content-Length" => payload.length}, [payload]]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def stop_servers
|
61
|
+
@servers.values.each(&:kill) if @servers
|
62
|
+
end
|
63
|
+
|
64
|
+
RSpec.configure do |c|
|
65
|
+
require 'net/http/server'
|
66
|
+
|
67
|
+
c.before(:suite) {
|
68
|
+
@server = {}
|
69
|
+
start_server 55441
|
70
|
+
start_server 55442
|
71
|
+
}
|
72
|
+
|
73
|
+
c.after(:suite) { stop_servers }
|
74
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: manticore
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- Chris Heald
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: addressable
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.3'
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '2.3'
|
25
|
+
prerelease: false
|
26
|
+
type: :runtime
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '1.3'
|
39
|
+
prerelease: false
|
40
|
+
type: :development
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
prerelease: false
|
54
|
+
type: :development
|
55
|
+
description: Manticore is an HTTP client built on the Apache HttpCore components
|
56
|
+
email:
|
57
|
+
- cheald@mashable.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .travis.yml
|
64
|
+
- APACHE-LICENSE-2.0.txt
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- lib/jar/commons-logging-1.1.3.jar
|
70
|
+
- lib/jar/httpclient-4.3.2.jar
|
71
|
+
- lib/jar/httpcore-4.3.1.jar
|
72
|
+
- lib/manticore.rb
|
73
|
+
- lib/manticore/async_response.rb
|
74
|
+
- lib/manticore/client.rb
|
75
|
+
- lib/manticore/facade.rb
|
76
|
+
- lib/manticore/response.rb
|
77
|
+
- lib/manticore/version.rb
|
78
|
+
- manticore.gemspec
|
79
|
+
- spec/manticore/client_spec.rb
|
80
|
+
- spec/manticore/facade_spec.rb
|
81
|
+
- spec/manticore/response_spec.rb
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
homepage: https://github.com/cheald/manticore
|
84
|
+
licenses:
|
85
|
+
- MIT
|
86
|
+
metadata: {}
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 2.2.1
|
104
|
+
signing_key:
|
105
|
+
specification_version: 4
|
106
|
+
summary: Manticore is an HTTP client built on the Apache HttpCore components
|
107
|
+
test_files:
|
108
|
+
- spec/manticore/client_spec.rb
|
109
|
+
- spec/manticore/facade_spec.rb
|
110
|
+
- spec/manticore/response_spec.rb
|
111
|
+
- spec/spec_helper.rb
|