typhoeus 0.1.24 → 0.1.31
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.
- data/CHANGELOG.markdown +23 -0
- data/README.textile +333 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/benchmarks/profile.rb +25 -0
- data/benchmarks/vs_nethttp.rb +35 -0
- data/examples/twitter.rb +21 -0
- data/lib/typhoeus/easy.rb +97 -9
- data/lib/typhoeus/hydra.rb +17 -0
- data/lib/typhoeus/multi.rb +4 -3
- data/lib/typhoeus/request.rb +45 -2
- data/lib/typhoeus/response.rb +8 -6
- data/lib/typhoeus/service.rb +20 -0
- data/lib/typhoeus.rb +1 -1
- data/profilers/valgrind.rb +24 -0
- data/spec/fixtures/result_set.xml +60 -0
- data/spec/servers/app.rb +11 -0
- data/spec/typhoeus/easy_spec.rb +39 -2
- data/spec/typhoeus/hydra_spec.rb +311 -0
- data/spec/typhoeus/remote_spec.rb +1 -1
- data/spec/typhoeus/request_spec.rb +195 -0
- data/typhoeus.gemspec +113 -0
- metadata +110 -29
data/lib/typhoeus/hydra.rb
CHANGED
|
@@ -130,17 +130,33 @@ module Typhoeus
|
|
|
130
130
|
|
|
131
131
|
def get_easy_object(request)
|
|
132
132
|
@running_requests += 1
|
|
133
|
+
|
|
133
134
|
easy = @easy_pool.pop || Easy.new
|
|
135
|
+
easy.verbose = request.verbose
|
|
136
|
+
if request.username || request.password
|
|
137
|
+
auth = { :username => request.username, :password => request.password }
|
|
138
|
+
auth[:method] = Typhoeus::Easy::AUTH_TYPES["CURLAUTH_#{request.auth_method.to_s.upcase}".to_sym] if request.auth_method
|
|
139
|
+
easy.auth = auth
|
|
140
|
+
end
|
|
134
141
|
easy.url = request.url
|
|
135
142
|
easy.method = request.method
|
|
136
143
|
easy.params = request.params if request.method == :post && !request.params.nil?
|
|
137
144
|
easy.headers = request.headers if request.headers
|
|
138
145
|
easy.request_body = request.body if request.body
|
|
139
146
|
easy.timeout = request.timeout if request.timeout
|
|
147
|
+
easy.connect_timeout = request.connect_timeout if request.connect_timeout
|
|
140
148
|
easy.follow_location = request.follow_location if request.follow_location
|
|
141
149
|
easy.max_redirects = request.max_redirects if request.max_redirects
|
|
142
150
|
easy.proxy = request.proxy if request.proxy
|
|
143
151
|
easy.disable_ssl_peer_verification if request.disable_ssl_peer_verification
|
|
152
|
+
easy.ssl_cert = request.ssl_cert
|
|
153
|
+
easy.ssl_cert_type = request.ssl_cert_type
|
|
154
|
+
easy.ssl_key = request.ssl_key
|
|
155
|
+
easy.ssl_key_type = request.ssl_key_type
|
|
156
|
+
easy.ssl_key_password = request.ssl_key_password
|
|
157
|
+
easy.ssl_cacert = request.ssl_cacert
|
|
158
|
+
easy.ssl_capath = request.ssl_capath
|
|
159
|
+
easy.verbose = request.verbose
|
|
144
160
|
|
|
145
161
|
easy.on_success do |easy|
|
|
146
162
|
queue_next
|
|
@@ -192,6 +208,7 @@ module Typhoeus
|
|
|
192
208
|
:headers => easy.response_header,
|
|
193
209
|
:body => easy.response_body,
|
|
194
210
|
:time => easy.total_time_taken,
|
|
211
|
+
:effective_url => easy.effective_url,
|
|
195
212
|
:request => request)
|
|
196
213
|
end
|
|
197
214
|
private :response_from_easy
|
data/lib/typhoeus/multi.rb
CHANGED
|
@@ -9,19 +9,20 @@ module Typhoeus
|
|
|
9
9
|
def remove(easy)
|
|
10
10
|
multi_remove_handle(easy)
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
def add(easy)
|
|
14
|
+
easy.set_headers() if easy.headers.empty?
|
|
14
15
|
@easy_handles << easy
|
|
15
16
|
multi_add_handle(easy)
|
|
16
17
|
end
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
def perform()
|
|
19
20
|
while active_handle_count > 0 do
|
|
20
21
|
multi_perform
|
|
21
22
|
end
|
|
22
23
|
reset_easy_handles
|
|
23
24
|
end
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
def cleanup()
|
|
26
27
|
multi_cleanup
|
|
27
28
|
end
|
data/lib/typhoeus/request.rb
CHANGED
|
@@ -1,13 +1,45 @@
|
|
|
1
1
|
module Typhoeus
|
|
2
2
|
class Request
|
|
3
|
-
attr_accessor :method, :params, :body, :headers, :timeout, :user_agent, :response, :cache_timeout, :follow_location, :max_redirects, :proxy, :disable_ssl_peer_verification
|
|
3
|
+
attr_accessor :method, :params, :body, :headers, :connect_timeout, :timeout, :user_agent, :response, :cache_timeout, :follow_location, :max_redirects, :proxy, :disable_ssl_peer_verification, :ssl_cert, :ssl_cert_type, :ssl_key, :ssl_key_type, :ssl_key_password, :ssl_cacert, :ssl_capath, :verbose, :username, :password,
|
|
4
|
+
:auth_method
|
|
5
|
+
|
|
4
6
|
attr_reader :url
|
|
5
7
|
|
|
8
|
+
# Initialize a new Request
|
|
9
|
+
#
|
|
10
|
+
# Options:
|
|
11
|
+
# * +url+ : Endpoint (URL) of the request
|
|
12
|
+
# * +options+ : A hash containing options among :
|
|
13
|
+
# ** +:method+ : :get (default) / :post / :put
|
|
14
|
+
# ** +:params+ : params as a Hash
|
|
15
|
+
# ** +:body+
|
|
16
|
+
# ** +:timeout+ : timeout (ms)
|
|
17
|
+
# ** +:connect_timeout+ : connect timeout (ms)
|
|
18
|
+
# ** +:headers+ : headers as Hash
|
|
19
|
+
# ** +:user_agent+ : user agent (string)
|
|
20
|
+
# ** +:cache_timeout+ : cache timeout (ms)
|
|
21
|
+
# ** +:follow_location
|
|
22
|
+
# ** +:max_redirects
|
|
23
|
+
# ** +:proxy
|
|
24
|
+
# ** +:disable_ssl_peer_verification
|
|
25
|
+
# ** +:ssl_cert
|
|
26
|
+
# ** +:ssl_cert_type
|
|
27
|
+
# ** +:ssl_key
|
|
28
|
+
# ** +:ssl_key_type
|
|
29
|
+
# ** +:ssl_key_password
|
|
30
|
+
# ** +:ssl_cacert
|
|
31
|
+
# ** +:ssl_capath
|
|
32
|
+
# ** +:verbose
|
|
33
|
+
# ** +:username
|
|
34
|
+
# ** +:password
|
|
35
|
+
# ** +:auth_method
|
|
36
|
+
#
|
|
6
37
|
def initialize(url, options = {})
|
|
7
38
|
@method = options[:method] || :get
|
|
8
39
|
@params = options[:params]
|
|
9
40
|
@body = options[:body]
|
|
10
41
|
@timeout = options[:timeout]
|
|
42
|
+
@connect_timeout = options[:connect_timeout]
|
|
11
43
|
@headers = options[:headers] || {}
|
|
12
44
|
@user_agent = options[:user_agent] || Typhoeus::USER_AGENT
|
|
13
45
|
@cache_timeout = options[:cache_timeout]
|
|
@@ -15,6 +47,17 @@ module Typhoeus
|
|
|
15
47
|
@max_redirects = options[:max_redirects]
|
|
16
48
|
@proxy = options[:proxy]
|
|
17
49
|
@disable_ssl_peer_verification = options[:disable_ssl_peer_verification]
|
|
50
|
+
@ssl_cert = options[:ssl_cert]
|
|
51
|
+
@ssl_cert_type = options[:ssl_cert_type]
|
|
52
|
+
@ssl_key = options[:ssl_key]
|
|
53
|
+
@ssl_key_type = options[:ssl_key_type]
|
|
54
|
+
@ssl_key_password = options[:ssl_key_password]
|
|
55
|
+
@ssl_cacert = options[:ssl_cacert]
|
|
56
|
+
@ssl_capath = options[:ssl_capath]
|
|
57
|
+
@verbose = options[:verbose]
|
|
58
|
+
@username = options[:username]
|
|
59
|
+
@password = options[:password]
|
|
60
|
+
@auth_method = options[:auth_method]
|
|
18
61
|
|
|
19
62
|
if @method == :post
|
|
20
63
|
@url = url
|
|
@@ -42,7 +85,7 @@ module Typhoeus
|
|
|
42
85
|
end
|
|
43
86
|
|
|
44
87
|
def params_string
|
|
45
|
-
params.keys.sort.collect do |k|
|
|
88
|
+
params.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |k|
|
|
46
89
|
value = params[k]
|
|
47
90
|
if value.is_a? Hash
|
|
48
91
|
value.keys.collect {|sk| Rack::Utils.escape("#{k}[#{sk}]") + "=" + Rack::Utils.escape(value[sk].to_s)}
|
data/lib/typhoeus/response.rb
CHANGED
|
@@ -3,8 +3,9 @@ module Typhoeus
|
|
|
3
3
|
attr_accessor :request
|
|
4
4
|
attr_reader :code, :headers, :body, :time,
|
|
5
5
|
:requested_url, :requested_remote_method,
|
|
6
|
-
:requested_http_method, :start_time
|
|
7
|
-
|
|
6
|
+
:requested_http_method, :start_time,
|
|
7
|
+
:effective_url
|
|
8
|
+
|
|
8
9
|
def initialize(params = {})
|
|
9
10
|
@code = params[:code]
|
|
10
11
|
@headers = params[:headers]
|
|
@@ -14,8 +15,9 @@ module Typhoeus
|
|
|
14
15
|
@requested_http_method = params[:requested_http_method]
|
|
15
16
|
@start_time = params[:start_time]
|
|
16
17
|
@request = params[:request]
|
|
18
|
+
@effective_url = params[:effective_url]
|
|
17
19
|
end
|
|
18
|
-
|
|
20
|
+
|
|
19
21
|
def headers_hash
|
|
20
22
|
headers.split("\n").map {|o| o.strip}.inject({}) do |hash, o|
|
|
21
23
|
if o.empty?
|
|
@@ -30,16 +32,16 @@ module Typhoeus
|
|
|
30
32
|
else
|
|
31
33
|
hash[key] = value
|
|
32
34
|
end
|
|
33
|
-
|
|
35
|
+
|
|
34
36
|
hash
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
|
-
|
|
40
|
+
|
|
39
41
|
def success?
|
|
40
42
|
@code >= 200 && @code < 300
|
|
41
43
|
end
|
|
42
|
-
|
|
44
|
+
|
|
43
45
|
def modified?
|
|
44
46
|
@code != 304
|
|
45
47
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Typhoeus
|
|
2
|
+
class Service
|
|
3
|
+
def initialize(host, port)
|
|
4
|
+
@host = host
|
|
5
|
+
@port = port
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def get(resource, params)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def put(resource, params)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def post(resource, params)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def delete(resource, params)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/typhoeus.rb
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# go to ext/typhoeus and run ruby extconf.rb && make before running
|
|
3
|
+
# this.
|
|
4
|
+
|
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + "/../ext")
|
|
6
|
+
require File.dirname(__FILE__) + "/../lib/typhoeus"
|
|
7
|
+
|
|
8
|
+
klass = Class.new { include Typhoeus }
|
|
9
|
+
|
|
10
|
+
loops = ENV['LOOPS'].to_i
|
|
11
|
+
url = ARGV.first || (raise "requires URL!")
|
|
12
|
+
|
|
13
|
+
loops.times do |i|
|
|
14
|
+
puts "On loop #{i}" if i % 10 == 0
|
|
15
|
+
results = []
|
|
16
|
+
5.times do
|
|
17
|
+
results << klass.get(url)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# fire requests
|
|
21
|
+
results[0].code
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
puts "Ran #{loops} loops on #{url}!"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<result_set>
|
|
2
|
+
<ttl>20</ttl>
|
|
3
|
+
<result>
|
|
4
|
+
<id>1</id>
|
|
5
|
+
<name>hello</name>
|
|
6
|
+
<description>
|
|
7
|
+
this is a long description for a text field of some kind.
|
|
8
|
+
this is a long description for a text field of some kind.
|
|
9
|
+
this is a long description for a text field of some kind.
|
|
10
|
+
this is a long description for a text field of some kind.
|
|
11
|
+
this is a long description for a text field of some kind.
|
|
12
|
+
this is a long description for a text field of some kind.
|
|
13
|
+
this is a long description for a text field of some kind.
|
|
14
|
+
this is a long description for a text field of some kind.
|
|
15
|
+
this is a long description for a text field of some kind.
|
|
16
|
+
this is a long description for a text field of some kind.
|
|
17
|
+
this is a long description for a text field of some kind.
|
|
18
|
+
this is a long description for a text field of some kind.
|
|
19
|
+
this is a long description for a text field of some kind.
|
|
20
|
+
</description>
|
|
21
|
+
</result>
|
|
22
|
+
<result>
|
|
23
|
+
<id>2</id>
|
|
24
|
+
<name>hello</name>
|
|
25
|
+
<description>
|
|
26
|
+
this is a long description for a text field of some kind.
|
|
27
|
+
this is a long description for a text field of some kind.
|
|
28
|
+
this is a long description for a text field of some kind.
|
|
29
|
+
this is a long description for a text field of some kind.
|
|
30
|
+
this is a long description for a text field of some kind.
|
|
31
|
+
this is a long description for a text field of some kind.
|
|
32
|
+
this is a long description for a text field of some kind.
|
|
33
|
+
this is a long description for a text field of some kind.
|
|
34
|
+
this is a long description for a text field of some kind.
|
|
35
|
+
this is a long description for a text field of some kind.
|
|
36
|
+
this is a long description for a text field of some kind.
|
|
37
|
+
this is a long description for a text field of some kind.
|
|
38
|
+
this is a long description for a text field of some kind.
|
|
39
|
+
</description>
|
|
40
|
+
</result>
|
|
41
|
+
<result>
|
|
42
|
+
<id>3</id>
|
|
43
|
+
<name>hello</name>
|
|
44
|
+
<description>
|
|
45
|
+
this is a long description for a text field of some kind.
|
|
46
|
+
this is a long description for a text field of some kind.
|
|
47
|
+
this is a long description for a text field of some kind.
|
|
48
|
+
this is a long description for a text field of some kind.
|
|
49
|
+
this is a long description for a text field of some kind.
|
|
50
|
+
this is a long description for a text field of some kind.
|
|
51
|
+
this is a long description for a text field of some kind.
|
|
52
|
+
this is a long description for a text field of some kind.
|
|
53
|
+
this is a long description for a text field of some kind.
|
|
54
|
+
this is a long description for a text field of some kind.
|
|
55
|
+
this is a long description for a text field of some kind.
|
|
56
|
+
this is a long description for a text field of some kind.
|
|
57
|
+
this is a long description for a text field of some kind.
|
|
58
|
+
</description>
|
|
59
|
+
</result>
|
|
60
|
+
</result_set>
|
data/spec/servers/app.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
require 'rubygems'
|
|
3
3
|
require 'sinatra'
|
|
4
4
|
require 'json'
|
|
5
|
+
require 'zlib'
|
|
5
6
|
|
|
6
7
|
@@fail_count = 0
|
|
7
8
|
get '/fail/:number' do
|
|
@@ -43,11 +44,21 @@ get '/auth_ntlm' do
|
|
|
43
44
|
# we're just checking for the existence if NTLM auth header here. It's validation
|
|
44
45
|
# is too troublesome and really doesn't bother is much, it's up to libcurl to make
|
|
45
46
|
# it valid
|
|
47
|
+
response['WWW-Authenticate'] = 'NTLM'
|
|
46
48
|
is_ntlm_auth = /^NTLM/ =~ request.env['HTTP_AUTHORIZATION']
|
|
47
49
|
true if is_ntlm_auth
|
|
48
50
|
throw(:halt, [401, "Not authorized\n"]) if !is_ntlm_auth
|
|
49
51
|
end
|
|
50
52
|
|
|
53
|
+
get '/gzipped' do
|
|
54
|
+
req_env = request.env.to_json
|
|
55
|
+
z = Zlib::Deflate.new
|
|
56
|
+
gzipped_env = z.deflate(req_env, Zlib::FINISH)
|
|
57
|
+
z.close
|
|
58
|
+
response['Content-Encoding'] = 'gzip'
|
|
59
|
+
gzipped_env
|
|
60
|
+
end
|
|
61
|
+
|
|
51
62
|
get '/**' do
|
|
52
63
|
sleep params["delay"].to_i if params.has_key?("delay")
|
|
53
64
|
request.env.merge!(:body => request.body.read).to_json
|
data/spec/typhoeus/easy_spec.rb
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
|
2
2
|
|
|
3
|
-
describe Typhoeus::Easy do
|
|
3
|
+
describe Typhoeus::Easy do
|
|
4
|
+
describe "#supports_zlib" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@easy = Typhoeus::Easy.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should return true if the version string has zlib" do
|
|
10
|
+
@easy.stub!(:curl_version).and_return("libcurl/7.20.0 OpenSSL/0.9.8l zlib/1.2.3 libidn/1.16")
|
|
11
|
+
@easy.supports_zlib?.should be_true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should return false if the version string doesn't have zlib" do
|
|
15
|
+
@easy.stub!(:curl_version).and_return("libcurl/7.20.0 OpenSSL/0.9.8l libidn/1.16")
|
|
16
|
+
@easy.supports_zlib?.should be_false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
4
20
|
describe "options" do
|
|
5
21
|
it "should not follow redirects if not instructed to" do
|
|
6
22
|
e = Typhoeus::Easy.new
|
|
@@ -101,6 +117,14 @@ describe Typhoeus::Easy do
|
|
|
101
117
|
end
|
|
102
118
|
end
|
|
103
119
|
|
|
120
|
+
describe "purge" do
|
|
121
|
+
it "should set custom request to purge" do
|
|
122
|
+
easy = Typhoeus::Easy.new
|
|
123
|
+
easy.should_receive(:set_option).with(Typhoeus::Easy::OPTION_VALUES[:CURLOPT_CUSTOMREQUEST], "PURGE").once
|
|
124
|
+
easy.method = :purge
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
104
128
|
describe "head" do
|
|
105
129
|
it "should perform a head" do
|
|
106
130
|
easy = Typhoeus::Easy.new
|
|
@@ -208,5 +232,18 @@ describe Typhoeus::Easy do
|
|
|
208
232
|
easy.response_code.should == 200
|
|
209
233
|
easy.response_body.should include("this is a body!")
|
|
210
234
|
end
|
|
211
|
-
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
describe "encoding/compression support" do
|
|
238
|
+
|
|
239
|
+
it "should send valid encoding headers and decode the response" do
|
|
240
|
+
easy = Typhoeus::Easy.new
|
|
241
|
+
easy.url = "http://localhost:3002/gzipped"
|
|
242
|
+
easy.method = :get
|
|
243
|
+
easy.perform
|
|
244
|
+
easy.response_code.should == 200
|
|
245
|
+
JSON.parse(easy.response_body)["HTTP_ACCEPT_ENCODING"].should == "deflate, gzip"
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
end
|
|
212
249
|
end
|