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.
- data/CHANGELOG.markdown +84 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +56 -0
- data/LICENSE +20 -0
- data/Rakefile +43 -0
- data/ext/typhoeus/.gitignore +7 -0
- data/ext/typhoeus/extconf.rb +65 -0
- data/ext/typhoeus/native.c +12 -0
- data/ext/typhoeus/native.h +22 -0
- data/ext/typhoeus/typhoeus_easy.c +232 -0
- data/ext/typhoeus/typhoeus_easy.h +20 -0
- data/ext/typhoeus/typhoeus_form.c +59 -0
- data/ext/typhoeus/typhoeus_form.h +13 -0
- data/ext/typhoeus/typhoeus_multi.c +217 -0
- data/ext/typhoeus/typhoeus_multi.h +16 -0
- data/lib/typhoeus.rb +58 -0
- data/lib/typhoeus/.gitignore +1 -0
- data/lib/typhoeus/easy.rb +413 -0
- data/lib/typhoeus/filter.rb +28 -0
- data/lib/typhoeus/form.rb +32 -0
- data/lib/typhoeus/hydra.rb +250 -0
- data/lib/typhoeus/hydra/callbacks.rb +24 -0
- data/lib/typhoeus/hydra/connect_options.rb +61 -0
- data/lib/typhoeus/hydra/stubbing.rb +68 -0
- data/lib/typhoeus/hydra_mock.rb +131 -0
- data/lib/typhoeus/multi.rb +37 -0
- data/lib/typhoeus/normalized_header_hash.rb +58 -0
- data/lib/typhoeus/remote.rb +306 -0
- data/lib/typhoeus/remote_method.rb +108 -0
- data/lib/typhoeus/remote_proxy_object.rb +50 -0
- data/lib/typhoeus/request.rb +269 -0
- data/lib/typhoeus/response.rb +122 -0
- data/lib/typhoeus/service.rb +20 -0
- data/lib/typhoeus/utils.rb +74 -0
- data/lib/typhoeus/version.rb +3 -0
- data/spec/fixtures/placeholder.gif +0 -0
- data/spec/fixtures/placeholder.txt +1 -0
- data/spec/fixtures/placeholder.ukn +0 -0
- data/spec/fixtures/result_set.xml +60 -0
- data/spec/servers/app.rb +97 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/typhoeus_localhost_server.rb +58 -0
- data/spec/typhoeus/easy_spec.rb +391 -0
- data/spec/typhoeus/filter_spec.rb +35 -0
- data/spec/typhoeus/form_spec.rb +117 -0
- data/spec/typhoeus/hydra_mock_spec.rb +300 -0
- data/spec/typhoeus/hydra_spec.rb +602 -0
- data/spec/typhoeus/multi_spec.rb +74 -0
- data/spec/typhoeus/normalized_header_hash_spec.rb +41 -0
- data/spec/typhoeus/remote_method_spec.rb +141 -0
- data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
- data/spec/typhoeus/remote_spec.rb +695 -0
- data/spec/typhoeus/request_spec.rb +387 -0
- data/spec/typhoeus/response_spec.rb +192 -0
- data/spec/typhoeus/utils_spec.rb +22 -0
- data/typhoeus.gemspec +35 -0
- 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,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
|
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/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
|