typhoeus 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +4 -0
  4. data/.travis.yml +10 -0
  5. data/CHANGELOG.md +7 -1
  6. data/CONTRIBUTING.md +16 -0
  7. data/Guardfile +9 -0
  8. data/README.md +303 -1
  9. data/UPGRADE.md +55 -0
  10. data/lib/rack/typhoeus/middleware/params_decoder.rb +1 -1
  11. data/lib/rack/typhoeus/middleware/params_decoder/helper.rb +6 -2
  12. data/lib/typhoeus/adapters/faraday.rb +4 -1
  13. data/lib/typhoeus/easy_factory.rb +36 -15
  14. data/lib/typhoeus/hydra/before.rb +2 -1
  15. data/lib/typhoeus/hydra/cacheable.rb +1 -0
  16. data/lib/typhoeus/hydra/memoizable.rb +1 -0
  17. data/lib/typhoeus/hydra/queueable.rb +15 -3
  18. data/lib/typhoeus/request.rb +6 -2
  19. data/lib/typhoeus/request/marshal.rb +3 -2
  20. data/lib/typhoeus/response/informations.rb +4 -0
  21. data/lib/typhoeus/version.rb +1 -1
  22. data/perf/profile.rb +14 -0
  23. data/perf/vs_nethttp.rb +64 -0
  24. data/spec/rack/typhoeus/middleware/params_decoder/helper_spec.rb +132 -0
  25. data/spec/rack/typhoeus/middleware/params_decoder_spec.rb +31 -0
  26. data/spec/spec_helper.rb +35 -0
  27. data/spec/support/localhost_server.rb +94 -0
  28. data/spec/support/server.rb +108 -0
  29. data/spec/typhoeus/adapters/faraday_spec.rb +245 -0
  30. data/spec/typhoeus/config_spec.rb +15 -0
  31. data/spec/typhoeus/easy_factory_spec.rb +96 -0
  32. data/spec/typhoeus/errors/no_stub_spec.rb +13 -0
  33. data/spec/typhoeus/expectation_spec.rb +273 -0
  34. data/spec/typhoeus/hydra/addable_spec.rb +22 -0
  35. data/spec/typhoeus/hydra/before_spec.rb +97 -0
  36. data/spec/typhoeus/hydra/block_connection_spec.rb +18 -0
  37. data/spec/typhoeus/hydra/cacheable_spec.rb +68 -0
  38. data/spec/typhoeus/hydra/memoizable_spec.rb +53 -0
  39. data/spec/typhoeus/hydra/queueable_spec.rb +34 -0
  40. data/spec/typhoeus/hydra/runnable_spec.rb +155 -0
  41. data/spec/typhoeus/hydra/stubbable_spec.rb +28 -0
  42. data/spec/typhoeus/hydra_spec.rb +26 -0
  43. data/spec/typhoeus/pool_spec.rb +79 -0
  44. data/spec/typhoeus/request/actions_spec.rb +19 -0
  45. data/spec/typhoeus/request/before_spec.rb +92 -0
  46. data/spec/typhoeus/request/block_connection_spec.rb +75 -0
  47. data/spec/typhoeus/request/cacheable_spec.rb +80 -0
  48. data/spec/typhoeus/request/callbacks_spec.rb +91 -0
  49. data/spec/typhoeus/request/marshal_spec.rb +62 -0
  50. data/spec/typhoeus/request/memoizable_spec.rb +34 -0
  51. data/spec/typhoeus/request/operations_spec.rb +70 -0
  52. data/spec/typhoeus/request/responseable_spec.rb +13 -0
  53. data/spec/typhoeus/request/stubbable_spec.rb +27 -0
  54. data/spec/typhoeus/request_spec.rb +131 -0
  55. data/spec/typhoeus/response/header_spec.rb +97 -0
  56. data/spec/typhoeus/response/informations_spec.rb +218 -0
  57. data/spec/typhoeus/response/status_spec.rb +218 -0
  58. data/spec/typhoeus/response_spec.rb +81 -0
  59. data/spec/typhoeus_spec.rb +105 -0
  60. data/typhoeus.gemspec +25 -0
  61. metadata +101 -27
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Rack::Typhoeus::Middleware::ParamsDecoder" do
4
+
5
+ before(:all) do
6
+ require "rack/typhoeus"
7
+ end
8
+
9
+ let(:app) do
10
+ stub
11
+ end
12
+
13
+ let(:env) do
14
+ stub
15
+ end
16
+
17
+ let(:klass) do
18
+ Rack::Typhoeus::Middleware::ParamsDecoder
19
+ end
20
+
21
+ describe "#call" do
22
+ end
23
+
24
+ context "when requesting" do
25
+ let(:response) { Typhoeus.get("localhost:3001", :params => {:x => [:a]}) }
26
+
27
+ it "transforms parameters" do
28
+ expect(response.body).to include("query_hash\":{\"x\":[\"a\"]}")
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
3
+
4
+ require "bundler"
5
+ Bundler.setup
6
+ require "typhoeus"
7
+ require "rspec"
8
+
9
+ if defined? require_relative
10
+ require_relative 'support/localhost_server.rb'
11
+ require_relative 'support/server.rb'
12
+ else
13
+ require 'support/localhost_server.rb'
14
+ require 'support/server.rb'
15
+ end
16
+
17
+ RSpec.configure do |config|
18
+ config.order = :rand
19
+
20
+ config.before(:suite) do
21
+ LocalhostServer.new(TESTSERVER.new, 3001)
22
+ end
23
+
24
+ config.after do
25
+ Typhoeus::Pool.clear
26
+ Typhoeus::Expectation.clear
27
+ Typhoeus.before.clear
28
+ Typhoeus.on_complete.clear
29
+ Typhoeus.on_success.clear
30
+ Typhoeus.on_failure.clear
31
+ Typhoeus::Config.verbose = false
32
+ Typhoeus::Config.block_connection = false
33
+ Typhoeus::Config.memoize = false
34
+ end
35
+ end
@@ -0,0 +1,94 @@
1
+ require 'rack'
2
+ require 'rack/handler/webrick'
3
+ require 'net/http'
4
+
5
+ # The code for this is inspired by Capybara's server:
6
+ # http://github.com/jnicklas/capybara/blob/0.3.9/lib/capybara/server.rb
7
+ class LocalhostServer
8
+ READY_MESSAGE = "Server ready"
9
+
10
+ class Identify
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ if env["PATH_INFO"] == "/__identify__"
17
+ [200, {}, [LocalhostServer::READY_MESSAGE]]
18
+ else
19
+ @app.call(env)
20
+ end
21
+ end
22
+ end
23
+
24
+ attr_reader :port
25
+
26
+ def initialize(rack_app, port = nil)
27
+ @port = port || find_available_port
28
+ @rack_app = rack_app
29
+ concurrently { boot }
30
+ wait_until(10, "Boot failed.") { booted? }
31
+ end
32
+
33
+ private
34
+
35
+ def find_available_port
36
+ server = TCPServer.new('127.0.0.1', 0)
37
+ server.addr[1]
38
+ ensure
39
+ server.close if server
40
+ end
41
+
42
+ def boot
43
+ # Use WEBrick since it's part of the ruby standard library and is available on all ruby interpreters.
44
+ options = { :Port => port }
45
+ options.merge!(:AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new)) unless ENV['VERBOSE_SERVER']
46
+ Rack::Handler::WEBrick.run(Identify.new(@rack_app), options)
47
+ end
48
+
49
+ def booted?
50
+ res = ::Net::HTTP.get_response("localhost", '/__identify__', port)
51
+ if res.is_a?(::Net::HTTPSuccess) or res.is_a?(::Net::HTTPRedirection)
52
+ return res.body == READY_MESSAGE
53
+ end
54
+ rescue Errno::ECONNREFUSED, Errno::EBADF
55
+ return false
56
+ end
57
+
58
+ def concurrently
59
+ if should_use_subprocess?
60
+ pid = Process.fork do
61
+ trap(:INT) { ::Rack::Handler::WEBrick.shutdown }
62
+ yield
63
+ exit # manually exit; otherwise this sub-process will re-run the specs that haven't run yet.
64
+ end
65
+
66
+ at_exit do
67
+ Process.kill('INT', pid)
68
+ begin
69
+ Process.wait(pid)
70
+ rescue Errno::ECHILD
71
+ # ignore this error...I think it means the child process has already exited.
72
+ end
73
+ end
74
+ else
75
+ Thread.new { yield }
76
+ end
77
+ end
78
+
79
+ def should_use_subprocess?
80
+ # !ENV['THREADED']
81
+ false
82
+ end
83
+
84
+ def wait_until(timeout, error_message, &block)
85
+ start_time = Time.now
86
+
87
+ while true
88
+ return if yield
89
+ raise TimeoutError.new(error_message) if (Time.now - start_time) > timeout
90
+ sleep(0.05)
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+ require 'json'
3
+ require 'zlib'
4
+ require 'sinatra/base'
5
+ require 'rack/typhoeus'
6
+
7
+ TESTSERVER = Sinatra.new do
8
+ set :logging, false
9
+ use Rack::Typhoeus::Middleware::ParamsDecoder
10
+
11
+ fail_count = 0
12
+
13
+ post '/file' do
14
+ {
15
+ 'content-type' => params[:file][:type],
16
+ 'filename' => params[:file][:filename],
17
+ 'content' => params[:file][:tempfile].read,
18
+ 'request-content-type' => request.env['CONTENT_TYPE']
19
+ }.to_json
20
+ end
21
+
22
+ get '/multiple-headers' do
23
+ [200, { 'Set-Cookie' => %w[ foo bar ], 'Content-Type' => 'text/plain' }, ['']]
24
+ end
25
+
26
+ get '/fail/:number' do
27
+ if fail_count >= params[:number].to_i
28
+ "ok"
29
+ else
30
+ fail_count += 1
31
+ error 500, "oh noes!"
32
+ end
33
+ end
34
+
35
+ get '/fail_forever' do
36
+ error 500, "oh noes!"
37
+ end
38
+
39
+ get '/redirect' do
40
+ redirect '/'
41
+ end
42
+
43
+ get '/bad_redirect' do
44
+ redirect '/bad_redirect'
45
+ end
46
+
47
+ get '/auth_basic/:username/:password' do
48
+ @auth ||= Rack::Auth::Basic::Request.new(request.env)
49
+ # Check that we've got a basic auth, and that it's credentials match the ones
50
+ # provided in the request
51
+ if @auth.provided? && @auth.basic? && @auth.credentials == [ params[:username], params[:password] ]
52
+ # auth is valid - confirm it
53
+ true
54
+ else
55
+ # invalid auth - request the authentication
56
+ response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth")
57
+ throw(:halt, [401, "Not authorized\n"])
58
+ end
59
+ end
60
+
61
+ get '/auth_ntlm' do
62
+ # we're just checking for the existence if NTLM auth header here. It's validation
63
+ # is too troublesome and really doesn't bother is much, it's up to libcurl to make
64
+ # it valid
65
+ response['WWW-Authenticate'] = 'NTLM'
66
+ is_ntlm_auth = /^NTLM/ =~ request.env['HTTP_AUTHORIZATION']
67
+ true if is_ntlm_auth
68
+ throw(:halt, [401, "Not authorized\n"]) if !is_ntlm_auth
69
+ end
70
+
71
+ get '/gzipped' do
72
+ req_env = request.env.to_json
73
+ z = Zlib::Deflate.new
74
+ gzipped_env = z.deflate(req_env, Zlib::FINISH)
75
+ z.close
76
+ response['Content-Encoding'] = 'gzip'
77
+ gzipped_env
78
+ end
79
+
80
+ get '/**' do
81
+ sleep params["delay"].to_i if params.has_key?("delay")
82
+ request.env.merge!(:body => request.body.read).to_json
83
+ end
84
+
85
+ head '/**' do
86
+ sleep params["delay"].to_i if params.has_key?("delay")
87
+ end
88
+
89
+ put '/**' do
90
+ request.env.merge!(:body => request.body.read).to_json
91
+ end
92
+
93
+ post '/**' do
94
+ request.env.merge!(:body => request.body.read).to_json
95
+ end
96
+
97
+ delete '/**' do
98
+ request.env.merge!(:body => request.body.read).to_json
99
+ end
100
+
101
+ patch '/**' do
102
+ request.env.merge!(:body => request.body.read).to_json
103
+ end
104
+
105
+ options '/**' do
106
+ request.env.merge!(:body => request.body.read).to_json
107
+ end
108
+ end
@@ -0,0 +1,245 @@
1
+ require 'spec_helper'
2
+ require 'typhoeus/adapters/faraday'
3
+
4
+ describe Faraday::Adapter::Typhoeus do
5
+ let(:base_url) { "http://localhost:3001" }
6
+ let(:adapter) { described_class.new }
7
+ let(:request) { Typhoeus::Request.new(base_url) }
8
+ let(:conn) do
9
+ Faraday.new(:url => base_url) do |faraday|
10
+ faraday.adapter :typhoeus
11
+ end
12
+ end
13
+ let(:response) { conn.get("/") }
14
+
15
+ context "when parallel" do
16
+ it "returns a faraday response" do
17
+ response = nil
18
+ conn.in_parallel { response = conn.get("/") }
19
+ expect(response).to be_a(Faraday::Response)
20
+ end
21
+
22
+ it "succeeds" do
23
+ response = nil
24
+ conn.in_parallel { response = conn.get("/") }
25
+ expect(response.status).to be(200)
26
+ end
27
+ end
28
+
29
+ context "when not parallel" do
30
+ it "returns a faraday response" do
31
+ expect(response).to be_a(Faraday::Response)
32
+ end
33
+
34
+ it "succeeds" do
35
+ expect(response.status).to be(200)
36
+ end
37
+ end
38
+
39
+ describe "#perform_request" do
40
+ let(:env) { {} }
41
+
42
+ context "when body" do
43
+ let(:env) { { :body => double(:read => "body") } }
44
+
45
+ it "reads body" do
46
+ expect(adapter.method(:read_body).call(env)).to eq("body")
47
+ end
48
+ end
49
+
50
+ context "parallel_manager" do
51
+ context "when given" do
52
+ let(:env) { { :parallel_manager => double(:queue => true), :ssl => {}, :request => {} } }
53
+
54
+ it "uses" do
55
+ adapter.method(:perform_request).call(env)
56
+ end
57
+ end
58
+
59
+ context "when not given" do
60
+ let(:env) { { :method => :get, :ssl => {}, :request => {} } }
61
+
62
+ it "falls back to single" do
63
+ Typhoeus::Request.should_receive(:new).and_return(double(:options => {}, :on_complete => [], :run => true))
64
+ adapter.method(:perform_request).call(env)
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#request" do
71
+ let(:env) do
72
+ { :url => "url", :method => :get, :body => "body", :request_headers => {}, :ssl => {}, :request => {} }
73
+ end
74
+
75
+ let(:request) { adapter.method(:request).call(env) }
76
+
77
+ it "returns request" do
78
+ expect(request).to be_a(Typhoeus::Request)
79
+ end
80
+
81
+ it "sets url" do
82
+ expect(request.base_url).to eq("url")
83
+ end
84
+
85
+ it "sets http method" do
86
+ expect(request.original_options[:method]).to eq(:get)
87
+ end
88
+
89
+ it "sets body" do
90
+ expect(request.original_options[:body]).to eq("body")
91
+ end
92
+
93
+ it "sets headers" do
94
+ expect(request.original_options[:headers]).to eq({})
95
+ end
96
+
97
+ it "sets on_complete callback" do
98
+ expect(request.on_complete).to have(1).items
99
+ end
100
+ end
101
+
102
+ describe "#configure_socket" do
103
+ let(:env) { { :request => { :bind => { :host => "interface" } } } }
104
+
105
+ before { adapter.method(:configure_socket).call(request, env) }
106
+
107
+ context "when host" do
108
+ it "sets interface" do
109
+ expect(request.options[:interface]).to eq("interface")
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "#configure_timeout" do
115
+ before { adapter.method(:configure_timeout).call(request, env) }
116
+
117
+ context "when timeout" do
118
+ let(:env) { { :request => { :timeout => 1 } } }
119
+
120
+ it "sets timeout_ms" do
121
+ expect(request.options[:timeout_ms]).to eq(1000)
122
+ end
123
+ end
124
+
125
+ context "when open_timeout" do
126
+ let(:env) { { :request => { :open_timeout => 1 } } }
127
+
128
+ it "sets connecttimeout_ms" do
129
+ expect(request.options[:connecttimeout_ms]).to eq(1000)
130
+ end
131
+ end
132
+ end
133
+
134
+ describe "#configure_proxy" do
135
+ before { adapter.method(:configure_proxy).call(request, env) }
136
+
137
+ context "when proxy" do
138
+ let(:env) { { :request => { :proxy => { :uri => double(:host => "localhost", :port => "3001") } } } }
139
+
140
+ it "sets proxy" do
141
+ expect(request.options[:proxy]).to eq("localhost:3001")
142
+ end
143
+
144
+ context "when username and password" do
145
+ let(:env) do
146
+ { :request => { :proxy => {
147
+ :uri => double(:host => :a, :port => :b),
148
+ :username => "a",
149
+ :password => "b"
150
+ } } }
151
+ end
152
+
153
+ it "sets proxyuserpwd" do
154
+ expect(request.options[:proxyuserpwd]).to eq("a:b")
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ describe "#configure_ssl" do
161
+ before { adapter.method(:configure_ssl).call(request, env) }
162
+
163
+ context "when version" do
164
+ let(:env) { { :ssl => { :version => "a" } } }
165
+
166
+ it "sets sslversion" do
167
+ expect(request.options[:sslversion]).to eq("a")
168
+ end
169
+ end
170
+
171
+ context "when client_cert" do
172
+ let(:env) { { :ssl => { :client_cert => "a" } } }
173
+
174
+ it "sets sslcert" do
175
+ expect(request.options[:sslcert]).to eq("a")
176
+ end
177
+ end
178
+
179
+ context "when client_key" do
180
+ let(:env) { { :ssl => { :client_key => "a" } } }
181
+
182
+ it "sets sslkey" do
183
+ expect(request.options[:sslkey]).to eq("a")
184
+ end
185
+ end
186
+
187
+ context "when ca_file" do
188
+ let(:env) { { :ssl => { :ca_file => "a" } } }
189
+
190
+ it "sets cainfo" do
191
+ expect(request.options[:cainfo]).to eq("a")
192
+ end
193
+ end
194
+
195
+ context "when ca_path" do
196
+ let(:env) { { :ssl => { :ca_path => "a" } } }
197
+
198
+ it "sets capath" do
199
+ expect(request.options[:capath]).to eq("a")
200
+ end
201
+ end
202
+
203
+ context "when verify is false" do
204
+ let(:env) { { :ssl => { :verify => false } } }
205
+
206
+ it "sets ssl_verifyhost to 0" do
207
+ expect(request.options[:ssl_verifyhost]).to eq(0)
208
+ end
209
+
210
+ it "sets ssl_verifypeer to false" do
211
+ expect(request.options[:ssl_verifypeer]).to be_false
212
+ end
213
+ end
214
+
215
+ context "when verify is true" do
216
+ let(:env) { { :ssl => { :verify => true } } }
217
+
218
+ it "sets ssl_verifyhost to 2" do
219
+ expect(request.options[:ssl_verifyhost]).to eq(2)
220
+ end
221
+
222
+ it "sets ssl_verifypeer to true" do
223
+ expect(request.options[:ssl_verifypeer]).to be_true
224
+ end
225
+ end
226
+ end
227
+
228
+ describe "#parallel?" do
229
+ context "when parallel_manager" do
230
+ let(:env) { { :parallel_manager => true } }
231
+
232
+ it "returns true" do
233
+ expect(adapter.method(:parallel?).call(env)).to be_true
234
+ end
235
+ end
236
+
237
+ context "when no parallel_manager" do
238
+ let(:env) { { :parallel_manager => nil } }
239
+
240
+ it "returns false" do
241
+ expect(adapter.method(:parallel?).call(env)).to be_false
242
+ end
243
+ end
244
+ end
245
+ end