curb 0.1.4 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of curb might be problematic. Click here for more details.
- data/README +26 -3
- data/Rakefile +20 -69
- data/doc.rb +1 -1
- data/ext/curb.c +21 -20
- data/ext/curb.h +12 -4
- data/ext/curb_config.h +42 -0
- data/ext/curb_easy.c +626 -207
- data/ext/curb_easy.h +23 -3
- data/ext/curb_errors.c +61 -8
- data/ext/curb_errors.h +11 -0
- data/ext/curb_multi.c +353 -0
- data/ext/curb_multi.h +25 -0
- data/ext/curb_postfield.c +14 -4
- data/ext/extconf.rb +104 -7
- data/{ext → lib}/curb.rb +2 -0
- data/{ext → lib}/curl.rb +0 -0
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +52 -0
- data/tests/helper.rb +141 -0
- data/tests/tc_curl_download.rb +27 -0
- data/tests/tc_curl_easy.rb +67 -3
- data/tests/tc_curl_multi.rb +249 -0
- metadata +66 -61
- data/samples/gmail.rb +0 -48
data/README
CHANGED
@@ -2,21 +2,22 @@
|
|
2
2
|
|
3
3
|
* http://curb.rubyforge.org/
|
4
4
|
* http://rubyforge.org/projects/curb
|
5
|
+
* http://github.com/taf2/curb/tree/master
|
5
6
|
|
6
7
|
Curb (probably CUrl-RuBy or something) provides Ruby-language bindings for the
|
7
8
|
libcurl(3), a fully-featured client-side URL transfer library.
|
8
9
|
cURL and libcurl live at http://curl.haxx.se/ .
|
9
10
|
|
10
|
-
Curb is a work-in-progress, and currently only supports libcurl's 'easy'
|
11
|
+
Curb is a work-in-progress, and currently only supports libcurl's 'easy' and 'multi' modes.
|
11
12
|
|
12
13
|
=== License
|
13
14
|
|
14
|
-
Curb is copyright (c)2006 Ross Bamford, and released under the terms of the
|
15
|
+
Curb is copyright (c) 2006 Ross Bamford, and released under the terms of the
|
15
16
|
Ruby license. See the LICENSE file for the gory details.
|
16
17
|
|
17
18
|
=== You will need
|
18
19
|
|
19
|
-
* A working Ruby installation (1.8+, tested with 1.8.5)
|
20
|
+
* A working Ruby installation (1.8+, tested with 1.8.5, 1.8.6, 1.8.7, and 1.9.1)
|
20
21
|
* A working (lib)curl installation, with development stuff (7.5+, tested with 7.15)
|
21
22
|
* A sane build environment
|
22
23
|
|
@@ -104,3 +105,25 @@ HTTP POST file upload:
|
|
104
105
|
c = Curl::Easy.new("http://my.rails.box/files/upload")
|
105
106
|
c.multipart_form_post = true
|
106
107
|
c.http_post(Curl::PostField.file('myfile.rb'))
|
108
|
+
|
109
|
+
Multi Interface:
|
110
|
+
responses = {}
|
111
|
+
requests = ["http://www.google.co.uk/", "http://www.ruby-lang.org/"]
|
112
|
+
m = Curl::Multi.new
|
113
|
+
# add a few easy handles
|
114
|
+
requests.each do |url|
|
115
|
+
responses[url] = ""
|
116
|
+
c = Curl::Easy.new(url) do|curl|
|
117
|
+
curl.follow_location = true
|
118
|
+
curl.on_body{|data| responses[url] << data; data.size }
|
119
|
+
end
|
120
|
+
m.add(c)
|
121
|
+
end
|
122
|
+
|
123
|
+
m.perform do
|
124
|
+
puts "idling... can do some work here, including add new requests"
|
125
|
+
end
|
126
|
+
|
127
|
+
requests.each do|url|
|
128
|
+
puts responses[url]
|
129
|
+
end
|
data/Rakefile
CHANGED
@@ -4,12 +4,6 @@ require 'rake/clean'
|
|
4
4
|
require 'rake/testtask'
|
5
5
|
require 'rake/rdoctask'
|
6
6
|
|
7
|
-
begin
|
8
|
-
require 'rake/gempackagetask'
|
9
|
-
rescue LoadError
|
10
|
-
$stderr.puts("Rubygems support disabled")
|
11
|
-
end
|
12
|
-
|
13
7
|
CLEAN.include '**/*.o'
|
14
8
|
CLEAN.include "**/*.#{Config::MAKEFILE_CONFIG['DLEXT']}"
|
15
9
|
CLOBBER.include 'doc'
|
@@ -21,8 +15,8 @@ def announce(msg='')
|
|
21
15
|
$stderr.puts msg
|
22
16
|
end
|
23
17
|
|
24
|
-
desc "Default Task (
|
25
|
-
task :default => :
|
18
|
+
desc "Default Task (Test project)"
|
19
|
+
task :default => :test
|
26
20
|
|
27
21
|
# Determine the current version of the software
|
28
22
|
if File.read('ext/curb.h') =~ /\s*CURB_VERSION\s*['"](\d.+)['"]/
|
@@ -61,7 +55,7 @@ def make(target = '')
|
|
61
55
|
end
|
62
56
|
|
63
57
|
# Let make handle dependencies between c/o/so - we'll just run it.
|
64
|
-
file CURB_SO => 'ext/Makefile' do
|
58
|
+
file CURB_SO => (['ext/Makefile'] + Dir['ext/*.c'] + Dir['ext/*.h']) do
|
65
59
|
m = make
|
66
60
|
fail "Make failed (status #{m})" unless m == 0
|
67
61
|
end
|
@@ -130,73 +124,30 @@ task :doc_upload => [ :doc ] do
|
|
130
124
|
end
|
131
125
|
end
|
132
126
|
|
133
|
-
# Packaging ------------------------------------------------
|
134
|
-
PKG_FILES = FileList[
|
135
|
-
'ext/*.rb',
|
136
|
-
'ext/*.c',
|
137
|
-
'ext/*.h',
|
138
|
-
'tests/**/*',
|
139
|
-
'samples/**/*',
|
140
|
-
'doc.rb',
|
141
|
-
'[A-Z]*',
|
142
|
-
]
|
143
|
-
|
144
127
|
if ! defined?(Gem)
|
145
128
|
warn "Package Target requires RubyGEMs"
|
146
129
|
else
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
s.description = <<-EOF
|
155
|
-
C-language Ruby bindings for the libcurl(3) URL transfer library.
|
156
|
-
EOF
|
157
|
-
s.extensions = 'ext/extconf.rb'
|
158
|
-
|
159
|
-
#### Which files are to be included in this gem?
|
160
|
-
|
161
|
-
s.files = PKG_FILES.to_a
|
162
|
-
|
163
|
-
#### Load-time details
|
164
|
-
s.require_path = 'lib'
|
165
|
-
|
166
|
-
#### Documentation and testing.
|
167
|
-
s.has_rdoc = true
|
168
|
-
s.extra_rdoc_files = Dir['ext/*.c'] << 'ext/curb.rb' << 'README' << 'LICENSE'
|
169
|
-
s.rdoc_options <<
|
170
|
-
'--title' << 'Curb API' <<
|
171
|
-
'--main' << 'README'
|
172
|
-
|
173
|
-
s.test_files = Dir.glob('tests/tc_*.rb')
|
174
|
-
|
175
|
-
#### Author and project details.
|
176
|
-
|
177
|
-
s.author = "Ross Bamford"
|
178
|
-
s.email = "curb-devel@rubyforge.org"
|
179
|
-
s.homepage = "http://curb.rubyforge.org"
|
180
|
-
s.rubyforge_project = "curb"
|
181
|
-
end
|
182
|
-
|
183
|
-
# Quick fix for Ruby 1.8.3 / YAML bug
|
184
|
-
if (RUBY_VERSION == '1.8.3')
|
185
|
-
def spec.to_yaml
|
186
|
-
out = super
|
187
|
-
out = '--- ' + out unless out =~ /^---/
|
188
|
-
out
|
189
|
-
end
|
130
|
+
desc 'Generate gem specification'
|
131
|
+
task :gemspec do
|
132
|
+
require 'erb'
|
133
|
+
tspec = ERB.new(File.read(File.join(File.dirname(__FILE__),'lib','curb.gemspec.erb')))
|
134
|
+
File.open(File.join(File.dirname(__FILE__),'curb.gemspec'),'wb') do|f|
|
135
|
+
f << tspec.result
|
136
|
+
end
|
190
137
|
end
|
191
138
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
139
|
+
desc 'Build gem'
|
140
|
+
task :package => :gemspec do
|
141
|
+
require 'rubygems/specification'
|
142
|
+
spec_source = File.read File.join(File.dirname(__FILE__),'curb.gemspec')
|
143
|
+
spec = nil
|
144
|
+
# see: http://gist.github.com/16215
|
145
|
+
Thread.new { spec = eval("$SAFE = 3\n#{spec_source}") }.join
|
146
|
+
spec.validate
|
147
|
+
Gem::Builder.new(spec).build
|
148
|
+
end
|
197
149
|
end
|
198
150
|
|
199
|
-
|
200
151
|
# --------------------------------------------------------------------
|
201
152
|
# Creating a release
|
202
153
|
desc "Make a new release (Requires SVN commit / webspace access)"
|
data/doc.rb
CHANGED
@@ -34,7 +34,7 @@ begin
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
system("rdoc --title='Curb - libcurl bindings for ruby' --main=README #{pp_srcdir}/*.c README LICENSE
|
37
|
+
system("rdoc --title='Curb - libcurl bindings for ruby' --main=README #{pp_srcdir}/*.c README LICENSE lib/curb.rb")
|
38
38
|
ensure
|
39
39
|
rm_rf(tmpdir)
|
40
40
|
end
|
data/ext/curb.c
CHANGED
@@ -42,7 +42,7 @@ static VALUE ruby_curl_kerberos4_q(VALUE mod) {
|
|
42
42
|
* For libcurl versions < 7.10, always returns false.
|
43
43
|
*/
|
44
44
|
static VALUE ruby_curl_ssl_q(VALUE mod) {
|
45
|
-
#ifdef
|
45
|
+
#ifdef HAVE_CURL_VERSION_SSL
|
46
46
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
47
47
|
return((ver->features & CURL_VERSION_SSL) ? Qtrue : Qfalse);
|
48
48
|
#else
|
@@ -58,7 +58,7 @@ static VALUE ruby_curl_ssl_q(VALUE mod) {
|
|
58
58
|
* using libz. For libcurl versions < 7.10, always returns false.
|
59
59
|
*/
|
60
60
|
static VALUE ruby_curl_libz_q(VALUE mod) {
|
61
|
-
#ifdef
|
61
|
+
#ifdef HAVE_CURL_VERSION_LIBZ
|
62
62
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
63
63
|
return((ver->features & CURL_VERSION_LIBZ) ? Qtrue : Qfalse);
|
64
64
|
#else
|
@@ -74,7 +74,7 @@ static VALUE ruby_curl_libz_q(VALUE mod) {
|
|
74
74
|
* For libcurl versions < 7.10.6, always returns false.
|
75
75
|
*/
|
76
76
|
static VALUE ruby_curl_ntlm_q(VALUE mod) {
|
77
|
-
#ifdef
|
77
|
+
#ifdef HAVE_CURL_VERSION_NTLM
|
78
78
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
79
79
|
return((ver->features & CURL_VERSION_NTLM) ? Qtrue : Qfalse);
|
80
80
|
#else
|
@@ -90,7 +90,7 @@ static VALUE ruby_curl_ntlm_q(VALUE mod) {
|
|
90
90
|
* For libcurl versions < 7.10.6, always returns false.
|
91
91
|
*/
|
92
92
|
static VALUE ruby_curl_gssnegotiate_q(VALUE mod) {
|
93
|
-
#ifdef
|
93
|
+
#ifdef HAVE_CURL_VERSION_GSSNEGOTIATE
|
94
94
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
95
95
|
return((ver->features & CURL_VERSION_GSSNEGOTIATE) ? Qtrue : Qfalse);
|
96
96
|
#else
|
@@ -107,7 +107,7 @@ static VALUE ruby_curl_gssnegotiate_q(VALUE mod) {
|
|
107
107
|
* false.
|
108
108
|
*/
|
109
109
|
static VALUE ruby_curl_debug_q(VALUE mod) {
|
110
|
-
#ifdef
|
110
|
+
#ifdef HAVE_CURL_VERSION_DEBUG
|
111
111
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
112
112
|
return((ver->features & CURL_VERSION_DEBUG) ? Qtrue : Qfalse);
|
113
113
|
#else
|
@@ -125,7 +125,7 @@ static VALUE ruby_curl_debug_q(VALUE mod) {
|
|
125
125
|
* For libcurl versions < 7.10.7, always returns false.
|
126
126
|
*/
|
127
127
|
static VALUE ruby_curl_asyncdns_q(VALUE mod) {
|
128
|
-
#ifdef
|
128
|
+
#ifdef HAVE_CURL_VERSION_ASYNCHDNS
|
129
129
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
130
130
|
return((ver->features & CURL_VERSION_ASYNCHDNS) ? Qtrue : Qfalse);
|
131
131
|
#else
|
@@ -142,7 +142,7 @@ static VALUE ruby_curl_asyncdns_q(VALUE mod) {
|
|
142
142
|
* in RFC 2478). For libcurl versions < 7.10.8, always returns false.
|
143
143
|
*/
|
144
144
|
static VALUE ruby_curl_spnego_q(VALUE mod) {
|
145
|
-
#ifdef
|
145
|
+
#ifdef HAVE_CURL_VERSION_SPNEGO
|
146
146
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
147
147
|
return((ver->features & CURL_VERSION_SPNEGO) ? Qtrue : Qfalse);
|
148
148
|
#else
|
@@ -158,7 +158,7 @@ static VALUE ruby_curl_spnego_q(VALUE mod) {
|
|
158
158
|
* files. For libcurl versions < 7.11.1, always returns false.
|
159
159
|
*/
|
160
160
|
static VALUE ruby_curl_largefile_q(VALUE mod) {
|
161
|
-
#ifdef
|
161
|
+
#ifdef HAVE_CURL_VERSION_LARGEFILE
|
162
162
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
163
163
|
return((ver->features & CURL_VERSION_LARGEFILE) ? Qtrue : Qfalse);
|
164
164
|
#else
|
@@ -175,7 +175,7 @@ static VALUE ruby_curl_largefile_q(VALUE mod) {
|
|
175
175
|
* always returns false.
|
176
176
|
*/
|
177
177
|
static VALUE ruby_curl_idn_q(VALUE mod) {
|
178
|
-
#ifdef
|
178
|
+
#ifdef HAVE_CURL_VERSION_IDN
|
179
179
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
180
180
|
return((ver->features & CURL_VERSION_IDN) ? Qtrue : Qfalse);
|
181
181
|
#else
|
@@ -194,7 +194,7 @@ static VALUE ruby_curl_idn_q(VALUE mod) {
|
|
194
194
|
* For libcurl versions < 7.13.2, always returns false.
|
195
195
|
*/
|
196
196
|
static VALUE ruby_curl_sspi_q(VALUE mod) {
|
197
|
-
#ifdef
|
197
|
+
#ifdef HAVE_CURL_VERSION_SSPI
|
198
198
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
199
199
|
return((ver->features & CURL_VERSION_SSPI) ? Qtrue : Qfalse);
|
200
200
|
#else
|
@@ -210,7 +210,7 @@ static VALUE ruby_curl_sspi_q(VALUE mod) {
|
|
210
210
|
* conversions. For libcurl versions < 7.15.4, always returns false.
|
211
211
|
*/
|
212
212
|
static VALUE ruby_curl_conv_q(VALUE mod) {
|
213
|
-
#ifdef
|
213
|
+
#ifdef HAVE_CURL_VERSION_CONV
|
214
214
|
curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
|
215
215
|
return((ver->features & CURL_VERSION_CONV) ? Qtrue : Qfalse);
|
216
216
|
#else
|
@@ -254,63 +254,63 @@ void Init_curb_core() {
|
|
254
254
|
rb_define_const(mCurl, "CURLINFO_DATA_OUT", INT2FIX(CURLINFO_DATA_OUT));
|
255
255
|
|
256
256
|
/* When passed to Curl::Easy#proxy_type , indicates that the proxy is an HTTP proxy. (libcurl >= 7.10) */
|
257
|
-
#ifdef
|
257
|
+
#ifdef HAVE_CURLPROXY_HTTP
|
258
258
|
rb_define_const(mCurl, "CURLPROXY_HTTP", INT2FIX(CURLPROXY_HTTP));
|
259
259
|
#else
|
260
260
|
rb_define_const(mCurl, "CURLPROXY_HTTP", INT2FIX(-1));
|
261
261
|
#endif
|
262
262
|
|
263
263
|
/* When passed to Curl::Easy#proxy_type , indicates that the proxy is a SOCKS4 proxy. (libcurl >= 7.15.2) */
|
264
|
-
#ifdef
|
264
|
+
#ifdef HAVE_CURLPROXY_SOCKS4
|
265
265
|
rb_define_const(mCurl, "CURLPROXY_SOCKS4", INT2FIX(CURLPROXY_SOCKS4));
|
266
266
|
#else
|
267
267
|
rb_define_const(mCurl, "CURLPROXY_SOCKS4", INT2FIX(-2));
|
268
268
|
#endif
|
269
269
|
|
270
270
|
/* When passed to Curl::Easy#proxy_type , indicates that the proxy is a SOCKS5 proxy. (libcurl >= 7.10) */
|
271
|
-
#ifdef
|
271
|
+
#ifdef HAVE_CURLPROXY_SOCKS5
|
272
272
|
rb_define_const(mCurl, "CURLPROXY_SOCKS5", INT2FIX(CURLPROXY_SOCKS5));
|
273
273
|
#else
|
274
274
|
rb_define_const(mCurl, "CURLPROXY_SOCKS5", INT2FIX(-2));
|
275
275
|
#endif
|
276
276
|
|
277
277
|
/* When passed to Curl::Easy#http_auth_types or Curl::Easy#proxy_auth_types, directs libcurl to use Basic authentication. */
|
278
|
-
#ifdef
|
278
|
+
#ifdef HAVE_CURLAUTH_BASIC
|
279
279
|
rb_define_const(mCurl, "CURLAUTH_BASIC", INT2FIX(CURLAUTH_BASIC));
|
280
280
|
#else
|
281
281
|
rb_define_const(mCurl, "CURLAUTH_BASIC", INT2FIX(0);
|
282
282
|
#endif
|
283
283
|
|
284
284
|
/* When passed to Curl::Easy#http_auth_types or Curl::Easy#proxy_auth_types, directs libcurl to use Digest authentication. */
|
285
|
-
#ifdef
|
285
|
+
#ifdef HAVE_CURLAUTH_DIGEST
|
286
286
|
rb_define_const(mCurl, "CURLAUTH_DIGEST", INT2FIX(CURLAUTH_DIGEST));
|
287
287
|
#else
|
288
288
|
rb_define_const(mCurl, "CURLAUTH_DIGEST", INT2FIX(0));
|
289
289
|
#endif
|
290
290
|
|
291
291
|
/* When passed to Curl::Easy#http_auth_types or Curl::Easy#proxy_auth_types, directs libcurl to use GSS Negotiate authentication. Requires a suitable GSS-API library. */
|
292
|
-
#ifdef
|
292
|
+
#ifdef HAVE_CURLAUTH_GSSNEGOTIATE
|
293
293
|
rb_define_const(mCurl, "CURLAUTH_GSSNEGOTIATE", INT2FIX(CURLAUTH_GSSNEGOTIATE));
|
294
294
|
#else
|
295
295
|
rb_define_const(mCurl, "CURLAUTH_GSSNEGOTIATE", INT2FIX(0));
|
296
296
|
#endif
|
297
297
|
|
298
298
|
/* When passed to Curl::Easy#http_auth_types or Curl::Easy#proxy_auth_types, directs libcurl to use HTTP NTLM authentication. Requires MS Windows or OpenSSL support. */
|
299
|
-
#ifdef
|
299
|
+
#ifdef HAVE_CURLAUTH_NTLM
|
300
300
|
rb_define_const(mCurl, "CURLAUTH_NTLM", INT2FIX(CURLAUTH_NTLM));
|
301
301
|
#else
|
302
302
|
rb_define_const(mCurl, "CURLAUTH_NTLM", INT2FIX(0));
|
303
303
|
#endif
|
304
304
|
|
305
305
|
/* When passed to Curl::Easy#http_auth_types or Curl::Easy#proxy_auth_types, allows libcurl to select any suitable authentication method except basic. */
|
306
|
-
#ifdef
|
306
|
+
#ifdef HAVE_CURLAUTH_ANYSAFE
|
307
307
|
rb_define_const(mCurl, "CURLAUTH_ANYSAFE", INT2FIX(CURLAUTH_ANYSAFE));
|
308
308
|
#else
|
309
309
|
rb_define_const(mCurl, "CURLAUTH_ANYSAFE", INT2FIX(0));
|
310
310
|
#endif
|
311
311
|
|
312
312
|
/* When passed to Curl::Easy#http_auth_types or Curl::Easy#proxy_auth_types, allows libcurl to select any suitable authentication method. */
|
313
|
-
#ifdef
|
313
|
+
#ifdef HAVE_CURLAUTH_ANY
|
314
314
|
rb_define_const(mCurl, "CURLAUTH_ANY", INT2FIX(CURLAUTH_ANY));
|
315
315
|
#else
|
316
316
|
rb_define_const(mCurl, "CURLAUTH_ANY", INT2FIX(0));
|
@@ -333,4 +333,5 @@ void Init_curb_core() {
|
|
333
333
|
init_curb_errors();
|
334
334
|
init_curb_easy();
|
335
335
|
init_curb_postfield();
|
336
|
+
init_curb_multi();
|
336
337
|
}
|
data/ext/curb.h
CHANGED
@@ -11,18 +11,20 @@
|
|
11
11
|
#include <ruby.h>
|
12
12
|
#include <curl/curl.h>
|
13
13
|
|
14
|
+
#include "curb_config.h"
|
14
15
|
#include "curb_easy.h"
|
15
16
|
#include "curb_errors.h"
|
16
17
|
#include "curb_postfield.h"
|
18
|
+
#include "curb_multi.h"
|
17
19
|
|
18
20
|
#include "curb_macros.h"
|
19
21
|
|
20
22
|
// These should be managed from the Rake 'release' task.
|
21
|
-
#define CURB_VERSION "0.1
|
22
|
-
#define CURB_VER_NUM
|
23
|
+
#define CURB_VERSION "0.3.1"
|
24
|
+
#define CURB_VER_NUM 310
|
23
25
|
#define CURB_VER_MAJ 0
|
24
|
-
#define CURB_VER_MIN
|
25
|
-
#define CURB_VER_MIC
|
26
|
+
#define CURB_VER_MIN 3
|
27
|
+
#define CURB_VER_MIC 1
|
26
28
|
#define CURB_VER_PATCH 0
|
27
29
|
|
28
30
|
|
@@ -31,6 +33,12 @@
|
|
31
33
|
#define RSTRING_LEN(x) RSTRING(x)->len
|
32
34
|
#endif
|
33
35
|
|
36
|
+
#ifdef HAVE_RUBY19_HASH
|
37
|
+
#define RHASH_LEN(hash) RHASH(hash)->ntbl->num_entries
|
38
|
+
#else
|
39
|
+
#define RHASH_LEN(hash) RHASH(hash)->tbl->num_entries
|
40
|
+
#endif
|
41
|
+
|
34
42
|
extern VALUE mCurl;
|
35
43
|
|
36
44
|
extern void Init_curb_core();
|
data/ext/curb_config.h
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#ifndef CURB_CONFIG_H
|
2
|
+
#define CURB_CONFIG_H
|
3
|
+
#define HAVE_CURLINFO_REDIRECT_TIME 1
|
4
|
+
#define HAVE_CURLINFO_RESPONSE_CODE 1
|
5
|
+
#define HAVE_CURLINFO_FILETIME 1
|
6
|
+
#define HAVE_CURLINFO_REDIRECT_COUNT 1
|
7
|
+
#define HAVE_CURLINFO_OS_ERRNO 1
|
8
|
+
#define HAVE_CURLINFO_NUM_CONNECTS 1
|
9
|
+
#define HAVE_CURLINFO_FTP_ENTRY_PATH 1
|
10
|
+
#define HAVE_CURL_VERSION_SSL 1
|
11
|
+
#define HAVE_CURL_VERSION_LIBZ 1
|
12
|
+
#define HAVE_CURL_VERSION_NTLM 1
|
13
|
+
#define HAVE_CURL_VERSION_GSSNEGOTIATE 1
|
14
|
+
#define HAVE_CURL_VERSION_DEBUG 1
|
15
|
+
#define HAVE_CURL_VERSION_ASYNCHDNS 1
|
16
|
+
#define HAVE_CURL_VERSION_SPNEGO 1
|
17
|
+
#define HAVE_CURL_VERSION_LARGEFILE 1
|
18
|
+
#define HAVE_CURL_VERSION_IDN 1
|
19
|
+
#define HAVE_CURL_VERSION_SSPI 1
|
20
|
+
#define HAVE_CURL_VERSION_CONV 1
|
21
|
+
#define HAVE_CURLPROXY_HTTP 1
|
22
|
+
#define HAVE_CURLPROXY_SOCKS4 1
|
23
|
+
#define HAVE_CURLPROXY_SOCKS5 1
|
24
|
+
#define HAVE_CURLAUTH_BASIC 1
|
25
|
+
#define HAVE_CURLAUTH_DIGEST 1
|
26
|
+
#define HAVE_CURLAUTH_GSSNEGOTIATE 1
|
27
|
+
#define HAVE_CURLAUTH_NTLM 1
|
28
|
+
#define HAVE_CURLAUTH_ANYSAFE 1
|
29
|
+
#define HAVE_CURLAUTH_ANY 1
|
30
|
+
#define HAVE_CURLE_TFTP_NOTFOUND 1
|
31
|
+
#define HAVE_CURLE_TFTP_PERM 1
|
32
|
+
#define HAVE_CURLE_TFTP_DISKFULL 1
|
33
|
+
#define HAVE_CURLE_TFTP_ILLEGAL 1
|
34
|
+
#define HAVE_CURLE_TFTP_UNKNOWNID 1
|
35
|
+
#define HAVE_CURLE_TFTP_EXISTS 1
|
36
|
+
#define HAVE_CURLE_TFTP_NOSUCHUSER 1
|
37
|
+
#define HAVE_CURLE_SEND_FAIL_REWIND 1
|
38
|
+
#define HAVE_CURLE_SSL_ENGINE_INITFAILED 1
|
39
|
+
#define HAVE_CURLE_LOGIN_DENIED 1
|
40
|
+
#define HAVE_RUBY19_ST_H 1
|
41
|
+
#define HAVE_CURL_EASY_ESCAPE 1
|
42
|
+
#endif
|
data/ext/curb_easy.c
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
#include "curb_errors.h"
|
9
9
|
#include "curb_postfield.h"
|
10
10
|
|
11
|
+
#include <errno.h>
|
11
12
|
#include <string.h>
|
12
13
|
|
13
14
|
extern VALUE mCurl;
|
@@ -33,6 +34,42 @@ static size_t default_data_handler(char *stream,
|
|
33
34
|
rb_str_buf_cat(out, stream, size * nmemb);
|
34
35
|
return size * nmemb;
|
35
36
|
}
|
37
|
+
typedef struct _PutStream {
|
38
|
+
char *buffer;
|
39
|
+
size_t offset, len;
|
40
|
+
} PutStream;
|
41
|
+
|
42
|
+
// size_t function( void *ptr, size_t size, size_t nmemb, void *stream);
|
43
|
+
static size_t read_data_handler(void *ptr,
|
44
|
+
size_t size,
|
45
|
+
size_t nmemb,
|
46
|
+
void *stream) {
|
47
|
+
|
48
|
+
PutStream *pstream = (PutStream*)stream;
|
49
|
+
size_t sent_bytes = (size * nmemb);
|
50
|
+
size_t remaining = pstream->len - pstream->offset;
|
51
|
+
|
52
|
+
// amount remaining is less then the buffer to send - can send it all
|
53
|
+
if( remaining < sent_bytes ) {
|
54
|
+
memcpy(ptr, pstream->buffer+pstream->offset, remaining);
|
55
|
+
sent_bytes = remaining;
|
56
|
+
pstream->offset += remaining;
|
57
|
+
}
|
58
|
+
else if( remaining > sent_bytes ) { // sent_bytes <= remaining - send what we can fit in the buffer(ptr)
|
59
|
+
memcpy(ptr, pstream->buffer+pstream->offset, sent_bytes);
|
60
|
+
pstream->offset += sent_bytes;
|
61
|
+
}
|
62
|
+
else { // they're equal
|
63
|
+
memcpy(ptr, pstream->buffer+pstream->offset, --sent_bytes);
|
64
|
+
pstream->offset += sent_bytes;
|
65
|
+
}
|
66
|
+
if (sent_bytes == 0) {
|
67
|
+
free(pstream);
|
68
|
+
}
|
69
|
+
|
70
|
+
//printf("sent_bytes: %ld of %ld\n", sent_bytes, remaining);
|
71
|
+
return sent_bytes;
|
72
|
+
}
|
36
73
|
|
37
74
|
static size_t proc_data_handler(char *stream,
|
38
75
|
size_t size,
|
@@ -92,11 +129,21 @@ void curl_easy_mark(ruby_curl_easy *rbce) {
|
|
92
129
|
rb_gc_mark(rbce->proxypwd);
|
93
130
|
rb_gc_mark(rbce->headers);
|
94
131
|
rb_gc_mark(rbce->cookiejar);
|
132
|
+
rb_gc_mark(rbce->cert);
|
133
|
+
rb_gc_mark(rbce->encoding);
|
134
|
+
rb_gc_mark(rbce->success_proc);
|
135
|
+
rb_gc_mark(rbce->failure_proc);
|
136
|
+
rb_gc_mark(rbce->complete_proc);
|
95
137
|
|
96
138
|
rb_gc_mark(rbce->postdata_buffer);
|
139
|
+
rb_gc_mark(rbce->bodybuf);
|
140
|
+
rb_gc_mark(rbce->headerbuf);
|
97
141
|
}
|
98
142
|
|
99
143
|
void curl_easy_free(ruby_curl_easy *rbce) {
|
144
|
+
if (rbce->curl_headers) {
|
145
|
+
curl_slist_free_all(rbce->curl_headers);
|
146
|
+
}
|
100
147
|
curl_easy_cleanup(rbce->curl);
|
101
148
|
free(rbce);
|
102
149
|
}
|
@@ -115,9 +162,10 @@ void curl_easy_free(ruby_curl_easy *rbce) {
|
|
115
162
|
* the instance is returned.
|
116
163
|
*/
|
117
164
|
static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
|
165
|
+
CURLcode ecode;
|
118
166
|
VALUE url, blk;
|
119
167
|
VALUE new_curl;
|
120
|
-
|
168
|
+
|
121
169
|
rb_scan_args(argc, argv, "01&", &url, &blk);
|
122
170
|
|
123
171
|
ruby_curl_easy *rbce = ALLOC(ruby_curl_easy);
|
@@ -139,6 +187,11 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
|
|
139
187
|
rbce->proxypwd = Qnil;
|
140
188
|
rbce->headers = rb_hash_new();
|
141
189
|
rbce->cookiejar = Qnil;
|
190
|
+
rbce->cert = Qnil;
|
191
|
+
rbce->encoding = Qnil;
|
192
|
+
rbce->success_proc = Qnil;
|
193
|
+
rbce->failure_proc = Qnil;
|
194
|
+
rbce->complete_proc = Qnil;
|
142
195
|
|
143
196
|
/* various-typed opts */
|
144
197
|
rbce->local_port = 0;
|
@@ -168,13 +221,22 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
|
|
168
221
|
|
169
222
|
/* buffers */
|
170
223
|
rbce->postdata_buffer = Qnil;
|
224
|
+
rbce->bodybuf = Qnil;
|
225
|
+
rbce->headerbuf = Qnil;
|
226
|
+
rbce->curl_headers = NULL;
|
171
227
|
|
172
228
|
new_curl = Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, rbce);
|
173
229
|
|
174
230
|
if (blk != Qnil) {
|
175
231
|
rb_funcall(blk, idCall, 1, new_curl);
|
176
232
|
}
|
177
|
-
|
233
|
+
|
234
|
+
/* set the rbce pointer to the curl handle */
|
235
|
+
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
236
|
+
if (ecode != CURLE_OK) {
|
237
|
+
raise_curl_easy_error_exception(ecode);
|
238
|
+
}
|
239
|
+
|
178
240
|
return new_curl;
|
179
241
|
}
|
180
242
|
|
@@ -194,6 +256,7 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
194
256
|
newrbce = ALLOC(ruby_curl_easy);
|
195
257
|
memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
|
196
258
|
newrbce->curl = curl_easy_duphandle(rbce->curl);
|
259
|
+
newrbce->curl_headers = NULL;
|
197
260
|
|
198
261
|
return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
|
199
262
|
}
|
@@ -390,6 +453,48 @@ static VALUE ruby_curl_easy_cookiejar_get(VALUE self) {
|
|
390
453
|
CURB_OBJECT_GETTER(ruby_curl_easy, cookiejar);
|
391
454
|
}
|
392
455
|
|
456
|
+
/*
|
457
|
+
* call-seq:
|
458
|
+
* easy.cert = "cert.file" => ""
|
459
|
+
*
|
460
|
+
* Set a cert file to use for this Curl::Easy instance. This file
|
461
|
+
* will be used to validate SSL connections.
|
462
|
+
*
|
463
|
+
*/
|
464
|
+
static VALUE ruby_curl_easy_cert_set(VALUE self, VALUE cert) {
|
465
|
+
CURB_OBJECT_SETTER(ruby_curl_easy, cert);
|
466
|
+
}
|
467
|
+
|
468
|
+
/*
|
469
|
+
* call-seq:
|
470
|
+
* easy.cert => "cert.file"
|
471
|
+
*
|
472
|
+
* Obtain the cert file to use for this Curl::Easy instance.
|
473
|
+
*/
|
474
|
+
static VALUE ruby_curl_easy_cert_get(VALUE self) {
|
475
|
+
CURB_OBJECT_GETTER(ruby_curl_easy, cert);
|
476
|
+
}
|
477
|
+
|
478
|
+
/*
|
479
|
+
* call-seq:
|
480
|
+
* easy.encoding= => "string"
|
481
|
+
*
|
482
|
+
* Set the accepted encoding types, curl will handle all of the decompression
|
483
|
+
*
|
484
|
+
*/
|
485
|
+
static VALUE ruby_curl_easy_encoding_set(VALUE self, VALUE encoding) {
|
486
|
+
CURB_OBJECT_SETTER(ruby_curl_easy, encoding);
|
487
|
+
}
|
488
|
+
/*
|
489
|
+
* call-seq:
|
490
|
+
* easy.encoding => "string"
|
491
|
+
*
|
492
|
+
* Get the set encoding types
|
493
|
+
*
|
494
|
+
*/
|
495
|
+
static VALUE ruby_curl_easy_encoding_get(VALUE self) {
|
496
|
+
CURB_OBJECT_GETTER(ruby_curl_easy, encoding);
|
497
|
+
}
|
393
498
|
|
394
499
|
/* ================== IMMED ATTRS ==================*/
|
395
500
|
|
@@ -953,6 +1058,50 @@ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
|
|
953
1058
|
CURB_HANDLER_PROC_SETTER(ruby_curl_easy, body_proc);
|
954
1059
|
}
|
955
1060
|
|
1061
|
+
/*
|
1062
|
+
* call-seq:
|
1063
|
+
* easy.on_success { ... } => <old handler>
|
1064
|
+
*
|
1065
|
+
* Assign or remove the +on_success+ handler for this Curl::Easy instance.
|
1066
|
+
* To remove a previously-supplied handler, call this method with no
|
1067
|
+
* attached block.
|
1068
|
+
*
|
1069
|
+
* The +on_success+ handler is called when the request is finished with a
|
1070
|
+
* status of 20x
|
1071
|
+
*/
|
1072
|
+
static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
|
1073
|
+
CURB_HANDLER_PROC_SETTER(ruby_curl_easy, success_proc);
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
/*
|
1077
|
+
* call-seq:
|
1078
|
+
* easy.on_failure { ... } => <old handler>
|
1079
|
+
*
|
1080
|
+
* Assign or remove the +on_failure+ handler for this Curl::Easy instance.
|
1081
|
+
* To remove a previously-supplied handler, call this method with no
|
1082
|
+
* attached block.
|
1083
|
+
*
|
1084
|
+
* The +on_failure+ handler is called when the request is finished with a
|
1085
|
+
* status of 50x
|
1086
|
+
*/
|
1087
|
+
static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
|
1088
|
+
CURB_HANDLER_PROC_SETTER(ruby_curl_easy, failure_proc);
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
/*
|
1092
|
+
* call-seq:
|
1093
|
+
* easy.on_complete { ... } => <old handler>
|
1094
|
+
*
|
1095
|
+
* Assign or remove the +on_complete+ handler for this Curl::Easy instance.
|
1096
|
+
* To remove a previously-supplied handler, call this method with no
|
1097
|
+
* attached block.
|
1098
|
+
*
|
1099
|
+
* The +on_complete+ handler is called when the request is finished.
|
1100
|
+
*/
|
1101
|
+
static VALUE ruby_curl_easy_on_complete_set(int argc, VALUE *argv, VALUE self) {
|
1102
|
+
CURB_HANDLER_PROC_SETTER(ruby_curl_easy, complete_proc);
|
1103
|
+
}
|
1104
|
+
|
956
1105
|
/*
|
957
1106
|
* call-seq:
|
958
1107
|
* easy.on_header { |header_data| ... } => <old handler>
|
@@ -1044,234 +1193,393 @@ static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
|
|
1044
1193
|
}
|
1045
1194
|
|
1046
1195
|
/***********************************************
|
1047
|
-
*
|
1048
|
-
*
|
1049
|
-
*
|
1050
|
-
* methods are responsible for setting up stuff specific to that type,
|
1051
|
-
* then calling this to handle common stuff and do the perform.
|
1052
|
-
*
|
1196
|
+
*
|
1197
|
+
* Setup a connection
|
1198
|
+
*
|
1053
1199
|
* Always returns Qtrue, rb_raise on error.
|
1054
|
-
*
|
1055
1200
|
*/
|
1056
|
-
|
1201
|
+
VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, VALUE *body_buffer, VALUE *header_buffer, struct curl_slist **hdrs ) {
|
1057
1202
|
// TODO this could do with a bit of refactoring...
|
1058
1203
|
CURL *curl;
|
1059
|
-
CURLcode result = -1;
|
1060
|
-
struct curl_slist *headers = NULL;
|
1061
1204
|
|
1062
1205
|
curl = rbce->curl;
|
1063
1206
|
|
1064
|
-
if (rbce->url
|
1065
|
-
|
1066
|
-
|
1207
|
+
if (rbce->url == Qnil) {
|
1208
|
+
rb_raise(eCurlErrError, "No URL supplied");
|
1209
|
+
}
|
1210
|
+
|
1211
|
+
VALUE url = rb_check_string_type(rbce->url);
|
1212
|
+
|
1213
|
+
// Need to configure the handler as per settings in rbce
|
1214
|
+
curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
|
1067
1215
|
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &default_data_handler);
|
1114
|
-
curl_easy_setopt(curl, CURLOPT_HEADERDATA, headerbuf);
|
1115
|
-
}
|
1216
|
+
// network stuff and auth
|
1217
|
+
if (rbce->interface != Qnil) {
|
1218
|
+
curl_easy_setopt(curl, CURLOPT_INTERFACE, StringValuePtr(rbce->interface));
|
1219
|
+
} else {
|
1220
|
+
curl_easy_setopt(curl, CURLOPT_INTERFACE, NULL);
|
1221
|
+
}
|
1222
|
+
|
1223
|
+
if (rbce->userpwd != Qnil) {
|
1224
|
+
curl_easy_setopt(curl, CURLOPT_USERPWD, StringValuePtr(rbce->userpwd));
|
1225
|
+
} else {
|
1226
|
+
curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
if (rbce->proxy_url != Qnil) {
|
1230
|
+
curl_easy_setopt(curl, CURLOPT_PROXY, StringValuePtr(rbce->proxy_url));
|
1231
|
+
} else {
|
1232
|
+
curl_easy_setopt(curl, CURLOPT_PROXY, NULL);
|
1233
|
+
}
|
1234
|
+
|
1235
|
+
if (rbce->proxypwd != Qnil) {
|
1236
|
+
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, StringValuePtr(rbce->proxypwd));
|
1237
|
+
} else {
|
1238
|
+
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
// body/header procs
|
1242
|
+
if (rbce->body_proc != Qnil) {
|
1243
|
+
*body_buffer = Qnil;
|
1244
|
+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler);
|
1245
|
+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce->body_proc);
|
1246
|
+
} else {
|
1247
|
+
*body_buffer = rb_str_buf_new(32768);
|
1248
|
+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&default_data_handler);
|
1249
|
+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, *body_buffer);
|
1250
|
+
}
|
1251
|
+
|
1252
|
+
if (rbce->header_proc != Qnil) {
|
1253
|
+
*header_buffer = Qnil;
|
1254
|
+
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler);
|
1255
|
+
curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce->header_proc);
|
1256
|
+
} else {
|
1257
|
+
*header_buffer = rb_str_buf_new(32768);
|
1258
|
+
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&default_data_handler);
|
1259
|
+
curl_easy_setopt(curl, CURLOPT_HEADERDATA, *header_buffer);
|
1260
|
+
}
|
1116
1261
|
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
1122
|
-
} else {
|
1123
|
-
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
|
1124
|
-
}
|
1125
|
-
|
1126
|
-
if (rbce->debug_proc != Qnil) {
|
1127
|
-
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, &proc_debug_handler);
|
1128
|
-
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, rbce->debug_proc);
|
1129
|
-
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
1130
|
-
} else {
|
1131
|
-
// have to remove handler to re-enable standard verbosity
|
1132
|
-
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, NULL);
|
1133
|
-
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, NULL);
|
1134
|
-
curl_easy_setopt(curl, CURLOPT_VERBOSE, rbce->verbose);
|
1135
|
-
}
|
1136
|
-
|
1137
|
-
/* general opts */
|
1138
|
-
|
1139
|
-
curl_easy_setopt(curl, CURLOPT_HEADER, rbce->header_in_body);
|
1140
|
-
|
1141
|
-
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, rbce->follow_location);
|
1142
|
-
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
1143
|
-
|
1144
|
-
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, rbce->proxy_tunnel);
|
1145
|
-
curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
|
1146
|
-
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
|
1147
|
-
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_peer);
|
1148
|
-
|
1149
|
-
if ((rbce->use_netrc != Qnil) && (rbce->use_netrc != Qfalse)) {
|
1150
|
-
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_OPTIONAL);
|
1151
|
-
} else {
|
1152
|
-
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_IGNORED);
|
1153
|
-
}
|
1262
|
+
/* encoding */
|
1263
|
+
if (rbce->encoding != Qnil) {
|
1264
|
+
curl_easy_setopt(curl, CURLOPT_ENCODING, StringValuePtr(rbce->encoding));
|
1265
|
+
}
|
1154
1266
|
|
1155
|
-
|
1156
|
-
|
1157
|
-
curl_easy_setopt(curl,
|
1158
|
-
curl_easy_setopt(curl,
|
1159
|
-
curl_easy_setopt(curl,
|
1267
|
+
// progress and debug procs
|
1268
|
+
if (rbce->progress_proc != Qnil) {
|
1269
|
+
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&proc_progress_handler);
|
1270
|
+
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, rbce->progress_proc);
|
1271
|
+
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
1272
|
+
} else {
|
1273
|
+
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
|
1274
|
+
}
|
1275
|
+
|
1276
|
+
if (rbce->debug_proc != Qnil) {
|
1277
|
+
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, (curl_debug_callback)&proc_debug_handler);
|
1278
|
+
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, rbce->debug_proc);
|
1279
|
+
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
1280
|
+
} else {
|
1281
|
+
// have to remove handler to re-enable standard verbosity
|
1282
|
+
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, NULL);
|
1283
|
+
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, NULL);
|
1284
|
+
curl_easy_setopt(curl, CURLOPT_VERBOSE, rbce->verbose);
|
1285
|
+
}
|
1286
|
+
|
1287
|
+
/* general opts */
|
1288
|
+
|
1289
|
+
curl_easy_setopt(curl, CURLOPT_HEADER, rbce->header_in_body);
|
1290
|
+
|
1291
|
+
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, rbce->follow_location);
|
1292
|
+
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
1293
|
+
|
1294
|
+
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, rbce->proxy_tunnel);
|
1295
|
+
curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
|
1296
|
+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
|
1297
|
+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_peer);
|
1298
|
+
|
1299
|
+
if ((rbce->use_netrc != Qnil) && (rbce->use_netrc != Qfalse)) {
|
1300
|
+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_OPTIONAL);
|
1301
|
+
} else {
|
1302
|
+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_IGNORED);
|
1303
|
+
}
|
1304
|
+
|
1305
|
+
curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
|
1306
|
+
|
1307
|
+
curl_easy_setopt(curl, CURLOPT_TIMEOUT, rbce->timeout);
|
1308
|
+
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
|
1309
|
+
curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
|
1160
1310
|
|
1161
1311
|
#if LIBCURL_VERSION_NUM >= 0x070a08
|
1162
|
-
|
1312
|
+
curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
|
1163
1313
|
#else
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1314
|
+
if (rbce->ftp_response_timeout > 0) {
|
1315
|
+
rb_warn("Installed libcurl is too old to support ftp_response_timeout");
|
1316
|
+
}
|
1167
1317
|
#endif
|
1318
|
+
|
1319
|
+
// Set up localport / proxy port
|
1320
|
+
// FIXME these won't get returned to default if they're unset Ruby
|
1321
|
+
if (rbce->proxy_port > 0) {
|
1322
|
+
curl_easy_setopt(curl, CURLOPT_PROXYPORT, rbce->proxy_port);
|
1323
|
+
}
|
1324
|
+
|
1325
|
+
if (rbce->local_port > 0) {
|
1326
|
+
#if LIBCURL_VERSION_NUM >= 0x070f02
|
1327
|
+
curl_easy_setopt(curl, CURLOPT_LOCALPORT, rbce->local_port);
|
1168
1328
|
|
1169
|
-
|
1170
|
-
|
1171
|
-
if (rbce->proxy_port > 0) {
|
1172
|
-
curl_easy_setopt(curl, CURLOPT_PROXYPORT, rbce->proxy_port);
|
1329
|
+
if (rbce->local_port_range > 0) {
|
1330
|
+
curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, rbce->local_port_range);
|
1173
1331
|
}
|
1174
|
-
|
1175
|
-
if (rbce->local_port > 0) {
|
1176
|
-
#if LIBCURL_VERSION_NUM >= 0x070f02
|
1177
|
-
curl_easy_setopt(curl, CURLOPT_LOCALPORT, rbce->local_port);
|
1178
|
-
|
1179
|
-
if (rbce->local_port_range > 0) {
|
1180
|
-
curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, rbce->local_port_range);
|
1181
|
-
}
|
1182
1332
|
#else
|
1183
|
-
|
1333
|
+
rb_warn("Installed libcurl is too old to support local_port");
|
1184
1334
|
#endif
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1335
|
+
}
|
1336
|
+
|
1337
|
+
if (rbce->proxy_type != -1) {
|
1188
1338
|
#if LIBCURL_VERSION_NUM >= 0x070a00
|
1189
|
-
|
1190
|
-
|
1191
|
-
} else {
|
1192
|
-
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, rbce->proxy_type);
|
1193
|
-
}
|
1339
|
+
if (rbce->proxy_type == -2) {
|
1340
|
+
rb_warn("Installed libcurl is too old to support the selected proxy type");
|
1194
1341
|
} else {
|
1195
|
-
curl_easy_setopt(curl, CURLOPT_PROXYTYPE,
|
1342
|
+
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, rbce->proxy_type);
|
1343
|
+
}
|
1344
|
+
} else {
|
1345
|
+
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
1196
1346
|
#else
|
1197
|
-
|
1347
|
+
rb_warn("Installed libcurl is too old to support proxy_type");
|
1198
1348
|
#endif
|
1199
|
-
|
1349
|
+
}
|
1200
1350
|
|
1201
|
-
|
1351
|
+
if (rbce->http_auth_types > 0) {
|
1202
1352
|
#if LIBCURL_VERSION_NUM >= 0x070a06
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1353
|
+
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, rbce->http_auth_types);
|
1354
|
+
} else {
|
1355
|
+
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
|
1206
1356
|
#else
|
1207
|
-
|
1357
|
+
rb_warn("Installed libcurl is too old to support http_auth_types");
|
1208
1358
|
#endif
|
1209
|
-
|
1359
|
+
}
|
1210
1360
|
|
1211
|
-
|
1361
|
+
if (rbce->proxy_auth_types > 0) {
|
1212
1362
|
#if LIBCURL_VERSION_NUM >= 0x070a07
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1363
|
+
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, rbce->proxy_auth_types);
|
1364
|
+
} else {
|
1365
|
+
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
1216
1366
|
#else
|
1217
|
-
|
1367
|
+
rb_warn("Installed libcurl is too old to support proxy_auth_types");
|
1218
1368
|
#endif
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
/* Set up HTTP cookie handling if necessary
|
1372
|
+
FIXME this may not get disabled if it's enabled, the disabled again from ruby.
|
1373
|
+
*/
|
1374
|
+
if (rbce->enable_cookies) {
|
1375
|
+
if (rbce->cookiejar != Qnil) {
|
1376
|
+
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, StringValuePtr(rbce->cookiejar));
|
1377
|
+
} else {
|
1378
|
+
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); /* "" = magic to just enable */
|
1219
1379
|
}
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
} else {
|
1238
|
-
VALUE headers_str = rb_obj_as_string(rbce->headers);
|
1239
|
-
headers = curl_slist_append(headers, StringValuePtr(headers_str));
|
1240
|
-
}
|
1241
|
-
|
1242
|
-
if (headers) {
|
1243
|
-
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
1244
|
-
}
|
1380
|
+
}
|
1381
|
+
|
1382
|
+
/* Set up HTTPS cert handling if necessary */
|
1383
|
+
if (rbce->cert != Qnil) {
|
1384
|
+
curl_easy_setopt(curl, CURLOPT_SSLCERT, StringValuePtr(rbce->cert));
|
1385
|
+
curl_easy_setopt(curl, CURLOPT_CAINFO, "/usr/local/share/curl/curl-ca-bundle.crt");
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
/* Setup HTTP headers if necessary */
|
1389
|
+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
|
1390
|
+
|
1391
|
+
if (rbce->headers != Qnil) {
|
1392
|
+
if ((rb_type(rbce->headers) == T_ARRAY) || (rb_type(rbce->headers) == T_HASH)) {
|
1393
|
+
rb_iterate(rb_each, rbce->headers, cb_each_http_header, (VALUE)hdrs);
|
1394
|
+
} else {
|
1395
|
+
VALUE headers_str = rb_obj_as_string(rbce->headers);
|
1396
|
+
*hdrs = curl_slist_append(*hdrs, StringValuePtr(headers_str));
|
1245
1397
|
}
|
1246
1398
|
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
// Free everything up
|
1251
|
-
if (headers) {
|
1252
|
-
curl_slist_free_all(headers);
|
1399
|
+
if (*hdrs) {
|
1400
|
+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *hdrs);
|
1253
1401
|
}
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
return Qnil;
|
1405
|
+
}
|
1406
|
+
/***********************************************
|
1407
|
+
*
|
1408
|
+
* Clean up a connection
|
1409
|
+
*
|
1410
|
+
* Always returns Qtrue.
|
1411
|
+
*/
|
1412
|
+
VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce, VALUE bodybuf, VALUE headerbuf, struct curl_slist *headers ) {
|
1413
|
+
|
1414
|
+
// Free everything up
|
1415
|
+
if (headers) {
|
1416
|
+
curl_slist_free_all(headers);
|
1417
|
+
rbce->curl_headers = NULL;
|
1418
|
+
}
|
1419
|
+
|
1420
|
+
// Sort out the built-in body/header data.
|
1421
|
+
if (bodybuf != Qnil) {
|
1422
|
+
if (TYPE(bodybuf) == T_STRING) {
|
1257
1423
|
rbce->body_data = rb_str_to_str(bodybuf);
|
1258
|
-
}
|
1424
|
+
}
|
1425
|
+
else if (rb_respond_to(bodybuf, rb_intern("to_s"))) {
|
1426
|
+
rbce->body_data = rb_funcall(bodybuf, rb_intern("to_s"), 0);
|
1427
|
+
}
|
1428
|
+
else {
|
1259
1429
|
rbce->body_data = Qnil;
|
1260
1430
|
}
|
1431
|
+
} else {
|
1432
|
+
rbce->body_data = Qnil;
|
1433
|
+
}
|
1261
1434
|
|
1262
|
-
|
1435
|
+
if (headerbuf != Qnil) {
|
1436
|
+
if (TYPE(headerbuf) == T_STRING) {
|
1263
1437
|
rbce->header_data = rb_str_to_str(headerbuf);
|
1264
|
-
}
|
1438
|
+
}
|
1439
|
+
else if (rb_respond_to(headerbuf, rb_intern("to_s"))) {
|
1440
|
+
rbce->header_data = rb_funcall(headerbuf, rb_intern("to_s"), 0);
|
1441
|
+
}
|
1442
|
+
else {
|
1265
1443
|
rbce->header_data = Qnil;
|
1266
1444
|
}
|
1445
|
+
} else {
|
1446
|
+
rbce->header_data = Qnil;
|
1447
|
+
}
|
1448
|
+
|
1449
|
+
return Qnil;
|
1450
|
+
}
|
1451
|
+
|
1452
|
+
/***********************************************
|
1453
|
+
*
|
1454
|
+
* This is the main worker for the perform methods (get, post, head, put).
|
1455
|
+
* It's not surfaced as a Ruby method - instead, the individual request
|
1456
|
+
* methods are responsible for setting up stuff specific to that type,
|
1457
|
+
* then calling this to handle common stuff and do the perform.
|
1458
|
+
*
|
1459
|
+
* Always returns Qtrue, rb_raise on error.
|
1460
|
+
*
|
1461
|
+
*/
|
1462
|
+
static VALUE handle_perform(VALUE self, ruby_curl_easy *rbce) {
|
1463
|
+
|
1464
|
+
int msgs;
|
1465
|
+
int still_running = 1;
|
1466
|
+
CURLcode result = -1;
|
1467
|
+
CURLMcode mcode = -1;
|
1468
|
+
CURLM *multi_handle = curl_multi_init();
|
1469
|
+
struct curl_slist *headers = NULL;
|
1470
|
+
VALUE bodybuf = Qnil, headerbuf = Qnil;
|
1471
|
+
// char errors[CURL_ERROR_SIZE*2];
|
1472
|
+
|
1473
|
+
ruby_curl_easy_setup(rbce, &bodybuf, &headerbuf, &headers);
|
1474
|
+
// curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, errors);
|
1475
|
+
// curl_easy_setopt(rbce->curl, CURLOPT_VERBOSE, 1);
|
1476
|
+
|
1477
|
+
// if( rb_thread_alone() ) {
|
1478
|
+
// result = curl_easy_perform(rbce->curl);
|
1479
|
+
// }
|
1480
|
+
// else {
|
1481
|
+
|
1482
|
+
/* NOTE:
|
1483
|
+
* We create an Curl multi handle here and use rb_thread_select allowing other ruby threads to
|
1484
|
+
* perform actions... ideally we'd have just 1 shared multi handle per all curl easy handles globally
|
1485
|
+
*/
|
1486
|
+
mcode = curl_multi_add_handle(multi_handle, rbce->curl);
|
1487
|
+
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
1488
|
+
raise_curl_multi_error_exception(mcode);
|
1489
|
+
}
|
1267
1490
|
|
1268
|
-
|
1491
|
+
while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &still_running)) ) ;
|
1492
|
+
|
1493
|
+
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
1494
|
+
raise_curl_multi_error_exception(mcode);
|
1495
|
+
}
|
1496
|
+
|
1497
|
+
while(still_running) {
|
1498
|
+
struct timeval timeout;
|
1499
|
+
int rc; /* select() return code */
|
1500
|
+
int maxfd;
|
1501
|
+
|
1502
|
+
fd_set fdread;
|
1503
|
+
fd_set fdwrite;
|
1504
|
+
fd_set fdexcep;
|
1505
|
+
|
1506
|
+
FD_ZERO(&fdread);
|
1507
|
+
FD_ZERO(&fdwrite);
|
1508
|
+
FD_ZERO(&fdexcep);
|
1509
|
+
|
1510
|
+
//time_t timer = time(NULL);
|
1511
|
+
/* get file descriptors from the transfers */
|
1512
|
+
mcode = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
1513
|
+
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
1514
|
+
raise_curl_multi_error_exception(mcode);
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
/* set a suitable timeout to play around with - ruby seems to be greedy about this and won't necessarily yield so the timeout is small.. */
|
1518
|
+
timeout.tv_sec = 0.0;
|
1519
|
+
timeout.tv_usec = 100000.0;
|
1520
|
+
rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
|
1521
|
+
if (rc < 0) {
|
1522
|
+
rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
|
1523
|
+
}
|
1524
|
+
|
1525
|
+
if( rc >= 0 ) {
|
1526
|
+
switch(rc) {
|
1527
|
+
case 0:
|
1528
|
+
//printf("timeout(%.6f) :", difftime(time(NULL), timer) );
|
1529
|
+
default:
|
1530
|
+
//printf("readable/writable: %d\n", rc);
|
1531
|
+
/* timeout or readable/writable sockets */
|
1532
|
+
while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &still_running)) );
|
1533
|
+
break;
|
1534
|
+
}
|
1535
|
+
}
|
1536
|
+
else {
|
1537
|
+
// error
|
1538
|
+
}
|
1539
|
+
|
1540
|
+
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
1541
|
+
raise_curl_multi_error_exception(mcode);
|
1542
|
+
}
|
1543
|
+
|
1544
|
+
}
|
1545
|
+
|
1546
|
+
/* check for errors */
|
1547
|
+
CURLMsg *msg = curl_multi_info_read(multi_handle, &msgs);
|
1548
|
+
if (msg && msg->msg == CURLMSG_DONE) {
|
1549
|
+
result = msg->data.result;
|
1550
|
+
}
|
1551
|
+
|
1552
|
+
curl_multi_remove_handle(multi_handle, rbce->curl);
|
1553
|
+
curl_multi_cleanup(multi_handle);
|
1554
|
+
// }
|
1555
|
+
|
1556
|
+
ruby_curl_easy_cleanup(self, rbce, bodybuf, headerbuf, headers);
|
1557
|
+
|
1558
|
+
if (rbce->complete_proc != Qnil) {
|
1559
|
+
rb_funcall( rbce->complete_proc, idCall, 1, self );
|
1560
|
+
}
|
1561
|
+
|
1562
|
+
/* check the request status and determine if on_success or on_failure should be called */
|
1563
|
+
long response_code = -1;
|
1564
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &response_code);
|
1565
|
+
if (result != 0) {
|
1566
|
+
// printf("error: %s\n", errors);
|
1567
|
+
if (rbce->failure_proc != Qnil) {
|
1568
|
+
rb_funcall( rbce->failure_proc, idCall, 1, self );
|
1569
|
+
} else {
|
1269
1570
|
raise_curl_easy_error_exception(result);
|
1270
1571
|
}
|
1271
|
-
} else {
|
1272
|
-
rb_raise(eCurlErrError, "No URL supplied");
|
1273
1572
|
}
|
1274
|
-
|
1573
|
+
else if (rbce->success_proc != Qnil &&
|
1574
|
+
/* NOTE: we allow response_code == 0, in the case the file is being read from disk */
|
1575
|
+
((response_code >= 200 && response_code < 300) || response_code == 0)) {
|
1576
|
+
rb_funcall( rbce->success_proc, idCall, 1, self );
|
1577
|
+
}
|
1578
|
+
else if (rbce->failure_proc != Qnil &&
|
1579
|
+
(response_code >= 300 && response_code <= 999)) {
|
1580
|
+
rb_funcall( rbce->failure_proc, idCall, 1, self );
|
1581
|
+
}
|
1582
|
+
|
1275
1583
|
return Qtrue;
|
1276
1584
|
}
|
1277
1585
|
|
@@ -1292,7 +1600,31 @@ static VALUE ruby_curl_easy_perform_get(VALUE self) {
|
|
1292
1600
|
|
1293
1601
|
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
1294
1602
|
|
1295
|
-
return handle_perform(rbce);
|
1603
|
+
return handle_perform(self,rbce);
|
1604
|
+
}
|
1605
|
+
|
1606
|
+
/*
|
1607
|
+
* call-seq:
|
1608
|
+
* easy.http_delete
|
1609
|
+
*
|
1610
|
+
* DELETE the currently configured URL using the current options set for
|
1611
|
+
* this Curl::Easy instance. This method always returns true, or raises
|
1612
|
+
* an exception (defined under Curl::Err) on error.
|
1613
|
+
*/
|
1614
|
+
static VALUE ruby_curl_easy_perform_delete(VALUE self) {
|
1615
|
+
ruby_curl_easy *rbce;
|
1616
|
+
CURL *curl;
|
1617
|
+
|
1618
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1619
|
+
curl = rbce->curl;
|
1620
|
+
|
1621
|
+
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
1622
|
+
|
1623
|
+
VALUE retval = handle_perform(self,rbce);
|
1624
|
+
|
1625
|
+
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
1626
|
+
|
1627
|
+
return retval;
|
1296
1628
|
}
|
1297
1629
|
|
1298
1630
|
/*
|
@@ -1341,7 +1673,9 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
1341
1673
|
rb_scan_args(argc, argv, "*", &args_ary);
|
1342
1674
|
|
1343
1675
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1344
|
-
curl = rbce->curl;
|
1676
|
+
curl = curl_easy_duphandle(rbce->curl);
|
1677
|
+
curl_easy_cleanup(rbce->curl);
|
1678
|
+
rbce->curl = curl;
|
1345
1679
|
|
1346
1680
|
if (rbce->multipart_form_post) {
|
1347
1681
|
VALUE ret;
|
@@ -1359,7 +1693,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
1359
1693
|
|
1360
1694
|
curl_easy_setopt(curl, CURLOPT_POST, 0);
|
1361
1695
|
curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
|
1362
|
-
ret = handle_perform(rbce);
|
1696
|
+
ret = handle_perform(self,rbce);
|
1363
1697
|
curl_formfree(first);
|
1364
1698
|
|
1365
1699
|
return ret;
|
@@ -1378,7 +1712,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
1378
1712
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
|
1379
1713
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
|
1380
1714
|
|
1381
|
-
return handle_perform(rbce);
|
1715
|
+
return handle_perform(self,rbce);
|
1382
1716
|
}
|
1383
1717
|
}
|
1384
1718
|
}
|
@@ -1392,10 +1726,17 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
1392
1726
|
* method always returns true, or raises an exception (defined under
|
1393
1727
|
* Curl::Err) on error.
|
1394
1728
|
*
|
1395
|
-
* TODO Not yet implemented
|
1396
1729
|
*/
|
1397
|
-
static VALUE ruby_curl_easy_perform_head(VALUE self) {
|
1398
|
-
|
1730
|
+
static VALUE ruby_curl_easy_perform_head(VALUE self) {
|
1731
|
+
ruby_curl_easy *rbce;
|
1732
|
+
CURL *curl;
|
1733
|
+
|
1734
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1735
|
+
curl = rbce->curl;
|
1736
|
+
|
1737
|
+
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
|
1738
|
+
|
1739
|
+
return handle_perform(self,rbce);
|
1399
1740
|
}
|
1400
1741
|
|
1401
1742
|
/*
|
@@ -1405,11 +1746,35 @@ static VALUE ruby_curl_easy_perform_head(VALUE self) {
|
|
1405
1746
|
* PUT the supplied data to the currently configured URL using the
|
1406
1747
|
* current options set for this Curl::Easy instance. This method always
|
1407
1748
|
* returns true, or raises an exception (defined under Curl::Err) on error.
|
1408
|
-
*
|
1409
|
-
* TODO Not yet implemented
|
1410
1749
|
*/
|
1411
|
-
static VALUE ruby_curl_easy_perform_put(VALUE self) {
|
1412
|
-
|
1750
|
+
static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
1751
|
+
ruby_curl_easy *rbce;
|
1752
|
+
CURL *curl;
|
1753
|
+
|
1754
|
+
PutStream *pstream = (PutStream*)malloc(sizeof(PutStream));
|
1755
|
+
memset(pstream, 0, sizeof(PutStream));
|
1756
|
+
|
1757
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1758
|
+
curl = rbce->curl;
|
1759
|
+
|
1760
|
+
pstream->len = RSTRING_LEN(data);
|
1761
|
+
pstream->buffer = StringValuePtr(data);
|
1762
|
+
|
1763
|
+
|
1764
|
+
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
|
1765
|
+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
1766
|
+
curl_easy_setopt(curl, CURLOPT_READDATA, pstream);
|
1767
|
+
//printf("uploading %d bytes\n", pstream->len);
|
1768
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, pstream->len);
|
1769
|
+
|
1770
|
+
VALUE ret = handle_perform(self, rbce);
|
1771
|
+
/* cleanup */
|
1772
|
+
curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
|
1773
|
+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
1774
|
+
curl_easy_setopt(curl, CURLOPT_READDATA, NULL);
|
1775
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
1776
|
+
|
1777
|
+
return ret;
|
1413
1778
|
}
|
1414
1779
|
|
1415
1780
|
/* =================== DATA FUNCS =============== */
|
@@ -1477,7 +1842,7 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
|
|
1477
1842
|
long code;
|
1478
1843
|
|
1479
1844
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1480
|
-
#ifdef
|
1845
|
+
#ifdef HAVE_CURLINFO_RESPONSE_CODE
|
1481
1846
|
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
|
1482
1847
|
#else
|
1483
1848
|
// old libcurl
|
@@ -1521,7 +1886,7 @@ static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
|
|
1521
1886
|
* returned.
|
1522
1887
|
*/
|
1523
1888
|
static VALUE ruby_curl_easy_file_time_get(VALUE self) {
|
1524
|
-
#ifdef
|
1889
|
+
#ifdef HAVE_CURLINFO_FILETIME
|
1525
1890
|
ruby_curl_easy *rbce;
|
1526
1891
|
long time;
|
1527
1892
|
|
@@ -1635,7 +2000,7 @@ static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
|
|
1635
2000
|
* Requires libcurl 7.9.7 or higher, otherwise -1 is always returned.
|
1636
2001
|
*/
|
1637
2002
|
static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
|
1638
|
-
#ifdef
|
2003
|
+
#ifdef HAVE_CURLINFO_REDIRECT_TIME
|
1639
2004
|
ruby_curl_easy *rbce;
|
1640
2005
|
double time;
|
1641
2006
|
|
@@ -1658,7 +2023,7 @@ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
|
|
1658
2023
|
* Requires libcurl 7.9.7 or higher, otherwise -1 is always returned.
|
1659
2024
|
*/
|
1660
2025
|
static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
|
1661
|
-
#ifdef
|
2026
|
+
#ifdef HAVE_CURLINFO_REDIRECT_COUNT
|
1662
2027
|
ruby_curl_easy *rbce;
|
1663
2028
|
long count;
|
1664
2029
|
|
@@ -1883,7 +2248,7 @@ Pass a pointer to a long to receive a bitmask indicating the authentication meth
|
|
1883
2248
|
* libcurl 7.12.2 or higher, otherwise 0 is always returned).
|
1884
2249
|
*/
|
1885
2250
|
static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
|
1886
|
-
#ifdef
|
2251
|
+
#ifdef HAVE_CURLINFO_OS_ERRNO
|
1887
2252
|
ruby_curl_easy *rbce;
|
1888
2253
|
long result;
|
1889
2254
|
|
@@ -1912,7 +2277,7 @@ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
|
|
1912
2277
|
* (requires libcurl 7.12.3 or higher, otherwise -1 is always returned).
|
1913
2278
|
*/
|
1914
2279
|
static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
|
1915
|
-
#ifdef
|
2280
|
+
#ifdef HAVE_CURLINFO_NUM_CONNECTS
|
1916
2281
|
ruby_curl_easy *rbce;
|
1917
2282
|
long result;
|
1918
2283
|
|
@@ -1953,14 +2318,14 @@ Pass a pointer to a long to receive the last socket used by this curl session. I
|
|
1953
2318
|
* (requires libcurl 7.15.4 or higher, otherwise +nil+ is always returned).
|
1954
2319
|
*/
|
1955
2320
|
static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
1956
|
-
#ifdef
|
2321
|
+
#ifdef HAVE_CURLINFO_FTP_ENTRY_PATH
|
1957
2322
|
ruby_curl_easy *rbce;
|
1958
|
-
char* path;
|
2323
|
+
char* path = NULL;
|
1959
2324
|
|
1960
2325
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1961
2326
|
curl_easy_getinfo(rbce->curl, CURLINFO_FTP_ENTRY_PATH, &path);
|
1962
2327
|
|
1963
|
-
if (
|
2328
|
+
if (path && path[0]) { // curl returns NULL or empty string if none
|
1964
2329
|
return rb_str_new2(path);
|
1965
2330
|
} else {
|
1966
2331
|
return Qnil;
|
@@ -2077,6 +2442,50 @@ static VALUE ruby_curl_easy_class_perform_get(int argc, VALUE *argv, VALUE klass
|
|
2077
2442
|
return c;
|
2078
2443
|
}
|
2079
2444
|
|
2445
|
+
/*
|
2446
|
+
* call-seq:
|
2447
|
+
* Curl::Easy.http_delete(url) { |easy| ... } => #<Curl::Easy...>
|
2448
|
+
*
|
2449
|
+
* Convenience method that creates a new Curl::Easy instance with
|
2450
|
+
* the specified URL and calls +http_delete+, before returning the new instance.
|
2451
|
+
*
|
2452
|
+
* If a block is supplied, the new instance will be yielded just prior to
|
2453
|
+
* the +http_delete+ call.
|
2454
|
+
*/
|
2455
|
+
static VALUE ruby_curl_easy_class_perform_delete(int argc, VALUE *argv, VALUE klass) {
|
2456
|
+
VALUE c = ruby_curl_easy_new(argc, argv, klass);
|
2457
|
+
|
2458
|
+
if (rb_block_given_p()) {
|
2459
|
+
rb_yield(c);
|
2460
|
+
}
|
2461
|
+
|
2462
|
+
ruby_curl_easy_perform_delete(c);
|
2463
|
+
return c;
|
2464
|
+
}
|
2465
|
+
|
2466
|
+
/*
|
2467
|
+
* call-seq:
|
2468
|
+
* Curl::Easy.http_head(url) { |easy| ... } => #<Curl::Easy...>
|
2469
|
+
*
|
2470
|
+
* Convenience method that creates a new Curl::Easy instance with
|
2471
|
+
* the specified URL and calls +http_head+, before returning the new instance.
|
2472
|
+
*
|
2473
|
+
* If a block is supplied, the new instance will be yielded just prior to
|
2474
|
+
* the +http_head+ call.
|
2475
|
+
*/
|
2476
|
+
static VALUE ruby_curl_easy_class_perform_head(int argc, VALUE *argv, VALUE klass) {
|
2477
|
+
VALUE c = ruby_curl_easy_new(argc, argv, klass);
|
2478
|
+
|
2479
|
+
if (rb_block_given_p()) {
|
2480
|
+
rb_yield(c);
|
2481
|
+
}
|
2482
|
+
|
2483
|
+
ruby_curl_easy_perform_head(c);
|
2484
|
+
return c;
|
2485
|
+
}
|
2486
|
+
|
2487
|
+
// TODO: add convenience method for http_post
|
2488
|
+
|
2080
2489
|
/*
|
2081
2490
|
* call-seq:
|
2082
2491
|
* Curl::Easy.http_post(url, "some=urlencoded%20form%20data&and=so%20on") => true
|
@@ -2123,8 +2532,10 @@ void init_curb_easy() {
|
|
2123
2532
|
/* Class methods */
|
2124
2533
|
rb_define_singleton_method(cCurlEasy, "new", ruby_curl_easy_new, -1);
|
2125
2534
|
rb_define_singleton_method(cCurlEasy, "perform", ruby_curl_easy_class_perform, -1);
|
2535
|
+
rb_define_singleton_method(cCurlEasy, "http_delete", ruby_curl_easy_class_perform_delete, -1);
|
2126
2536
|
rb_define_singleton_method(cCurlEasy, "http_get", ruby_curl_easy_class_perform_get, -1);
|
2127
2537
|
rb_define_singleton_method(cCurlEasy, "http_post", ruby_curl_easy_class_perform_post, -1);
|
2538
|
+
rb_define_singleton_method(cCurlEasy, "http_head", ruby_curl_easy_class_perform_head, -1);
|
2128
2539
|
|
2129
2540
|
/* Attributes for config next perform */
|
2130
2541
|
rb_define_method(cCurlEasy, "url=", ruby_curl_easy_url_set, 1);
|
@@ -2141,6 +2552,10 @@ void init_curb_easy() {
|
|
2141
2552
|
rb_define_method(cCurlEasy, "proxypwd", ruby_curl_easy_proxypwd_get, 0);
|
2142
2553
|
rb_define_method(cCurlEasy, "cookiejar=", ruby_curl_easy_cookiejar_set, 1);
|
2143
2554
|
rb_define_method(cCurlEasy, "cookiejar", ruby_curl_easy_cookiejar_get, 0);
|
2555
|
+
rb_define_method(cCurlEasy, "cert=", ruby_curl_easy_cert_set, 1);
|
2556
|
+
rb_define_method(cCurlEasy, "cert", ruby_curl_easy_cert_get, 0);
|
2557
|
+
rb_define_method(cCurlEasy, "encoding=", ruby_curl_easy_encoding_set, 1);
|
2558
|
+
rb_define_method(cCurlEasy, "encoding", ruby_curl_easy_encoding_get, 0);
|
2144
2559
|
|
2145
2560
|
rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
|
2146
2561
|
rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
|
@@ -2192,12 +2607,16 @@ void init_curb_easy() {
|
|
2192
2607
|
rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
|
2193
2608
|
rb_define_method(cCurlEasy, "on_progress", ruby_curl_easy_on_progress_set, -1);
|
2194
2609
|
rb_define_method(cCurlEasy, "on_debug", ruby_curl_easy_on_debug_set, -1);
|
2195
|
-
|
2610
|
+
rb_define_method(cCurlEasy, "on_success", ruby_curl_easy_on_success_set, -1);
|
2611
|
+
rb_define_method(cCurlEasy, "on_failure", ruby_curl_easy_on_failure_set, -1);
|
2612
|
+
rb_define_method(cCurlEasy, "on_complete", ruby_curl_easy_on_complete_set, -1);
|
2613
|
+
|
2196
2614
|
rb_define_method(cCurlEasy, "perform", ruby_curl_easy_perform, 0);
|
2615
|
+
rb_define_method(cCurlEasy, "http_delete", ruby_curl_easy_perform_delete, 0);
|
2197
2616
|
rb_define_method(cCurlEasy, "http_get", ruby_curl_easy_perform_get, 0);
|
2198
2617
|
rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
|
2199
2618
|
rb_define_method(cCurlEasy, "http_head", ruby_curl_easy_perform_head, 0);
|
2200
|
-
rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put,
|
2619
|
+
rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 1);
|
2201
2620
|
|
2202
2621
|
/* Post-perform info methods */
|
2203
2622
|
rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
|