typhoeus 0.2.0 → 0.2.4

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 (50) hide show
  1. data/CHANGELOG.markdown +26 -1
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +2 -0
  4. data/LICENSE +20 -0
  5. data/README.textile +44 -5
  6. data/Rakefile +8 -5
  7. data/VERSION +1 -1
  8. data/examples/file.rb +12 -0
  9. data/examples/times.rb +40 -0
  10. data/ext/typhoeus/.gitignore +2 -1
  11. data/ext/typhoeus/native.c +1 -0
  12. data/ext/typhoeus/native.h +1 -0
  13. data/ext/typhoeus/typhoeus_easy.c +32 -7
  14. data/ext/typhoeus/typhoeus_easy.h +1 -0
  15. data/ext/typhoeus/typhoeus_form.c +59 -0
  16. data/ext/typhoeus/typhoeus_form.h +13 -0
  17. data/ext/typhoeus/typhoeus_multi.c +15 -29
  18. data/lib/typhoeus/easy.rb +74 -48
  19. data/lib/typhoeus/form.rb +32 -0
  20. data/lib/typhoeus/hydra/connect_options.rb +19 -3
  21. data/lib/typhoeus/hydra.rb +40 -7
  22. data/lib/typhoeus/multi.rb +7 -5
  23. data/lib/typhoeus/remote.rb +1 -1
  24. data/lib/typhoeus/remote_proxy_object.rb +2 -0
  25. data/lib/typhoeus/request.rb +17 -14
  26. data/lib/typhoeus/response.rb +16 -1
  27. data/lib/typhoeus/utils.rb +38 -0
  28. data/lib/typhoeus.rb +1 -0
  29. data/spec/fixtures/placeholder.gif +0 -0
  30. data/spec/fixtures/placeholder.txt +1 -0
  31. data/spec/fixtures/placeholder.ukn +0 -0
  32. data/spec/servers/app.rb +10 -0
  33. data/spec/spec.opts +1 -0
  34. data/spec/spec_helper.rb +3 -0
  35. data/spec/typhoeus/easy_spec.rb +74 -7
  36. data/spec/typhoeus/filter_spec.rb +2 -2
  37. data/spec/typhoeus/form_spec.rb +107 -0
  38. data/spec/typhoeus/hydra_mock_spec.rb +1 -1
  39. data/spec/typhoeus/hydra_spec.rb +108 -38
  40. data/spec/typhoeus/multi_spec.rb +1 -1
  41. data/spec/typhoeus/normalized_header_hash_spec.rb +1 -1
  42. data/spec/typhoeus/remote_method_spec.rb +2 -2
  43. data/spec/typhoeus/remote_proxy_object_spec.rb +1 -1
  44. data/spec/typhoeus/remote_spec.rb +1 -1
  45. data/spec/typhoeus/request_spec.rb +50 -5
  46. data/spec/typhoeus/response_spec.rb +13 -1
  47. data/spec/typhoeus/utils_spec.rb +1 -1
  48. data/typhoeus.gemspec +93 -75
  49. metadata +70 -28
  50. data/.gitignore +0 -3
data/lib/typhoeus/easy.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Typhoeus
2
2
  class Easy
3
- attr_reader :response_body, :response_header, :method, :headers, :url, :params
3
+ attr_reader :response_body, :response_header, :method, :headers, :url, :params, :curl_return_code
4
4
  attr_accessor :start_time
5
5
 
6
6
  # These integer codes are available in curl/curl.h
@@ -28,6 +28,9 @@ module Typhoeus
28
28
  :CURLOPT_USERPWD => 10000 + 5,
29
29
  :CURLOPT_VERBOSE => 41,
30
30
  :CURLOPT_PROXY => 10004,
31
+ :CURLOPT_PROXYUSERPWD => 10000 + 6,
32
+ :CURLOPT_PROXYTYPE => 101,
33
+ :CURLOPT_PROXYAUTH => 111,
31
34
  :CURLOPT_VERIFYPEER => 64,
32
35
  :CURLOPT_NOBODY => 44,
33
36
  :CURLOPT_ENCODING => 10000 + 102,
@@ -37,13 +40,19 @@ module Typhoeus
37
40
  :CURLOPT_SSLKEYTYPE => 10088,
38
41
  :CURLOPT_KEYPASSWD => 10026,
39
42
  :CURLOPT_CAINFO => 10065,
40
- :CURLOPT_CAPATH => 10097
43
+ :CURLOPT_CAPATH => 10097,
41
44
  }
42
45
  INFO_VALUES = {
43
- :CURLINFO_RESPONSE_CODE => 2097154,
44
- :CURLINFO_TOTAL_TIME => 3145731,
45
- :CURLINFO_HTTPAUTH_AVAIL => 0x200000 + 23,
46
- :CURLINFO_EFFECTIVE_URL => 0x100000 + 1
46
+ :CURLINFO_RESPONSE_CODE => 2097154,
47
+ :CURLINFO_TOTAL_TIME => 3145731,
48
+ :CURLINFO_HTTPAUTH_AVAIL => 0x200000 + 23,
49
+ :CURLINFO_EFFECTIVE_URL => 0x100000 + 1,
50
+ :CURLINFO_NAMELOOKUP_TIME => 0x300000 + 4,
51
+ :CURLINFO_CONNECT_TIME => 0x300000 + 5,
52
+ :CURLINFO_PRETRANSFER_TIME => 0x300000 + 6,
53
+ :CURLINFO_STARTTRANSFER_TIME => 0x300000 + 17,
54
+ :CURLINFO_APPCONNECT_TIME => 0x300000 + 33,
55
+
47
56
  }
48
57
  AUTH_TYPES = {
49
58
  :CURLAUTH_BASIC => 1,
@@ -53,6 +62,14 @@ module Typhoeus
53
62
  :CURLAUTH_DIGEST_IE => 16,
54
63
  :CURLAUTH_AUTO => 16 | 8 | 4 | 2 | 1
55
64
  }
65
+ PROXY_TYPES = {
66
+ :CURLPROXY_HTTP => 0,
67
+ :CURLPROXY_HTTP_1_0 => 1,
68
+ :CURLPROXY_SOCKS4 => 4,
69
+ :CURLPROXY_SOCKS5 => 5,
70
+ :CURLPROXY_SOCKS4A => 6,
71
+ }
72
+
56
73
 
57
74
  def initialize
58
75
  @method = :get
@@ -67,7 +84,13 @@ module Typhoeus
67
84
  end
68
85
 
69
86
  def proxy=(proxy)
70
- set_option(OPTION_VALUES[:CURLOPT_PROXY], proxy)
87
+ set_option(OPTION_VALUES[:CURLOPT_PROXY], proxy[:server])
88
+ set_option(OPTION_VALUES[:CURLOPT_PROXYTYPE], proxy[:type]) if proxy[:type]
89
+ end
90
+
91
+ def proxy_auth=(authinfo)
92
+ set_option(OPTION_VALUES[:CURLOPT_PROXYUSERPWD], "#{authinfo[:username]}:#{authinfo[:password]}")
93
+ set_option(OPTION_VALUES[:CURLOPT_PROXYAUTH], authinfo[:method]) if authinfo[:method]
71
94
  end
72
95
 
73
96
  def auth=(authinfo)
@@ -87,6 +110,26 @@ module Typhoeus
87
110
  get_info_double(INFO_VALUES[:CURLINFO_TOTAL_TIME])
88
111
  end
89
112
 
113
+ def start_transfer_time
114
+ get_info_double(INFO_VALUES[:CURLINFO_STARTTRANSFER_TIME])
115
+ end
116
+
117
+ def app_connect_time
118
+ get_info_double(INFO_VALUES[:CURLINFO_APPCONNECT_TIME])
119
+ end
120
+
121
+ def pretransfer_time
122
+ get_info_double(INFO_VALUES[:CURLINFO_PRETRANSFER_TIME])
123
+ end
124
+
125
+ def connect_time
126
+ get_info_double(INFO_VALUES[:CURLINFO_CONNECT_TIME])
127
+ end
128
+
129
+ def name_lookup_time
130
+ get_info_double(INFO_VALUES[:CURLINFO_NAMELOOKUP_TIME])
131
+ end
132
+
90
133
  def effective_url
91
134
  get_info_string(INFO_VALUES[:CURLINFO_EFFECTIVE_URL])
92
135
  end
@@ -106,7 +149,7 @@ module Typhoeus
106
149
  def max_redirects=(redirects)
107
150
  set_option(OPTION_VALUES[:CURLOPT_MAXREDIRS], redirects)
108
151
  end
109
-
152
+
110
153
  def connect_timeout=(milliseconds)
111
154
  @connect_timeout = milliseconds
112
155
  set_option(OPTION_VALUES[:CURLOPT_NOSIGNAL], 1)
@@ -120,7 +163,7 @@ module Typhoeus
120
163
  end
121
164
 
122
165
  def timed_out?
123
- @timeout && total_time_taken > @timeout && response_code == 0
166
+ curl_return_code == 28
124
167
  end
125
168
 
126
169
  def supports_zlib?
@@ -174,24 +217,22 @@ module Typhoeus
174
217
  set_option(OPTION_VALUES[:CURLOPT_COPYPOSTFIELDS], data)
175
218
  end
176
219
 
220
+ def params
221
+ @form.nil? ? {} : @form.params
222
+ end
223
+
177
224
  def params=(params)
178
- @params = params
179
- params_string = params.keys.collect do |k|
180
- value = params[k]
181
- if value.is_a? Hash
182
- value.keys.collect {|sk| Typhoeus::Utils.escape("#{k}[#{sk}]") + "=" + Typhoeus::Utils.escape(value[sk].to_s)}
183
- elsif value.is_a? Array
184
- key = Typhoeus::Utils.escape(k.to_s)
185
- value.collect { |v| "#{key}=#{Typhoeus::Utils.escape(v.to_s)}" }.join('&')
186
- else
187
- "#{Typhoeus::Utils.escape(k.to_s)}=#{Typhoeus::Utils.escape(params[k].to_s)}"
188
- end
189
- end.flatten.join("&")
225
+ @form = Typhoeus::Form.new(params)
190
226
 
191
227
  if method == :post
192
- self.post_data = params_string
228
+ @form.process!
229
+ if @form.multipart?
230
+ set_option(OPTION_VALUES[:CURLOPT_HTTPPOST], @form)
231
+ else
232
+ self.post_data = @form.to_s
233
+ end
193
234
  else
194
- self.url = "#{url}?#{params_string}"
235
+ self.url = "#{url}?#{@form.to_s}"
195
236
  end
196
237
  end
197
238
 
@@ -205,7 +246,7 @@ module Typhoeus
205
246
  # Set SSL certificate type
206
247
  # " The string should be the format of your certificate. Supported formats are "PEM" and "DER" "
207
248
  def ssl_cert_type=(cert_type)
208
- raise "Invalid ssl cert type : '#{cert_type}'..." if cert_type and !%w(PEM DER).include?(cert_type)
249
+ raise "Invalid ssl cert type : '#{cert_type}'..." if cert_type and !%w(PEM DER).include?(cert_type)
209
250
  set_option(OPTION_VALUES[:CURLOPT_SSLCERTTYPE], cert_type)
210
251
  end
211
252
 
@@ -244,17 +285,20 @@ module Typhoeus
244
285
  end
245
286
 
246
287
  def set_option(option, value)
247
- if value.class == String
248
- easy_setopt_string(option, value)
249
- elsif value
250
- easy_setopt_long(option, value)
288
+ case value
289
+ when String
290
+ easy_setopt_string(option, value)
291
+ when Typhoeus::Form
292
+ easy_setopt_form(option, value)
293
+ else
294
+ easy_setopt_long(option, value) if value
251
295
  end
252
296
  end
253
297
 
254
298
  def perform
255
299
  set_headers()
256
300
  easy_perform()
257
- resp_code = response_code()
301
+ resp_code = response_code()
258
302
  if resp_code >= 200 && resp_code <= 299
259
303
  success
260
304
  else
@@ -283,7 +327,7 @@ module Typhoeus
283
327
  @success = block
284
328
  end
285
329
 
286
- # gets called when finished and response code is 300-599
330
+ # gets called when finished and response code is 300-599 or curl returns an error code
287
331
  def failure
288
332
  @failure.call(self) if @failure
289
333
  end
@@ -296,25 +340,7 @@ module Typhoeus
296
340
  @failure = block
297
341
  end
298
342
 
299
- def retries
300
- @retries ||= 0
301
- end
302
-
303
- def increment_retries
304
- @retries ||= 0
305
- @retries += 1
306
- end
307
-
308
- def max_retries
309
- @max_retries ||= 40
310
- end
311
-
312
- def max_retries?
313
- retries >= max_retries
314
- end
315
-
316
343
  def reset
317
- @retries = 0
318
344
  @response_code = 0
319
345
  @response_header = ""
320
346
  @response_body = ""
@@ -0,0 +1,32 @@
1
+ require 'mime/types'
2
+
3
+ module Typhoeus
4
+ class Form
5
+ attr_accessor :params
6
+ attr_reader :traversal
7
+
8
+ def initialize(params = {})
9
+ @params = params
10
+ end
11
+
12
+ def traversal
13
+ @traversal ||= Typhoeus::Utils.traverse_params_hash(params)
14
+ end
15
+
16
+ def process!
17
+ # add params
18
+ traversal[:params].each { |p| formadd_param(p[0], p[1]) }
19
+
20
+ # add files
21
+ traversal[:files].each { |file_args| formadd_file(*file_args) }
22
+ end
23
+
24
+ def multipart?
25
+ !traversal[:files].empty?
26
+ end
27
+
28
+ def to_s
29
+ Typhoeus::Utils.traversal_to_param_string(traversal, false)
30
+ end
31
+ end
32
+ end
@@ -12,9 +12,10 @@ module Typhoeus
12
12
  #
13
13
  # @raises NetConnectNotAllowedError
14
14
  def check_allow_net_connect!(request)
15
- if !Typhoeus::Hydra.allow_net_connect? and (!Typhoeus::Hydra.ignore_localhost? or !request.localhost?)
16
- raise NetConnectNotAllowedError, "Real HTTP requests are not allowed. Unregistered request: #{request.inspect}"
17
- end
15
+ return if Typhoeus::Hydra.allow_net_connect?
16
+ return if Typhoeus::Hydra.ignore_hosts.include?(request.host_domain)
17
+
18
+ raise NetConnectNotAllowedError, "Real HTTP requests are not allowed. Unregistered request: #{request.inspect}"
18
19
  end
19
20
  private :check_allow_net_connect!
20
21
 
@@ -39,7 +40,22 @@ module Typhoeus
39
40
  def ignore_localhost?
40
41
  ignore_localhost
41
42
  end
43
+
44
+ def ignore_hosts
45
+ @ignore_hosts ||= []
46
+
47
+ if ignore_localhost?
48
+ @ignore_hosts + Typhoeus::Request::LOCALHOST_ALIASES
49
+ else
50
+ @ignore_hosts
51
+ end
52
+ end
53
+
54
+ def ignore_hosts=(hosts)
55
+ @ignore_hosts = hosts
56
+ end
42
57
  end
43
58
  end
44
59
  end
45
60
  end
61
+
@@ -32,6 +32,17 @@ module Typhoeus
32
32
  @hydra = val
33
33
  end
34
34
 
35
+ #
36
+ # Abort the run on a best-effort basis.
37
+ #
38
+ # It won't abort the current burst of @max_concurrency requests,
39
+ # however it won't fire the rest of the queued requests so the run
40
+ # will be aborted as soon as possible...
41
+ #
42
+ def abort
43
+ @queued_requests.clear
44
+ end
45
+
35
46
  def clear_cache_callbacks
36
47
  @cache_setter = nil
37
48
  @cache_getter = nil
@@ -82,8 +93,11 @@ module Typhoeus
82
93
  end
83
94
 
84
95
  @multi.perform
96
+ ensure
97
+ @multi.reset_easy_handles{|easy| release_easy_object(easy)}
85
98
  @memoized_requests = {}
86
99
  @retrieved_from_cache = {}
100
+ @running_requests = 0
87
101
  end
88
102
 
89
103
  def disable_memoization
@@ -131,6 +145,19 @@ module Typhoeus
131
145
  auth[:method] = Typhoeus::Easy::AUTH_TYPES["CURLAUTH_#{request.auth_method.to_s.upcase}".to_sym] if request.auth_method
132
146
  easy.auth = auth
133
147
  end
148
+
149
+ if request.proxy
150
+ proxy = { :server => request.proxy }
151
+ proxy[:type] = Typhoeus::Easy::PROXY_TYPES["CURLPROXY_#{request.proxy_type.to_s.upcase}".to_sym] if request.proxy_type
152
+ easy.proxy = proxy if request.proxy
153
+ end
154
+
155
+ if request.proxy_username || request.proxy_password
156
+ auth = { :username => request.proxy_username, :password => request.proxy_password }
157
+ auth[:method] = Typhoeus::Easy::AUTH_TYPES["CURLAUTH_#{request.proxy_auth_method.to_s.upcase}".to_sym] if request.proxy_auth_method
158
+ easy.proxy_auth = auth
159
+ end
160
+
134
161
  easy.url = request.url
135
162
  easy.method = request.method
136
163
  easy.params = request.params if request.method == :post && !request.params.nil?
@@ -140,7 +167,6 @@ module Typhoeus
140
167
  easy.connect_timeout = request.connect_timeout if request.connect_timeout
141
168
  easy.follow_location = request.follow_location if request.follow_location
142
169
  easy.max_redirects = request.max_redirects if request.max_redirects
143
- easy.proxy = request.proxy if request.proxy
144
170
  easy.disable_ssl_peer_verification if request.disable_ssl_peer_verification
145
171
  easy.ssl_cert = request.ssl_cert
146
172
  easy.ssl_cert_type = request.ssl_cert_type
@@ -200,12 +226,19 @@ module Typhoeus
200
226
  private :handle_request
201
227
 
202
228
  def response_from_easy(easy, request)
203
- Response.new(:code => easy.response_code,
204
- :headers => easy.response_header,
205
- :body => easy.response_body,
206
- :time => easy.total_time_taken,
207
- :effective_url => easy.effective_url,
208
- :request => request)
229
+ Response.new(:code => easy.response_code,
230
+ :headers => easy.response_header,
231
+ :body => easy.response_body,
232
+ :time => easy.total_time_taken,
233
+ :start_transfer_time => easy.start_transfer_time,
234
+ :app_connect_time => easy.app_connect_time,
235
+ :pretransfer_time => easy.pretransfer_time,
236
+ :connect_time => easy.connect_time,
237
+ :name_lookup_time => easy.name_lookup_time,
238
+ :effective_url => easy.effective_url,
239
+ :curl_return_code => easy.curl_return_code,
240
+ :curl_error_message => easy.curl_error_message,
241
+ :request => request)
209
242
  end
210
243
  private :response_from_easy
211
244
  end
@@ -3,16 +3,16 @@ module Typhoeus
3
3
  attr_reader :easy_handles
4
4
 
5
5
  def initialize
6
- reset_easy_handles
6
+ @easy_handles = []
7
7
  end
8
8
 
9
9
  def remove(easy)
10
- multi_remove_handle(easy)
10
+ multi_remove_handle(easy) if @easy_handles.include?(easy)
11
11
  end
12
12
 
13
13
  def add(easy)
14
+ raise "trying to add easy handle twice" if @easy_handles.include?(easy)
14
15
  easy.set_headers() if easy.headers.empty?
15
- @easy_handles << easy
16
16
  multi_add_handle(easy)
17
17
  end
18
18
 
@@ -27,9 +27,11 @@ module Typhoeus
27
27
  multi_cleanup
28
28
  end
29
29
 
30
- private
31
30
  def reset_easy_handles
32
- @easy_handles = []
31
+ @easy_handles.dup.each do |easy|
32
+ multi_remove_handle(easy)
33
+ yield easy if block_given?
34
+ end
33
35
  end
34
36
  end
35
37
  end
@@ -1,5 +1,5 @@
1
1
  module Typhoeus
2
- USER_AGENT = "Typhoeus - http://github.com/pauldix/typhoeus/tree/master"
2
+ USER_AGENT = "Typhoeus - http://github.com/dbalatero/typhoeus/tree/master"
3
3
 
4
4
  def self.included(base)
5
5
  base.extend ClassMethods
@@ -22,6 +22,8 @@ module Typhoeus
22
22
  unless @proxied_object
23
23
  Typhoeus.perform_easy_requests
24
24
  response = Response.new(:code => @easy.response_code,
25
+ :curl_return_code => @easy.curl_return_code,
26
+ :curl_error_message => @easy.curl_error_message,
25
27
  :headers => @easy.response_header,
26
28
  :body => @easy.response_body,
27
29
  :time => @easy.total_time_taken,
@@ -6,10 +6,12 @@ module Typhoeus
6
6
  attr_writer :headers
7
7
  attr_accessor :method, :params, :body, :connect_timeout, :timeout,
8
8
  :user_agent, :response, :cache_timeout, :follow_location,
9
- :max_redirects, :proxy, :disable_ssl_peer_verification,
9
+ :max_redirects, :proxy, :proxy_username,:proxy_password,
10
+ :disable_ssl_peer_verification,
10
11
  :ssl_cert, :ssl_cert_type, :ssl_key, :ssl_key_type,
11
12
  :ssl_key_password, :ssl_cacert, :ssl_capath, :verbose,
12
- :username, :password, :auth_method, :user_agent
13
+ :username, :password, :auth_method, :user_agent,
14
+ :proxy_auth_method, :proxy_type
13
15
 
14
16
  # Initialize a new Request
15
17
  #
@@ -52,6 +54,10 @@ module Typhoeus
52
54
  @follow_location = options[:follow_location]
53
55
  @max_redirects = options[:max_redirects]
54
56
  @proxy = options[:proxy]
57
+ @proxy_type = options[:proxy_type]
58
+ @proxy_username = options[:proxy_username]
59
+ @proxy_password = options[:proxy_password]
60
+ @proxy_auth_method = options[:proxy_auth_method]
55
61
  @disable_ssl_peer_verification = options[:disable_ssl_peer_verification]
56
62
  @ssl_cert = options[:ssl_cert]
57
63
  @ssl_cert_type = options[:ssl_cert_type]
@@ -78,8 +84,10 @@ module Typhoeus
78
84
  @handled_response = nil
79
85
  end
80
86
 
87
+ LOCALHOST_ALIASES = %w[ localhost 127.0.0.1 0.0.0.0 ]
88
+
81
89
  def localhost?
82
- %(localhost 127.0.0.1 0.0.0.0).include?(@parsed_uri.host)
90
+ LOCALHOST_ALIASES.include?(@parsed_uri.host)
83
91
  end
84
92
 
85
93
  def host
@@ -92,23 +100,18 @@ module Typhoeus
92
100
  end
93
101
  end
94
102
 
103
+ def host_domain
104
+ @parsed_uri.host
105
+ end
106
+
95
107
  def headers
96
108
  @headers["User-Agent"] = @user_agent
97
109
  @headers
98
110
  end
99
111
 
100
112
  def params_string
101
- params.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |k|
102
- value = params[k]
103
- if value.is_a? Hash
104
- value.keys.collect {|sk| Typhoeus::Utils.escape("#{k}[#{sk}]") + "=" + Typhoeus::Utils.escape(value[sk].to_s)}
105
- elsif value.is_a? Array
106
- key = Typhoeus::Utils.escape(k.to_s)
107
- value.collect { |v| "#{key}[]=#{Typhoeus::Utils.escape(v.to_s)}" }.join('&')
108
- else
109
- "#{Typhoeus::Utils.escape(k.to_s)}=#{Typhoeus::Utils.escape(params[k].to_s)}"
110
- end
111
- end.flatten.join("&")
113
+ traversal = Typhoeus::Utils.traverse_params_hash(params)
114
+ Typhoeus::Utils.traversal_to_param_string(traversal)
112
115
  end
113
116
 
114
117
  def on_complete(&block)
@@ -4,11 +4,17 @@ module Typhoeus
4
4
  attr_reader :code, :headers, :body, :time,
5
5
  :requested_url, :requested_remote_method,
6
6
  :requested_http_method, :start_time,
7
- :effective_url
7
+ :effective_url, :start_transfer_time,
8
+ :app_connect_time, :pretransfer_time,
9
+ :connect_time, :name_lookup_time,
10
+ :curl_return_code, :curl_error_message
11
+
8
12
  attr_writer :headers_hash
9
13
 
10
14
  def initialize(params = {})
11
15
  @code = params[:code]
16
+ @curl_return_code = params[:curl_return_code]
17
+ @curl_error_message = params[:curl_error_message]
12
18
  @status_message = params[:status_message]
13
19
  @http_version = params[:http_version]
14
20
  @headers = params[:headers] || ''
@@ -17,6 +23,11 @@ module Typhoeus
17
23
  @requested_url = params[:requested_url]
18
24
  @requested_http_method = params[:requested_http_method]
19
25
  @start_time = params[:start_time]
26
+ @start_transfer_time = params[:start_transfer_time]
27
+ @app_connect_time = params[:app_connect_time]
28
+ @pretransfer_time = params[:pretransfer_time]
29
+ @connect_time = params[:connect_time]
30
+ @name_lookup_time = params[:name_lookup_time]
20
31
  @request = params[:request]
21
32
  @effective_url = params[:effective_url]
22
33
  @mock = params[:mock] || false # default
@@ -67,6 +78,10 @@ module Typhoeus
67
78
  @code != 304
68
79
  end
69
80
 
81
+ def timed_out?
82
+ curl_return_code == 28
83
+ end
84
+
70
85
  private
71
86
 
72
87
  def first_header_line
@@ -8,6 +8,44 @@ module Typhoeus
8
8
  end
9
9
  module_function :escape
10
10
 
11
+ # Params are NOT escaped.
12
+ def traverse_params_hash(hash, result = nil, current_key = nil)
13
+ result ||= { :files => [], :params => [] }
14
+
15
+ hash.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |key|
16
+ new_key = (current_key ? "#{current_key}[#{key}]" : key).to_s
17
+ case hash[key]
18
+ when Hash
19
+ traverse_params_hash(hash[key], result, new_key)
20
+ when Array
21
+ array_key = "#{new_key}[]"
22
+ hash[key].each do |v|
23
+ result[:params] << [array_key, v.to_s]
24
+ end
25
+ when File
26
+ filename = File.basename(hash[key].path)
27
+ types = MIME::Types.type_for(filename)
28
+ result[:files] << [
29
+ new_key,
30
+ filename,
31
+ types.empty? ? 'application/octet-stream' : types[0].to_s,
32
+ File.expand_path(hash[key].path)
33
+ ]
34
+ else
35
+ result[:params] << [new_key, hash[key].to_s]
36
+ end
37
+ end
38
+ result
39
+ end
40
+ module_function :traverse_params_hash
41
+
42
+ def traversal_to_param_string(traversal, escape = true)
43
+ traversal[:params].collect { |param|
44
+ "#{Typhoeus::Utils.escape(param[0])}=#{Typhoeus::Utils.escape(param[1])}"
45
+ }.join('&')
46
+ end
47
+ module_function :traversal_to_param_string
48
+
11
49
  # Return the bytesize of String; uses String#size under Ruby 1.8 and
12
50
  # String#bytesize under 1.9.
13
51
  if ''.respond_to?(:bytesize)
data/lib/typhoeus.rb CHANGED
@@ -5,6 +5,7 @@ require 'digest/sha2'
5
5
  require 'typhoeus/utils'
6
6
  require 'typhoeus/normalized_header_hash'
7
7
  require 'typhoeus/easy'
8
+ require 'typhoeus/form'
8
9
  require 'typhoeus/multi'
9
10
  require 'typhoeus/native'
10
11
  require 'typhoeus/filter'
Binary file
@@ -0,0 +1 @@
1
+ This file is used to test uploading.
File without changes
data/spec/servers/app.rb CHANGED
@@ -5,6 +5,16 @@ require 'json'
5
5
  require 'zlib'
6
6
 
7
7
  @@fail_count = 0
8
+
9
+ post '/file' do
10
+ {
11
+ 'content-type' => params[:file][:type],
12
+ 'filename' => params[:file][:filename],
13
+ 'content' => params[:file][:tempfile].read,
14
+ 'request-content-type' => request.env['CONTENT_TYPE']
15
+ }.to_json
16
+ end
17
+
8
18
  get '/fail/:number' do
9
19
  if @@fail_count >= params[:number].to_i
10
20
  "ok"
data/spec/spec.opts CHANGED
@@ -1,2 +1,3 @@
1
1
  --diff
2
2
  --color
3
+ --backtrace
data/spec/spec_helper.rb CHANGED
@@ -9,3 +9,6 @@ path = File.expand_path(File.dirname(__FILE__) + "/../lib/")
9
9
  $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
10
10
 
11
11
  require path + '/typhoeus'
12
+
13
+ Spec::Runner.configure do |config|
14
+ end