arachni-typhoeus 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG.markdown +43 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +30 -0
  5. data/README.textile +6 -0
  6. data/Rakefile +40 -0
  7. data/VERSION +1 -0
  8. data/benchmarks/profile.rb +25 -0
  9. data/benchmarks/vs_nethttp.rb +35 -0
  10. data/examples/twitter.rb +21 -0
  11. data/ext/typhoeus/.gitignore +7 -0
  12. data/ext/typhoeus/extconf.rb +65 -0
  13. data/ext/typhoeus/native.c +11 -0
  14. data/ext/typhoeus/native.h +21 -0
  15. data/ext/typhoeus/typhoeus_easy.c +220 -0
  16. data/ext/typhoeus/typhoeus_easy.h +19 -0
  17. data/ext/typhoeus/typhoeus_multi.c +211 -0
  18. data/ext/typhoeus/typhoeus_multi.h +16 -0
  19. data/lib/typhoeus.rb +58 -0
  20. data/lib/typhoeus/.gitignore +1 -0
  21. data/lib/typhoeus/easy.rb +366 -0
  22. data/lib/typhoeus/filter.rb +28 -0
  23. data/lib/typhoeus/hydra.rb +245 -0
  24. data/lib/typhoeus/hydra/callbacks.rb +24 -0
  25. data/lib/typhoeus/hydra/connect_options.rb +61 -0
  26. data/lib/typhoeus/hydra/stubbing.rb +52 -0
  27. data/lib/typhoeus/hydra_mock.rb +131 -0
  28. data/lib/typhoeus/multi.rb +37 -0
  29. data/lib/typhoeus/normalized_header_hash.rb +58 -0
  30. data/lib/typhoeus/remote.rb +306 -0
  31. data/lib/typhoeus/remote_method.rb +108 -0
  32. data/lib/typhoeus/remote_proxy_object.rb +50 -0
  33. data/lib/typhoeus/request.rb +210 -0
  34. data/lib/typhoeus/response.rb +91 -0
  35. data/lib/typhoeus/service.rb +20 -0
  36. data/lib/typhoeus/utils.rb +24 -0
  37. data/profilers/valgrind.rb +24 -0
  38. data/spec/fixtures/result_set.xml +60 -0
  39. data/spec/servers/app.rb +84 -0
  40. data/spec/spec.opts +2 -0
  41. data/spec/spec_helper.rb +11 -0
  42. data/spec/typhoeus/easy_spec.rb +284 -0
  43. data/spec/typhoeus/filter_spec.rb +35 -0
  44. data/spec/typhoeus/hydra_mock_spec.rb +300 -0
  45. data/spec/typhoeus/hydra_spec.rb +526 -0
  46. data/spec/typhoeus/multi_spec.rb +74 -0
  47. data/spec/typhoeus/normalized_header_hash_spec.rb +41 -0
  48. data/spec/typhoeus/remote_method_spec.rb +141 -0
  49. data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
  50. data/spec/typhoeus/remote_spec.rb +695 -0
  51. data/spec/typhoeus/request_spec.rb +276 -0
  52. data/spec/typhoeus/response_spec.rb +151 -0
  53. data/spec/typhoeus/utils_spec.rb +22 -0
  54. data/typhoeus.gemspec +123 -0
  55. metadata +196 -0
@@ -0,0 +1,276 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Typhoeus::Request do
4
+ describe "#inspect" do
5
+ before(:each) do
6
+ @request = Typhoeus::Request.new('http://www.google.com/',
7
+ :body => "a=1&b=2",
8
+ :params => { :c => 'ok' },
9
+ :method => :get,
10
+ :headers => { 'Content-Type' => 'text/html' })
11
+ end
12
+
13
+ it "should dump out the URI" do
14
+ @request.inspect.should =~ /http:\/\/www\.google\.com/
15
+ end
16
+
17
+ it "should dump out the body" do
18
+ @request.inspect.should =~ /a=1&b=2/
19
+ end
20
+
21
+ it "should dump params" do
22
+ @request.inspect.should =~ /:c\s*=>\s*"ok"/
23
+ end
24
+
25
+ it "should dump the method" do
26
+ @request.inspect.should =~ /:get/
27
+ end
28
+
29
+ it "should dump out headers" do
30
+ @request.inspect.should =~ /"Content-Type"\s*=>\s*"text\/html"/
31
+ end
32
+ end
33
+
34
+ describe "#localhost?" do
35
+ %w(localhost 127.0.0.1 0.0.0.0).each do |host|
36
+ it "should be true for the #{host} host" do
37
+ req = Typhoeus::Request.new("http://#{host}")
38
+ req.should be_localhost
39
+ end
40
+ end
41
+
42
+ it "should be false for other domains" do
43
+ req = Typhoeus::Request.new("http://google.com")
44
+ req.should_not be_localhost
45
+ end
46
+ end
47
+
48
+ describe "#params_string" do
49
+ it "should dump a sorted string" do
50
+ request = Typhoeus::Request.new(
51
+ "http://google.com",
52
+ :params => {
53
+ 'b' => 'fdsa',
54
+ 'a' => 'jlk',
55
+ 'c' => '789'
56
+ }
57
+ )
58
+
59
+ request.params_string.should == "a=jlk&b=fdsa&c=789"
60
+ end
61
+
62
+ it "should accept symboled keys" do
63
+ request = Typhoeus::Request.new('http://google.com',
64
+ :params => {
65
+ :b => 'fdsa',
66
+ :a => 'jlk',
67
+ :c => '789'
68
+ })
69
+ request.params_string.should == "a=jlk&b=fdsa&c=789"
70
+ end
71
+
72
+ it "should translate params with values that are arrays to the proper format" do
73
+ request = Typhoeus::Request.new('http://google.com',
74
+ :params => {
75
+ :a => ['789','2434']
76
+ })
77
+ request.params_string.should == "a[]=789&a[]=2434"
78
+ end
79
+ end
80
+
81
+ describe "quick request methods" do
82
+ it "can run a GET synchronously" do
83
+ response = Typhoeus::Request.get("http://localhost:3000", :params => {:q => "hi"}, :headers => {:foo => "bar"})
84
+ response.code.should == 200
85
+ JSON.parse(response.body)["REQUEST_METHOD"].should == "GET"
86
+ end
87
+
88
+ it "can run a POST synchronously" do
89
+ response = Typhoeus::Request.post("http://localhost:3000", :params => {:q => "hi"}, :headers => {:foo => "bar"})
90
+ response.code.should == 200
91
+ json = JSON.parse(response.body)
92
+ json["REQUEST_METHOD"].should == "POST"
93
+ json["rack.request.query_hash"]["q"].should == "hi"
94
+ end
95
+
96
+ it "can run a PUT synchronously" do
97
+ response = Typhoeus::Request.put("http://localhost:3000", :params => {:q => "hi"}, :headers => {:foo => "bar"})
98
+ response.code.should == 200
99
+ JSON.parse(response.body)["REQUEST_METHOD"].should == "PUT"
100
+ end
101
+
102
+ it "can run a DELETE synchronously" do
103
+ response = Typhoeus::Request.delete("http://localhost:3000", :params => {:q => "hi"}, :headers => {:foo => "bar"})
104
+ response.code.should == 200
105
+ JSON.parse(response.body)["REQUEST_METHOD"].should == "DELETE"
106
+ end
107
+ end
108
+
109
+ it "takes url as the first argument" do
110
+ Typhoeus::Request.new("http://localhost:3000").url.should == "http://localhost:3000"
111
+ end
112
+
113
+ it "should parse the host from the url" do
114
+ Typhoeus::Request.new("http://localhost:3000/whatever?hi=foo").host.should == "http://localhost:3000"
115
+ Typhoeus::Request.new("http://localhost:3000?hi=foo").host.should == "http://localhost:3000"
116
+ Typhoeus::Request.new("http://localhost:3000").host.should == "http://localhost:3000"
117
+ end
118
+
119
+ it "takes method as an option" do
120
+ Typhoeus::Request.new("http://localhost:3000", :method => :get).method.should == :get
121
+ end
122
+
123
+ it "takes headers as an option" do
124
+ headers = {:foo => :bar}
125
+ request = Typhoeus::Request.new("http://localhost:3000", :headers => headers)
126
+ request.headers.should == headers
127
+ end
128
+
129
+ it "takes params as an option and adds them to the url" do
130
+ Typhoeus::Request.new("http://localhost:3000", :params => {:foo => "bar"}).url.should == "http://localhost:3000?foo=bar"
131
+ end
132
+
133
+ it "takes request body as an option" do
134
+ Typhoeus::Request.new("http://localhost:3000", :body => "whatever").body.should == "whatever"
135
+ end
136
+
137
+ it "takes timeout as an option" do
138
+ Typhoeus::Request.new("http://localhost:3000", :timeout => 10).timeout.should == 10
139
+ end
140
+
141
+ it "takes cache_timeout as an option" do
142
+ Typhoeus::Request.new("http://localhost:3000", :cache_timeout => 60).cache_timeout.should == 60
143
+ end
144
+
145
+ it "takes follow_location as an option" do
146
+ Typhoeus::Request.new("http://localhost:3000", :follow_location => true).follow_location.should == true
147
+ end
148
+
149
+ it "takes max_redirects as an option" do
150
+ Typhoeus::Request.new("http://localhost:3000", :max_redirects => 10).max_redirects.should == 10
151
+ end
152
+
153
+ it "has the associated response object" do
154
+ request = Typhoeus::Request.new("http://localhost:3000")
155
+ request.response = :foo
156
+ request.response.should == :foo
157
+ end
158
+
159
+ it "has an on_complete handler that is called when the request is completed" do
160
+ request = Typhoeus::Request.new("http://localhost:3000")
161
+ foo = nil
162
+ request.on_complete do |response|
163
+ foo = response
164
+ end
165
+ request.response = :bar
166
+ request.call_handlers
167
+ foo.should == :bar
168
+ end
169
+
170
+ it "has an on_complete setter" do
171
+ foo = nil
172
+ proc = Proc.new {|response| foo = response}
173
+ request = Typhoeus::Request.new("http://localhost:3000")
174
+ request.on_complete = proc
175
+ request.response = :bar
176
+ request.call_handlers
177
+ foo.should == :bar
178
+ end
179
+
180
+ it "stores the handled response that is the return value from the on_complete block" do
181
+ request = Typhoeus::Request.new("http://localhost:3000")
182
+ request.on_complete do |response|
183
+ "handled"
184
+ end
185
+ request.response = :bar
186
+ request.call_handlers
187
+ request.handled_response.should == "handled"
188
+ end
189
+
190
+ it "has an after_complete handler that recieves what on_complete returns" do
191
+ request = Typhoeus::Request.new("http://localhost:3000")
192
+ request.on_complete do |response|
193
+ "handled"
194
+ end
195
+ good = nil
196
+ request.after_complete do |object|
197
+ good = object == "handled"
198
+ end
199
+ request.call_handlers
200
+ good.should be_true
201
+ end
202
+
203
+ it "has an after_complete setter" do
204
+ request = Typhoeus::Request.new("http://localhost:3000")
205
+ request.on_complete do |response|
206
+ "handled"
207
+ end
208
+ good = nil
209
+ proc = Proc.new {|object| good = object == "handled"}
210
+ request.after_complete = proc
211
+
212
+ request.call_handlers
213
+ good.should be_true
214
+ end
215
+
216
+ describe "time info" do
217
+ it "should have time" do
218
+ response = Typhoeus::Request.get("http://localhost:3000")
219
+ response.time.should > 0
220
+ end
221
+
222
+ it "should have connect time" do
223
+ response = Typhoeus::Request.get("http://localhost:3000")
224
+ response.connect_time.should > 0
225
+ end
226
+
227
+ it "should have app connect time" do
228
+ response = Typhoeus::Request.get("http://localhost:3000")
229
+ response.app_connect_time.should > 0
230
+ end
231
+
232
+ it "should have start transfer time" do
233
+ response = Typhoeus::Request.get("http://localhost:3000")
234
+ response.start_transfer_time.should > 0
235
+ end
236
+
237
+ it "should have pre-transfer time" do
238
+ response = Typhoeus::Request.get("http://localhost:3000")
239
+ response.pretransfer_time.should > 0
240
+ end
241
+
242
+ end
243
+
244
+
245
+ describe "authentication" do
246
+
247
+ it "should allow to set username and password" do
248
+ auth = { :username => 'foo', :password => 'bar' }
249
+ e = Typhoeus::Request.get(
250
+ "http://localhost:3001/auth_basic/#{auth[:username]}/#{auth[:password]}",
251
+ auth
252
+ )
253
+ e.code.should == 200
254
+ end
255
+
256
+ it "should allow to set authentication method" do
257
+ auth = {
258
+ :username => 'username',
259
+ :password => 'password',
260
+ :auth_method => :ntlm
261
+ }
262
+ e = Typhoeus::Request.get(
263
+ "http://localhost:3001/auth_ntlm",
264
+ auth
265
+ )
266
+ e.code.should == 200
267
+ end
268
+
269
+ end
270
+
271
+ describe "retry" do
272
+ it "should take a retry option"
273
+ it "should count the number of times a request has failed"
274
+ end
275
+
276
+ end
@@ -0,0 +1,151 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Typhoeus::Response do
4
+ describe "timed_out?" do
5
+ it "should return true if curl return code is 28" do
6
+ response = Typhoeus::Response.new(:curl_return_code => 28)
7
+ response.should be_timed_out
8
+ end
9
+
10
+ it "should return false for not 28" do
11
+ response = Typhoeus::Response.new(:curl_return_code => 14)
12
+ response.should_not be_timed_out
13
+ end
14
+ end
15
+
16
+ describe "initialize" do
17
+ it "should store headers_hash" do
18
+ response = Typhoeus::Response.new(:headers_hash => {})
19
+ response.headers_hash.should == {}
20
+ end
21
+
22
+ it "allows header access using a different casing of the header key" do
23
+ response = Typhoeus::Response.new(:headers_hash => { 'content-type' => 'text/html' } )
24
+ response.headers_hash['Content-Type'].should == 'text/html'
25
+ end
26
+
27
+ it "should store response_code" do
28
+ Typhoeus::Response.new(:code => 200).code.should == 200
29
+ end
30
+
31
+ it "should store status_message" do
32
+ Typhoeus::Response.new(:status_message => 'Not Found').status_message.should == 'Not Found'
33
+ end
34
+
35
+ it "should return nil for status_message if none is given and no header is given" do
36
+ Typhoeus::Response.new.status_message.should be_nil
37
+ end
38
+
39
+ it "should store http_version" do
40
+ Typhoeus::Response.new(:http_version => '1.1').http_version.should == '1.1'
41
+ end
42
+
43
+ it "should return nil for http version if none is given and no header is given" do
44
+ Typhoeus::Response.new.http_version.should be_nil
45
+ end
46
+
47
+ it "should store response_headers" do
48
+ Typhoeus::Response.new(:headers => "a header!").headers.should == "a header!"
49
+ end
50
+
51
+ it "should store response_body" do
52
+ Typhoeus::Response.new(:body => "a body!").body.should == "a body!"
53
+ end
54
+
55
+ it "should store request_time" do
56
+ Typhoeus::Response.new(:time => 1.23).time.should == 1.23
57
+ end
58
+
59
+ it "should store requested_url" do
60
+ response = Typhoeus::Response.new(:requested_url => "http://test.com")
61
+ response.requested_url.should == "http://test.com"
62
+ end
63
+
64
+ it "should store requested_http_method" do
65
+ response = Typhoeus::Response.new(:requested_http_method => :delete)
66
+ response.requested_http_method.should == :delete
67
+ end
68
+
69
+ it "should store an associated request object" do
70
+ response = Typhoeus::Response.new(:request => "whatever")
71
+ response.request.should == "whatever"
72
+ end
73
+
74
+ it "should not default to be a mock response" do
75
+ response = Typhoeus::Response.new
76
+ response.should_not be_mock
77
+ end
78
+ end
79
+
80
+ describe "#mock?" do
81
+ it "should be true if it's a mock response" do
82
+ response = Typhoeus::Response.new(:mock => true)
83
+ response.should be_mock
84
+ end
85
+ end
86
+
87
+ describe "headers" do
88
+ it 'should return an empty hash from #headers_hash when no headers string is given' do
89
+ response = Typhoeus::Response.new.headers_hash.should == {}
90
+ end
91
+
92
+ describe "basic parsing" do
93
+ before(:all) do
94
+ @response = Typhoeus::Response.new(:headers => "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nStatus: 200\r\nX-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.9\r\nX-Cache: miss\r\nX-Runtime: 184\r\nETag: e001d08d9354ab7bc7c27a00163a3afa\r\nCache-Control: private, max-age=0, must-revalidate\r\nContent-Length: 4725\r\nSet-Cookie: _some_session=BAh7CDoGciIAOg9zZXNzaW9uX2lkIiU1OTQ2OTcwMjljMWM5ZTQwODU1NjQwYTViMmQxMTkxMjoGcyIKL2NhcnQ%3D--b4c4663932243090c961bb93d4ad5e4327064730; path=/; HttpOnly\r\nServer: nginx/0.6.37 + Phusion Passenger 2.2.4 (mod_rails/mod_rack)\r\nSet-Cookie: foo=bar; path=/;\r\nP3P: CP=\"NOI DSP COR NID ADMa OPTa OUR NOR\"\r\n\r\n")
95
+ end
96
+
97
+ it "can be accessed with lowercase keys" do
98
+ @response.headers_hash['content-type'].should == 'text/html; charset=utf-8'
99
+ end
100
+
101
+ it "can parse the headers into a hash" do
102
+ @response.headers_hash["Status"].should == "200"
103
+ @response.headers_hash["Set-Cookie"].should == ["_some_session=BAh7CDoGciIAOg9zZXNzaW9uX2lkIiU1OTQ2OTcwMjljMWM5ZTQwODU1NjQwYTViMmQxMTkxMjoGcyIKL2NhcnQ%3D--b4c4663932243090c961bb93d4ad5e4327064730; path=/; HttpOnly", "foo=bar; path=/;"]
104
+ @response.headers_hash["Content-Type"].should == "text/html; charset=utf-8"
105
+ end
106
+
107
+ it 'parses the status message' do
108
+ @response.status_message.should == 'OK'
109
+ end
110
+
111
+ it 'parses the HTTP version' do
112
+ @response.http_version.should == '1.1'
113
+ end
114
+
115
+ it 'parses all header keys except HTTP version declaration' do
116
+ @response.headers_hash.keys.should =~ %w[
117
+ X-Powered-By
118
+ P3p
119
+ X-Cache
120
+ Etag
121
+ X-Runtime
122
+ Content-Type
123
+ Content-Length
124
+ Server
125
+ Set-Cookie
126
+ Cache-Control
127
+ Connection
128
+ Status
129
+ ]
130
+ end
131
+ end
132
+
133
+ it "parses a header key that appears multiple times into an array" do
134
+ response = Typhoeus::Response.new(:headers => "HTTP/1.1 302 Found\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nStatus: 302\r\nX-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.9\r\nLocation: http://mckenzie-greenholt1512.myshopify.com/cart\r\nX-Runtime: 22\r\nCache-Control: no-cache\r\nContent-Length: 114\r\nSet-Cookie: cart=8fdd6a828d9c89a737a52668be0cebaf; path=/; expires=Fri, 12-Mar-2010 18:30:19 GMT\r\nSet-Cookie: _session=BAh7CToPc2Vzc2lvbl9pZCIlZTQzMDQzMDg1YjI3MTQ4MzAzMTZmMWZmMWJjMTU1NmI6CWNhcnQiJThmZGQ2YTgyOGQ5Yzg5YTczN2E1MjY2OGJlMGNlYmFmOgZyIgA6BnMiDi9jYXJ0L2FkZA%3D%3D--6b0a699625caed9597580d8e9b6ca5f5e5954125; path=/; HttpOnly\r\nServer: nginx/0.6.37 + Phusion Passenger 2.2.4 (mod_rails/mod_rack)\r\nP3P: CP=\"NOI DSP COR NID ADMa OPTa OUR NOR\"\r\n\r\n")
135
+ response.headers_hash["Set-Cookie"].should include("cart=8fdd6a828d9c89a737a52668be0cebaf; path=/; expires=Fri, 12-Mar-2010 18:30:19 GMT")
136
+ response.headers_hash["Set-Cookie"].should include("_session=BAh7CToPc2Vzc2lvbl9pZCIlZTQzMDQzMDg1YjI3MTQ4MzAzMTZmMWZmMWJjMTU1NmI6CWNhcnQiJThmZGQ2YTgyOGQ5Yzg5YTczN2E1MjY2OGJlMGNlYmFmOgZyIgA6BnMiDi9jYXJ0L2FkZA%3D%3D--6b0a699625caed9597580d8e9b6ca5f5e5954125; path=/; HttpOnly")
137
+ end
138
+ end
139
+
140
+ describe "status checking" do
141
+ it "is successful if response code is 200-299" do
142
+ Typhoeus::Response.new(:code => 220).success?.should be
143
+ Typhoeus::Response.new(:code => 400).success?.should_not be
144
+ end
145
+
146
+ it "is not modified if the status code is 304" do
147
+ Typhoeus::Response.new(:code => 304).modified?.should_not be
148
+ Typhoeus::Response.new(:code => 200).modified?.should be
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Typhoeus::Utils do
4
+ # Taken from Rack 1.2.1
5
+ describe "#escape" do
6
+ it "should escape correctly" do
7
+ Typhoeus::Utils.escape("fo<o>bar").should == "fo%3Co%3Ebar"
8
+ Typhoeus::Utils.escape("a space").should == "a+space"
9
+ Typhoeus::Utils.escape("q1!2\"'w$5&7/z8)?\\").
10
+ should == "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
11
+ end
12
+
13
+ it "should escape correctly for multibyte characters" do
14
+ matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
15
+ matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
16
+ Typhoeus::Utils.escape(matz_name).should == '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
17
+ matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
18
+ matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
19
+ Typhoeus::Utils.escape(matz_name_sep).should == '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
20
+ end
21
+ end
22
+ end