dbalatero-typhoeus 0.0.20
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/ext/typhoeus/Makefile +157 -0
- data/ext/typhoeus/extconf.rb +57 -0
- data/ext/typhoeus/native.c +11 -0
- data/ext/typhoeus/native.h +11 -0
- data/ext/typhoeus/typhoeus_easy.c +206 -0
- data/ext/typhoeus/typhoeus_easy.h +19 -0
- data/ext/typhoeus/typhoeus_multi.c +213 -0
- data/ext/typhoeus/typhoeus_multi.h +16 -0
- data/lib/typhoeus/easy.rb +210 -0
- data/lib/typhoeus/filter.rb +28 -0
- data/lib/typhoeus/multi.rb +34 -0
- data/lib/typhoeus/remote.rb +306 -0
- data/lib/typhoeus/remote_method.rb +108 -0
- data/lib/typhoeus/remote_proxy_object.rb +48 -0
- data/lib/typhoeus/response.rb +17 -0
- data/lib/typhoeus.rb +53 -0
- data/spec/servers/delay_fixture_server.rb +66 -0
- data/spec/servers/method_server.rb +51 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/typhoeus/easy_spec.rb +148 -0
- data/spec/typhoeus/filter_spec.rb +35 -0
- data/spec/typhoeus/multi_spec.rb +82 -0
- data/spec/typhoeus/remote_method_spec.rb +141 -0
- data/spec/typhoeus/remote_proxy_object_spec.rb +73 -0
- data/spec/typhoeus/remote_spec.rb +699 -0
- data/spec/typhoeus/response_spec.rb +31 -0
- metadata +81 -0
@@ -0,0 +1,157 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /usr/local/lib/ruby/1.8/i686-darwin9.6.0
|
8
|
+
hdrdir = $(topdir)
|
9
|
+
VPATH = $(srcdir):$(topdir):$(hdrdir)
|
10
|
+
exec_prefix = $(prefix)
|
11
|
+
prefix = $(DESTDIR)/usr/local
|
12
|
+
sharedstatedir = $(prefix)/com
|
13
|
+
mandir = $(datarootdir)/man
|
14
|
+
psdir = $(docdir)
|
15
|
+
oldincludedir = $(DESTDIR)/usr/include
|
16
|
+
localedir = $(datarootdir)/locale
|
17
|
+
bindir = $(exec_prefix)/bin
|
18
|
+
libexecdir = $(exec_prefix)/libexec
|
19
|
+
sitedir = $(libdir)/ruby/site_ruby
|
20
|
+
htmldir = $(docdir)
|
21
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
22
|
+
includedir = $(prefix)/include
|
23
|
+
infodir = $(datarootdir)/info
|
24
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
25
|
+
sysconfdir = $(prefix)/etc
|
26
|
+
libdir = $(exec_prefix)/lib
|
27
|
+
sbindir = $(exec_prefix)/sbin
|
28
|
+
rubylibdir = $(libdir)/ruby/$(ruby_version)
|
29
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
30
|
+
dvidir = $(docdir)
|
31
|
+
vendordir = $(libdir)/ruby/vendor_ruby
|
32
|
+
datarootdir = $(prefix)/share
|
33
|
+
pdfdir = $(docdir)
|
34
|
+
archdir = $(rubylibdir)/$(arch)
|
35
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
36
|
+
datadir = $(datarootdir)
|
37
|
+
localstatedir = $(prefix)/var
|
38
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
39
|
+
|
40
|
+
CC = gcc
|
41
|
+
LIBRUBY = $(LIBRUBY_A)
|
42
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
43
|
+
LIBRUBYARG_SHARED =
|
44
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
45
|
+
|
46
|
+
RUBY_EXTCONF_H =
|
47
|
+
CFLAGS = -fno-common -g -O2 -pipe -fno-common $(cflags) -g -DXP_UNIX -O3 -Wall -Wcast-qual -Wwrite-strings -Wconversion -Wmissing-noreturn -Winline
|
48
|
+
INCFLAGS = -I. -I. -I/usr/local/lib/ruby/1.8/i686-darwin9.6.0 -I.
|
49
|
+
DEFS =
|
50
|
+
CPPFLAGS = -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE
|
51
|
+
CXXFLAGS = $(CFLAGS)
|
52
|
+
ldflags = -L.
|
53
|
+
dldflags =
|
54
|
+
archflag =
|
55
|
+
DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
|
56
|
+
LDSHARED = cc -dynamic -bundle -undefined suppress -flat_namespace
|
57
|
+
AR = ar
|
58
|
+
EXEEXT =
|
59
|
+
|
60
|
+
RUBY_INSTALL_NAME = ruby
|
61
|
+
RUBY_SO_NAME = ruby
|
62
|
+
arch = i686-darwin9.6.0
|
63
|
+
sitearch = i686-darwin9.6.0
|
64
|
+
ruby_version = 1.8
|
65
|
+
ruby = /usr/local/bin/ruby
|
66
|
+
RUBY = $(ruby)
|
67
|
+
RM = rm -f
|
68
|
+
MAKEDIRS = mkdir -p
|
69
|
+
INSTALL = /usr/bin/install -c
|
70
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
71
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
72
|
+
COPY = cp
|
73
|
+
|
74
|
+
#### End of system configuration section. ####
|
75
|
+
|
76
|
+
preload =
|
77
|
+
|
78
|
+
libpath = . $(libdir) /opt/local/lib
|
79
|
+
LIBPATH = -L. -L$(libdir) -L/opt/local/lib
|
80
|
+
DEFFILE =
|
81
|
+
|
82
|
+
CLEANFILES = mkmf.log
|
83
|
+
DISTCLEANFILES =
|
84
|
+
|
85
|
+
extout =
|
86
|
+
extout_prefix =
|
87
|
+
target_prefix = /typhoeus
|
88
|
+
LOCAL_LIBS =
|
89
|
+
LIBS = -lcurl -ldl -lobjc
|
90
|
+
SRCS = native.c typhoeus_easy.c typhoeus_multi.c
|
91
|
+
OBJS = native.o typhoeus_easy.o typhoeus_multi.o
|
92
|
+
TARGET = native
|
93
|
+
DLLIB = $(TARGET).bundle
|
94
|
+
EXTSTATIC =
|
95
|
+
STATIC_LIB =
|
96
|
+
|
97
|
+
BINDIR = $(bindir)
|
98
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
99
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
100
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
101
|
+
|
102
|
+
TARGET_SO = $(DLLIB)
|
103
|
+
CLEANLIBS = $(TARGET).bundle $(TARGET).il? $(TARGET).tds $(TARGET).map
|
104
|
+
CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
|
105
|
+
|
106
|
+
all: $(DLLIB)
|
107
|
+
static: $(STATIC_LIB)
|
108
|
+
|
109
|
+
clean:
|
110
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
111
|
+
|
112
|
+
distclean: clean
|
113
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
114
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
115
|
+
|
116
|
+
realclean: distclean
|
117
|
+
install: install-so install-rb
|
118
|
+
|
119
|
+
install-so: $(RUBYARCHDIR)
|
120
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
121
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
122
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
123
|
+
install-rb: pre-install-rb install-rb-default
|
124
|
+
install-rb-default: pre-install-rb-default
|
125
|
+
pre-install-rb: Makefile
|
126
|
+
pre-install-rb-default: Makefile
|
127
|
+
$(RUBYARCHDIR):
|
128
|
+
$(MAKEDIRS) $@
|
129
|
+
|
130
|
+
site-install: site-install-so site-install-rb
|
131
|
+
site-install-so: install-so
|
132
|
+
site-install-rb: install-rb
|
133
|
+
|
134
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
135
|
+
|
136
|
+
.cc.o:
|
137
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
138
|
+
|
139
|
+
.cxx.o:
|
140
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
141
|
+
|
142
|
+
.cpp.o:
|
143
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
144
|
+
|
145
|
+
.C.o:
|
146
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
147
|
+
|
148
|
+
.c.o:
|
149
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
|
150
|
+
|
151
|
+
$(DLLIB): $(OBJS)
|
152
|
+
@-$(RM) $@
|
153
|
+
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
$(OBJS): ruby.h defines.h
|
@@ -0,0 +1,57 @@
|
|
1
|
+
ENV["ARCHFLAGS"] = "-arch #{`uname -p` =~ /powerpc/ ? 'ppc' : 'i386'}"
|
2
|
+
|
3
|
+
require 'mkmf'
|
4
|
+
|
5
|
+
ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
6
|
+
LIBDIR = Config::CONFIG['libdir']
|
7
|
+
INCLUDEDIR = Config::CONFIG['includedir']
|
8
|
+
|
9
|
+
use_macports = !(defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby')
|
10
|
+
|
11
|
+
$CFLAGS << " #{ENV["CFLAGS"]}"
|
12
|
+
if Config::CONFIG['target_os'] == 'mingw32'
|
13
|
+
$CFLAGS << " -DXP_WIN -DXP_WIN32"
|
14
|
+
else
|
15
|
+
$CFLAGS << " -g -DXP_UNIX"
|
16
|
+
end
|
17
|
+
|
18
|
+
$LIBPATH << "/opt/local/lib" if use_macports
|
19
|
+
|
20
|
+
$CFLAGS << " -O3 -Wall -Wcast-qual -Wwrite-strings -Wconversion -Wmissing-noreturn -Winline"
|
21
|
+
|
22
|
+
if Config::CONFIG['target_os'] == 'mingw32'
|
23
|
+
header = File.join(ROOT, 'cross', 'curl-7.19.4.win32', 'include')
|
24
|
+
unless find_header('curl/curl.h', header)
|
25
|
+
abort "need libcurl"
|
26
|
+
end
|
27
|
+
else
|
28
|
+
HEADER_DIRS = [
|
29
|
+
File.join(INCLUDEDIR, "curl"),
|
30
|
+
INCLUDEDIR,
|
31
|
+
'/usr/include/curl',
|
32
|
+
'/usr/local/include/curl'
|
33
|
+
]
|
34
|
+
|
35
|
+
[
|
36
|
+
'/opt/local/include/curl',
|
37
|
+
'/opt/local/include',
|
38
|
+
].each { |x| HEADER_DIRS.unshift(x) } if use_macports
|
39
|
+
|
40
|
+
unless find_header('curl/curl.h', *HEADER_DIRS)
|
41
|
+
abort "need libcurl"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if Config::CONFIG['target_os'] == 'mingw32'
|
46
|
+
find_library('curl', 'curl_easy_init',
|
47
|
+
File.join(ROOT, 'cross', 'curl-7.19.4.win32', 'bin'))
|
48
|
+
else
|
49
|
+
find_library('curl', 'curl_easy_init',
|
50
|
+
LIBDIR,
|
51
|
+
'/opt/local/lib',
|
52
|
+
'/usr/local/lib',
|
53
|
+
'/usr/lib'
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
create_makefile("typhoeus/native")
|
@@ -0,0 +1,206 @@
|
|
1
|
+
#include <typhoeus_easy.h>
|
2
|
+
|
3
|
+
static VALUE idAppend;
|
4
|
+
VALUE cTyphoeusEasy;
|
5
|
+
|
6
|
+
static void dealloc(CurlEasy *curl_easy) {
|
7
|
+
if (curl_easy->request_chunk != NULL) {
|
8
|
+
free(curl_easy->request_chunk);
|
9
|
+
}
|
10
|
+
|
11
|
+
if (curl_easy->headers != NULL) {
|
12
|
+
curl_slist_free_all(curl_easy->headers);
|
13
|
+
}
|
14
|
+
|
15
|
+
curl_easy_cleanup(curl_easy->curl);
|
16
|
+
|
17
|
+
free(curl_easy);
|
18
|
+
}
|
19
|
+
|
20
|
+
static VALUE easy_setopt_string(VALUE self, VALUE opt_name, VALUE parameter) {
|
21
|
+
CurlEasy *curl_easy;
|
22
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
23
|
+
|
24
|
+
long opt = NUM2LONG(opt_name);
|
25
|
+
curl_easy_setopt(curl_easy->curl, opt, StringValuePtr(parameter));
|
26
|
+
return opt_name;
|
27
|
+
}
|
28
|
+
|
29
|
+
static VALUE easy_setopt_long(VALUE self, VALUE opt_name, VALUE parameter) {
|
30
|
+
CurlEasy *curl_easy;
|
31
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
32
|
+
|
33
|
+
long opt = NUM2LONG(opt_name);
|
34
|
+
curl_easy_setopt(curl_easy->curl, opt, NUM2LONG(parameter));
|
35
|
+
return opt_name;
|
36
|
+
}
|
37
|
+
|
38
|
+
static VALUE easy_getinfo_string(VALUE self, VALUE info) {
|
39
|
+
char *info_string;
|
40
|
+
CurlEasy *curl_easy;
|
41
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
42
|
+
|
43
|
+
long opt = NUM2LONG(info);
|
44
|
+
curl_easy_getinfo(curl_easy->curl, opt, &info_string);
|
45
|
+
|
46
|
+
return rb_str_new2(info_string);
|
47
|
+
}
|
48
|
+
|
49
|
+
static VALUE easy_getinfo_long(VALUE self, VALUE info) {
|
50
|
+
long info_long;
|
51
|
+
CurlEasy *curl_easy;
|
52
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
53
|
+
|
54
|
+
long opt = NUM2LONG(info);
|
55
|
+
curl_easy_getinfo(curl_easy->curl, opt, &info_long);
|
56
|
+
|
57
|
+
return LONG2NUM(info_long);
|
58
|
+
}
|
59
|
+
|
60
|
+
static VALUE easy_getinfo_double(VALUE self, VALUE info) {
|
61
|
+
double info_double = 0;
|
62
|
+
CurlEasy *curl_easy;
|
63
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
64
|
+
|
65
|
+
long opt = NUM2LONG(info);
|
66
|
+
curl_easy_getinfo(curl_easy->curl, opt, &info_double);
|
67
|
+
|
68
|
+
return rb_float_new(info_double);
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE easy_perform(VALUE self) {
|
72
|
+
CurlEasy *curl_easy;
|
73
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
74
|
+
curl_easy_perform(curl_easy->curl);
|
75
|
+
|
76
|
+
return Qnil;
|
77
|
+
}
|
78
|
+
|
79
|
+
static size_t write_data_handler(char *stream, size_t size, size_t nmemb, VALUE val) {
|
80
|
+
rb_funcall(val, idAppend, 1, rb_str_new(stream, size * nmemb));
|
81
|
+
return size * nmemb;
|
82
|
+
}
|
83
|
+
|
84
|
+
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *data) {
|
85
|
+
int realsize = size * nmemb;
|
86
|
+
RequestChunk *mem = (RequestChunk *)data;
|
87
|
+
|
88
|
+
if (realsize > mem->size - mem->read) {
|
89
|
+
realsize = mem->size - mem->read;
|
90
|
+
}
|
91
|
+
|
92
|
+
if (realsize != 0) {
|
93
|
+
memcpy(ptr, &(mem->memory[mem->read]), realsize);
|
94
|
+
mem->read += realsize;
|
95
|
+
}
|
96
|
+
|
97
|
+
return realsize;
|
98
|
+
}
|
99
|
+
|
100
|
+
static void set_response_handlers(VALUE easy, CURL *curl) {
|
101
|
+
rb_iv_set(easy, "@response_body", rb_str_new2(""));
|
102
|
+
rb_iv_set(easy, "@response_header", rb_str_new2(""));
|
103
|
+
|
104
|
+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&write_data_handler);
|
105
|
+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, rb_iv_get(easy, "@response_body"));
|
106
|
+
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&write_data_handler);
|
107
|
+
curl_easy_setopt(curl, CURLOPT_HEADERDATA, rb_iv_get(easy, "@response_header"));
|
108
|
+
}
|
109
|
+
|
110
|
+
static VALUE easy_reset(VALUE self) {
|
111
|
+
CurlEasy *curl_easy;
|
112
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
113
|
+
|
114
|
+
if (curl_easy->request_chunk != NULL) {
|
115
|
+
free(curl_easy->request_chunk);
|
116
|
+
curl_easy->request_chunk = NULL;
|
117
|
+
}
|
118
|
+
|
119
|
+
if (curl_easy->headers != NULL) {
|
120
|
+
curl_slist_free_all(curl_easy->headers);
|
121
|
+
curl_easy->headers = NULL;
|
122
|
+
}
|
123
|
+
|
124
|
+
curl_easy_reset(curl_easy->curl);
|
125
|
+
|
126
|
+
set_response_handlers(self, curl_easy->curl);
|
127
|
+
|
128
|
+
return Qnil;
|
129
|
+
}
|
130
|
+
|
131
|
+
static VALUE easy_add_header(VALUE self, VALUE header) {
|
132
|
+
CurlEasy *curl_easy;
|
133
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
134
|
+
|
135
|
+
curl_easy->headers = curl_slist_append(curl_easy->headers, strdup(RSTRING_PTR(header)));
|
136
|
+
return header;
|
137
|
+
}
|
138
|
+
|
139
|
+
static VALUE easy_set_headers(VALUE self) {
|
140
|
+
CurlEasy *curl_easy;
|
141
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
142
|
+
|
143
|
+
curl_easy_setopt(curl_easy->curl, CURLOPT_HTTPHEADER, curl_easy->headers);
|
144
|
+
|
145
|
+
return Qnil;
|
146
|
+
}
|
147
|
+
|
148
|
+
static VALUE easy_set_request_body(VALUE self, VALUE data, VALUE content_length_header) {
|
149
|
+
CurlEasy *curl_easy;
|
150
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
151
|
+
|
152
|
+
curl_easy->request_chunk = ALLOC(RequestChunk);
|
153
|
+
curl_easy->request_chunk->size = RSTRING_LEN(data);
|
154
|
+
curl_easy->request_chunk->memory = StringValuePtr(data);
|
155
|
+
curl_easy->request_chunk->read = 0;
|
156
|
+
|
157
|
+
curl_easy_setopt(curl_easy->curl, CURLOPT_READFUNCTION, (curl_read_callback)read_callback);
|
158
|
+
curl_easy_setopt(curl_easy->curl, CURLOPT_READDATA, curl_easy->request_chunk);
|
159
|
+
curl_easy_setopt(curl_easy->curl, CURLOPT_INFILESIZE, RSTRING_LEN(data));
|
160
|
+
|
161
|
+
return Qnil;
|
162
|
+
}
|
163
|
+
|
164
|
+
static VALUE easy_escape(VALUE self, VALUE data, VALUE length) {
|
165
|
+
CurlEasy *curl_easy;
|
166
|
+
Data_Get_Struct(self, CurlEasy, curl_easy);
|
167
|
+
|
168
|
+
return rb_str_new2(curl_easy_escape(curl_easy->curl, StringValuePtr(data), NUM2INT(length)));
|
169
|
+
}
|
170
|
+
|
171
|
+
static VALUE version(VALUE self) {
|
172
|
+
return rb_str_new2(curl_version());
|
173
|
+
}
|
174
|
+
|
175
|
+
static VALUE new(int argc, VALUE *argv, VALUE klass) {
|
176
|
+
CURL *curl = curl_easy_init();
|
177
|
+
CurlEasy *curl_easy = ALLOC(CurlEasy);
|
178
|
+
curl_easy->curl = curl;
|
179
|
+
curl_easy->headers = NULL;
|
180
|
+
curl_easy->request_chunk = NULL;
|
181
|
+
VALUE easy = Data_Wrap_Struct(cTyphoeusEasy, 0, dealloc, curl_easy);
|
182
|
+
|
183
|
+
set_response_handlers(easy, curl);
|
184
|
+
|
185
|
+
rb_obj_call_init(easy, argc, argv);
|
186
|
+
|
187
|
+
return easy;
|
188
|
+
}
|
189
|
+
|
190
|
+
void init_typhoeus_easy() {
|
191
|
+
VALUE klass = cTyphoeusEasy = rb_define_class_under(mTyphoeus, "Easy", rb_cObject);
|
192
|
+
idAppend = rb_intern("<<");
|
193
|
+
rb_define_singleton_method(klass, "new", new, -1);
|
194
|
+
rb_define_private_method(klass, "easy_setopt_string", easy_setopt_string, 2);
|
195
|
+
rb_define_private_method(klass, "easy_setopt_long", easy_setopt_long, 2);
|
196
|
+
rb_define_private_method(klass, "easy_getinfo_string", easy_getinfo_string, 1);
|
197
|
+
rb_define_private_method(klass, "easy_getinfo_long", easy_getinfo_long, 1);
|
198
|
+
rb_define_private_method(klass, "easy_getinfo_double", easy_getinfo_double, 1);
|
199
|
+
rb_define_private_method(klass, "easy_perform", easy_perform, 0);
|
200
|
+
rb_define_private_method(klass, "easy_reset", easy_reset, 0);
|
201
|
+
rb_define_private_method(klass, "easy_set_request_body", easy_set_request_body, 1);
|
202
|
+
rb_define_private_method(klass, "easy_set_headers", easy_set_headers, 0);
|
203
|
+
rb_define_private_method(klass, "easy_add_header", easy_add_header, 1);
|
204
|
+
rb_define_private_method(klass, "easy_escape", easy_escape, 2);
|
205
|
+
rb_define_private_method(klass, "version", version, 0);
|
206
|
+
}
|
@@ -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,213 @@
|
|
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(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
|
+
if (result == 7) {
|
79
|
+
VALUE max_retries = rb_funcall(easy, rb_intern("max_retries?"), 0);
|
80
|
+
if (max_retries != Qtrue) {
|
81
|
+
multi_remove_handle(self, easy);
|
82
|
+
multi_add_handle(self, easy);
|
83
|
+
CurlMulti *curl_multi;
|
84
|
+
Data_Get_Struct(self, CurlMulti, curl_multi);
|
85
|
+
curl_multi_perform(curl_multi->multi, &(curl_multi->running));
|
86
|
+
|
87
|
+
rb_funcall(easy, rb_intern("increment_retries"), 0);
|
88
|
+
|
89
|
+
continue;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
multi_remove_handle(self, easy);
|
93
|
+
|
94
|
+
if (result != 0) {
|
95
|
+
rb_funcall(easy, rb_intern("failure"), 0);
|
96
|
+
}
|
97
|
+
else if ((response_code >= 200 && response_code < 300) || response_code == 0) {
|
98
|
+
rb_funcall(easy, rb_intern("success"), 0);
|
99
|
+
}
|
100
|
+
else if (response_code >= 300 && response_code < 600) {
|
101
|
+
rb_funcall(easy, rb_intern("failure"), 0);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
/* called within ruby_curl_multi_perform */
|
108
|
+
static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running) {
|
109
|
+
CURLMcode mcode;
|
110
|
+
|
111
|
+
do {
|
112
|
+
mcode = curl_multi_perform(multi_handle, still_running);
|
113
|
+
} while (mcode == CURLM_CALL_MULTI_PERFORM);
|
114
|
+
|
115
|
+
if (mcode != CURLM_OK) {
|
116
|
+
rb_raise(mcode, "an error occured while running perform");
|
117
|
+
}
|
118
|
+
|
119
|
+
multi_read_info( self, multi_handle );
|
120
|
+
}
|
121
|
+
|
122
|
+
static VALUE multi_perform(VALUE self) {
|
123
|
+
CURLMcode mcode;
|
124
|
+
CurlMulti *curl_multi;
|
125
|
+
int maxfd, rc;
|
126
|
+
fd_set fdread, fdwrite, fdexcep;
|
127
|
+
|
128
|
+
long timeout;
|
129
|
+
struct timeval tv = {0, 0};
|
130
|
+
|
131
|
+
Data_Get_Struct(self, CurlMulti, curl_multi);
|
132
|
+
|
133
|
+
rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
|
134
|
+
while(curl_multi->running) {
|
135
|
+
FD_ZERO(&fdread);
|
136
|
+
FD_ZERO(&fdwrite);
|
137
|
+
FD_ZERO(&fdexcep);
|
138
|
+
|
139
|
+
/* get the curl suggested time out */
|
140
|
+
mcode = curl_multi_timeout(curl_multi->multi, &timeout);
|
141
|
+
if (mcode != CURLM_OK) {
|
142
|
+
rb_raise(mcode, "an error occured getting the timeout");
|
143
|
+
}
|
144
|
+
|
145
|
+
if (timeout == 0) { /* no delay */
|
146
|
+
rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
|
147
|
+
continue;
|
148
|
+
}
|
149
|
+
else if (timeout == -1) {
|
150
|
+
timeout = 1;
|
151
|
+
}
|
152
|
+
|
153
|
+
tv.tv_sec = timeout / 1000;
|
154
|
+
tv.tv_usec = (timeout * 1000) % 1000000;
|
155
|
+
|
156
|
+
/* load the fd sets from the multi handle */
|
157
|
+
mcode = curl_multi_fdset(curl_multi->multi, &fdread, &fdwrite, &fdexcep, &maxfd);
|
158
|
+
if (mcode != CURLM_OK) {
|
159
|
+
rb_raise(mcode, "an error occured getting the fdset");
|
160
|
+
}
|
161
|
+
|
162
|
+
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
|
163
|
+
if (rc < 0) {
|
164
|
+
rb_raise(rb_eRuntimeError, "error on thread select");
|
165
|
+
}
|
166
|
+
rb_curl_multi_run( self, curl_multi->multi, &(curl_multi->running) );
|
167
|
+
|
168
|
+
}
|
169
|
+
|
170
|
+
return Qnil;
|
171
|
+
}
|
172
|
+
|
173
|
+
static VALUE active_handle_count(VALUE self) {
|
174
|
+
CurlMulti *curl_multi;
|
175
|
+
Data_Get_Struct(self, CurlMulti, curl_multi);
|
176
|
+
|
177
|
+
return INT2NUM(curl_multi->active);
|
178
|
+
}
|
179
|
+
|
180
|
+
static VALUE multi_cleanup(VALUE self) {
|
181
|
+
CurlMulti *curl_multi;
|
182
|
+
Data_Get_Struct(self, CurlMulti, curl_multi);
|
183
|
+
|
184
|
+
curl_multi_cleanup(curl_multi->multi);
|
185
|
+
curl_multi->active = 0;
|
186
|
+
curl_multi->running = 0;
|
187
|
+
|
188
|
+
return Qnil;
|
189
|
+
}
|
190
|
+
|
191
|
+
static VALUE new(int argc, VALUE *argv, VALUE klass) {
|
192
|
+
CurlMulti *curl_multi = ALLOC(CurlMulti);
|
193
|
+
curl_multi->multi = curl_multi_init();
|
194
|
+
curl_multi->active = 0;
|
195
|
+
curl_multi->running = 0;
|
196
|
+
|
197
|
+
VALUE multi = Data_Wrap_Struct(cTyphoeusMulti, 0, dealloc, curl_multi);
|
198
|
+
|
199
|
+
rb_obj_call_init(multi, argc, argv);
|
200
|
+
|
201
|
+
return multi;
|
202
|
+
}
|
203
|
+
|
204
|
+
void init_typhoeus_multi() {
|
205
|
+
VALUE klass = cTyphoeusMulti = rb_define_class_under(mTyphoeus, "Multi", rb_cObject);
|
206
|
+
|
207
|
+
rb_define_singleton_method(klass, "new", new, -1);
|
208
|
+
rb_define_private_method(klass, "multi_add_handle", multi_add_handle, 1);
|
209
|
+
rb_define_private_method(klass, "multi_remove_handle", multi_remove_handle, 1);
|
210
|
+
rb_define_private_method(klass, "multi_perform", multi_perform, 0);
|
211
|
+
rb_define_private_method(klass, "multi_cleanup", multi_cleanup, 0);
|
212
|
+
rb_define_private_method(klass, "active_handle_count", active_handle_count, 0);
|
213
|
+
}
|
@@ -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
|