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,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,211 @@
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(rb_eRuntimeError, "An error occured adding the handle: %d: %s", mcode, curl_multi_strerror(mcode));
20
+ }
21
+
22
+ curl_easy_setopt(curl_easy->curl, CURLOPT_PRIVATE, easy);
23
+ curl_multi->active++;
24
+
25
+ VALUE easy_handles = rb_iv_get(self, "@easy_handles");
26
+ rb_ary_push(easy_handles, easy);
27
+
28
+ if (mcode == CURLM_CALL_MULTI_PERFORM) {
29
+ curl_multi_perform(curl_multi->multi, &(curl_multi->running));
30
+ }
31
+ //
32
+ // if (curl_multi->running) {
33
+ // printf("call read_info on add<br/>");
34
+ // multi_read_info(self, curl_multi->multi);
35
+ // }
36
+
37
+ return easy;
38
+ }
39
+
40
+ static VALUE multi_remove_handle(VALUE self, VALUE easy) {
41
+ CurlEasy *curl_easy;
42
+ Data_Get_Struct(easy, CurlEasy, curl_easy);
43
+ CurlMulti *curl_multi;
44
+ Data_Get_Struct(self, CurlMulti, curl_multi);
45
+
46
+ curl_multi->active--;
47
+ curl_multi_remove_handle(curl_multi->multi, curl_easy->curl);
48
+
49
+ VALUE easy_handles = rb_iv_get(self, "@easy_handles");
50
+ rb_ary_delete(easy_handles, easy);
51
+
52
+ return easy;
53
+ }
54
+
55
+ static void multi_read_info(VALUE self, CURLM *multi_handle) {
56
+ int msgs_left, result;
57
+ CURLMsg *msg;
58
+ CURLcode ecode;
59
+ CURL *easy_handle;
60
+ VALUE easy;
61
+
62
+ /* check for finished easy handles and remove from the multi handle */
63
+ while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
64
+
65
+ if (msg->msg != CURLMSG_DONE) {
66
+ continue;
67
+ }
68
+
69
+ easy_handle = msg->easy_handle;
70
+ result = msg->data.result;
71
+ if (easy_handle) {
72
+ ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &easy);
73
+ if (ecode != 0) {
74
+ rb_raise(rb_eRuntimeError, "error getting easy object: %d: %s", ecode, curl_easy_strerror(ecode));
75
+ }
76
+
77
+ long response_code = -1;
78
+ curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &response_code);
79
+
80
+ multi_remove_handle(self, easy);
81
+ rb_iv_set(easy, "@curl_return_code", INT2FIX(result));
82
+
83
+ if (result != 0) {
84
+ rb_funcall(easy, rb_intern("failure"), 0);
85
+ }
86
+ else if ((response_code >= 200 && response_code < 300) || response_code == 0) {
87
+ rb_funcall(easy, rb_intern("success"), 0);
88
+ }
89
+ else if (response_code >= 300 && response_code < 600) {
90
+ rb_funcall(easy, rb_intern("failure"), 0);
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ /* called by multi_perform and fire_and_forget */
97
+ static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running) {
98
+ CURLMcode mcode;
99
+
100
+ do {
101
+ mcode = curl_multi_perform(multi_handle, still_running);
102
+ } while (mcode == CURLM_CALL_MULTI_PERFORM);
103
+
104
+ if (mcode != CURLM_OK) {
105
+ rb_raise(rb_eRuntimeError, "an error occured while running perform: %d: %s", mcode, curl_multi_strerror(mcode));
106
+ }
107
+
108
+ multi_read_info( self, multi_handle );
109
+ }
110
+
111
+ static VALUE fire_and_forget(VALUE self) {
112
+ CurlMulti *curl_multi;
113
+ Data_Get_Struct(self, CurlMulti, curl_multi);
114
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
115
+
116
+ return Qnil;
117
+ }
118
+
119
+ static VALUE multi_perform(VALUE self) {
120
+ CURLMcode mcode;
121
+ CurlMulti *curl_multi;
122
+ int maxfd, rc;
123
+ fd_set fdread, fdwrite, fdexcep;
124
+
125
+ long timeout;
126
+ struct timeval tv = {0, 0};
127
+
128
+ Data_Get_Struct(self, CurlMulti, curl_multi);
129
+
130
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
131
+ while(curl_multi->running) {
132
+ FD_ZERO(&fdread);
133
+ FD_ZERO(&fdwrite);
134
+ FD_ZERO(&fdexcep);
135
+
136
+ /* get the curl suggested time out */
137
+ mcode = curl_multi_timeout(curl_multi->multi, &timeout);
138
+ if (mcode != CURLM_OK) {
139
+ rb_raise(rb_eRuntimeError, "an error occured getting the timeout: %d: %s", mcode, curl_multi_strerror(mcode));
140
+ }
141
+
142
+ if (timeout == 0) { /* no delay */
143
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
144
+ continue;
145
+ }
146
+ else if (timeout < 0) {
147
+ timeout = 1;
148
+ }
149
+
150
+ tv.tv_sec = timeout / 1000;
151
+ tv.tv_usec = (timeout * 1000) % 1000000;
152
+
153
+ /* load the fd sets from the multi handle */
154
+ mcode = curl_multi_fdset(curl_multi->multi, &fdread, &fdwrite, &fdexcep, &maxfd);
155
+ if (mcode != CURLM_OK) {
156
+ rb_raise(rb_eRuntimeError, "an error occured getting the fdset: %d: %s", mcode, curl_multi_strerror(mcode));
157
+ }
158
+
159
+ rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
160
+ if (rc < 0) {
161
+ rb_raise(rb_eRuntimeError, "error on thread select");
162
+ }
163
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
164
+
165
+ }
166
+
167
+ return Qnil;
168
+ }
169
+
170
+ static VALUE active_handle_count(VALUE self) {
171
+ CurlMulti *curl_multi;
172
+ Data_Get_Struct(self, CurlMulti, curl_multi);
173
+
174
+ return INT2FIX(curl_multi->active);
175
+ }
176
+
177
+ static VALUE multi_cleanup(VALUE self) {
178
+ CurlMulti *curl_multi;
179
+ Data_Get_Struct(self, CurlMulti, curl_multi);
180
+
181
+ curl_multi_cleanup(curl_multi->multi);
182
+ curl_multi->active = 0;
183
+ curl_multi->running = 0;
184
+
185
+ return Qnil;
186
+ }
187
+
188
+ static VALUE new(int argc, VALUE *argv, VALUE klass) {
189
+ CurlMulti *curl_multi = ALLOC(CurlMulti);
190
+ curl_multi->multi = curl_multi_init();
191
+ curl_multi->active = 0;
192
+ curl_multi->running = 0;
193
+
194
+ VALUE multi = Data_Wrap_Struct(cTyphoeusMulti, 0, dealloc, curl_multi);
195
+
196
+ rb_obj_call_init(multi, argc, argv);
197
+
198
+ return multi;
199
+ }
200
+
201
+ void init_typhoeus_multi() {
202
+ VALUE klass = cTyphoeusMulti = rb_define_class_under(mTyphoeus, "Multi", rb_cObject);
203
+
204
+ rb_define_singleton_method(klass, "new", new, -1);
205
+ rb_define_private_method(klass, "multi_add_handle", multi_add_handle, 1);
206
+ rb_define_private_method(klass, "multi_remove_handle", multi_remove_handle, 1);
207
+ rb_define_private_method(klass, "multi_perform", multi_perform, 0);
208
+ rb_define_private_method(klass, "multi_cleanup", multi_cleanup, 0);
209
+ rb_define_private_method(klass, "active_handle_count", active_handle_count, 0);
210
+ rb_define_method(klass, "fire_and_forget", fire_and_forget, 0);
211
+ }
@@ -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
data/lib/typhoeus.rb ADDED
@@ -0,0 +1,58 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../ext")
3
+
4
+ require 'digest/sha2'
5
+ require 'typhoeus/utils'
6
+ require 'typhoeus/normalized_header_hash'
7
+ require 'typhoeus/easy'
8
+ require 'typhoeus/multi'
9
+ require 'typhoeus/native'
10
+ require 'typhoeus/filter'
11
+ require 'typhoeus/remote_method'
12
+ require 'typhoeus/remote'
13
+ require 'typhoeus/remote_proxy_object'
14
+ require 'typhoeus/response'
15
+ require 'typhoeus/request'
16
+ require 'typhoeus/hydra'
17
+ require 'typhoeus/hydra_mock'
18
+
19
+ module Typhoeus
20
+ VERSION = File.read(File.dirname(__FILE__) + "/../VERSION").chomp
21
+
22
+ def self.easy_object_pool
23
+ @easy_objects ||= []
24
+ end
25
+
26
+ def self.init_easy_object_pool
27
+ 20.times do
28
+ easy_object_pool << Typhoeus::Easy.new
29
+ end
30
+ end
31
+
32
+ def self.release_easy_object(easy)
33
+ easy.reset
34
+ easy_object_pool << easy
35
+ end
36
+
37
+ def self.get_easy_object
38
+ if easy_object_pool.empty?
39
+ Typhoeus::Easy.new
40
+ else
41
+ easy_object_pool.pop
42
+ end
43
+ end
44
+
45
+ def self.add_easy_request(easy_object)
46
+ Thread.current[:curl_multi] ||= Typhoeus::Multi.new
47
+ Thread.current[:curl_multi].add(easy_object)
48
+ end
49
+
50
+ def self.perform_easy_requests
51
+ multi = Thread.current[:curl_multi]
52
+ start_time = Time.now
53
+ multi.easy_handles.each do |easy|
54
+ easy.start_time = start_time
55
+ end
56
+ multi.perform
57
+ end
58
+ end
@@ -0,0 +1 @@
1
+ native.bundle
@@ -0,0 +1,366 @@
1
+ module Typhoeus
2
+ class Easy
3
+ attr_reader :response_body, :response_header, :method, :headers, :url, :params, :curl_return_code
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
+ # 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_NOSIGNAL => 99,
24
+ :CURLOPT_HTTPHEADER => 10023,
25
+ :CURLOPT_FOLLOWLOCATION => 52,
26
+ :CURLOPT_MAXREDIRS => 68,
27
+ :CURLOPT_HTTPAUTH => 107,
28
+ :CURLOPT_USERPWD => 10000 + 5,
29
+ :CURLOPT_VERBOSE => 41,
30
+ :CURLOPT_PROXY => 10004,
31
+ :CURLOPT_PROXYUSERPWD => 10000 + 6,
32
+ :CURLOPT_PROXYTYPE => 101,
33
+ :CURLOPT_PROXYAUTH => 111,
34
+ :CURLOPT_VERIFYPEER => 64,
35
+ :CURLOPT_NOBODY => 44,
36
+ :CURLOPT_ENCODING => 10000 + 102,
37
+ :CURLOPT_SSLCERT => 10025,
38
+ :CURLOPT_SSLCERTTYPE => 10086,
39
+ :CURLOPT_SSLKEY => 10087,
40
+ :CURLOPT_SSLKEYTYPE => 10088,
41
+ :CURLOPT_KEYPASSWD => 10026,
42
+ :CURLOPT_CAINFO => 10065,
43
+ :CURLOPT_CAPATH => 10097
44
+ }
45
+ INFO_VALUES = {
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
+
56
+ }
57
+ AUTH_TYPES = {
58
+ :CURLAUTH_BASIC => 1,
59
+ :CURLAUTH_DIGEST => 2,
60
+ :CURLAUTH_GSSNEGOTIATE => 4,
61
+ :CURLAUTH_NTLM => 8,
62
+ :CURLAUTH_DIGEST_IE => 16,
63
+ :CURLAUTH_AUTO => 16 | 8 | 4 | 2 | 1
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
+
73
+
74
+ def initialize
75
+ @method = :get
76
+ @headers = {}
77
+
78
+ # Enable encoding/compression support
79
+ set_option(OPTION_VALUES[:CURLOPT_ENCODING], '')
80
+ end
81
+
82
+ def headers=(hash)
83
+ @headers = hash
84
+ end
85
+
86
+ def 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]
94
+ end
95
+
96
+ def auth=(authinfo)
97
+ set_option(OPTION_VALUES[:CURLOPT_USERPWD], "#{authinfo[:username]}:#{authinfo[:password]}")
98
+ set_option(OPTION_VALUES[:CURLOPT_HTTPAUTH], authinfo[:method]) if authinfo[:method]
99
+ end
100
+
101
+ def auth_methods
102
+ get_info_long(INFO_VALUES[:CURLINFO_HTTPAUTH_AVAIL])
103
+ end
104
+
105
+ def verbose=(boolean)
106
+ set_option(OPTION_VALUES[:CURLOPT_VERBOSE], !!boolean ? 1 : 0)
107
+ end
108
+
109
+ def total_time_taken
110
+ get_info_double(INFO_VALUES[:CURLINFO_TOTAL_TIME])
111
+ end
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
+
133
+ def effective_url
134
+ get_info_string(INFO_VALUES[:CURLINFO_EFFECTIVE_URL])
135
+ end
136
+
137
+ def response_code
138
+ get_info_long(INFO_VALUES[:CURLINFO_RESPONSE_CODE])
139
+ end
140
+
141
+ def follow_location=(boolean)
142
+ if boolean
143
+ set_option(OPTION_VALUES[:CURLOPT_FOLLOWLOCATION], 1)
144
+ else
145
+ set_option(OPTION_VALUES[:CURLOPT_FOLLOWLOCATION], 0)
146
+ end
147
+ end
148
+
149
+ def max_redirects=(redirects)
150
+ set_option(OPTION_VALUES[:CURLOPT_MAXREDIRS], redirects)
151
+ end
152
+
153
+ def connect_timeout=(milliseconds)
154
+ @connect_timeout = milliseconds
155
+ set_option(OPTION_VALUES[:CURLOPT_NOSIGNAL], 1)
156
+ set_option(OPTION_VALUES[:CURLOPT_CONNECTTIMEOUT_MS], milliseconds)
157
+ end
158
+
159
+ def timeout=(milliseconds)
160
+ @timeout = milliseconds
161
+ set_option(OPTION_VALUES[:CURLOPT_NOSIGNAL], 1)
162
+ set_option(OPTION_VALUES[:CURLOPT_TIMEOUT_MS], milliseconds)
163
+ end
164
+
165
+ def timed_out?
166
+ curl_return_code == 28
167
+ end
168
+
169
+ def supports_zlib?
170
+ !!(curl_version.match(/zlib/))
171
+ end
172
+
173
+ def request_body=(request_body)
174
+ @request_body = request_body
175
+ if @method == :put
176
+ easy_set_request_body(@request_body)
177
+ headers["Transfer-Encoding"] = ""
178
+ headers["Expect"] = ""
179
+ else
180
+ self.post_data = request_body
181
+ end
182
+ end
183
+
184
+ def user_agent=(user_agent)
185
+ set_option(OPTION_VALUES[:CURLOPT_USERAGENT], user_agent)
186
+ end
187
+
188
+ def url=(url)
189
+ @url = url
190
+ set_option(OPTION_VALUES[:CURLOPT_URL], url)
191
+ end
192
+
193
+ def disable_ssl_peer_verification
194
+ set_option(OPTION_VALUES[:CURLOPT_VERIFYPEER], 0)
195
+ end
196
+
197
+ def method=(method)
198
+ @method = method
199
+ if method == :get
200
+ set_option(OPTION_VALUES[:CURLOPT_HTTPGET], 1)
201
+ elsif method == :post
202
+ set_option(OPTION_VALUES[:CURLOPT_HTTPPOST], 1)
203
+ self.post_data = ""
204
+ elsif method == :put
205
+ set_option(OPTION_VALUES[:CURLOPT_UPLOAD], 1)
206
+ self.request_body = "" unless @request_body
207
+ elsif method == :head
208
+ set_option(OPTION_VALUES[:CURLOPT_NOBODY], 1)
209
+ else
210
+ set_option(OPTION_VALUES[:CURLOPT_CUSTOMREQUEST], method.to_s.upcase)
211
+ end
212
+ end
213
+
214
+ def post_data=(data)
215
+ @post_data_set = true
216
+ set_option(OPTION_VALUES[:CURLOPT_POSTFIELDSIZE], data.length)
217
+ set_option(OPTION_VALUES[:CURLOPT_COPYPOSTFIELDS], data)
218
+ end
219
+
220
+ def params=(params)
221
+ @params = params
222
+ params_string = params.keys.collect do |k|
223
+ value = params[k]
224
+ if value.is_a? Hash
225
+ value.keys.collect {|sk| Typhoeus::Utils.escape("#{k}[#{sk}]") + "=" + Typhoeus::Utils.escape(value[sk].to_s)}
226
+ elsif value.is_a? Array
227
+ key = Typhoeus::Utils.escape(k.to_s)
228
+ value.collect { |v| "#{key}=#{Typhoeus::Utils.escape(v.to_s)}" }.join('&')
229
+ else
230
+ "#{Typhoeus::Utils.escape(k.to_s)}=#{Typhoeus::Utils.escape(params[k].to_s)}"
231
+ end
232
+ end.flatten.join("&")
233
+
234
+ if method == :post
235
+ self.post_data = params_string
236
+ else
237
+ self.url = "#{url}?#{params_string}"
238
+ end
239
+ end
240
+
241
+ # Set SSL certificate
242
+ # " The string should be the file name of your certificate. "
243
+ # The default format is "PEM" and can be changed with ssl_cert_type=
244
+ def ssl_cert=(cert)
245
+ set_option(OPTION_VALUES[:CURLOPT_SSLCERT], cert)
246
+ end
247
+
248
+ # Set SSL certificate type
249
+ # " The string should be the format of your certificate. Supported formats are "PEM" and "DER" "
250
+ def ssl_cert_type=(cert_type)
251
+ raise "Invalid ssl cert type : '#{cert_type}'..." if cert_type and !%w(PEM DER).include?(cert_type)
252
+ set_option(OPTION_VALUES[:CURLOPT_SSLCERTTYPE], cert_type)
253
+ end
254
+
255
+ # Set SSL Key file
256
+ # " The string should be the file name of your private key. "
257
+ # The default format is "PEM" and can be changed with ssl_key_type=
258
+ #
259
+ def ssl_key=(key)
260
+ set_option(OPTION_VALUES[:CURLOPT_SSLKEY], key)
261
+ end
262
+
263
+ # Set SSL Key type
264
+ # " The string should be the format of your private key. Supported formats are "PEM", "DER" and "ENG". "
265
+ #
266
+ def ssl_key_type=(key_type)
267
+ raise "Invalid ssl key type : '#{key_type}'..." if key_type and !%w(PEM DER ENG).include?(key_type)
268
+ set_option(OPTION_VALUES[:CURLOPT_SSLKEYTYPE], key_type)
269
+ end
270
+
271
+ def ssl_key_password=(key_password)
272
+ set_option(OPTION_VALUES[:CURLOPT_KEYPASSWD], key_password)
273
+ end
274
+
275
+ # Set SSL CACERT
276
+ # " File holding one or more certificates to verify the peer with. "
277
+ #
278
+ def ssl_cacert=(cacert)
279
+ set_option(OPTION_VALUES[:CURLOPT_CAINFO], cacert)
280
+ end
281
+
282
+ # Set CAPATH
283
+ # " directory holding multiple CA certificates to verify the peer with. The certificate directory must be prepared using the openssl c_rehash utility. "
284
+ #
285
+ def ssl_capath=(capath)
286
+ set_option(OPTION_VALUES[:CURLOPT_CAPATH], capath)
287
+ end
288
+
289
+ def set_option(option, value)
290
+ if value.class == String
291
+ easy_setopt_string(option, value)
292
+ elsif value
293
+ easy_setopt_long(option, value)
294
+ end
295
+ end
296
+
297
+ def perform
298
+ set_headers()
299
+ easy_perform()
300
+ resp_code = response_code()
301
+ if resp_code >= 200 && resp_code <= 299
302
+ success
303
+ else
304
+ failure
305
+ end
306
+ resp_code
307
+ end
308
+
309
+ def set_headers
310
+ headers.each_pair do |key, value|
311
+ easy_add_header("#{key}: #{value}")
312
+ end
313
+ easy_set_headers() unless headers.empty?
314
+ end
315
+
316
+ # gets called when finished and response code is 200-299
317
+ def success
318
+ @success.call(self) if @success
319
+ end
320
+
321
+ def on_success(&block)
322
+ @success = block
323
+ end
324
+
325
+ def on_success=(block)
326
+ @success = block
327
+ end
328
+
329
+ # gets called when finished and response code is 300-599 or curl returns an error code
330
+ def failure
331
+ @failure.call(self) if @failure
332
+ end
333
+
334
+ def on_failure(&block)
335
+ @failure = block
336
+ end
337
+
338
+ def on_failure=(block)
339
+ @failure = block
340
+ end
341
+
342
+ def reset
343
+ @response_code = 0
344
+ @response_header = ""
345
+ @response_body = ""
346
+ easy_reset()
347
+ end
348
+
349
+ def get_info_string(option)
350
+ easy_getinfo_string(option)
351
+ end
352
+
353
+ def get_info_long(option)
354
+ easy_getinfo_long(option)
355
+ end
356
+
357
+ def get_info_double(option)
358
+ easy_getinfo_double(option)
359
+ end
360
+
361
+ def curl_version
362
+ version
363
+ end
364
+
365
+ end
366
+ end