marnen-typhoeus 0.3.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 (57) hide show
  1. data/CHANGELOG.markdown +84 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +56 -0
  4. data/LICENSE +20 -0
  5. data/Rakefile +43 -0
  6. data/ext/typhoeus/.gitignore +7 -0
  7. data/ext/typhoeus/extconf.rb +65 -0
  8. data/ext/typhoeus/native.c +12 -0
  9. data/ext/typhoeus/native.h +22 -0
  10. data/ext/typhoeus/typhoeus_easy.c +232 -0
  11. data/ext/typhoeus/typhoeus_easy.h +20 -0
  12. data/ext/typhoeus/typhoeus_form.c +59 -0
  13. data/ext/typhoeus/typhoeus_form.h +13 -0
  14. data/ext/typhoeus/typhoeus_multi.c +217 -0
  15. data/ext/typhoeus/typhoeus_multi.h +16 -0
  16. data/lib/typhoeus.rb +58 -0
  17. data/lib/typhoeus/.gitignore +1 -0
  18. data/lib/typhoeus/easy.rb +413 -0
  19. data/lib/typhoeus/filter.rb +28 -0
  20. data/lib/typhoeus/form.rb +32 -0
  21. data/lib/typhoeus/hydra.rb +250 -0
  22. data/lib/typhoeus/hydra/callbacks.rb +24 -0
  23. data/lib/typhoeus/hydra/connect_options.rb +61 -0
  24. data/lib/typhoeus/hydra/stubbing.rb +68 -0
  25. data/lib/typhoeus/hydra_mock.rb +131 -0
  26. data/lib/typhoeus/multi.rb +37 -0
  27. data/lib/typhoeus/normalized_header_hash.rb +58 -0
  28. data/lib/typhoeus/remote.rb +306 -0
  29. data/lib/typhoeus/remote_method.rb +108 -0
  30. data/lib/typhoeus/remote_proxy_object.rb +50 -0
  31. data/lib/typhoeus/request.rb +269 -0
  32. data/lib/typhoeus/response.rb +122 -0
  33. data/lib/typhoeus/service.rb +20 -0
  34. data/lib/typhoeus/utils.rb +74 -0
  35. data/lib/typhoeus/version.rb +3 -0
  36. data/spec/fixtures/placeholder.gif +0 -0
  37. data/spec/fixtures/placeholder.txt +1 -0
  38. data/spec/fixtures/placeholder.ukn +0 -0
  39. data/spec/fixtures/result_set.xml +60 -0
  40. data/spec/servers/app.rb +97 -0
  41. data/spec/spec_helper.rb +19 -0
  42. data/spec/support/typhoeus_localhost_server.rb +58 -0
  43. data/spec/typhoeus/easy_spec.rb +391 -0
  44. data/spec/typhoeus/filter_spec.rb +35 -0
  45. data/spec/typhoeus/form_spec.rb +117 -0
  46. data/spec/typhoeus/hydra_mock_spec.rb +300 -0
  47. data/spec/typhoeus/hydra_spec.rb +602 -0
  48. data/spec/typhoeus/multi_spec.rb +74 -0
  49. data/spec/typhoeus/normalized_header_hash_spec.rb +41 -0
  50. data/spec/typhoeus/remote_method_spec.rb +141 -0
  51. data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
  52. data/spec/typhoeus/remote_spec.rb +695 -0
  53. data/spec/typhoeus/request_spec.rb +387 -0
  54. data/spec/typhoeus/response_spec.rb +192 -0
  55. data/spec/typhoeus/utils_spec.rb +22 -0
  56. data/typhoeus.gemspec +35 -0
  57. metadata +235 -0
@@ -0,0 +1,20 @@
1
+ #ifndef TYPHOEUS_EASY
2
+ #define TYPHOEUS_EASY
3
+
4
+ #include <native.h>
5
+ #include <typhoeus_form.h>
6
+
7
+ void init_typhoeus_easy();
8
+ typedef struct {
9
+ const char *memory;
10
+ int size;
11
+ int read;
12
+ } RequestChunk;
13
+
14
+ typedef struct {
15
+ RequestChunk *request_chunk;
16
+ CURL *curl;
17
+ struct curl_slist *headers;
18
+ } CurlEasy;
19
+
20
+ #endif
@@ -0,0 +1,59 @@
1
+ #include <typhoeus_form.h>
2
+
3
+ VALUE cTyphoeusForm;
4
+
5
+ static void dealloc(CurlForm *curl_form) {
6
+ curl_formfree(curl_form->first);
7
+ free(curl_form);
8
+ }
9
+
10
+ static VALUE formadd_file(VALUE self,
11
+ VALUE name,
12
+ VALUE filename,
13
+ VALUE content_type,
14
+ VALUE path) {
15
+ CurlForm *curl_form;
16
+ Data_Get_Struct(self, CurlForm, curl_form);
17
+
18
+ return INT2NUM((long) curl_formadd(&curl_form->first, &curl_form->last,
19
+ CURLFORM_COPYNAME, RSTRING_PTR(name),
20
+ CURLFORM_NAMELENGTH, (long)RSTRING_LEN(name),
21
+ CURLFORM_FILENAME, RSTRING_PTR(filename),
22
+ CURLFORM_CONTENTTYPE, RSTRING_PTR(content_type),
23
+ CURLFORM_FILE, RSTRING_PTR(path),
24
+ CURLFORM_END
25
+ ));
26
+ }
27
+
28
+ static VALUE formadd_param(VALUE self, VALUE name, VALUE value) {
29
+ CurlForm *curl_form;
30
+ Data_Get_Struct(self, CurlForm, curl_form);
31
+
32
+ return INT2NUM((long)curl_formadd(&curl_form->first, &curl_form->last,
33
+ CURLFORM_COPYNAME, RSTRING_PTR(name),
34
+ CURLFORM_NAMELENGTH, (long)RSTRING_LEN(name),
35
+ CURLFORM_COPYCONTENTS, RSTRING_PTR(value),
36
+ CURLFORM_CONTENTSLENGTH, (long)RSTRING_LEN(value),
37
+ CURLFORM_END
38
+ ));
39
+ }
40
+
41
+ static VALUE new(int argc, VALUE *argv, VALUE klass) {
42
+ CurlForm *curl_form = ALLOC(CurlForm);
43
+ curl_form->first = NULL;
44
+ curl_form->last = NULL;
45
+
46
+ VALUE form = Data_Wrap_Struct(cTyphoeusForm, 0, dealloc, curl_form);
47
+
48
+ rb_obj_call_init(form, argc, argv);
49
+
50
+ return form;
51
+ }
52
+
53
+ void init_typhoeus_form() {
54
+ VALUE klass = cTyphoeusForm = rb_define_class_under(mTyphoeus, "Form", rb_cObject);
55
+
56
+ rb_define_singleton_method(klass, "new", new, -1);
57
+ rb_define_private_method(klass, "formadd_file", formadd_file, 4);
58
+ rb_define_private_method(klass, "formadd_param", formadd_param, 2);
59
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef TYPHOEUS_FORM
2
+ #define TYPHOEUS_FORM
3
+
4
+ #include <native.h>
5
+
6
+ typedef struct {
7
+ struct curl_httppost *first;
8
+ struct curl_httppost *last;
9
+ } CurlForm;
10
+
11
+ void init_typhoeus_form();
12
+
13
+ #endif
@@ -0,0 +1,217 @@
1
+ /* Make sure select() works with >1024 file handles open. */
2
+ #include <sys/types.h>
3
+ #undef __FD_SETSIZE
4
+ #define __FD_SETSIZE 524288
5
+
6
+ #include <typhoeus_multi.h>
7
+ #include <errno.h>
8
+
9
+ static void multi_read_info(VALUE self, CURLM *multi_handle);
10
+
11
+ static void dealloc(CurlMulti *curl_multi) {
12
+ curl_multi_cleanup(curl_multi->multi);
13
+ free(curl_multi);
14
+ }
15
+
16
+ static VALUE multi_add_handle(VALUE self, VALUE easy) {
17
+ CurlEasy *curl_easy;
18
+ Data_Get_Struct(easy, CurlEasy, curl_easy);
19
+ CurlMulti *curl_multi;
20
+ Data_Get_Struct(self, CurlMulti, curl_multi);
21
+ CURLMcode mcode;
22
+
23
+ mcode = curl_multi_add_handle(curl_multi->multi, curl_easy->curl);
24
+ if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
25
+ rb_raise(rb_eRuntimeError, "An error occured adding the handle: %d: %s", mcode, curl_multi_strerror(mcode));
26
+ }
27
+
28
+ curl_easy_setopt(curl_easy->curl, CURLOPT_PRIVATE, easy);
29
+ curl_multi->active++;
30
+
31
+ VALUE easy_handles = rb_iv_get(self, "@easy_handles");
32
+ rb_ary_push(easy_handles, easy);
33
+
34
+ if (mcode == CURLM_CALL_MULTI_PERFORM) {
35
+ curl_multi_perform(curl_multi->multi, &(curl_multi->running));
36
+ }
37
+ //
38
+ // if (curl_multi->running) {
39
+ // printf("call read_info on add<br/>");
40
+ // multi_read_info(self, curl_multi->multi);
41
+ // }
42
+
43
+ return easy;
44
+ }
45
+
46
+ static VALUE multi_remove_handle(VALUE self, VALUE easy) {
47
+ CurlEasy *curl_easy;
48
+ Data_Get_Struct(easy, CurlEasy, curl_easy);
49
+ CurlMulti *curl_multi;
50
+ Data_Get_Struct(self, CurlMulti, curl_multi);
51
+
52
+ curl_multi->active--;
53
+ curl_multi_remove_handle(curl_multi->multi, curl_easy->curl);
54
+
55
+ VALUE easy_handles = rb_iv_get(self, "@easy_handles");
56
+ rb_ary_delete(easy_handles, easy);
57
+
58
+ return easy;
59
+ }
60
+
61
+ static void multi_read_info(VALUE self, CURLM *multi_handle) {
62
+ int msgs_left, result;
63
+ CURLMsg *msg;
64
+ CURLcode ecode;
65
+ CURL *easy_handle;
66
+ VALUE easy;
67
+
68
+ /* check for finished easy handles and remove from the multi handle */
69
+ while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
70
+
71
+ if (msg->msg != CURLMSG_DONE) {
72
+ continue;
73
+ }
74
+
75
+ easy_handle = msg->easy_handle;
76
+ result = msg->data.result;
77
+ if (easy_handle) {
78
+ ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &easy);
79
+ if (ecode != 0) {
80
+ rb_raise(rb_eRuntimeError, "error getting easy object: %d: %s", ecode, curl_easy_strerror(ecode));
81
+ }
82
+
83
+ long response_code = -1;
84
+ curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &response_code);
85
+
86
+ multi_remove_handle(self, easy);
87
+ rb_iv_set(easy, "@curl_return_code", INT2FIX(result));
88
+
89
+ if (result != 0) {
90
+ rb_funcall(easy, rb_intern("failure"), 0);
91
+ }
92
+ else if ((response_code >= 200 && response_code < 300) || response_code == 0) {
93
+ rb_funcall(easy, rb_intern("success"), 0);
94
+ }
95
+ else {
96
+ rb_funcall(easy, rb_intern("failure"), 0);
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ /* called by multi_perform and fire_and_forget */
103
+ static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running) {
104
+ CURLMcode mcode;
105
+
106
+ do {
107
+ mcode = curl_multi_perform(multi_handle, still_running);
108
+ } while (mcode == CURLM_CALL_MULTI_PERFORM);
109
+
110
+ if (mcode != CURLM_OK) {
111
+ rb_raise(rb_eRuntimeError, "an error occured while running perform: %d: %s", mcode, curl_multi_strerror(mcode));
112
+ }
113
+
114
+ multi_read_info( self, multi_handle );
115
+ }
116
+
117
+ static VALUE fire_and_forget(VALUE self) {
118
+ CurlMulti *curl_multi;
119
+ Data_Get_Struct(self, CurlMulti, curl_multi);
120
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
121
+
122
+ return Qnil;
123
+ }
124
+
125
+ static VALUE multi_perform(VALUE self) {
126
+ CURLMcode mcode;
127
+ CurlMulti *curl_multi;
128
+ int maxfd, rc;
129
+ fd_set fdread, fdwrite, fdexcep;
130
+
131
+ long timeout;
132
+ struct timeval tv = {0, 0};
133
+
134
+ Data_Get_Struct(self, CurlMulti, curl_multi);
135
+
136
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
137
+ while(curl_multi->running) {
138
+ FD_ZERO(&fdread);
139
+ FD_ZERO(&fdwrite);
140
+ FD_ZERO(&fdexcep);
141
+
142
+ /* get the curl suggested time out */
143
+ mcode = curl_multi_timeout(curl_multi->multi, &timeout);
144
+ if (mcode != CURLM_OK) {
145
+ rb_raise(rb_eRuntimeError, "an error occured getting the timeout: %d: %s", mcode, curl_multi_strerror(mcode));
146
+ }
147
+
148
+ if (timeout == 0) { /* no delay */
149
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
150
+ continue;
151
+ }
152
+ else if (timeout < 0) {
153
+ timeout = 1;
154
+ }
155
+
156
+ tv.tv_sec = timeout / 1000;
157
+ tv.tv_usec = (timeout * 1000) % 1000000;
158
+
159
+ /* load the fd sets from the multi handle */
160
+ mcode = curl_multi_fdset(curl_multi->multi, &fdread, &fdwrite, &fdexcep, &maxfd);
161
+ if (mcode != CURLM_OK) {
162
+ rb_raise(rb_eRuntimeError, "an error occured getting the fdset: %d: %s", mcode, curl_multi_strerror(mcode));
163
+ }
164
+
165
+ rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
166
+ if (rc < 0) {
167
+ rb_raise(rb_eRuntimeError, "error on thread select: %d", errno);
168
+ }
169
+ rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
170
+
171
+ }
172
+
173
+ return Qnil;
174
+ }
175
+
176
+ static VALUE active_handle_count(VALUE self) {
177
+ CurlMulti *curl_multi;
178
+ Data_Get_Struct(self, CurlMulti, curl_multi);
179
+
180
+ return INT2FIX(curl_multi->active);
181
+ }
182
+
183
+ static VALUE multi_cleanup(VALUE self) {
184
+ CurlMulti *curl_multi;
185
+ Data_Get_Struct(self, CurlMulti, curl_multi);
186
+
187
+ curl_multi_cleanup(curl_multi->multi);
188
+ curl_multi->active = 0;
189
+ curl_multi->running = 0;
190
+
191
+ return Qnil;
192
+ }
193
+
194
+ static VALUE new(int argc, VALUE *argv, VALUE klass) {
195
+ CurlMulti *curl_multi = ALLOC(CurlMulti);
196
+ curl_multi->multi = curl_multi_init();
197
+ curl_multi->active = 0;
198
+ curl_multi->running = 0;
199
+
200
+ VALUE multi = Data_Wrap_Struct(cTyphoeusMulti, 0, dealloc, curl_multi);
201
+
202
+ rb_obj_call_init(multi, argc, argv);
203
+
204
+ return multi;
205
+ }
206
+
207
+ void init_typhoeus_multi() {
208
+ VALUE klass = cTyphoeusMulti = rb_define_class_under(mTyphoeus, "Multi", rb_cObject);
209
+
210
+ rb_define_singleton_method(klass, "new", new, -1);
211
+ rb_define_private_method(klass, "multi_add_handle", multi_add_handle, 1);
212
+ rb_define_private_method(klass, "multi_remove_handle", multi_remove_handle, 1);
213
+ rb_define_private_method(klass, "multi_perform", multi_perform, 0);
214
+ rb_define_private_method(klass, "multi_cleanup", multi_cleanup, 0);
215
+ rb_define_private_method(klass, "active_handle_count", active_handle_count, 0);
216
+ rb_define_method(klass, "fire_and_forget", fire_and_forget, 0);
217
+ }
@@ -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,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/form'
9
+ require 'typhoeus/multi'
10
+ require 'typhoeus/native'
11
+ require 'typhoeus/filter'
12
+ require 'typhoeus/remote_method'
13
+ require 'typhoeus/remote'
14
+ require 'typhoeus/remote_proxy_object'
15
+ require 'typhoeus/response'
16
+ require 'typhoeus/request'
17
+ require 'typhoeus/hydra'
18
+ require 'typhoeus/hydra_mock'
19
+ require 'typhoeus/version'
20
+
21
+ module Typhoeus
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,413 @@
1
+ module Typhoeus
2
+ class Easy
3
+ attr_reader :response_body, :response_header, :method, :headers, :url, :params, :curl_return_code, :ssl_version
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_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
+ def initialize
89
+ @method = :get
90
+ @headers = {}
91
+
92
+ set_defaults
93
+ end
94
+
95
+ def set_defaults
96
+ # Enable encoding/compression support
97
+ self.encoding = ''
98
+ self.ssl_version = :default
99
+ end
100
+
101
+ def encoding=(encoding)
102
+ # Enable encoding/compression support
103
+ set_option(OPTION_VALUES[:CURLOPT_ENCODING], encoding)
104
+ end
105
+
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
109
+
110
+ set_option(OPTION_VALUES[:CURLOPT_SSLVERSION], SSL_VERSIONS[version])
111
+ end
112
+
113
+ def headers=(hash)
114
+ @headers = hash
115
+ end
116
+
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
+ def params
263
+ @form.nil? ? {} : @form.params
264
+ end
265
+
266
+ def params=(params)
267
+ @form = Typhoeus::Form.new(params)
268
+
269
+ if method == :post
270
+ @form.process!
271
+ if @form.multipart?
272
+ set_option(OPTION_VALUES[:CURLOPT_HTTPPOST], @form)
273
+ else
274
+ self.post_data = @form.to_s
275
+ end
276
+ else
277
+ self.url = "#{url}?#{@form.to_s}"
278
+ end
279
+ end
280
+
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
+ def perform
341
+ set_headers()
342
+ easy_perform()
343
+ resp_code = response_code()
344
+ if resp_code >= 200 && resp_code <= 299
345
+ success
346
+ else
347
+ failure
348
+ end
349
+ resp_code
350
+ end
351
+
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
378
+
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
399
+
400
+ def get_info_long(option)
401
+ easy_getinfo_long(option)
402
+ end
403
+
404
+ def get_info_double(option)
405
+ easy_getinfo_double(option)
406
+ end
407
+
408
+ def curl_version
409
+ version
410
+ end
411
+
412
+ end
413
+ end