arachni-typhoeus 0.2.0

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.
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