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 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' mode.
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 (Build packages)"
25
- task :default => :package
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
- spec = Gem::Specification.new do |s|
148
-
149
- #### Basic information.
150
-
151
- s.name = 'curb'
152
- s.version = PKG_VERSION
153
- s.summary = "Ruby bindings for the libcurl(3) URL transfer library."
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
- package_task = Rake::GemPackageTask.new(spec) do |pkg|
193
- pkg.need_zip = true
194
- pkg.need_tar_gz = true
195
- pkg.package_dir = 'pkg'
196
- end
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 ext/curb.rb")
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 CURL_VERSION_SSL
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 CURL_VERSION_LIBZ
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 CURL_VERSION_NTLM
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 CURL_VERSION_GSSNEGOTIATE
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 CURL_VERSION_DEBUG
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 CURL_VERSION_ASYNCHDNS
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 CURL_VERSION_SPNEGO
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 CURL_VERSION_LARGEFILE
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 CURL_VERSION_IDN
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 CURL_VERSION_SSPI
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 CURL_VERSION_CONV
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 CURLPROXY_HTTP
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 CURLPROXY_SOCKS4
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 CURLPROXY_SOCKS5
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 CURLAUTH_BASIC
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 CURLAUTH_DIGEST
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 CURLAUTH_GSSNEGOTIATE
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 CURLAUTH_NTLM
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 CURLAUTH_ANYSAFE
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 CURLAUTH_ANY
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.4"
22
- #define CURB_VER_NUM 140
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 1
25
- #define CURB_VER_MIC 4
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();
@@ -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
@@ -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 { ... } => &lt;old handler&gt;
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 { ... } => &lt;old handler&gt;
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 { ... } => &lt;old handler&gt;
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| ... } => &lt;old handler&gt;
@@ -1044,234 +1193,393 @@ static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
1044
1193
  }
1045
1194
 
1046
1195
  /***********************************************
1047
- *
1048
- * This is the main worker for the perform methods (get, post, head, put).
1049
- * It's not surfaced as a Ruby method - instead, the individual request
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
- static VALUE handle_perform(ruby_curl_easy *rbce) {
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 != Qnil) {
1065
- VALUE url = rb_check_string_type(rbce->url);
1066
- VALUE bodybuf, headerbuf;
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
- // Need to configure the handler as per settings in rbce
1069
- curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
1070
-
1071
- // network stuff and auth
1072
- if (rbce->interface != Qnil) {
1073
- curl_easy_setopt(curl, CURLOPT_INTERFACE, StringValuePtr(rbce->interface));
1074
- } else {
1075
- curl_easy_setopt(curl, CURLOPT_INTERFACE, NULL);
1076
- }
1077
-
1078
- if (rbce->userpwd != Qnil) {
1079
- curl_easy_setopt(curl, CURLOPT_USERPWD, StringValuePtr(rbce->userpwd));
1080
- } else {
1081
- curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
1082
- }
1083
-
1084
- if (rbce->proxy_url != Qnil) {
1085
- curl_easy_setopt(curl, CURLOPT_PROXY, StringValuePtr(rbce->proxy_url));
1086
- } else {
1087
- curl_easy_setopt(curl, CURLOPT_PROXY, NULL);
1088
- }
1089
-
1090
- if (rbce->proxypwd != Qnil) {
1091
- curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, StringValuePtr(rbce->proxypwd));
1092
- } else {
1093
- curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
1094
- }
1095
-
1096
- // body/header procs
1097
- if (rbce->body_proc != Qnil) {
1098
- bodybuf = Qnil;
1099
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &proc_data_handler);
1100
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce->body_proc);
1101
- } else {
1102
- bodybuf = rb_str_buf_new(32768);
1103
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &default_data_handler);
1104
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, bodybuf);
1105
- }
1106
-
1107
- if (rbce->header_proc != Qnil) {
1108
- headerbuf = Qnil;
1109
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &proc_data_handler);
1110
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce->header_proc);
1111
- } else {
1112
- headerbuf = rb_str_buf_new(32768);
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
- // progress and debug procs
1118
- if (rbce->progress_proc != Qnil) {
1119
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &proc_progress_handler);
1120
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, rbce->progress_proc);
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
- curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
1156
-
1157
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, rbce->timeout);
1158
- curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
1159
- curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
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
- curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
1312
+ curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
1163
1313
  #else
1164
- if (rbce->ftp_response_timeout > 0) {
1165
- rb_warn("Installed libcurl is too old to support ftp_response_timeout");
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
- // Set up localport / proxy port
1170
- // FIXME these won't get returned to default if they're unset Ruby
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
- rb_warn("Installed libcurl is too old to support local_port");
1333
+ rb_warn("Installed libcurl is too old to support local_port");
1184
1334
  #endif
1185
- }
1186
-
1187
- if (rbce->proxy_type != -1) {
1335
+ }
1336
+
1337
+ if (rbce->proxy_type != -1) {
1188
1338
  #if LIBCURL_VERSION_NUM >= 0x070a00
1189
- if (rbce->proxy_type == -2) {
1190
- rb_warn("Installed libcurl is too old to support the selected proxy type");
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, CURLPROXY_HTTP);
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
- rb_warn("Installed libcurl is too old to support proxy_type");
1347
+ rb_warn("Installed libcurl is too old to support proxy_type");
1198
1348
  #endif
1199
- }
1349
+ }
1200
1350
 
1201
- if (rbce->http_auth_types > 0) {
1351
+ if (rbce->http_auth_types > 0) {
1202
1352
  #if LIBCURL_VERSION_NUM >= 0x070a06
1203
- curl_easy_setopt(curl, CURLOPT_HTTPAUTH, rbce->http_auth_types);
1204
- } else {
1205
- curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
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
- rb_warn("Installed libcurl is too old to support http_auth_types");
1357
+ rb_warn("Installed libcurl is too old to support http_auth_types");
1208
1358
  #endif
1209
- }
1359
+ }
1210
1360
 
1211
- if (rbce->proxy_auth_types > 0) {
1361
+ if (rbce->proxy_auth_types > 0) {
1212
1362
  #if LIBCURL_VERSION_NUM >= 0x070a07
1213
- curl_easy_setopt(curl, CURLOPT_PROXYAUTH, rbce->proxy_auth_types);
1214
- } else {
1215
- curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
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
- rb_warn("Installed libcurl is too old to support proxy_auth_types");
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
- // Set up HTTP cookie handling if necessary
1222
- // FIXME this may not get disabled if it's enabled, the disabled again from ruby.
1223
- if (rbce->enable_cookies) {
1224
- if (rbce->cookiejar != Qnil) {
1225
- curl_easy_setopt(curl, CURLOPT_COOKIEJAR, StringValuePtr(rbce->cookiejar));
1226
- } else {
1227
- curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); /* "" = magic to just enable */
1228
- }
1229
- }
1230
-
1231
- // Setup HTTP headers if necessary
1232
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); // clear
1233
-
1234
- if (rbce->headers != Qnil) {
1235
- if ((rb_type(rbce->headers) == T_ARRAY) || (rb_type(rbce->headers) == T_HASH)) {
1236
- rb_iterate(rb_each, rbce->headers, cb_each_http_header, (VALUE)&headers);
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
- // Okay, do it.
1248
- result = curl_easy_perform(curl);
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
- // Sort out the built-in body/header data.
1256
- if (bodybuf != Qnil) {
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
- } else {
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
- if (headerbuf != Qnil) {
1435
+ if (headerbuf != Qnil) {
1436
+ if (TYPE(headerbuf) == T_STRING) {
1263
1437
  rbce->header_data = rb_str_to_str(headerbuf);
1264
- } else {
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
- if (result != 0) {
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
- rb_raise(eCurlErrError, "Not yet implemented");
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
- rb_raise(eCurlErrError, "Not yet implemented");
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 CURLINFO_RESPONSE_CODE
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 CURLINFO_FILETIME
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 CURLINFO_REDIRECT_TIME
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 CURLINFO_REDIRECT_COUNT
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 CURLINFO_OS_ERRNO
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 CURLINFO_NUM_CONNECTS
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 CURLINFO_FTP_ENTRY_PATH
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 (type && type[0]) { // curl returns NULL or empty string if none
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| ... } => #&lt;Curl::Easy...&gt;
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| ... } => #&lt;Curl::Easy...&gt;
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, 0);
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);