tech-angels-typhoeus 0.1.36

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.gitignore +2 -0
  2. data/README.textile +312 -0
  3. data/Rakefile +39 -0
  4. data/VERSION +1 -0
  5. data/benchmarks/profile.rb +25 -0
  6. data/benchmarks/vs_nethttp.rb +35 -0
  7. data/examples/twitter.rb +21 -0
  8. data/ext/typhoeus/.gitignore +5 -0
  9. data/ext/typhoeus/Makefile +157 -0
  10. data/ext/typhoeus/extconf.rb +65 -0
  11. data/ext/typhoeus/native.c +11 -0
  12. data/ext/typhoeus/native.h +21 -0
  13. data/ext/typhoeus/typhoeus_easy.c +207 -0
  14. data/ext/typhoeus/typhoeus_easy.h +19 -0
  15. data/ext/typhoeus/typhoeus_multi.c +225 -0
  16. data/ext/typhoeus/typhoeus_multi.h +16 -0
  17. data/lib/typhoeus.rb +55 -0
  18. data/lib/typhoeus/.gitignore +1 -0
  19. data/lib/typhoeus/easy.rb +329 -0
  20. data/lib/typhoeus/filter.rb +28 -0
  21. data/lib/typhoeus/hydra.rb +235 -0
  22. data/lib/typhoeus/multi.rb +35 -0
  23. data/lib/typhoeus/remote.rb +306 -0
  24. data/lib/typhoeus/remote_method.rb +108 -0
  25. data/lib/typhoeus/remote_proxy_object.rb +48 -0
  26. data/lib/typhoeus/request.rb +159 -0
  27. data/lib/typhoeus/response.rb +49 -0
  28. data/lib/typhoeus/service.rb +20 -0
  29. data/profilers/valgrind.rb +24 -0
  30. data/spec/fixtures/result_set.xml +60 -0
  31. data/spec/servers/app.rb +73 -0
  32. data/spec/spec.opts +2 -0
  33. data/spec/spec_helper.rb +11 -0
  34. data/spec/typhoeus/easy_spec.rb +236 -0
  35. data/spec/typhoeus/filter_spec.rb +35 -0
  36. data/spec/typhoeus/hydra_spec.rb +311 -0
  37. data/spec/typhoeus/multi_spec.rb +74 -0
  38. data/spec/typhoeus/remote_method_spec.rb +141 -0
  39. data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
  40. data/spec/typhoeus/remote_spec.rb +695 -0
  41. data/spec/typhoeus/request_spec.rb +169 -0
  42. data/spec/typhoeus/response_spec.rb +63 -0
  43. data/typhoeus.gemspec +112 -0
  44. metadata +203 -0
@@ -0,0 +1,19 @@
1
+ #ifndef TYPHOEUS_EASY
2
+ #define TYPHOEUS_EASY
3
+
4
+ #include <native.h>
5
+
6
+ void init_typhoeus_easy();
7
+ typedef struct {
8
+ const char *memory;
9
+ int size;
10
+ int read;
11
+ } RequestChunk;
12
+
13
+ typedef struct {
14
+ RequestChunk *request_chunk;
15
+ CURL *curl;
16
+ struct curl_slist *headers;
17
+ } CurlEasy;
18
+
19
+ #endif
@@ -0,0 +1,225 @@
1
+ #include <typhoeus_multi.h>
2
+
3
+ static void multi_read_info(VALUE self, CURLM *multi_handle);
4
+
5
+ static void dealloc(CurlMulti *curl_multi) {
6
+ curl_multi_cleanup(curl_multi->multi);
7
+ free(curl_multi);
8
+ }
9
+
10
+ static VALUE multi_add_handle(VALUE self, VALUE easy) {
11
+ CurlEasy *curl_easy;
12
+ Data_Get_Struct(easy, CurlEasy, curl_easy);
13
+ CurlMulti *curl_multi;
14
+ Data_Get_Struct(self, CurlMulti, curl_multi);
15
+ CURLMcode mcode;
16
+
17
+ mcode = curl_multi_add_handle(curl_multi->multi, curl_easy->curl);
18
+ if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
19
+ rb_raise((VALUE)mcode, "An error occured adding the handle");
20
+ }
21
+
22
+ curl_easy_setopt(curl_easy->curl, CURLOPT_PRIVATE, easy);
23
+ curl_multi->active++;
24
+
25
+ if (mcode == CURLM_CALL_MULTI_PERFORM) {
26
+ curl_multi_perform(curl_multi->multi, &(curl_multi->running));
27
+ }
28
+ //
29
+ // if (curl_multi->running) {
30
+ // printf("call read_info on add<br/>");
31
+ // multi_read_info(self, curl_multi->multi);
32
+ // }
33
+
34
+ return easy;
35
+ }
36
+
37
+ static VALUE multi_remove_handle(VALUE self, VALUE easy) {
38
+ CurlEasy *curl_easy;
39
+ Data_Get_Struct(easy, CurlEasy, curl_easy);
40
+ CurlMulti *curl_multi;
41
+ Data_Get_Struct(self, CurlMulti, curl_multi);
42
+
43
+ curl_multi->active--;
44
+ curl_multi_remove_handle(curl_multi->multi, curl_easy->curl);
45
+
46
+ return easy;
47
+ }
48
+
49
+ static void multi_read_info(VALUE self, CURLM *multi_handle) {
50
+ int msgs_left, result;
51
+ CURLMsg *msg;
52
+ CURLcode ecode;
53
+ CURL *easy_handle;
54
+ VALUE easy;
55
+
56
+ /* check for finished easy handles and remove from the multi handle */
57
+ while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
58
+
59
+ if (msg->msg != CURLMSG_DONE) {
60
+ continue;
61
+ }
62
+
63
+ easy_handle = msg->easy_handle;
64
+ result = msg->data.result;
65
+ if (easy_handle) {
66
+ ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &easy);
67
+ if (ecode != 0) {
68
+ rb_raise(ecode, "error getting easy object");
69
+ }
70
+
71
+ long response_code = -1;
72
+ curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &response_code);
73
+
74
+ // TODO: find out what the real problem is here and fix it.
75
+ // this next bit is a horrible hack. For some reason my tests against a local server on my laptop
76
+ // fail intermittently and return this result number. However, it will succeed if you try it a few
77
+ // more times. Also noteworthy is that this doens't happen when hitting an external server. WTF?!
78
+
79
+ // Sandofsky says:
80
+ // This is caused by OS X first attempting to resolve using IPV6.
81
+ // Hack solution: connect to yourself with 127.0.0.1, not localhost
82
+ // http://curl.haxx.se/mail/tracker-2009-09/0018.html
83
+ if (result == 7) {
84
+ VALUE max_retries = rb_funcall(easy, rb_intern("max_retries?"), 0);
85
+ if (max_retries != Qtrue) {
86
+ multi_remove_handle(self, easy);
87
+ multi_add_handle(self, easy);
88
+ CurlMulti *curl_multi;
89
+ Data_Get_Struct(self, CurlMulti, curl_multi);
90
+ curl_multi_perform(curl_multi->multi, &(curl_multi->running));
91
+
92
+ rb_funcall(easy, rb_intern("increment_retries"), 0);
93
+
94
+ continue;
95
+ }
96
+ }
97
+ multi_remove_handle(self, easy);
98
+
99
+ if (result != 0) {
100
+ rb_funcall(easy, rb_intern("failure"), 0);
101
+ }
102
+ else if ((response_code >= 200 && response_code < 300) || response_code == 0) {
103
+ rb_funcall(easy, rb_intern("success"), 0);
104
+ }
105
+ else if (response_code >= 300 && response_code < 600) {
106
+ rb_funcall(easy, rb_intern("failure"), 0);
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ /* called by multi_perform and fire_and_forget */
113
+ static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running) {
114
+ CURLMcode mcode;
115
+
116
+ do {
117
+ mcode = curl_multi_perform(multi_handle, still_running);
118
+ } while (mcode == CURLM_CALL_MULTI_PERFORM);
119
+
120
+ if (mcode != CURLM_OK) {
121
+ rb_raise((VALUE)mcode, "an error occured while running perform");
122
+ }
123
+
124
+ multi_read_info( self, multi_handle );
125
+ }
126
+
127
+ static VALUE fire_and_forget(VALUE self) {
128
+ CurlMulti *curl_multi;
129
+ Data_Get_Struct(self, CurlMulti, curl_multi);
130
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
131
+ }
132
+
133
+ static VALUE multi_perform(VALUE self) {
134
+ CURLMcode mcode;
135
+ CurlMulti *curl_multi;
136
+ int maxfd, rc;
137
+ fd_set fdread, fdwrite, fdexcep;
138
+
139
+ long timeout;
140
+ struct timeval tv = {0, 0};
141
+
142
+ Data_Get_Struct(self, CurlMulti, curl_multi);
143
+
144
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
145
+ while(curl_multi->running) {
146
+ FD_ZERO(&fdread);
147
+ FD_ZERO(&fdwrite);
148
+ FD_ZERO(&fdexcep);
149
+
150
+ /* get the curl suggested time out */
151
+ mcode = curl_multi_timeout(curl_multi->multi, &timeout);
152
+ if (mcode != CURLM_OK) {
153
+ rb_raise((VALUE)mcode, "an error occured getting the timeout");
154
+ }
155
+
156
+ if (timeout == 0) { /* no delay */
157
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
158
+ continue;
159
+ }
160
+ else if (timeout < 0) {
161
+ timeout = 1;
162
+ }
163
+
164
+ tv.tv_sec = timeout / 1000;
165
+ tv.tv_usec = (timeout * 1000) % 1000000;
166
+
167
+ /* load the fd sets from the multi handle */
168
+ mcode = curl_multi_fdset(curl_multi->multi, &fdread, &fdwrite, &fdexcep, &maxfd);
169
+ if (mcode != CURLM_OK) {
170
+ rb_raise((VALUE)mcode, "an error occured getting the fdset");
171
+ }
172
+
173
+ rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
174
+ if (rc < 0) {
175
+ rb_raise(rb_eRuntimeError, "error on thread select");
176
+ }
177
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
178
+
179
+ }
180
+
181
+ return Qnil;
182
+ }
183
+
184
+ static VALUE active_handle_count(VALUE self) {
185
+ CurlMulti *curl_multi;
186
+ Data_Get_Struct(self, CurlMulti, curl_multi);
187
+
188
+ return INT2NUM(curl_multi->active);
189
+ }
190
+
191
+ static VALUE multi_cleanup(VALUE self) {
192
+ CurlMulti *curl_multi;
193
+ Data_Get_Struct(self, CurlMulti, curl_multi);
194
+
195
+ curl_multi_cleanup(curl_multi->multi);
196
+ curl_multi->active = 0;
197
+ curl_multi->running = 0;
198
+
199
+ return Qnil;
200
+ }
201
+
202
+ static VALUE new(int argc, VALUE *argv, VALUE klass) {
203
+ CurlMulti *curl_multi = ALLOC(CurlMulti);
204
+ curl_multi->multi = curl_multi_init();
205
+ curl_multi->active = 0;
206
+ curl_multi->running = 0;
207
+
208
+ VALUE multi = Data_Wrap_Struct(cTyphoeusMulti, 0, dealloc, curl_multi);
209
+
210
+ rb_obj_call_init(multi, argc, argv);
211
+
212
+ return multi;
213
+ }
214
+
215
+ void init_typhoeus_multi() {
216
+ VALUE klass = cTyphoeusMulti = rb_define_class_under(mTyphoeus, "Multi", rb_cObject);
217
+
218
+ rb_define_singleton_method(klass, "new", new, -1);
219
+ rb_define_private_method(klass, "multi_add_handle", multi_add_handle, 1);
220
+ rb_define_private_method(klass, "multi_remove_handle", multi_remove_handle, 1);
221
+ rb_define_private_method(klass, "multi_perform", multi_perform, 0);
222
+ rb_define_private_method(klass, "multi_cleanup", multi_cleanup, 0);
223
+ rb_define_private_method(klass, "active_handle_count", active_handle_count, 0);
224
+ rb_define_method(klass, "fire_and_forget", fire_and_forget, 0);
225
+ }
@@ -0,0 +1,16 @@
1
+ #ifndef TYPHOEUS_MULTI
2
+ #define TYPHOEUS_MULTI
3
+
4
+ #include <native.h>
5
+ #include <typhoeus_easy.h>
6
+
7
+ VALUE cTyphoeusMulti;
8
+ typedef struct {
9
+ int running;
10
+ int active;
11
+ CURLM *multi;
12
+ } CurlMulti;
13
+
14
+ void init_typhoeus_multi();
15
+
16
+ #endif
@@ -0,0 +1,55 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__))
2
+
3
+ require 'rack/utils'
4
+ require 'digest/sha2'
5
+ require 'typhoeus/easy'
6
+ require 'typhoeus/multi'
7
+ require 'typhoeus/native'
8
+ require 'typhoeus/filter'
9
+ require 'typhoeus/remote_method'
10
+ require 'typhoeus/remote'
11
+ require 'typhoeus/remote_proxy_object'
12
+ require 'typhoeus/response'
13
+ require 'typhoeus/request'
14
+ require 'typhoeus/hydra'
15
+
16
+ module Typhoeus
17
+ VERSION = File.read(File.dirname(__FILE__) + "/../VERSION").chomp
18
+
19
+ def self.easy_object_pool
20
+ @easy_objects ||= []
21
+ end
22
+
23
+ def self.init_easy_object_pool
24
+ 20.times do
25
+ easy_object_pool << Typhoeus::Easy.new
26
+ end
27
+ end
28
+
29
+ def self.release_easy_object(easy)
30
+ easy.reset
31
+ easy_object_pool << easy
32
+ end
33
+
34
+ def self.get_easy_object
35
+ if easy_object_pool.empty?
36
+ Typhoeus::Easy.new
37
+ else
38
+ easy_object_pool.pop
39
+ end
40
+ end
41
+
42
+ def self.add_easy_request(easy_object)
43
+ Thread.current[:curl_multi] ||= Typhoeus::Multi.new
44
+ Thread.current[:curl_multi].add(easy_object)
45
+ end
46
+
47
+ def self.perform_easy_requests
48
+ multi = Thread.current[:curl_multi]
49
+ start_time = Time.now
50
+ multi.easy_handles.each do |easy|
51
+ easy.start_time = start_time
52
+ end
53
+ multi.perform
54
+ end
55
+ end
@@ -0,0 +1 @@
1
+ native.bundle
@@ -0,0 +1,329 @@
1
+ module Typhoeus
2
+ class Easy
3
+ attr_reader :response_body, :response_header, :method, :headers, :url, :params
4
+ attr_accessor :start_time
5
+
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
+ :CURLOPT_NOSIGNAL => 99,
20
+ :CURLOPT_HTTPHEADER => 10023,
21
+ :CURLOPT_FOLLOWLOCATION => 52,
22
+ :CURLOPT_MAXREDIRS => 68,
23
+ :CURLOPT_HTTPAUTH => 107,
24
+ :CURLOPT_USERPWD => 10000 + 5,
25
+ :CURLOPT_VERBOSE => 41,
26
+ :CURLOPT_PROXY => 10004,
27
+ :CURLOPT_VERIFYPEER => 64,
28
+ :CURLOPT_NOBODY => 44,
29
+ :CURLOPT_ENCODING => 102,
30
+ :CURLOPT_SSLCERT => 10025,
31
+ :CURLOPT_SSLCERTTYPE => 10086,
32
+ :CURLOPT_SSLKEY => 10087,
33
+ :CURLOPT_SSLKEYTYPE => 10088,
34
+ :CURLOPT_KEYPASSWD => 10026,
35
+ :CURLOPT_CAINFO => 10065,
36
+ :CURLOPT_CAPATH => 10097
37
+ }
38
+ INFO_VALUES = {
39
+ :CURLINFO_RESPONSE_CODE => 2097154,
40
+ :CURLINFO_TOTAL_TIME => 3145731,
41
+ :CURLINFO_HTTPAUTH_AVAIL => 0x200000 + 23,
42
+ :CURLINFO_EFFECTIVE_URL => 0x100000 + 1
43
+ }
44
+ AUTH_TYPES = {
45
+ :CURLAUTH_BASIC => 1,
46
+ :CURLAUTH_DIGEST => 2,
47
+ :CURLAUTH_GSSNEGOTIATE => 4,
48
+ :CURLAUTH_NTLM => 8,
49
+ :CURLAUTH_DIGEST_IE => 16
50
+ }
51
+
52
+ def initialize
53
+ @method = :get
54
+ @headers = {}
55
+
56
+ set_option(OPTION_VALUES[:CURLOPT_ENCODING], 'zlib') if supports_zlib?
57
+ end
58
+
59
+ def headers=(hash)
60
+ @headers = hash
61
+ end
62
+
63
+ def proxy=(proxy)
64
+ set_option(OPTION_VALUES[:CURLOPT_PROXY], proxy)
65
+ end
66
+
67
+ def auth=(authinfo)
68
+ set_option(OPTION_VALUES[:CURLOPT_USERPWD], "#{authinfo[:username]}:#{authinfo[:password]}")
69
+ set_option(OPTION_VALUES[:CURLOPT_HTTPAUTH], authinfo[:method]) if authinfo[:method]
70
+ end
71
+
72
+ def auth_methods
73
+ get_info_long(INFO_VALUES[:CURLINFO_HTTPAUTH_AVAIL])
74
+ end
75
+
76
+ def verbose=(boolean)
77
+ set_option(OPTION_VALUES[:CURLOPT_VERBOSE], !!boolean ? 1 : 0)
78
+ end
79
+
80
+ def total_time_taken
81
+ get_info_double(INFO_VALUES[:CURLINFO_TOTAL_TIME])
82
+ end
83
+
84
+ def effective_url
85
+ get_info_string(INFO_VALUES[:CURLINFO_EFFECTIVE_URL])
86
+ end
87
+
88
+ def response_code
89
+ get_info_long(INFO_VALUES[:CURLINFO_RESPONSE_CODE])
90
+ end
91
+
92
+ def follow_location=(boolean)
93
+ if boolean
94
+ set_option(OPTION_VALUES[:CURLOPT_FOLLOWLOCATION], 1)
95
+ else
96
+ set_option(OPTION_VALUES[:CURLOPT_FOLLOWLOCATION], 0)
97
+ end
98
+ end
99
+
100
+ def max_redirects=(redirects)
101
+ set_option(OPTION_VALUES[:CURLOPT_MAXREDIRS], redirects)
102
+ end
103
+
104
+ def timeout=(milliseconds)
105
+ @timeout = milliseconds
106
+ set_option(OPTION_VALUES[:CURLOPT_NOSIGNAL], 1)
107
+ set_option(OPTION_VALUES[:CURLOPT_TIMEOUT_MS], milliseconds)
108
+ end
109
+
110
+ def timed_out?
111
+ @timeout && total_time_taken > @timeout && response_code == 0
112
+ end
113
+
114
+ def supports_zlib?
115
+ !!(curl_version.match(/zlib/))
116
+ end
117
+
118
+ def request_body=(request_body)
119
+ @request_body = request_body
120
+ if @method == :put
121
+ easy_set_request_body(@request_body)
122
+ headers["Transfer-Encoding"] = ""
123
+ headers["Expect"] = ""
124
+ else
125
+ self.post_data = request_body
126
+ end
127
+ end
128
+
129
+ def user_agent=(user_agent)
130
+ set_option(OPTION_VALUES[:CURLOPT_USERAGENT], user_agent)
131
+ end
132
+
133
+ def url=(url)
134
+ @url = url
135
+ set_option(OPTION_VALUES[:CURLOPT_URL], url)
136
+ end
137
+
138
+ def disable_ssl_peer_verification
139
+ set_option(OPTION_VALUES[:CURLOPT_VERIFYPEER], 0)
140
+ end
141
+
142
+ def method=(method)
143
+ @method = method
144
+ if method == :get
145
+ set_option(OPTION_VALUES[:CURLOPT_HTTPGET], 1)
146
+ elsif method == :post
147
+ set_option(OPTION_VALUES[:CURLOPT_HTTPPOST], 1)
148
+ self.post_data = ""
149
+ elsif method == :put
150
+ set_option(OPTION_VALUES[:CURLOPT_UPLOAD], 1)
151
+ self.request_body = "" unless @request_body
152
+ elsif method == :head
153
+ set_option(OPTION_VALUES[:CURLOPT_NOBODY], 1)
154
+ else
155
+ set_option(OPTION_VALUES[:CURLOPT_CUSTOMREQUEST], method.to_s.upcase)
156
+ end
157
+ end
158
+
159
+ def post_data=(data)
160
+ @post_data_set = true
161
+ set_option(OPTION_VALUES[:CURLOPT_POSTFIELDSIZE], data.length)
162
+ set_option(OPTION_VALUES[:CURLOPT_COPYPOSTFIELDS], data)
163
+ end
164
+
165
+ def params=(params)
166
+ @params = params
167
+ params_string = params.keys.collect do |k|
168
+ value = params[k]
169
+ if value.is_a? Hash
170
+ value.keys.collect {|sk| Rack::Utils.escape("#{k}[#{sk}]") + "=" + Rack::Utils.escape(value[sk].to_s)}
171
+ elsif value.is_a? Array
172
+ key = Rack::Utils.escape(k.to_s)
173
+ value.collect { |v| "#{key}=#{Rack::Utils.escape(v.to_s)}" }.join('&')
174
+ else
175
+ "#{Rack::Utils.escape(k.to_s)}=#{Rack::Utils.escape(params[k].to_s)}"
176
+ end
177
+ end.flatten.join("&")
178
+
179
+ if method == :post
180
+ self.post_data = params_string
181
+ else
182
+ self.url = "#{url}?#{params_string}"
183
+ end
184
+ end
185
+
186
+ # Set SSL certificate
187
+ # " The string should be the file name of your certificate. "
188
+ # The default format is "PEM" and can be changed with ssl_cert_type=
189
+ def ssl_cert=(cert)
190
+ set_option(OPTION_VALUES[:CURLOPT_SSLCERT], cert)
191
+ end
192
+
193
+ # Set SSL certificate type
194
+ # " The string should be the format of your certificate. Supported formats are "PEM" and "DER" "
195
+ def ssl_cert_type=(cert_type)
196
+ raise "Invalid ssl cert type : '#{cert_type}'..." if cert_type and !%w(PEM DER).include?(cert_type)
197
+ set_option(OPTION_VALUES[:CURLOPT_SSLCERTTYPE], cert_type)
198
+ end
199
+
200
+ # Set SSL Key file
201
+ # " The string should be the file name of your private key. "
202
+ # The default format is "PEM" and can be changed with ssl_key_type=
203
+ #
204
+ def ssl_key=(key)
205
+ set_option(OPTION_VALUES[:CURLOPT_SSLKEY], key)
206
+ end
207
+
208
+ # Set SSL Key type
209
+ # " The string should be the format of your private key. Supported formats are "PEM", "DER" and "ENG". "
210
+ #
211
+ def ssl_key_type=(key_type)
212
+ raise "Invalid ssl key type : '#{key_type}'..." if key_type and !%w(PEM DER ENG).include?(key_type)
213
+ set_option(OPTION_VALUES[:CURLOPT_SSLKEYTYPE], key_type)
214
+ end
215
+
216
+ def ssl_key_password=(key_password)
217
+ set_option(OPTION_VALUES[:CURLOPT_KEYPASSWD], key_password)
218
+ end
219
+
220
+ # Set SSL CACERT
221
+ # " File holding one or more certificates to verify the peer with. "
222
+ #
223
+ def ssl_cacert=(cacert)
224
+ set_option(OPTION_VALUES[:CURLOPT_CAINFO], cacert)
225
+ end
226
+
227
+ # Set CAPATH
228
+ # " directory holding multiple CA certificates to verify the peer with. The certificate directory must be prepared using the openssl c_rehash utility. "
229
+ #
230
+ def ssl_capath=(capath)
231
+ set_option(OPTION_VALUES[:CURLOPT_CAPATH], capath)
232
+ end
233
+
234
+ def set_option(option, value)
235
+ if value.class == String
236
+ easy_setopt_string(option, value)
237
+ elsif value
238
+ easy_setopt_long(option, value)
239
+ end
240
+ end
241
+
242
+ def perform
243
+ set_headers()
244
+ easy_perform()
245
+ resp_code = response_code()
246
+ if resp_code >= 200 && resp_code <= 299
247
+ success
248
+ else
249
+ failure
250
+ end
251
+ resp_code
252
+ end
253
+
254
+ def set_headers
255
+ headers.each_pair do |key, value|
256
+ easy_add_header("#{key}: #{value}")
257
+ end
258
+ easy_set_headers() unless headers.empty?
259
+ end
260
+
261
+ # gets called when finished and response code is 200-299
262
+ def success
263
+ @success.call(self) if @success
264
+ end
265
+
266
+ def on_success(&block)
267
+ @success = block
268
+ end
269
+
270
+ def on_success=(block)
271
+ @success = block
272
+ end
273
+
274
+ # gets called when finished and response code is 300-599
275
+ def failure
276
+ @failure.call(self) if @failure
277
+ end
278
+
279
+ def on_failure(&block)
280
+ @failure = block
281
+ end
282
+
283
+ def on_failure=(block)
284
+ @failure = block
285
+ end
286
+
287
+ def retries
288
+ @retries ||= 0
289
+ end
290
+
291
+ def increment_retries
292
+ @retries ||= 0
293
+ @retries += 1
294
+ end
295
+
296
+ def max_retries
297
+ @max_retries ||= 40
298
+ end
299
+
300
+ def max_retries?
301
+ retries >= max_retries
302
+ end
303
+
304
+ def reset
305
+ @retries = 0
306
+ @response_code = 0
307
+ @response_header = ""
308
+ @response_body = ""
309
+ easy_reset()
310
+ end
311
+
312
+ def get_info_string(option)
313
+ easy_getinfo_string(option)
314
+ end
315
+
316
+ def get_info_long(option)
317
+ easy_getinfo_long(option)
318
+ end
319
+
320
+ def get_info_double(option)
321
+ easy_getinfo_double(option)
322
+ end
323
+
324
+ def curl_version
325
+ version
326
+ end
327
+
328
+ end
329
+ end