typhoeus 0.3.3 → 0.4.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 (59) hide show
  1. data/{CHANGELOG.markdown → CHANGELOG.md} +21 -12
  2. data/LICENSE +2 -0
  3. data/README.md +455 -0
  4. data/Rakefile +6 -26
  5. data/lib/typhoeus.rb +4 -6
  6. data/lib/typhoeus/curl.rb +453 -0
  7. data/lib/typhoeus/easy.rb +60 -358
  8. data/lib/typhoeus/easy/auth.rb +14 -0
  9. data/lib/typhoeus/easy/callbacks.rb +33 -0
  10. data/lib/typhoeus/easy/ffi_helper.rb +61 -0
  11. data/lib/typhoeus/easy/infos.rb +90 -0
  12. data/lib/typhoeus/easy/options.rb +115 -0
  13. data/lib/typhoeus/easy/proxy.rb +20 -0
  14. data/lib/typhoeus/easy/ssl.rb +82 -0
  15. data/lib/typhoeus/form.rb +30 -1
  16. data/lib/typhoeus/{normalized_header_hash.rb → header.rb} +2 -6
  17. data/lib/typhoeus/hydra.rb +9 -12
  18. data/lib/typhoeus/hydra_mock.rb +2 -2
  19. data/lib/typhoeus/multi.rb +118 -9
  20. data/lib/typhoeus/param_processor.rb +43 -0
  21. data/lib/typhoeus/request.rb +18 -21
  22. data/lib/typhoeus/response.rb +5 -4
  23. data/lib/typhoeus/utils.rb +14 -27
  24. data/lib/typhoeus/version.rb +1 -1
  25. metadata +155 -152
  26. data/Gemfile.lock +0 -37
  27. data/ext/typhoeus/.gitignore +0 -7
  28. data/ext/typhoeus/extconf.rb +0 -65
  29. data/ext/typhoeus/native.c +0 -12
  30. data/ext/typhoeus/native.h +0 -22
  31. data/ext/typhoeus/typhoeus_easy.c +0 -232
  32. data/ext/typhoeus/typhoeus_easy.h +0 -20
  33. data/ext/typhoeus/typhoeus_form.c +0 -59
  34. data/ext/typhoeus/typhoeus_form.h +0 -13
  35. data/ext/typhoeus/typhoeus_multi.c +0 -217
  36. data/ext/typhoeus/typhoeus_multi.h +0 -16
  37. data/lib/typhoeus/.gitignore +0 -1
  38. data/lib/typhoeus/service.rb +0 -20
  39. data/spec/fixtures/placeholder.gif +0 -0
  40. data/spec/fixtures/placeholder.txt +0 -1
  41. data/spec/fixtures/placeholder.ukn +0 -0
  42. data/spec/fixtures/result_set.xml +0 -60
  43. data/spec/servers/app.rb +0 -97
  44. data/spec/spec_helper.rb +0 -19
  45. data/spec/support/typhoeus_localhost_server.rb +0 -58
  46. data/spec/typhoeus/easy_spec.rb +0 -391
  47. data/spec/typhoeus/filter_spec.rb +0 -35
  48. data/spec/typhoeus/form_spec.rb +0 -117
  49. data/spec/typhoeus/hydra_mock_spec.rb +0 -300
  50. data/spec/typhoeus/hydra_spec.rb +0 -602
  51. data/spec/typhoeus/multi_spec.rb +0 -74
  52. data/spec/typhoeus/normalized_header_hash_spec.rb +0 -41
  53. data/spec/typhoeus/remote_method_spec.rb +0 -141
  54. data/spec/typhoeus/remote_proxy_object_spec.rb +0 -65
  55. data/spec/typhoeus/remote_spec.rb +0 -695
  56. data/spec/typhoeus/request_spec.rb +0 -387
  57. data/spec/typhoeus/response_spec.rb +0 -192
  58. data/spec/typhoeus/utils_spec.rb +0 -22
  59. data/typhoeus.gemspec +0 -33
data/lib/typhoeus/easy.rb CHANGED
@@ -1,264 +1,61 @@
1
+ require 'typhoeus/easy/ffi_helper'
2
+ require 'typhoeus/easy/options'
3
+ require 'typhoeus/easy/ssl'
4
+ require 'typhoeus/easy/auth'
5
+ require 'typhoeus/easy/proxy'
6
+ require 'typhoeus/easy/callbacks'
7
+ require 'typhoeus/easy/infos'
8
+
1
9
  module Typhoeus
2
10
  class Easy
3
- attr_reader :response_body, :response_header, :method, :headers, :url, :params, :curl_return_code, :ssl_version
11
+ include Typhoeus::EasyFu::FFIHelper
12
+ include Typhoeus::EasyFu::Options
13
+ include Typhoeus::EasyFu::SSL
14
+ include Typhoeus::EasyFu::Auth
15
+ include Typhoeus::EasyFu::Proxy
16
+ include Typhoeus::EasyFu::Callbacks
17
+ include Typhoeus::EasyFu::Infos
18
+
19
+ OPTION_VALUES = Curl::Option.to_hash.dup
20
+ Curl::Option.to_hash.each {|key, value| OPTION_VALUES["CURLOPT_#{key.to_s.upcase}".to_sym] = value }
21
+ INFO_VALUES = Curl::Info.to_hash.dup
22
+ Curl::Info.to_hash.each {|key, value| INFO_VALUES["CURLINFO_#{key.to_s.upcase}".to_sym] = value }
23
+ AUTH_TYPES = Curl::Auth.to_hash.dup
24
+ Curl::Auth.to_hash.each {|key, value| AUTH_TYPES["CURLAUTH_#{key.to_s.upcase}".to_sym] = value }
25
+ PROXY_TYPES = Curl::Proxy.to_hash.dup
26
+ Curl::Proxy.to_hash.each {|key, value| PROXY_TYPES["CURLPROXY_#{key.to_s.upcase}".to_sym] = value }
27
+ SSL_VERSIONS = Curl::SSLVersion.to_hash.dup
28
+ Curl::SSLVersion.to_hash.each {|key, value| SSL_VERSIONS["CURL_SSLVERSION_#{key.to_s.upcase}".to_sym] = value }
29
+
30
+ attr_reader :url, :header_list
4
31
  attr_accessor :start_time
5
32
 
6
- # These integer codes are available in curl/curl.h
7
- CURLINFO_STRING = 1048576
8
- OPTION_VALUES = {
9
- :CURLOPT_URL => 10002,
10
- :CURLOPT_HTTPGET => 80,
11
- :CURLOPT_HTTPPOST => 10024,
12
- :CURLOPT_UPLOAD => 46,
13
- :CURLOPT_CUSTOMREQUEST => 10036,
14
- :CURLOPT_POSTFIELDS => 10015,
15
- :CURLOPT_COPYPOSTFIELDS => 10165,
16
- :CURLOPT_POSTFIELDSIZE => 60,
17
- :CURLOPT_USERAGENT => 10018,
18
- :CURLOPT_TIMEOUT_MS => 155,
19
- # Time-out connect operations after this amount of milliseconds.
20
- # [Only works on unix-style/SIGALRM operating systems. IOW, does
21
- # not work on Windows.
22
- :CURLOPT_CONNECTTIMEOUT_MS => 156,
23
- :CURLOPT_INTERFACE => 10000 + 62,
24
- :CURLOPT_NOSIGNAL => 99,
25
- :CURLOPT_HTTPHEADER => 10023,
26
- :CURLOPT_FOLLOWLOCATION => 52,
27
- :CURLOPT_MAXREDIRS => 68,
28
- :CURLOPT_HTTPAUTH => 107,
29
- :CURLOPT_USERPWD => 10000 + 5,
30
- :CURLOPT_VERBOSE => 41,
31
- :CURLOPT_PROXY => 10004,
32
- :CURLOPT_PROXYUSERPWD => 10000 + 6,
33
- :CURLOPT_PROXYTYPE => 101,
34
- :CURLOPT_PROXYAUTH => 111,
35
- :CURLOPT_VERIFYPEER => 64,
36
- :CURLOPT_VERIFYHOST => 81,
37
- :CURLOPT_NOBODY => 44,
38
- :CURLOPT_ENCODING => 10000 + 102,
39
- :CURLOPT_SSLCERT => 10025,
40
- :CURLOPT_SSLCERTTYPE => 10086,
41
- :CURLOPT_SSLKEY => 10087,
42
- :CURLOPT_SSLKEYTYPE => 10088,
43
- :CURLOPT_SSLVERSION => 32,
44
- :CURLOPT_KEYPASSWD => 10026,
45
- :CURLOPT_CAINFO => 10065,
46
- :CURLOPT_CAPATH => 10097,
47
- }
48
- INFO_VALUES = {
49
- :CURLINFO_RESPONSE_CODE => 2097154,
50
- :CURLINFO_TOTAL_TIME => 3145731,
51
- :CURLINFO_HTTPAUTH_AVAIL => 0x200000 + 23,
52
- :CURLINFO_EFFECTIVE_URL => 0x100000 + 1,
53
- :CURLINFO_PRIMARY_IP => 0x100000 + 32,
54
- :CURLINFO_NAMELOOKUP_TIME => 0x300000 + 4,
55
- :CURLINFO_CONNECT_TIME => 0x300000 + 5,
56
- :CURLINFO_PRETRANSFER_TIME => 0x300000 + 6,
57
- :CURLINFO_STARTTRANSFER_TIME => 0x300000 + 17,
58
- :CURLINFO_APPCONNECT_TIME => 0x300000 + 33,
59
-
60
- }
61
- AUTH_TYPES = {
62
- :CURLAUTH_BASIC => 1,
63
- :CURLAUTH_DIGEST => 2,
64
- :CURLAUTH_GSSNEGOTIATE => 4,
65
- :CURLAUTH_NTLM => 8,
66
- :CURLAUTH_DIGEST_IE => 16,
67
- :CURLAUTH_AUTO => 16 | 8 | 4 | 2 | 1
68
- }
69
- PROXY_TYPES = {
70
- :CURLPROXY_HTTP => 0,
71
- :CURLPROXY_HTTP_1_0 => 1,
72
- :CURLPROXY_SOCKS4 => 4,
73
- :CURLPROXY_SOCKS5 => 5,
74
- :CURLPROXY_SOCKS4A => 6,
75
- }
76
-
77
- SSL_VERSIONS = {
78
- :CURL_SSLVERSION_DEFAULT => 0,
79
- :CURL_SSLVERSION_TLSv1 => 1,
80
- :CURL_SSLVERSION_SSLv2 => 2,
81
- :CURL_SSLVERSION_SSLv3 => 3,
82
- :default => 0,
83
- :tlsv1 => 1,
84
- :sslv2 => 2,
85
- :sslv3 => 3
86
- }
87
-
88
33
  def initialize
89
- @method = :get
90
- @headers = {}
91
-
92
- set_defaults
34
+ Curl.init
35
+ reset(true)
36
+ ObjectSpace.define_finalizer(self, self.class.finalizer(self))
93
37
  end
94
38
 
95
- def set_defaults
96
- # Enable encoding/compression support
97
- self.encoding = ''
98
- self.ssl_version = :default
39
+ def method
40
+ @method ||= :get
99
41
  end
100
42
 
101
- def encoding=(encoding)
102
- # Enable encoding/compression support
103
- set_option(OPTION_VALUES[:CURLOPT_ENCODING], encoding)
43
+ def headers
44
+ @header ||= {}
104
45
  end
105
46
 
106
- def ssl_version=(version)
107
- raise "Invalid SSL version: '#{version}' supplied! Please supply one as listed in Typhoeus::Easy::SSL_VERSIONS" unless SSL_VERSIONS.has_key?(version)
108
- @ssl_version = version
47
+ def response_body
48
+ @response_body ||= ""
49
+ end
109
50
 
110
- set_option(OPTION_VALUES[:CURLOPT_SSLVERSION], SSL_VERSIONS[version])
51
+ def response_header
52
+ @response_header ||= ""
111
53
  end
112
54
 
113
55
  def headers=(hash)
114
56
  @headers = hash
115
57
  end
116
58
 
117
- def interface=(interface)
118
- @interface = interface
119
- set_option(OPTION_VALUES[:CURLOPT_INTERFACE], interface)
120
- end
121
-
122
- def proxy=(proxy)
123
- set_option(OPTION_VALUES[:CURLOPT_PROXY], proxy[:server])
124
- set_option(OPTION_VALUES[:CURLOPT_PROXYTYPE], proxy[:type]) if proxy[:type]
125
- end
126
-
127
- def proxy_auth=(authinfo)
128
- set_option(OPTION_VALUES[:CURLOPT_PROXYUSERPWD], "#{authinfo[:username]}:#{authinfo[:password]}")
129
- set_option(OPTION_VALUES[:CURLOPT_PROXYAUTH], authinfo[:method]) if authinfo[:method]
130
- end
131
-
132
- def auth=(authinfo)
133
- set_option(OPTION_VALUES[:CURLOPT_USERPWD], "#{authinfo[:username]}:#{authinfo[:password]}")
134
- set_option(OPTION_VALUES[:CURLOPT_HTTPAUTH], authinfo[:method]) if authinfo[:method]
135
- end
136
-
137
- def auth_methods
138
- get_info_long(INFO_VALUES[:CURLINFO_HTTPAUTH_AVAIL])
139
- end
140
-
141
- def verbose=(boolean)
142
- set_option(OPTION_VALUES[:CURLOPT_VERBOSE], !!boolean ? 1 : 0)
143
- end
144
-
145
- def total_time_taken
146
- get_info_double(INFO_VALUES[:CURLINFO_TOTAL_TIME])
147
- end
148
-
149
- def start_transfer_time
150
- get_info_double(INFO_VALUES[:CURLINFO_STARTTRANSFER_TIME])
151
- end
152
-
153
- def app_connect_time
154
- get_info_double(INFO_VALUES[:CURLINFO_APPCONNECT_TIME])
155
- end
156
-
157
- def pretransfer_time
158
- get_info_double(INFO_VALUES[:CURLINFO_PRETRANSFER_TIME])
159
- end
160
-
161
- def connect_time
162
- get_info_double(INFO_VALUES[:CURLINFO_CONNECT_TIME])
163
- end
164
-
165
- def name_lookup_time
166
- get_info_double(INFO_VALUES[:CURLINFO_NAMELOOKUP_TIME])
167
- end
168
-
169
- def effective_url
170
- get_info_string(INFO_VALUES[:CURLINFO_EFFECTIVE_URL])
171
- end
172
-
173
- def primary_ip
174
- get_info_string(INFO_VALUES[:CURLINFO_PRIMARY_IP])
175
- end
176
-
177
- def response_code
178
- get_info_long(INFO_VALUES[:CURLINFO_RESPONSE_CODE])
179
- end
180
-
181
- def follow_location=(boolean)
182
- if boolean
183
- set_option(OPTION_VALUES[:CURLOPT_FOLLOWLOCATION], 1)
184
- else
185
- set_option(OPTION_VALUES[:CURLOPT_FOLLOWLOCATION], 0)
186
- end
187
- end
188
-
189
- def max_redirects=(redirects)
190
- set_option(OPTION_VALUES[:CURLOPT_MAXREDIRS], redirects)
191
- end
192
-
193
- def connect_timeout=(milliseconds)
194
- @connect_timeout = milliseconds
195
- set_option(OPTION_VALUES[:CURLOPT_NOSIGNAL], 1)
196
- set_option(OPTION_VALUES[:CURLOPT_CONNECTTIMEOUT_MS], milliseconds)
197
- end
198
-
199
- def timeout=(milliseconds)
200
- @timeout = milliseconds
201
- set_option(OPTION_VALUES[:CURLOPT_NOSIGNAL], 1)
202
- set_option(OPTION_VALUES[:CURLOPT_TIMEOUT_MS], milliseconds)
203
- end
204
-
205
- def timed_out?
206
- curl_return_code == 28
207
- end
208
-
209
- def supports_zlib?
210
- !!(curl_version.match(/zlib/))
211
- end
212
-
213
- def request_body=(request_body)
214
- @request_body = request_body
215
- if @method == :put
216
- easy_set_request_body(@request_body.to_s)
217
- else
218
- self.post_data = request_body
219
- end
220
- end
221
-
222
- def user_agent=(user_agent)
223
- set_option(OPTION_VALUES[:CURLOPT_USERAGENT], user_agent)
224
- end
225
-
226
- def url=(url)
227
- @url = url
228
- set_option(OPTION_VALUES[:CURLOPT_URL], url)
229
- end
230
-
231
- def disable_ssl_peer_verification
232
- set_option(OPTION_VALUES[:CURLOPT_VERIFYPEER], 0)
233
- end
234
-
235
- def disable_ssl_host_verification
236
- set_option(OPTION_VALUES[:CURLOPT_VERIFYHOST], 0)
237
- end
238
-
239
- def method=(method)
240
- @method = method
241
- if method == :get
242
- set_option(OPTION_VALUES[:CURLOPT_HTTPGET], 1)
243
- elsif method == :post
244
- set_option(OPTION_VALUES[:CURLOPT_HTTPPOST], 1)
245
- self.post_data = ""
246
- elsif method == :put
247
- set_option(OPTION_VALUES[:CURLOPT_UPLOAD], 1)
248
- self.request_body = @request_body.to_s
249
- elsif method == :head
250
- set_option(OPTION_VALUES[:CURLOPT_NOBODY], 1)
251
- else
252
- set_option(OPTION_VALUES[:CURLOPT_CUSTOMREQUEST], method.to_s.upcase)
253
- end
254
- end
255
-
256
- def post_data=(data)
257
- @post_data_set = true
258
- set_option(OPTION_VALUES[:CURLOPT_POSTFIELDSIZE], data.bytesize)
259
- set_option(OPTION_VALUES[:CURLOPT_COPYPOSTFIELDS], data)
260
- end
261
-
262
59
  def params
263
60
  @form.nil? ? {} : @form.params
264
61
  end
@@ -269,7 +66,7 @@ module Typhoeus
269
66
  if method == :post
270
67
  @form.process!
271
68
  if @form.multipart?
272
- set_option(OPTION_VALUES[:CURLOPT_HTTPPOST], @form)
69
+ set_option(:httppost, @form)
273
70
  else
274
71
  self.post_data = @form.to_s
275
72
  end
@@ -278,68 +75,9 @@ module Typhoeus
278
75
  end
279
76
  end
280
77
 
281
- # Set SSL certificate
282
- # " The string should be the file name of your certificate. "
283
- # The default format is "PEM" and can be changed with ssl_cert_type=
284
- def ssl_cert=(cert)
285
- set_option(OPTION_VALUES[:CURLOPT_SSLCERT], cert)
286
- end
287
-
288
- # Set SSL certificate type
289
- # " The string should be the format of your certificate. Supported formats are "PEM" and "DER" "
290
- def ssl_cert_type=(cert_type)
291
- raise "Invalid ssl cert type : '#{cert_type}'..." if cert_type and !%w(PEM DER p12).include?(cert_type)
292
- set_option(OPTION_VALUES[:CURLOPT_SSLCERTTYPE], cert_type)
293
- end
294
-
295
- # Set SSL Key file
296
- # " The string should be the file name of your private key. "
297
- # The default format is "PEM" and can be changed with ssl_key_type=
298
- #
299
- def ssl_key=(key)
300
- set_option(OPTION_VALUES[:CURLOPT_SSLKEY], key)
301
- end
302
-
303
- # Set SSL Key type
304
- # " The string should be the format of your private key. Supported formats are "PEM", "DER" and "ENG". "
305
- #
306
- def ssl_key_type=(key_type)
307
- raise "Invalid ssl key type : '#{key_type}'..." if key_type and !%w(PEM DER ENG).include?(key_type)
308
- set_option(OPTION_VALUES[:CURLOPT_SSLKEYTYPE], key_type)
309
- end
310
-
311
- def ssl_key_password=(key_password)
312
- set_option(OPTION_VALUES[:CURLOPT_KEYPASSWD], key_password)
313
- end
314
-
315
- # Set SSL CACERT
316
- # " File holding one or more certificates to verify the peer with. "
317
- #
318
- def ssl_cacert=(cacert)
319
- set_option(OPTION_VALUES[:CURLOPT_CAINFO], cacert)
320
- end
321
-
322
- # Set CAPATH
323
- # " directory holding multiple CA certificates to verify the peer with. The certificate directory must be prepared using the openssl c_rehash utility. "
324
- #
325
- def ssl_capath=(capath)
326
- set_option(OPTION_VALUES[:CURLOPT_CAPATH], capath)
327
- end
328
-
329
- def set_option(option, value)
330
- case value
331
- when String
332
- easy_setopt_string(option, value)
333
- when Typhoeus::Form
334
- easy_setopt_form(option, value)
335
- else
336
- easy_setopt_long(option, value) if value
337
- end
338
- end
339
-
340
78
  def perform
341
79
  set_headers()
342
- easy_perform()
80
+ @curl_return_code = Curl.easy_perform(handle)
343
81
  resp_code = response_code()
344
82
  if resp_code >= 200 && resp_code <= 299
345
83
  success
@@ -349,65 +87,29 @@ module Typhoeus
349
87
  resp_code
350
88
  end
351
89
 
352
- def set_headers
353
- headers.each_pair do |key, value|
354
- easy_add_header("#{key}: #{value}")
355
- end
356
- easy_set_headers() unless headers.empty?
357
- end
358
-
359
- # gets called when finished and response code is not 2xx,
360
- # or curl returns an error code.
361
- def success
362
- @success.call(self) if @success
363
- end
364
-
365
- def on_success(&block)
366
- @success = block
367
- end
368
-
369
- def on_success=(block)
370
- @success = block
371
- end
372
-
373
- # gets called when finished and response code is 300-599
374
- # or curl returns an error code
375
- def failure
376
- @failure.call(self) if @failure
377
- end
90
+ def reset(fresh = nil)
91
+ unless fresh
92
+ @response_code = 0
93
+ @response_header = ""
94
+ @response_body = ""
95
+ @request_body = ""
378
96
 
379
- def on_failure(&block)
380
- @failure = block
381
- end
382
-
383
- def on_failure=(block)
384
- @failure = block
385
- end
386
-
387
- def reset
388
- @response_code = 0
389
- @response_header = ""
390
- @response_body = ""
391
- @request_body = ""
392
- easy_reset()
393
- set_defaults
394
- end
395
-
396
- def get_info_string(option)
397
- easy_getinfo_string(option)
398
- end
97
+ if @header_list
98
+ Curl.slist_free_all(@header_list)
99
+ @header_list = nil
100
+ end
399
101
 
400
- def get_info_long(option)
401
- easy_getinfo_long(option)
402
- end
102
+ Curl.easy_reset(handle)
103
+ end
403
104
 
404
- def get_info_double(option)
405
- easy_getinfo_double(option)
105
+ self.write_function = body_write_callback
106
+ self.header_function = header_write_callback
107
+ self.encoding = ''
108
+ self.ssl_version = :default
406
109
  end
407
110
 
408
- def curl_version
409
- version
111
+ def curl_return_code=(code)
112
+ @curl_return_code = (code.class == Symbol ? code : Curl::EasyCode[code])
410
113
  end
411
-
412
114
  end
413
115
  end