tech-angels-typhoeus 0.1.36

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