curb 0.6.5.0 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/curb_easy.c CHANGED
@@ -28,6 +28,10 @@ VALUE cCurlEasy;
28
28
 
29
29
  /* ================== CURL HANDLER FUNCS ==============*/
30
30
 
31
+ static VALUE callback_exception(VALUE unused) {
32
+ return Qfalse;
33
+ }
34
+
31
35
  /* These handle both body and header data */
32
36
  static size_t default_data_handler(char *stream,
33
37
  size_t size,
@@ -57,7 +61,7 @@ static size_t read_data_handler(void *ptr,
57
61
  return 0;
58
62
  }
59
63
  }
60
- else {
64
+ else if (rb_respond_to(stream, rb_intern("to_s"))) {
61
65
  ruby_curl_upload *rbcu;
62
66
  VALUE str;
63
67
  size_t len;
@@ -68,6 +72,7 @@ static size_t read_data_handler(void *ptr,
68
72
  len = RSTRING_LEN(str);
69
73
  remaining = len - rbcu->offset;
70
74
  str_ptr = RSTRING_PTR(str);
75
+
71
76
  if( remaining < read_bytes ) {
72
77
  if( remaining > 0 ) {
73
78
  memcpy(ptr, str_ptr+rbcu->offset, remaining);
@@ -86,7 +91,9 @@ static size_t read_data_handler(void *ptr,
86
91
  }
87
92
  return read_bytes;
88
93
  }
89
-
94
+ else {
95
+ return 0;
96
+ }
90
97
  }
91
98
 
92
99
  static size_t proc_data_handler(char *stream,
@@ -108,114 +115,117 @@ static size_t proc_data_handler(char *stream,
108
115
  }
109
116
  }
110
117
 
118
+ static size_t proc_data_handler_body(char *stream,
119
+ size_t size,
120
+ size_t nmemb,
121
+ ruby_curl_easy *rbce)
122
+ {
123
+ size_t ret;
124
+ rbce->callback_active = 1;
125
+ ret = proc_data_handler(stream, size, nmemb, rb_easy_get("body_proc"));
126
+ rbce->callback_active = 0;
127
+ return ret;
128
+ }
129
+ static size_t proc_data_handler_header(char *stream,
130
+ size_t size,
131
+ size_t nmemb,
132
+ ruby_curl_easy *rbce)
133
+ {
134
+ size_t ret;
135
+ rbce->callback_active = 1;
136
+ ret = proc_data_handler(stream, size, nmemb, rb_easy_get("header_proc"));
137
+ rbce->callback_active = 0;
138
+ return ret;
139
+ }
140
+
141
+
142
+ static VALUE call_progress_handler(VALUE ary) {
143
+ return rb_funcall(rb_ary_entry(ary, 0), idCall, 4,
144
+ rb_ary_entry(ary, 1), // rb_float_new(dltotal),
145
+ rb_ary_entry(ary, 2), // rb_float_new(dlnow),
146
+ rb_ary_entry(ary, 3), // rb_float_new(ultotal),
147
+ rb_ary_entry(ary, 4)); // rb_float_new(ulnow));
148
+ }
149
+
111
150
  static int proc_progress_handler(VALUE proc,
112
151
  double dltotal,
113
152
  double dlnow,
114
153
  double ultotal,
115
154
  double ulnow) {
116
155
  VALUE procret;
156
+ VALUE callargs = rb_ary_new2(5);
157
+
158
+ rb_ary_store(callargs, 0, proc);
159
+ rb_ary_store(callargs, 1, rb_float_new(dltotal));
160
+ rb_ary_store(callargs, 2, rb_float_new(dlnow));
161
+ rb_ary_store(callargs, 3, rb_float_new(ultotal));
162
+ rb_ary_store(callargs, 4, rb_float_new(ulnow));
117
163
 
118
- procret = rb_funcall(proc, idCall, 4, rb_float_new(dltotal),
119
- rb_float_new(dlnow),
120
- rb_float_new(ultotal),
121
- rb_float_new(ulnow));
164
+ //v = rb_rescue(range_check, (VALUE)args, range_failed, 0);
165
+ //procret = rb_funcall(proc, idCall, 4, rb_float_new(dltotal),
166
+ // rb_float_new(dlnow),
167
+ // rb_float_new(ultotal),
168
+ // rb_float_new(ulnow));
169
+ procret = rb_rescue(call_progress_handler, callargs, callback_exception, Qnil);
122
170
 
123
171
  return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
124
172
  }
125
173
 
174
+ static VALUE call_debug_handler(VALUE ary) {
175
+ return rb_funcall(rb_ary_entry(ary, 0), idCall, 2,
176
+ rb_ary_entry(ary, 1), // INT2FIX(type),
177
+ rb_ary_entry(ary, 2)); // rb_str_new(data, data_len)
178
+ }
126
179
  static int proc_debug_handler(CURL *curl,
127
180
  curl_infotype type,
128
181
  char *data,
129
182
  size_t data_len,
130
183
  VALUE proc) {
131
- rb_funcall(proc, idCall, 2, INT2FIX(type), rb_str_new(data, data_len));
184
+ VALUE callargs = rb_ary_new2(3);
185
+ rb_ary_store(callargs, 0, proc);
186
+ rb_ary_store(callargs, 1, INT2FIX(type));
187
+ rb_ary_store(callargs, 2, rb_str_new(data, data_len));
188
+ rb_rescue(call_debug_handler, callargs, callback_exception, Qnil);
189
+ /* no way to indicate to libcurl that we should break out given an exception in the on_debug handler...
190
+ * this means exceptions will be swallowed
191
+ */
192
+ //rb_funcall(proc, idCall, 2, INT2FIX(type), rb_str_new(data, data_len));
132
193
  return 0;
133
194
  }
134
195
 
135
196
  /* ================== MARK/FREE FUNC ==================*/
136
197
  void curl_easy_mark(ruby_curl_easy *rbce) {
137
- #if 0
138
- rb_gc_mark(rbce->url);
139
- rb_gc_mark(rbce->proxy_url);
140
- rb_gc_mark(rbce->body_proc);
141
- rb_gc_mark(rbce->body_data);
142
- rb_gc_mark(rbce->header_proc);
143
- rb_gc_mark(rbce->header_data);
144
- rb_gc_mark(rbce->progress_proc);
145
- rb_gc_mark(rbce->debug_proc);
146
- rb_gc_mark(rbce->interface_hm);
147
- rb_gc_mark(rbce->userpwd);
148
- #if HAVE_CURLOPT_USERNAME
149
- rb_gc_mark(rbce->username);
150
- #endif
151
- #if HAVE_CURLOPT_PASSWORD
152
- rb_gc_mark(rbce->password);
153
- #endif
154
- rb_gc_mark(rbce->proxypwd);
155
- rb_gc_mark(rbce->headers);
156
- rb_gc_mark(rbce->cookies);
157
- rb_gc_mark(rbce->cookiefile);
158
- rb_gc_mark(rbce->cookiejar);
159
- rb_gc_mark(rbce->cert);
160
- rb_gc_mark(rbce->cacert);
161
- rb_gc_mark(rbce->certpassword);
162
- rb_gc_mark(rbce->certtype);
163
- rb_gc_mark(rbce->encoding);
164
- rb_gc_mark(rbce->useragent);
165
- rb_gc_mark(rbce->success_proc);
166
- rb_gc_mark(rbce->failure_proc);
167
- rb_gc_mark(rbce->complete_proc);
168
-
169
- rb_gc_mark(rbce->postdata_buffer);
170
- rb_gc_mark(rbce->bodybuf);
171
- rb_gc_mark(rbce->headerbuf);
172
-
173
- if( rbce->upload != Qnil ) {
174
- rb_gc_mark(rbce->upload);
175
- }
176
- #endif
177
- rb_gc_mark(rbce->opts);
198
+ if (!NIL_P(rbce->opts)) { rb_gc_mark(rbce->opts); }
199
+ if (!NIL_P(rbce->multi)) { rb_gc_mark(rbce->multi); }
178
200
  }
179
201
 
180
- void curl_easy_free(ruby_curl_easy *rbce) {
202
+ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
181
203
  if (rbce->curl_headers) {
182
204
  curl_slist_free_all(rbce->curl_headers);
183
205
  }
184
- curl_easy_cleanup(rbce->curl);
185
- free(rbce);
186
- }
187
-
188
206
 
189
- /* ================= ALLOC METHODS ====================*/
207
+ if (rbce->curl_ftp_commands) {
208
+ curl_slist_free_all(rbce->curl_ftp_commands);
209
+ }
190
210
 
191
- /*
192
- * call-seq:
193
- * Curl::Easy.new => #&lt;Curl::Easy...&gt;
194
- * Curl::Easy.new(url = nil) => #&lt;Curl::Easy...&gt;
195
- * Curl::Easy.new(url = nil) { |self| ... } => #&lt;Curl::Easy...&gt;
196
- *
197
- * Create a new Curl::Easy instance, optionally supplying the URL.
198
- * The block form allows further configuration to be supplied before
199
- * the instance is returned.
200
- */
201
- static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
202
- CURLcode ecode;
203
- VALUE url, blk;
204
- VALUE new_curl;
205
- ruby_curl_easy *rbce;
211
+ if (rbce->curl) {
212
+ curl_easy_cleanup(rbce->curl);
213
+ }
214
+ }
206
215
 
207
- rb_scan_args(argc, argv, "01&", &url, &blk);
216
+ void curl_easy_free(ruby_curl_easy *rbce) {
217
+ ruby_curl_easy_free(rbce);
218
+ free(rbce);
219
+ }
208
220
 
209
- rbce = ALLOC(ruby_curl_easy);
210
221
 
211
- /* handler */
212
- rbce->curl = curl_easy_init();
222
+ /* ================= ALLOC METHODS ====================*/
213
223
 
224
+ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
214
225
  rbce->opts = rb_hash_new();
215
226
 
216
- rb_easy_set("url", url);
217
-
218
227
  rbce->curl_headers = NULL;
228
+ rbce->curl_ftp_commands = NULL;
219
229
 
220
230
  /* various-typed opts */
221
231
  rbce->local_port = 0;
@@ -229,12 +239,18 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
229
239
  rbce->connect_timeout = 0;
230
240
  rbce->dns_cache_timeout = 60;
231
241
  rbce->ftp_response_timeout = 0;
242
+ rbce->low_speed_limit = 0;
243
+ rbce->low_speed_time = 0;
244
+ rbce->ssl_version = -1;
245
+ rbce->use_ssl = -1;
246
+ rbce->ftp_filemethod = -1;
247
+ rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
232
248
 
233
249
  /* bool opts */
234
250
  rbce->proxy_tunnel = 0;
235
251
  rbce->fetch_file_time = 0;
236
252
  rbce->ssl_verify_peer = 1;
237
- rbce->ssl_verify_host = 1;
253
+ rbce->ssl_verify_host = 2;
238
254
  rbce->header_in_body = 0;
239
255
  rbce->use_netrc = 0;
240
256
  rbce->follow_location = 0;
@@ -242,9 +258,45 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
242
258
  rbce->verbose = 0;
243
259
  rbce->multipart_form_post = 0;
244
260
  rbce->enable_cookies = 0;
261
+ rbce->ignore_content_length = 0;
262
+ rbce->callback_active = 0;
263
+ }
264
+
265
+ /*
266
+ * call-seq:
267
+ * Curl::Easy.new => #&lt;Curl::Easy...&gt;
268
+ * Curl::Easy.new(url = nil) => #&lt;Curl::Easy...&gt;
269
+ * Curl::Easy.new(url = nil) { |self| ... } => #&lt;Curl::Easy...&gt;
270
+ *
271
+ * Create a new Curl::Easy instance, optionally supplying the URL.
272
+ * The block form allows further configuration to be supplied before
273
+ * the instance is returned.
274
+ */
275
+ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
276
+ CURLcode ecode;
277
+ VALUE url, blk;
278
+ VALUE new_curl;
279
+ ruby_curl_easy *rbce;
280
+
281
+ rb_scan_args(argc, argv, "01&", &url, &blk);
282
+
283
+ rbce = ALLOC(ruby_curl_easy);
284
+
285
+ /* handler */
286
+ rbce->curl = curl_easy_init();
287
+ if (!rbce->curl) {
288
+ rb_raise(eCurlErrFailedInit, "Failed to initialize easy handle");
289
+ }
245
290
 
246
291
  new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
247
292
 
293
+ rbce->multi = Qnil;
294
+ rbce->opts = Qnil;
295
+
296
+ ruby_curl_easy_zero(rbce);
297
+
298
+ rb_easy_set("url", url);
299
+
248
300
  /* set the new_curl pointer to the curl handle */
249
301
  ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)new_curl);
250
302
  if (ecode != CURLE_OK) {
@@ -275,67 +327,108 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
275
327
  memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
276
328
  newrbce->curl = curl_easy_duphandle(rbce->curl);
277
329
  newrbce->curl_headers = NULL;
330
+ newrbce->curl_ftp_commands = NULL;
278
331
 
279
332
  return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
280
333
  }
281
334
 
282
-
283
- /* ================ OBJ ATTRIBUTES ==================*/
284
-
285
335
  /*
286
336
  * call-seq:
287
- * easy.url = "http://some.url/" => "http://some.url/"
337
+ * easy.close => nil
288
338
  *
289
- * Set the URL for subsequent calls to +perform+. It is acceptable
290
- * (and even recommended) to reuse Curl::Easy instances by reassigning
291
- * the URL between calls to +perform+.
339
+ * Close the Curl::Easy instance. Any open connections are closed
340
+ * The easy handle is reinitialized. If a previous multi handle was
341
+ * open it is set to nil and will be cleared after a GC.
292
342
  */
293
- static VALUE ruby_curl_easy_url_set(VALUE self, VALUE url) {
294
- CURB_OBJECT_HSETTER(ruby_curl_easy, url);
343
+ static VALUE ruby_curl_easy_close(VALUE self) {
344
+ CURLcode ecode;
345
+ ruby_curl_easy *rbce;
346
+
347
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
348
+
349
+ if (rbce->callback_active) {
350
+ rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
351
+ }
352
+
353
+ ruby_curl_easy_free(rbce);
354
+
355
+ /* reinit the handle */
356
+ rbce->curl = curl_easy_init();
357
+ if (!rbce->curl) {
358
+ rb_raise(eCurlErrFailedInit, "Failed to initialize easy handle");
359
+ }
360
+
361
+ rbce->multi = Qnil;
362
+
363
+ ruby_curl_easy_zero(rbce);
364
+
365
+ /* give the new curl handle a reference back to the ruby object */
366
+ ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
367
+ if (ecode != CURLE_OK) {
368
+ raise_curl_easy_error_exception(ecode);
369
+ }
370
+
371
+ return Qnil;
295
372
  }
296
373
 
297
374
  /*
298
375
  * call-seq:
299
- * easy.url => "http://some.url/"
376
+ * easy.reset => Hash
300
377
  *
301
- * Obtain the URL that will be used by subsequent calls to +perform+.
378
+ * Reset the Curl::Easy instance, clears out all settings.
379
+ *
380
+ * from http://curl.haxx.se/libcurl/c/curl_easy_reset.html
381
+ * Re-initializes all options previously set on a specified CURL handle to the default values. This puts back the handle to the same state as it was in when it was just created with curl_easy_init(3).
382
+ * It does not change the following information kept in the handle: live connections, the Session ID cache, the DNS cache, the cookies and shares.
383
+ *
384
+ * The return value contains all settings stored.
302
385
  */
303
- static VALUE ruby_curl_easy_url_get(VALUE self) {
304
- CURB_OBJECT_HGETTER(ruby_curl_easy, url);
386
+ static VALUE ruby_curl_easy_reset(VALUE self) {
387
+ CURLcode ecode;
388
+ ruby_curl_easy *rbce;
389
+ VALUE opts_dup;
390
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
391
+
392
+ if (rbce->callback_active) {
393
+ rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
394
+ }
395
+
396
+ opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
397
+
398
+ curl_easy_reset(rbce->curl);
399
+ ruby_curl_easy_zero(rbce);
400
+
401
+ /* rest clobbers the private setting, so reset it to self */
402
+ ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
403
+ if (ecode != CURLE_OK) {
404
+ raise_curl_easy_error_exception(ecode);
405
+ }
406
+
407
+ /* Free everything up */
408
+ if (rbce->curl_headers) {
409
+ curl_slist_free_all(rbce->curl_headers);
410
+ rbce->curl_headers = NULL;
411
+ }
412
+
413
+ return opts_dup;
305
414
  }
306
415
 
416
+
417
+ /* ================ OBJ ATTRIBUTES ==================*/
418
+
307
419
  /*
308
420
  * call-seq:
309
- * easy.proxy_url = "some.url" => "some.url"
310
- *
311
- * Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
312
- * The URL should specify the the host name or dotted IP address. To specify
313
- * port number in this string, append :[port] to the end of the host name.
314
- * The proxy string may be prefixed with [protocol]:// since any such prefix
315
- * will be ignored. The proxy's port number may optionally be specified with
316
- * the separate option proxy_port .
317
- *
318
- * When you tell the library to use an HTTP proxy, libcurl will transparently
319
- * convert operations to HTTP even if you specify an FTP URL etc. This may have
320
- * an impact on what other features of the library you can use, such as
321
- * FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
322
- * tunneling is activated with proxy_tunnel = true.
421
+ * easy.url => string
323
422
  *
324
- * libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
325
- * *all_proxy* etc, if any of those is set. The proxy_url option does however
326
- * override any possibly set environment variables.
327
- *
328
- * Starting with libcurl 7.14.1, the proxy host string given in environment
329
- * variables can be specified the exact same way as the proxy can be set with
330
- * proxy_url, including protocol prefix (http://) and embedded user + password.
331
- */
332
- static VALUE ruby_curl_easy_proxy_url_set(VALUE self, VALUE proxy_url) {
333
- CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_url);
423
+ * Obtain the URL that will be used by subsequent calls to +perform+.
424
+ */
425
+ static VALUE ruby_curl_easy_url_get(VALUE self) {
426
+ CURB_OBJECT_HGETTER(ruby_curl_easy, url);
334
427
  }
335
428
 
336
429
  /*
337
430
  * call-seq:
338
- * easy.proxy_url => "some.url"
431
+ * easy.proxy_url => string
339
432
  *
340
433
  * Obtain the HTTP Proxy URL that will be used by subsequent calls to +perform+.
341
434
  */
@@ -345,8 +438,8 @@ static VALUE ruby_curl_easy_proxy_url_get(VALUE self) {
345
438
 
346
439
  /*
347
440
  * call-seq:
348
- * easy.headers = "Header: val" => ["Header: val", ...]
349
- * easy.headers = {"Header" => "val" ..., "Header" => "val"} => ["Header: val", ...]
441
+ * easy.headers = "Header: val" => "Header: val"
442
+ * easy.headers = {"Header" => "val" ..., "Header" => "val"} => {"Header: val", ...}
350
443
  * easy.headers = ["Header: val" ..., "Header: val"] => ["Header: val", ...]
351
444
  *
352
445
  * Set custom HTTP headers for following requests. This can be used to add
@@ -360,7 +453,7 @@ static VALUE ruby_curl_easy_proxy_url_get(VALUE self) {
360
453
  * To remove a standard header (this is useful when removing libcurls default
361
454
  * 'Expect: 100-Continue' header when using HTTP form posts):
362
455
  *
363
- * easy.headers["Expect:"] = ''
456
+ * easy.headers["Expect"] = ''
364
457
  *
365
458
  * Anything passed to libcurl as a header will be converted to a string during
366
459
  * the perform step.
@@ -371,7 +464,7 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
371
464
 
372
465
  /*
373
466
  * call-seq:
374
- * easy.headers => Hash, Array or Str
467
+ * easy.headers => Hash, Array or Str
375
468
  *
376
469
  * Obtain the custom HTTP headers for following requests.
377
470
  */
@@ -386,18 +479,7 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
386
479
 
387
480
  /*
388
481
  * call-seq:
389
- * easy.interface = "interface" => "interface"
390
- *
391
- * Set the interface name to use as the outgoing network interface.
392
- * The name can be an interface name, an IP address or a host name.
393
- */
394
- static VALUE ruby_curl_easy_interface_set(VALUE self, VALUE interface_hm) {
395
- CURB_OBJECT_HSETTER(ruby_curl_easy, interface_hm);
396
- }
397
-
398
- /*
399
- * call-seq:
400
- * easy.interface => "interface"
482
+ * easy.interface => string
401
483
  *
402
484
  * Obtain the interface name that is used as the outgoing network interface.
403
485
  * The name can be an interface name, an IP address or a host name.
@@ -408,18 +490,7 @@ static VALUE ruby_curl_easy_interface_get(VALUE self) {
408
490
 
409
491
  /*
410
492
  * call-seq:
411
- * easy.userpwd = "pwd string" => "pwd string"
412
- *
413
- * Set the username/password string to use for subsequent calls to +perform+.
414
- * The supplied string should have the form "username:password"
415
- */
416
- static VALUE ruby_curl_easy_userpwd_set(VALUE self, VALUE userpwd) {
417
- CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
418
- }
419
-
420
- /*
421
- * call-seq:
422
- * easy.userpwd => "pwd string"
493
+ * easy.userpwd => string
423
494
  *
424
495
  * Obtain the username/password string that will be used for subsequent
425
496
  * calls to +perform+.
@@ -430,19 +501,7 @@ static VALUE ruby_curl_easy_userpwd_get(VALUE self) {
430
501
 
431
502
  /*
432
503
  * call-seq:
433
- * easy.proxypwd = "pwd string" => "pwd string"
434
- *
435
- * Set the username/password string to use for proxy connection during
436
- * subsequent calls to +perform+. The supplied string should have the
437
- * form "username:password"
438
- */
439
- static VALUE ruby_curl_easy_proxypwd_set(VALUE self, VALUE proxypwd) {
440
- CURB_OBJECT_HSETTER(ruby_curl_easy, proxypwd);
441
- }
442
-
443
- /*
444
- * call-seq:
445
- * easy.proxypwd => "pwd string"
504
+ * easy.proxypwd => string
446
505
  *
447
506
  * Obtain the username/password string that will be used for proxy
448
507
  * connection during subsequent calls to +perform+. The supplied string
@@ -452,22 +511,9 @@ static VALUE ruby_curl_easy_proxypwd_get(VALUE self) {
452
511
  CURB_OBJECT_HGETTER(ruby_curl_easy, proxypwd);
453
512
  }
454
513
 
455
-
456
514
  /*
457
515
  * call-seq:
458
- * easy.cookies = "name1=content1; name2=content2;" => "pwd string"
459
- *
460
- * Set cookies to be sent by this Curl::Easy instance. The format of the string should
461
- * be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
462
- * Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
463
- */
464
- static VALUE ruby_curl_easy_cookies_set(VALUE self, VALUE cookies) {
465
- CURB_OBJECT_HSETTER(ruby_curl_easy, cookies);
466
- }
467
-
468
- /*
469
- * call-seq:
470
- * easy.cookies => "name1=content1; name2=content2;"
516
+ * easy.cookies => "name1=content1; name2=content2;"
471
517
  *
472
518
  * Obtain the cookies for this Curl::Easy instance.
473
519
  */
@@ -477,20 +523,7 @@ static VALUE ruby_curl_easy_cookies_get(VALUE self) {
477
523
 
478
524
  /*
479
525
  * call-seq:
480
- * easy.cookiefile = "cookies.txt" => "pwd string"
481
- *
482
- * Set a file that contains cookies to be sent in subsequent requests by this Curl::Easy instance.
483
- *
484
- * *Note* that you must set enable_cookies true to enable the cookie
485
- * engine, or this option will be ignored.
486
- */
487
- static VALUE ruby_curl_easy_cookiefile_set(VALUE self, VALUE cookiefile) {
488
- CURB_OBJECT_HSETTER(ruby_curl_easy, cookiefile);
489
- }
490
-
491
- /*
492
- * call-seq:
493
- * easy.cookiefile => "cookies.txt"
526
+ * easy.cookiefile => string
494
527
  *
495
528
  * Obtain the cookiefile file for this Curl::Easy instance.
496
529
  */
@@ -500,21 +533,7 @@ static VALUE ruby_curl_easy_cookiefile_get(VALUE self) {
500
533
 
501
534
  /*
502
535
  * call-seq:
503
- * easy.cookiejar = "cookiejar.file" => "pwd string"
504
- *
505
- * Set a cookiejar file to use for this Curl::Easy instance.
506
- * Cookies from the response will be written into this file.
507
- *
508
- * *Note* that you must set enable_cookies true to enable the cookie
509
- * engine, or this option will be ignored.
510
- */
511
- static VALUE ruby_curl_easy_cookiejar_set(VALUE self, VALUE cookiejar) {
512
- CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
513
- }
514
-
515
- /*
516
- * call-seq:
517
- * easy.cookiejar => "cookiejar.file"
536
+ * easy.cookiejar => string
518
537
  *
519
538
  * Obtain the cookiejar file to use for this Curl::Easy instance.
520
539
  */
@@ -524,7 +543,7 @@ static VALUE ruby_curl_easy_cookiejar_get(VALUE self) {
524
543
 
525
544
  /*
526
545
  * call-seq:
527
- * easy.cert = "cert.file" => ""
546
+ * easy.cert = string => ""
528
547
  *
529
548
  * Set a cert file to use for this Curl::Easy instance. This file
530
549
  * will be used to validate SSL connections.
@@ -536,7 +555,7 @@ static VALUE ruby_curl_easy_cert_set(VALUE self, VALUE cert) {
536
555
 
537
556
  /*
538
557
  * call-seq:
539
- * easy.cert => "cert.file"
558
+ * easy.cert => string
540
559
  *
541
560
  * Obtain the cert file to use for this Curl::Easy instance.
542
561
  */
@@ -546,7 +565,29 @@ static VALUE ruby_curl_easy_cert_get(VALUE self) {
546
565
 
547
566
  /*
548
567
  * call-seq:
549
- * easy.cacert = "cacert.file" => ""
568
+ * easy.cert_key = "cert_key.file" => ""
569
+ *
570
+ * Set a cert key to use for this Curl::Easy instance. This file
571
+ * will be used to validate SSL certificates.
572
+ *
573
+ */
574
+ static VALUE ruby_curl_easy_cert_key_set(VALUE self, VALUE cert_key) {
575
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cert_key);
576
+ }
577
+
578
+ /*
579
+ * call-seq:
580
+ * easy.cert_key => "cert_key.file"
581
+ *
582
+ * Obtain the cert key file to use for this Curl::Easy instance.
583
+ */
584
+ static VALUE ruby_curl_easy_cert_key_get(VALUE self) {
585
+ CURB_OBJECT_HGETTER(ruby_curl_easy, cert_key);
586
+ }
587
+
588
+ /*
589
+ * call-seq:
590
+ * easy.cacert = string => ""
550
591
  *
551
592
  * Set a cacert bundle to use for this Curl::Easy instance. This file
552
593
  * will be used to validate SSL certificates.
@@ -558,7 +599,7 @@ static VALUE ruby_curl_easy_cacert_set(VALUE self, VALUE cacert) {
558
599
 
559
600
  /*
560
601
  * call-seq:
561
- * easy.cacert => "cacert.file"
602
+ * easy.cacert => string
562
603
  *
563
604
  * Obtain the cacert file to use for this Curl::Easy instance.
564
605
  */
@@ -568,7 +609,7 @@ static VALUE ruby_curl_easy_cacert_get(VALUE self) {
568
609
 
569
610
  /*
570
611
  * call-seq:
571
- * easy.certpassword = "cert password" => ""
612
+ * easy.certpassword = string => ""
572
613
  *
573
614
  * Set a password used to open the specified cert
574
615
  */
@@ -590,7 +631,7 @@ static VALUE ruby_curl_easy_certtype_set(VALUE self, VALUE certtype) {
590
631
 
591
632
  /*
592
633
  * call-seq:
593
- * easy.certtype => "cert.type"
634
+ * easy.certtype => string
594
635
  *
595
636
  * Obtain the cert type used for this Curl::Easy instance
596
637
  */
@@ -600,7 +641,7 @@ static VALUE ruby_curl_easy_certtype_get(VALUE self) {
600
641
 
601
642
  /*
602
643
  * call-seq:
603
- * easy.encoding= => "string"
644
+ * easy.encoding = string => string
604
645
  *
605
646
  * Set the accepted encoding types, curl will handle all of the decompression
606
647
  *
@@ -610,7 +651,7 @@ static VALUE ruby_curl_easy_encoding_set(VALUE self, VALUE encoding) {
610
651
  }
611
652
  /*
612
653
  * call-seq:
613
- * easy.encoding => "string"
654
+ * easy.encoding => string
614
655
  *
615
656
  * Get the set encoding types
616
657
  *
@@ -621,7 +662,7 @@ static VALUE ruby_curl_easy_encoding_get(VALUE self) {
621
662
 
622
663
  /*
623
664
  * call-seq:
624
- * easy.useragent = "Ruby/Curb" => ""
665
+ * easy.useragent = "Ruby/Curb" => ""
625
666
  *
626
667
  * Set the user agent string for this Curl::Easy instance
627
668
  *
@@ -642,7 +683,7 @@ static VALUE ruby_curl_easy_useragent_get(VALUE self) {
642
683
 
643
684
  /*
644
685
  * call-seq:
645
- * easy.post_body = "some=form%20data&to=send" => string or nil
686
+ * easy.post_body = "some=form%20data&to=send" => string or nil
646
687
  *
647
688
  * Sets the POST body of this Curl::Easy instance. This is expected to be
648
689
  * URL encoded; no additional processing or encoding is done on the string.
@@ -662,12 +703,22 @@ static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
662
703
  curl = rbce->curl;
663
704
 
664
705
  if ( post_body == Qnil ) {
665
- //rbce->postdata_buffer = Qnil;
666
706
  rb_easy_del("postdata_buffer");
707
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
667
708
 
668
709
  } else {
669
- data = StringValuePtr(post_body);
670
- len = RSTRING_LEN(post_body);
710
+ if (rb_type(post_body) == T_STRING) {
711
+ data = StringValuePtr(post_body);
712
+ len = RSTRING_LEN(post_body);
713
+ }
714
+ else if (rb_respond_to(post_body, rb_intern("to_s"))) {
715
+ VALUE str_body = rb_funcall(post_body, rb_intern("to_s"), 0);
716
+ data = StringValuePtr(str_body);
717
+ len = RSTRING_LEN(post_body);
718
+ }
719
+ else {
720
+ rb_raise(rb_eRuntimeError, "post data must respond_to .to_s");
721
+ }
671
722
 
672
723
  // Store the string, since it has to hang around for the duration of the
673
724
  // request. See CURLOPT_POSTFIELDS in the libcurl docs.
@@ -686,7 +737,7 @@ static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
686
737
 
687
738
  /*
688
739
  * call-seq:
689
- * easy.post_body => "string" or nil
740
+ * easy.post_body => string or nil
690
741
  *
691
742
  * Obtain the POST body used in this Curl::Easy instance.
692
743
  */
@@ -706,6 +757,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
706
757
  ruby_curl_easy *rbce;
707
758
  CURL *curl;
708
759
  VALUE upload;
760
+ VALUE headers;
709
761
 
710
762
  Data_Get_Struct(self, ruby_curl_easy, rbce);
711
763
 
@@ -717,7 +769,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
717
769
  the easy handle is active or until the upload
718
770
  is complete or terminated... */
719
771
 
720
- curl_easy_setopt(curl, CURLOPT_NOBODY,0);
772
+ curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
721
773
  curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
722
774
  curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
723
775
  curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
@@ -732,23 +784,31 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
732
784
  }
733
785
  }
734
786
 
735
- VALUE headers = rb_easy_get("headers");
787
+ // exit fast if the payload is empty
788
+ if (NIL_P(data)) { return data; }
789
+
790
+ headers = rb_easy_get("headers");
736
791
  if( headers == Qnil ) {
737
792
  headers = rb_hash_new();
738
793
  }
794
+
739
795
  if (rb_respond_to(data, rb_intern("read"))) {
740
796
  VALUE stat = rb_funcall(data, rb_intern("stat"), 0);
741
- if( stat ) {
797
+ if( stat && rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil) {
742
798
  VALUE size;
743
799
  if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
744
800
  rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
745
801
  }
746
802
  size = rb_funcall(stat, rb_intern("size"), 0);
747
- curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2INT(size));
803
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2LONG(size));
748
804
  }
749
- else if( rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
805
+ else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil && rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
750
806
  rb_hash_aset(headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
751
807
  }
808
+ else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) ) {
809
+ VALUE size = rb_funcall(rb_hash_aref(headers, rb_str_new2("Content-Length")), rb_intern("to_i"), 0);
810
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2LONG(size));
811
+ }
752
812
  }
753
813
  else if (rb_respond_to(data, rb_intern("to_s"))) {
754
814
  curl_easy_setopt(curl, CURLOPT_INFILESIZE, RSTRING_LEN(data));
@@ -760,11 +820,29 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
760
820
  rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
761
821
  }
762
822
  rb_easy_set("headers",headers);
763
-
823
+
764
824
  // if we made it this far, all should be well.
765
825
  return data;
766
826
  }
767
827
 
828
+ /*
829
+ * call-seq:
830
+ * easy.ftp_commands = ["CWD /", "MKD directory"] => ["CWD /", ...]
831
+ *
832
+ * Explicitly sets the list of commands to execute on the FTP server when calling perform
833
+ */
834
+ static VALUE ruby_curl_easy_ftp_commands_set(VALUE self, VALUE ftp_commands) {
835
+ CURB_OBJECT_HSETTER(ruby_curl_easy, ftp_commands);
836
+ }
837
+
838
+ /*
839
+ * call-seq
840
+ * easy.ftp_commands => array or nil
841
+ */
842
+ static VALUE ruby_curl_easy_ftp_commands_get(VALUE self) {
843
+ CURB_OBJECT_HGETTER(ruby_curl_easy, ftp_commands);
844
+ }
845
+
768
846
  /* ================== IMMED ATTRS ==================*/
769
847
 
770
848
  /*
@@ -896,12 +974,15 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
896
974
  static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE self) {//VALUE self, VALUE http_auth_types) {
897
975
  ruby_curl_easy *rbce;
898
976
  VALUE args_ary;
899
- rb_scan_args(argc, argv, "*", &args_ary);
900
- Data_Get_Struct(self, ruby_curl_easy, rbce);
901
- int i, len = RARRAY_LEN(args_ary);
977
+ int i, len;
902
978
  char* node = NULL;
903
979
  long mask = 0x000000;
904
980
 
981
+ rb_scan_args(argc, argv, "*", &args_ary);
982
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
983
+
984
+ len = (int)RARRAY_LEN(args_ary);
985
+
905
986
  if (len == 1 && (TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM || rb_ary_entry(args_ary,0) == Qnil)) {
906
987
  if (rb_ary_entry(args_ary,0) == Qnil) {
907
988
  rbce->http_auth_types = 0;
@@ -1088,7 +1169,52 @@ static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self, VALUE ftp_respo
1088
1169
 
1089
1170
  /*
1090
1171
  * call-seq:
1091
- * easy.username = "foo" => String
1172
+ * easy.low_speed_limit = fixnum or nil => fixnum or nil
1173
+ *
1174
+ * Set the transfer speed (in bytes per second) that the transfer should be
1175
+ * below during +low_speed_time+ seconds for the library to consider it too
1176
+ * slow and abort.
1177
+ */
1178
+ static VALUE ruby_curl_easy_low_speed_limit_set(VALUE self, VALUE low_speed_limit) {
1179
+ CURB_IMMED_SETTER(ruby_curl_easy, low_speed_limit, 0);
1180
+ }
1181
+
1182
+ /*
1183
+ * call-seq:
1184
+ * easy.low_speed_limit => fixnum or nil
1185
+ *
1186
+ * Obtain the minimum transfer speed over +low_speed+time+ below which the
1187
+ * transfer will be aborted.
1188
+ */
1189
+ static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self, VALUE low_speed_limit) {
1190
+ CURB_IMMED_GETTER(ruby_curl_easy, low_speed_limit, 0);
1191
+ }
1192
+
1193
+ /*
1194
+ * call-seq:
1195
+ * easy.low_speed_time = fixnum or nil => fixnum or nil
1196
+ *
1197
+ * Set the time (in seconds) that the transfer should be below the
1198
+ * +low_speed_limit+ for the library to consider it too slow and abort.
1199
+ */
1200
+ static VALUE ruby_curl_easy_low_speed_time_set(VALUE self, VALUE low_speed_time) {
1201
+ CURB_IMMED_SETTER(ruby_curl_easy, low_speed_time, 0);
1202
+ }
1203
+
1204
+ /*
1205
+ * call-seq:
1206
+ * easy.low_speed_time => fixnum or nil
1207
+ *
1208
+ * Obtain the time that the transfer should be below +low_speed_limit+ for
1209
+ * the library to abort it.
1210
+ */
1211
+ static VALUE ruby_curl_easy_low_speed_time_get(VALUE self, VALUE low_speed_time) {
1212
+ CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
1213
+ }
1214
+
1215
+ /*
1216
+ * call-seq:
1217
+ * easy.username = string => string
1092
1218
  *
1093
1219
  * Set the HTTP Authentication username.
1094
1220
  */
@@ -1102,7 +1228,7 @@ static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
1102
1228
 
1103
1229
  /*
1104
1230
  * call-seq:
1105
- * easy.username => String
1231
+ * easy.username => string
1106
1232
  *
1107
1233
  * Get the current username
1108
1234
  */
@@ -1116,7 +1242,7 @@ static VALUE ruby_curl_easy_username_get(VALUE self, VALUE username) {
1116
1242
 
1117
1243
  /*
1118
1244
  * call-seq:
1119
- * easy.password = "foo" => String
1245
+ * easy.password = string => string
1120
1246
  *
1121
1247
  * Set the HTTP Authentication password.
1122
1248
  */
@@ -1130,7 +1256,7 @@ static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
1130
1256
 
1131
1257
  /*
1132
1258
  * call-seq:
1133
- * easy.password => String
1259
+ * easy.password => string
1134
1260
  *
1135
1261
  * Get the current password
1136
1262
  */
@@ -1142,11 +1268,75 @@ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
1142
1268
  #endif
1143
1269
  }
1144
1270
 
1271
+ /*
1272
+ * call-seq:
1273
+ * easy.ssl_version = value => fixnum or nil
1274
+ *
1275
+ * Sets the version of SSL/TLS that libcurl will attempt to use. Valid
1276
+ * options are Curl::CURL_SSLVERSION_TLSv1, Curl::CURL_SSLVERSION::SSLv2,
1277
+ * Curl::CURL_SSLVERSION_SSLv3 and Curl::CURL_SSLVERSION_DEFAULT
1278
+ */
1279
+ static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
1280
+ CURB_IMMED_SETTER(ruby_curl_easy, ssl_version, -1);
1281
+ }
1282
+
1283
+ /*
1284
+ * call-seq:
1285
+ * easy.ssl_version => fixnum
1286
+ *
1287
+ * Get the version of SSL/TLS that libcurl will attempt to use.
1288
+ */
1289
+ static VALUE ruby_curl_easy_ssl_version_get(VALUE self, VALUE ssl_version) {
1290
+ CURB_IMMED_GETTER(ruby_curl_easy, ssl_version, -1);
1291
+ }
1292
+
1293
+ /*
1294
+ * call-seq:
1295
+ * easy.use_ssl = value => fixnum or nil
1296
+ *
1297
+ * Ensure libcurl uses SSL for FTP connections. Valid options are Curl::CURL_USESSL_NONE,
1298
+ * Curl::CURL_USESSL_TRY, Curl::CURL_USESSL_CONTROL, and Curl::CURL_USESSL_ALL.
1299
+ */
1300
+ static VALUE ruby_curl_easy_use_ssl_set(VALUE self, VALUE use_ssl) {
1301
+ CURB_IMMED_SETTER(ruby_curl_easy, use_ssl, -1);
1302
+ }
1303
+
1304
+ /*
1305
+ * call-seq:
1306
+ * easy.use_ssl => fixnum
1307
+ *
1308
+ * Get the desired level for using SSL on FTP connections.
1309
+ */
1310
+ static VALUE ruby_curl_easy_use_ssl_get(VALUE self, VALUE use_ssl) {
1311
+ CURB_IMMED_GETTER(ruby_curl_easy, use_ssl, -1);
1312
+ }
1313
+
1314
+ /*
1315
+ * call-seq:
1316
+ * easy.ftp_filemethod = value => fixnum or nil
1317
+ *
1318
+ * Controls how libcurl reaches files on the server. Valid options are Curl::CURL_MULTICWD,
1319
+ * Curl::CURL_NOCWD, and Curl::CURL_SINGLECWD (see libcurl docs for CURLOPT_FTP_METHOD).
1320
+ */
1321
+ static VALUE ruby_curl_easy_ftp_filemethod_set(VALUE self, VALUE ftp_filemethod) {
1322
+ CURB_IMMED_SETTER(ruby_curl_easy, ftp_filemethod, -1);
1323
+ }
1324
+
1325
+ /*
1326
+ * call-seq
1327
+ * easy.ftp_filemethod => fixnum
1328
+ *
1329
+ * Get the configuration for how libcurl will reach files on the server.
1330
+ */
1331
+ static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self, VALUE ftp_filemethod) {
1332
+ CURB_IMMED_GETTER(ruby_curl_easy, ftp_filemethod, -1);
1333
+ }
1334
+
1145
1335
  /* ================== BOOL ATTRS ===================*/
1146
1336
 
1147
1337
  /*
1148
1338
  * call-seq:
1149
- * proxy_tunnel = boolean => boolean
1339
+ * easy.proxy_tunnel = boolean => boolean
1150
1340
  *
1151
1341
  * Configure whether this Curl instance will use proxy tunneling.
1152
1342
  */
@@ -1156,7 +1346,7 @@ static VALUE ruby_curl_easy_proxy_tunnel_set(VALUE self, VALUE proxy_tunnel) {
1156
1346
 
1157
1347
  /*
1158
1348
  * call-seq:
1159
- * proxy_tunnel? => boolean
1349
+ * easy.proxy_tunnel? => boolean
1160
1350
  *
1161
1351
  * Determine whether this Curl instance will use proxy tunneling.
1162
1352
  */
@@ -1166,7 +1356,7 @@ static VALUE ruby_curl_easy_proxy_tunnel_q(VALUE self) {
1166
1356
 
1167
1357
  /*
1168
1358
  * call-seq:
1169
- * fetch_file_time = boolean => boolean
1359
+ * easy.fetch_file_time = boolean => boolean
1170
1360
  *
1171
1361
  * Configure whether this Curl instance will fetch remote file
1172
1362
  * times, if available.
@@ -1177,7 +1367,7 @@ static VALUE ruby_curl_easy_fetch_file_time_set(VALUE self, VALUE fetch_file_tim
1177
1367
 
1178
1368
  /*
1179
1369
  * call-seq:
1180
- * fetch_file_time? => boolean
1370
+ * easy.fetch_file_time? => boolean
1181
1371
  *
1182
1372
  * Determine whether this Curl instance will fetch remote file
1183
1373
  * times, if available.
@@ -1188,7 +1378,7 @@ static VALUE ruby_curl_easy_fetch_file_time_q(VALUE self) {
1188
1378
 
1189
1379
  /*
1190
1380
  * call-seq:
1191
- * ssl_verify_peer = boolean => boolean
1381
+ * easy.ssl_verify_peer = boolean => boolean
1192
1382
  *
1193
1383
  * Configure whether this Curl instance will verify the SSL peer
1194
1384
  * certificate. When true (the default), and the verification fails to
@@ -1206,7 +1396,7 @@ static VALUE ruby_curl_easy_ssl_verify_peer_set(VALUE self, VALUE ssl_verify_pee
1206
1396
 
1207
1397
  /*
1208
1398
  * call-seq:
1209
- * ssl_verify_peer? => boolean
1399
+ * easy.ssl_verify_peer? => boolean
1210
1400
  *
1211
1401
  * Determine whether this Curl instance will verify the SSL peer
1212
1402
  * certificate.
@@ -1217,7 +1407,7 @@ static VALUE ruby_curl_easy_ssl_verify_peer_q(VALUE self) {
1217
1407
 
1218
1408
  /*
1219
1409
  * call-seq:
1220
- * ssl_verify_host = boolean => boolean
1410
+ * easy.ssl_verify_host = [0, 1, 2] => [0, 1, 2]
1221
1411
  *
1222
1412
  * Configure whether this Curl instance will verify that the server cert
1223
1413
  * is for the server it is known as. When true (the default) the server
@@ -1229,23 +1419,23 @@ static VALUE ruby_curl_easy_ssl_verify_peer_q(VALUE self) {
1229
1419
  * The server could be lying. To control lying, see ssl_verify_peer? .
1230
1420
  */
1231
1421
  static VALUE ruby_curl_easy_ssl_verify_host_set(VALUE self, VALUE ssl_verify_host) {
1232
- CURB_BOOLEAN_SETTER(ruby_curl_easy, ssl_verify_host);
1422
+ CURB_IMMED_SETTER(ruby_curl_easy, ssl_verify_host, 0);
1233
1423
  }
1234
1424
 
1235
1425
  /*
1236
1426
  * call-seq:
1237
- * ssl_verify_host? => boolean
1427
+ * easy.ssl_verify_host => number
1238
1428
  *
1239
1429
  * Determine whether this Curl instance will verify that the server cert
1240
1430
  * is for the server it is known as.
1241
1431
  */
1242
- static VALUE ruby_curl_easy_ssl_verify_host_q(VALUE self) {
1243
- CURB_BOOLEAN_GETTER(ruby_curl_easy, ssl_verify_host);
1432
+ static VALUE ruby_curl_easy_ssl_verify_host_get(VALUE self) {
1433
+ CURB_IMMED_GETTER(ruby_curl_easy, ssl_verify_host, 0);
1244
1434
  }
1245
1435
 
1246
1436
  /*
1247
1437
  * call-seq:
1248
- * header_in_body = boolean => boolean
1438
+ * easy.header_in_body = boolean => boolean
1249
1439
  *
1250
1440
  * Configure whether this Curl instance will return HTTP headers
1251
1441
  * combined with body data. If this option is set true, both header
@@ -1257,10 +1447,10 @@ static VALUE ruby_curl_easy_header_in_body_set(VALUE self, VALUE header_in_body)
1257
1447
 
1258
1448
  /*
1259
1449
  * call-seq:
1260
- * header_in_body? => boolean
1450
+ * easy.header_in_body? => boolean
1261
1451
  *
1262
- * Determine whether this Curl instance will verify the SSL peer
1263
- * certificate.
1452
+ * Determine whether this Curl instance will return HTTP headers
1453
+ * combined with body data.
1264
1454
  */
1265
1455
  static VALUE ruby_curl_easy_header_in_body_q(VALUE self) {
1266
1456
  CURB_BOOLEAN_GETTER(ruby_curl_easy, header_in_body);
@@ -1268,7 +1458,7 @@ static VALUE ruby_curl_easy_header_in_body_q(VALUE self) {
1268
1458
 
1269
1459
  /*
1270
1460
  * call-seq:
1271
- * use_netrc = boolean => boolean
1461
+ * easy.use_netrc = boolean => boolean
1272
1462
  *
1273
1463
  * Configure whether this Curl instance will use data from the user's
1274
1464
  * .netrc file for FTP connections.
@@ -1279,7 +1469,7 @@ static VALUE ruby_curl_easy_use_netrc_set(VALUE self, VALUE use_netrc) {
1279
1469
 
1280
1470
  /*
1281
1471
  * call-seq:
1282
- * use_netrc? => boolean
1472
+ * easy.use_netrc? => boolean
1283
1473
  *
1284
1474
  * Determine whether this Curl instance will use data from the user's
1285
1475
  * .netrc file for FTP connections.
@@ -1290,19 +1480,27 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
1290
1480
 
1291
1481
  /*
1292
1482
  * call-seq:
1293
- * follow_location = boolean => boolean
1294
1483
  *
1295
- * Configure whether this Curl instance will follow Location: headers
1296
- * in HTTP responses. Redirects will only be followed to the extent
1297
- * specified by +max_redirects+.
1484
+ * easy = Curl::Easy.new
1485
+ * easy.autoreferer=true
1298
1486
  */
1299
- static VALUE ruby_curl_easy_follow_location_set(VALUE self, VALUE follow_location) {
1300
- CURB_BOOLEAN_SETTER(ruby_curl_easy, follow_location);
1487
+ static VALUE ruby_curl_easy_autoreferer_set(VALUE self, VALUE autoreferer) {
1488
+ ruby_curl_easy *rbce;
1489
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1490
+
1491
+ if (Qtrue == autoreferer) {
1492
+ curl_easy_setopt(rbce->curl, CURLOPT_AUTOREFERER, 1);
1493
+ }
1494
+ else {
1495
+ curl_easy_setopt(rbce->curl, CURLOPT_AUTOREFERER, 0);
1496
+ }
1497
+
1498
+ return autoreferer;
1301
1499
  }
1302
1500
 
1303
1501
  /*
1304
1502
  * call-seq:
1305
- * follow_location? => boolean
1503
+ * easy.follow_location? => boolean
1306
1504
  *
1307
1505
  * Determine whether this Curl instance will follow Location: headers
1308
1506
  * in HTTP responses.
@@ -1313,7 +1511,7 @@ static VALUE ruby_curl_easy_follow_location_q(VALUE self) {
1313
1511
 
1314
1512
  /*
1315
1513
  * call-seq:
1316
- * unrestricted_auth = boolean => boolean
1514
+ * easy.unrestricted_auth = boolean => boolean
1317
1515
  *
1318
1516
  * Configure whether this Curl instance may use any HTTP authentication
1319
1517
  * method available when necessary.
@@ -1324,7 +1522,7 @@ static VALUE ruby_curl_easy_unrestricted_auth_set(VALUE self, VALUE unrestricted
1324
1522
 
1325
1523
  /*
1326
1524
  * call-seq:
1327
- * unrestricted_auth? => boolean
1525
+ * easy.unrestricted_auth? => boolean
1328
1526
  *
1329
1527
  * Determine whether this Curl instance may use any HTTP authentication
1330
1528
  * method available when necessary.
@@ -1398,7 +1596,7 @@ static VALUE ruby_curl_easy_enable_cookies_set(VALUE self, VALUE enable_cookies)
1398
1596
 
1399
1597
  /*
1400
1598
  * call-seq:
1401
- * easy.enable_cookies? => boolean
1599
+ * easy.enable_cookies? => boolean
1402
1600
  *
1403
1601
  * Determine whether the libcurl cookie engine is enabled for this
1404
1602
  * Curl::Easy instance.
@@ -1407,6 +1605,90 @@ static VALUE ruby_curl_easy_enable_cookies_q(VALUE self) {
1407
1605
  CURB_BOOLEAN_GETTER(ruby_curl_easy, enable_cookies);
1408
1606
  }
1409
1607
 
1608
+ /*
1609
+ * call-seq:
1610
+ * easy.ignore_content_length = boolean
1611
+ *
1612
+ * Configure whether this Curl::Easy instance should ignore the content
1613
+ * length header.
1614
+ */
1615
+ static VALUE ruby_curl_easy_ignore_content_length_set(VALUE self, VALUE ignore_content_length)
1616
+ {
1617
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, ignore_content_length);
1618
+ }
1619
+
1620
+ /*
1621
+ * call-seq:
1622
+ * easy.ignore_content_length? => boolean
1623
+ *
1624
+ * Determine whether this Curl::Easy instance ignores the content
1625
+ * length header.
1626
+ */
1627
+ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
1628
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, ignore_content_length);
1629
+ }
1630
+
1631
+ /*
1632
+ * call-seq:
1633
+ * easy.resolve_mode => symbol
1634
+ *
1635
+ * Determines what type of IP address this Curl::Easy instance
1636
+ * resolves DNS names to.
1637
+ */
1638
+ static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
1639
+ ruby_curl_easy *rbce;
1640
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1641
+
1642
+ unsigned short rm = rbce->resolve_mode;
1643
+
1644
+ switch(rm) {
1645
+ case CURL_IPRESOLVE_V4:
1646
+ return rb_easy_sym("ipv4");
1647
+ case CURL_IPRESOLVE_V6:
1648
+ return rb_easy_sym("ipv6");
1649
+ default:
1650
+ return rb_easy_sym("auto");
1651
+ }
1652
+ }
1653
+
1654
+ /*
1655
+ * call-seq:
1656
+ * easy.resolve_mode = symbol => symbol
1657
+ *
1658
+ * Configures what type of IP address this Curl::Easy instance
1659
+ * resolves DNS names to. Valid options are:
1660
+ *
1661
+ * [:auto] resolves DNS names to all IP versions your system allows
1662
+ * [:ipv4] resolves DNS names to IPv4 only
1663
+ * [:ipv6] resolves DNS names to IPv6 only
1664
+ */
1665
+ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
1666
+ if (TYPE(resolve_mode) != T_SYMBOL) {
1667
+ rb_raise(rb_eTypeError, "Must pass a symbol");
1668
+ return Qnil;
1669
+ } else {
1670
+ ruby_curl_easy *rbce;
1671
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1672
+
1673
+ ID resolve_mode_id = rb_to_id(resolve_mode);
1674
+
1675
+ if (resolve_mode_id == rb_intern("auto")) {
1676
+ rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
1677
+ return resolve_mode;
1678
+ } else if (resolve_mode_id == rb_intern("ipv4")) {
1679
+ rbce->resolve_mode = CURL_IPRESOLVE_V4;
1680
+ return resolve_mode;
1681
+ } else if (resolve_mode_id == rb_intern("ipv6")) {
1682
+ rbce->resolve_mode = CURL_IPRESOLVE_V6;
1683
+ return resolve_mode;
1684
+ } else {
1685
+ rb_raise(rb_eArgError, "Must set to one of :auto, :ipv4, :ipv6");
1686
+ return Qnil;
1687
+ }
1688
+ }
1689
+ }
1690
+
1691
+
1410
1692
  /* ================= EVENT PROCS ================== */
1411
1693
 
1412
1694
  /*
@@ -1430,7 +1712,7 @@ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
1430
1712
 
1431
1713
  /*
1432
1714
  * call-seq:
1433
- * easy.on_success { |easy| ... } => &lt;old handler&gt;
1715
+ * easy.on_success { |easy| ... } => &lt;old handler&gt;
1434
1716
  *
1435
1717
  * Assign or remove the +on_success+ handler for this Curl::Easy instance.
1436
1718
  * To remove a previously-supplied handler, call this method with no
@@ -1445,7 +1727,7 @@ static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
1445
1727
 
1446
1728
  /*
1447
1729
  * call-seq:
1448
- * easy.on_failure {|easy,code| ... } => &lt;old handler&gt;
1730
+ * easy.on_failure {|easy,code| ... } => &lt;old handler&gt;
1449
1731
  *
1450
1732
  * Assign or remove the +on_failure+ handler for this Curl::Easy instance.
1451
1733
  * To remove a previously-supplied handler, call this method with no
@@ -1460,7 +1742,37 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
1460
1742
 
1461
1743
  /*
1462
1744
  * call-seq:
1463
- * easy.on_complete {|easy| ... } => &lt;old handler&gt;
1745
+ * easy.on_missing {|easy,code| ... } => &lt;old handler;&gt;
1746
+ *
1747
+ * Assign or remove the on_missing handler for this Curl::Easy instance.
1748
+ * To remove a previously-supplied handler, call this method with no attached
1749
+ * block.
1750
+ *
1751
+ * The +on_missing+ handler is called when request is finished with a
1752
+ * status of 40x
1753
+ */
1754
+ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
1755
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, missing_proc);
1756
+ }
1757
+
1758
+ /*
1759
+ * call-seq:
1760
+ * easy.on_redirect {|easy,code| ... } => &lt;old handler;&gt;
1761
+ *
1762
+ * Assign or remove the on_redirect handler for this Curl::Easy instance.
1763
+ * To remove a previously-supplied handler, call this method with no attached
1764
+ * block.
1765
+ *
1766
+ * The +on_redirect+ handler is called when request is finished with a
1767
+ * status of 30x
1768
+ */
1769
+ static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
1770
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, redirect_proc);
1771
+ }
1772
+
1773
+ /*
1774
+ * call-seq:
1775
+ * easy.on_complete {|easy| ... } => &lt;old handler&gt;
1464
1776
  *
1465
1777
  * Assign or remove the +on_complete+ handler for this Curl::Easy instance.
1466
1778
  * To remove a previously-supplied handler, call this method with no
@@ -1536,7 +1848,10 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
1536
1848
  /***********************************************
1537
1849
  * This is an rb_iterate callback used to set up http headers.
1538
1850
  */
1539
- static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
1851
+ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
1852
+ struct curl_slist **list;
1853
+ Data_Get_Struct(wrap, struct curl_slist *, list);
1854
+
1540
1855
  VALUE header_str = Qnil;
1541
1856
 
1542
1857
  //rb_p(header);
@@ -1562,16 +1877,31 @@ static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
1562
1877
  return header_str;
1563
1878
  }
1564
1879
 
1880
+ /***********************************************
1881
+ * This is an rb_iterate callback used to set up ftp commands.
1882
+ */
1883
+ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
1884
+ struct curl_slist **list;
1885
+ Data_Get_Struct(wrap, struct curl_slist *, list);
1886
+
1887
+ VALUE ftp_command_string = rb_obj_as_string(ftp_command);
1888
+ *list = curl_slist_append(*list, StringValuePtr(ftp_command));
1889
+
1890
+ return ftp_command_string;
1891
+ }
1892
+
1565
1893
  /***********************************************
1566
1894
  *
1567
1895
  * Setup a connection
1568
1896
  *
1569
1897
  * Always returns Qtrue, rb_raise on error.
1570
1898
  */
1571
- VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1899
+ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
1572
1900
  // TODO this could do with a bit of refactoring...
1573
1901
  CURL *curl;
1574
1902
  VALUE url, _url = rb_easy_get("url");
1903
+ struct curl_slist **hdrs = &(rbce->curl_headers);
1904
+ struct curl_slist **cmds = &(rbce->curl_ftp_commands);
1575
1905
 
1576
1906
  curl = rbce->curl;
1577
1907
 
@@ -1581,7 +1911,6 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1581
1911
 
1582
1912
  url = rb_check_string_type(_url);
1583
1913
 
1584
- // Need to configure the handler as per settings in rbce
1585
1914
  curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
1586
1915
 
1587
1916
  // network stuff and auth
@@ -1615,22 +1944,22 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1615
1944
  curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
1616
1945
  }
1617
1946
 
1618
- if (!rb_easy_nil("proxy_url")) {
1619
- curl_easy_setopt(curl, CURLOPT_PROXY, rb_easy_get_str("proxy_url"));
1620
- } else {
1947
+ if (rb_easy_nil("proxy_url")) {
1621
1948
  curl_easy_setopt(curl, CURLOPT_PROXY, NULL);
1949
+ } else {
1950
+ curl_easy_setopt(curl, CURLOPT_PROXY, rb_easy_get_str("proxy_url"));
1622
1951
  }
1623
1952
 
1624
- if (!rb_easy_nil("proxypwd")) {
1625
- curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxy_pwd"));
1626
- } else {
1953
+ if (rb_easy_nil("proxypwd")) {
1627
1954
  curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
1955
+ } else {
1956
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxypwd"));
1628
1957
  }
1629
1958
 
1630
1959
  // body/header procs
1631
1960
  if (!rb_easy_nil("body_proc")) {
1632
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler);
1633
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, rb_easy_get("body_proc"));//rbce->body_proc);
1961
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
1962
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
1634
1963
  /* clear out the body_data if it was set */
1635
1964
  rb_easy_del("body_data");
1636
1965
  } else {
@@ -1640,8 +1969,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1640
1969
  }
1641
1970
 
1642
1971
  if (!rb_easy_nil("header_proc")) {
1643
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler);
1644
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, rb_easy_get("header_proc"));
1972
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler_header);
1973
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce);
1645
1974
  /* clear out the header_data if it was set */
1646
1975
  rb_easy_del("header_data");
1647
1976
  } else {
@@ -1678,19 +2007,18 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1678
2007
  /* general opts */
1679
2008
 
1680
2009
  curl_easy_setopt(curl, CURLOPT_HEADER, rbce->header_in_body);
1681
-
1682
2010
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, rbce->follow_location);
1683
2011
  curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
1684
2012
 
1685
2013
  curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, rbce->proxy_tunnel);
1686
2014
  curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
1687
2015
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
1688
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_peer);
2016
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_host);
1689
2017
 
1690
2018
  if ((rbce->use_netrc != Qnil) && (rbce->use_netrc != Qfalse)) {
1691
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_OPTIONAL);
2019
+ curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
1692
2020
  } else {
1693
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_IGNORED);
2021
+ curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
1694
2022
  }
1695
2023
 
1696
2024
  curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
@@ -1699,6 +2027,11 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1699
2027
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
1700
2028
  curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
1701
2029
 
2030
+ curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
2031
+
2032
+ curl_easy_setopt(curl, CURLOPT_IPRESOLVE, rbce->resolve_mode);
2033
+
2034
+
1702
2035
  #if LIBCURL_VERSION_NUM >= 0x070a08
1703
2036
  curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
1704
2037
  #else
@@ -1707,6 +2040,9 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1707
2040
  }
1708
2041
  #endif
1709
2042
 
2043
+ curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, rbce->low_speed_limit);
2044
+ curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, rbce->low_speed_time);
2045
+
1710
2046
  // Set up localport / proxy port
1711
2047
  // FIXME these won't get returned to default if they're unset Ruby
1712
2048
  if (rbce->proxy_port > 0) {
@@ -1780,20 +2116,45 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1780
2116
 
1781
2117
  /* Set up HTTPS cert handling if necessary */
1782
2118
  if (!rb_easy_nil("cert")) {
1783
- curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, rb_easy_get_str("certtype"));
2119
+ if (!rb_easy_nil("certtype")) {
2120
+ curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, rb_easy_get_str("certtype"));
2121
+ }
1784
2122
  curl_easy_setopt(curl, CURLOPT_SSLCERT, rb_easy_get_str("cert"));
1785
2123
  if (!rb_easy_nil("certpassword")) {
1786
2124
  curl_easy_setopt(curl, CURLOPT_SSLCERTPASSWD, rb_easy_get_str("certpassword"));
1787
2125
  }
2126
+ if (!rb_easy_nil("cert_key")) {
2127
+ curl_easy_setopt(curl, CURLOPT_SSLKEY, rb_easy_get_str("cert_key"));
2128
+ }
1788
2129
  }
2130
+
1789
2131
  if (!rb_easy_nil("cacert")) {
2132
+ curl_easy_setopt(curl, CURLOPT_CAINFO, rb_easy_get_str("cacert"));
2133
+ }
1790
2134
  #ifdef HAVE_CURL_CONFIG_CA
2135
+ else {
1791
2136
  curl_easy_setopt(curl, CURLOPT_CAINFO, CURL_CONFIG_CA);
1792
- #else
1793
- curl_easy_setopt(curl, CURLOPT_CAINFO, "/usr/local/share/curl/curl-ca-bundle.crt");
2137
+ }
1794
2138
  #endif
2139
+
2140
+ #ifdef CURL_VERSION_SSL
2141
+ if (rbce->ssl_version > 0) {
2142
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, rbce->ssl_version);
2143
+ }
2144
+
2145
+ if (rbce->use_ssl > 0) {
2146
+ curl_easy_setopt(curl, CURB_FTPSSL, rbce->use_ssl);
1795
2147
  }
2148
+ #else
2149
+ if (rbce->ssl_version > 0 || rbce->use_ssl > 0) {
2150
+ rb_warn("libcurl is not configured with SSL support");
2151
+ }
2152
+ #endif
1796
2153
 
2154
+ if (rbce->ftp_filemethod > 0) {
2155
+ curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, rbce->ftp_filemethod);
2156
+ }
2157
+
1797
2158
  /* Set the user-agent string if specified */
1798
2159
  if (!rb_easy_nil("useragent")) {
1799
2160
  curl_easy_setopt(curl, CURLOPT_USERAGENT, rb_easy_get_str("useragent"));
@@ -1804,7 +2165,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1804
2165
 
1805
2166
  if (!rb_easy_nil("headers")) {
1806
2167
  if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_HASH)) {
1807
- rb_iterate(rb_each, rb_easy_get("headers"), cb_each_http_header, (VALUE)hdrs);
2168
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, hdrs);
2169
+ rb_iterate(rb_each, rb_easy_get("headers"), cb_each_http_header, wrap);
1808
2170
  } else {
1809
2171
  VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
1810
2172
  *hdrs = curl_slist_append(*hdrs, StringValuePtr(headers_str));
@@ -1815,6 +2177,18 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1815
2177
  }
1816
2178
  }
1817
2179
 
2180
+ /* Setup FTP commands if necessary */
2181
+ if (!rb_easy_nil("ftp_commands")) {
2182
+ if (rb_easy_type_check("ftp_commands", T_ARRAY)) {
2183
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, cmds);
2184
+ rb_iterate(rb_each, rb_easy_get("ftp_commands"), cb_each_ftp_command, wrap);
2185
+ }
2186
+
2187
+ if (*cmds) {
2188
+ curl_easy_setopt(curl, CURLOPT_QUOTE, *cmds);
2189
+ }
2190
+ }
2191
+
1818
2192
  return Qnil;
1819
2193
  }
1820
2194
  /***********************************************
@@ -1823,17 +2197,24 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, struct curl_slist **hdrs ) {
1823
2197
  *
1824
2198
  * Always returns Qtrue.
1825
2199
  */
1826
- VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce, struct curl_slist *headers ) {
2200
+ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
1827
2201
 
1828
2202
  CURL *curl = rbce->curl;
1829
-
1830
- // Free everything up
1831
- if (headers) {
1832
- curl_slist_free_all(headers);
2203
+ struct curl_slist *ftp_commands;
2204
+
2205
+ /* Free everything up */
2206
+ if (rbce->curl_headers) {
2207
+ curl_slist_free_all(rbce->curl_headers);
1833
2208
  rbce->curl_headers = NULL;
1834
2209
  }
1835
2210
 
1836
- // clean up a PUT request's curl options.
2211
+ ftp_commands = rbce->curl_ftp_commands;
2212
+ if (ftp_commands) {
2213
+ curl_slist_free_all(ftp_commands);
2214
+ rbce->curl_ftp_commands = NULL;
2215
+ }
2216
+
2217
+ /* clean up a PUT request's curl options. */
1837
2218
  if (!rb_easy_nil("upload")) {
1838
2219
  rb_easy_del("upload"); // set the upload object to Qnil to let the GC clean up
1839
2220
  curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
@@ -1845,61 +2226,10 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce, struct curl_slis
1845
2226
  return Qnil;
1846
2227
  }
1847
2228
 
1848
- /***********************************************
1849
- *
1850
- * This is the main worker for the perform methods (get, post, head, put).
1851
- * It's not surfaced as a Ruby method - instead, the individual request
1852
- * methods are responsible for setting up stuff specific to that type,
1853
- * then calling this to handle common stuff and do the perform.
1854
- *
1855
- * Always returns Qtrue, rb_raise on error.
1856
- *
1857
- */
1858
- static VALUE handle_perform(VALUE self, ruby_curl_easy *rbce) {
1859
-
1860
- VALUE ret;
1861
- VALUE multi = ruby_curl_multi_new(cCurlMulti);
1862
-
1863
- rb_funcall(multi, rb_intern("add"), 1, self );
1864
- ret = rb_funcall(multi, rb_intern("perform"), 0);
1865
-
1866
- /* check for errors in the easy response and raise exceptions if anything went wrong and their is no on_failure handler */
1867
- if (rbce->last_result != 0 && rb_easy_nil("failure_proc")) {
1868
- raise_curl_easy_error_exception(rbce->last_result);
1869
- }
1870
-
1871
- return ret;
1872
- }
1873
-
1874
- /*
1875
- * call-seq:
1876
- * easy.http_get => true
1877
- *
1878
- * GET the currently configured URL using the current options set for
1879
- * this Curl::Easy instance. This method always returns true, or raises
1880
- * an exception (defined under Curl::Err) on error.
1881
- */
1882
- static VALUE ruby_curl_easy_perform_get(VALUE self) {
1883
- ruby_curl_easy *rbce;
1884
- CURL *curl;
1885
-
1886
- Data_Get_Struct(self, ruby_curl_easy, rbce);
1887
- curl = rbce->curl;
1888
-
1889
- curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
1890
-
1891
- return handle_perform(self,rbce);
1892
- }
1893
-
1894
2229
  /*
1895
- * call-seq:
1896
- * easy.http_delete
1897
- *
1898
- * DELETE the currently configured URL using the current options set for
1899
- * this Curl::Easy instance. This method always returns true, or raises
1900
- * an exception (defined under Curl::Err) on error.
2230
+ * Common implementation of easy.http(verb) and easy.http_delete
1901
2231
  */
1902
- static VALUE ruby_curl_easy_perform_delete(VALUE self) {
2232
+ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
1903
2233
  ruby_curl_easy *rbce;
1904
2234
  CURL *curl;
1905
2235
  VALUE retval;
@@ -1907,9 +2237,9 @@ static VALUE ruby_curl_easy_perform_delete(VALUE self) {
1907
2237
  Data_Get_Struct(self, ruby_curl_easy, rbce);
1908
2238
  curl = rbce->curl;
1909
2239
 
1910
- curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
2240
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
1911
2241
 
1912
- retval = handle_perform(self,rbce);
2242
+ retval = rb_funcall(self, rb_intern("perform"), 0);
1913
2243
 
1914
2244
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
1915
2245
 
@@ -1918,18 +2248,23 @@ static VALUE ruby_curl_easy_perform_delete(VALUE self) {
1918
2248
 
1919
2249
  /*
1920
2250
  * call-seq:
1921
- * easy.perform => true
2251
+ * easy.http(verb)
1922
2252
  *
1923
- * Transfer the currently configured URL using the options set for this
1924
- * Curl::Easy instance. If this is an HTTP URL, it will be transferred via
1925
- * the GET or HEAD request method.
2253
+ * Send an HTTP request with method set to verb, using the current options set for this Curl::Easy instance.
2254
+ * This method always returns true or raises an exception (defined under Curl::Err) on error.
1926
2255
  */
1927
- static VALUE ruby_curl_easy_perform(VALUE self) {
1928
- ruby_curl_easy *rbce;
1929
-
1930
- Data_Get_Struct(self, ruby_curl_easy, rbce);
1931
-
1932
- return handle_perform(self,rbce);
2256
+ static VALUE ruby_curl_easy_perform_verb(VALUE self, VALUE verb) {
2257
+ VALUE str_verb;
2258
+ if (rb_type(verb) == T_STRING) {
2259
+ return ruby_curl_easy_perform_verb_str(self, StringValueCStr(verb));
2260
+ }
2261
+ else if (rb_respond_to(verb,rb_intern("to_s"))) {
2262
+ str_verb = rb_funcall(verb, rb_intern("to_s"), 0);
2263
+ return ruby_curl_easy_perform_verb_str(self, StringValueCStr(str_verb));
2264
+ }
2265
+ else {
2266
+ rb_raise(rb_eRuntimeError, "Invalid HTTP VERB, must response to 'to_s'");
2267
+ }
1933
2268
  }
1934
2269
 
1935
2270
  /*
@@ -1967,6 +2302,8 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
1967
2302
  Data_Get_Struct(self, ruby_curl_easy, rbce);
1968
2303
  curl = rbce->curl;
1969
2304
 
2305
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2306
+
1970
2307
  if (rbce->multipart_form_post) {
1971
2308
  VALUE ret;
1972
2309
  struct curl_httppost *first = NULL, *last = NULL;
@@ -1975,6 +2312,17 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
1975
2312
  for (i = 0; i < argc; i++) {
1976
2313
  if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
1977
2314
  append_to_form(argv[i], &first, &last);
2315
+ } else if (rb_type(argv[i]) == T_ARRAY) {
2316
+ // see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
2317
+ int c = 0, argv_len = (int)RARRAY_LEN(argv[i]);
2318
+ for (; c < argv_len; ++c) {
2319
+ if (rb_obj_is_instance_of(rb_ary_entry(argv[i],c), cCurlPostField)) {
2320
+ append_to_form(rb_ary_entry(argv[i],c), &first, &last);
2321
+ } else {
2322
+ rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
2323
+ return Qnil;
2324
+ }
2325
+ }
1978
2326
  } else {
1979
2327
  rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
1980
2328
  return Qnil;
@@ -1983,12 +2331,13 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
1983
2331
 
1984
2332
  curl_easy_setopt(curl, CURLOPT_POST, 0);
1985
2333
  curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
1986
- ret = handle_perform(self,rbce);
2334
+ ret = rb_funcall(self, rb_intern("perform"), 0);
1987
2335
  curl_formfree(first);
1988
2336
 
1989
2337
  return ret;
1990
2338
  } else {
1991
2339
  VALUE post_body = Qnil;
2340
+ /* TODO: check for PostField.file and raise error before to_s fails */
1992
2341
  if ((post_body = rb_funcall(args_ary, idJoin, 1, rbstrAmp)) == Qnil) {
1993
2342
  rb_raise(eCurlErrError, "Failed to join arguments");
1994
2343
  return Qnil;
@@ -1999,78 +2348,14 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
1999
2348
  ruby_curl_easy_post_body_set(self, post_body);
2000
2349
  }
2001
2350
 
2002
- return handle_perform(self,rbce);
2003
- }
2004
- }
2005
- }
2006
-
2007
- /*
2008
- * call-seq:
2009
- * easy.http_head => true
2010
- *
2011
- * Request headers from the currently configured URL using the HEAD
2012
- * method and current options set for this Curl::Easy instance. This
2013
- * method always returns true, or raises an exception (defined under
2014
- * Curl::Err) on error.
2015
- *
2016
- */
2017
- static VALUE ruby_curl_easy_perform_head(VALUE self) {
2018
- ruby_curl_easy *rbce;
2019
- CURL *curl;
2020
- VALUE ret;
2021
-
2022
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2023
- curl = rbce->curl;
2024
-
2025
- curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
2026
-
2027
- ret = handle_perform(self,rbce);
2028
-
2029
- curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
2030
- return ret;
2031
- }
2032
-
2033
- /*
2034
- *call-seq:
2035
- * easy = Curl::Easy.new("url") do|c|
2036
- * c.head = true
2037
- * end
2038
- * easy.perform
2039
- */
2040
- static VALUE ruby_curl_easy_set_head_option(VALUE self, VALUE onoff) {
2041
- ruby_curl_easy *rbce;
2042
-
2043
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2044
-
2045
- if( onoff == Qtrue ) {
2046
- curl_easy_setopt(rbce->curl, CURLOPT_NOBODY, 1);
2047
- }
2048
- else {
2049
- curl_easy_setopt(rbce->curl, CURLOPT_NOBODY, 0);
2050
- }
2051
-
2052
- return onoff;
2053
- }
2054
- /*
2055
- *call-seq:
2056
- * easy = Curl::Easy.new("url") do|c|
2057
- * c.delete = true
2058
- * end
2059
- * easy.perform
2060
- */
2061
- static VALUE ruby_curl_easy_set_delete_option(VALUE self, VALUE onoff) {
2062
- ruby_curl_easy *rbce;
2063
-
2064
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2351
+ /* if post body is not defined, set it so we enable POST header, even though the request body is empty */
2352
+ if( rb_easy_nil("postdata_buffer") ) {
2353
+ ruby_curl_easy_post_body_set(self, post_body);
2354
+ }
2065
2355
 
2066
- if( onoff == Qtrue ) {
2067
- curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, "DELETE");
2068
- }
2069
- else {
2070
- curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, NULL);
2356
+ return rb_funcall(self, rb_intern("perform"), 0);
2357
+ }
2071
2358
  }
2072
-
2073
- return onoff;
2074
2359
  }
2075
2360
 
2076
2361
  /*
@@ -2084,27 +2369,17 @@ static VALUE ruby_curl_easy_set_delete_option(VALUE self, VALUE onoff) {
2084
2369
  static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
2085
2370
  ruby_curl_easy *rbce;
2086
2371
  CURL *curl;
2087
-
2372
+
2088
2373
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2089
2374
  curl = rbce->curl;
2090
-
2375
+
2376
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2091
2377
  ruby_curl_easy_put_data_set(self, data);
2092
-
2093
- return handle_perform(self, rbce);
2094
- }
2095
2378
 
2096
- /*
2097
- * call-seq:
2098
- * Curl::Easy.http_put(url, data) {|c| ... }
2099
- *
2100
- * see easy.http_put
2101
- */
2102
- static VALUE ruby_curl_easy_class_perform_put(VALUE klass, VALUE url, VALUE data) {
2103
- VALUE c = ruby_curl_easy_new(1, &url, klass);
2104
- ruby_curl_easy_perform_put(c, data);
2105
- return c;
2379
+ return rb_funcall(self, rb_intern("perform"), 0);
2106
2380
  }
2107
2381
 
2382
+
2108
2383
  /* =================== DATA FUNCS =============== */
2109
2384
 
2110
2385
  /*
@@ -2180,6 +2455,30 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
2180
2455
  return LONG2NUM(code);
2181
2456
  }
2182
2457
 
2458
+ #if defined(HAVE_CURLINFO_PRIMARY_IP)
2459
+ /*
2460
+ * call-seq:
2461
+ * easy.primary_ip => "xx.xx.xx.xx" or nil
2462
+ *
2463
+ * Retrieve the resolved IP of the most recent connection
2464
+ * done with this curl handle. This string may be IPv6 if
2465
+ * that's enabled. This feature requires curl 7.19.x and above
2466
+ */
2467
+ static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
2468
+ ruby_curl_easy *rbce;
2469
+ char* ip;
2470
+
2471
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2472
+ curl_easy_getinfo(rbce->curl, CURLINFO_PRIMARY_IP, &ip);
2473
+
2474
+ if (ip && ip[0]) { // curl returns empty string if none
2475
+ return rb_str_new2(ip);
2476
+ } else {
2477
+ return Qnil;
2478
+ }
2479
+ }
2480
+ #endif
2481
+
2183
2482
  /*
2184
2483
  * call-seq:
2185
2484
  * easy.http_connect_code => fixnum
@@ -2344,7 +2643,7 @@ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
2344
2643
 
2345
2644
  /*
2346
2645
  * call-seq:
2347
- * easy.redirect_count => integer
2646
+ * easy.redirect_count => integer
2348
2647
  *
2349
2648
  * Retrieve the total number of redirections that were actually followed.
2350
2649
  *
@@ -2366,6 +2665,36 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
2366
2665
 
2367
2666
  }
2368
2667
 
2668
+ /*
2669
+ * call-seq:
2670
+ * easy.redirect_url => "http://some.url" or nil
2671
+ *
2672
+ * Retrieve the URL a redirect would take you to if you
2673
+ * would enable CURLOPT_FOLLOWLOCATION.
2674
+ *
2675
+ * Requires libcurl 7.18.2 or higher, otherwise -1 is always returned.
2676
+ */
2677
+ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
2678
+ #ifdef HAVE_CURLINFO_REDIRECT_URL
2679
+ ruby_curl_easy *rbce;
2680
+ char* url;
2681
+
2682
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2683
+ curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_URL, &url);
2684
+
2685
+ if (url && url[0]) { // curl returns empty string if none
2686
+ return rb_str_new2(url);
2687
+ } else {
2688
+ return Qnil;
2689
+ }
2690
+ #else
2691
+ rb_warn("Installed libcurl is too old to support redirect_url");
2692
+ return INT2FIX(-1);
2693
+ #endif
2694
+ }
2695
+
2696
+
2697
+
2369
2698
  /*
2370
2699
  * call-seq:
2371
2700
  * easy.uploaded_bytes => float
@@ -2488,7 +2817,10 @@ static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
2488
2817
 
2489
2818
  /* TODO CURLINFO_SSL_ENGINES
2490
2819
 
2491
- Pass the address of a 'struct curl_slist *' to receive a linked-list of OpenSSL crypto-engines supported. Note that engines are normally implemented in separate dynamic libraries. Hence not all the returned engines may be available at run-time. NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done with it, as libcurl will not free the data for you. (Added in 7.12.3)
2820
+ Pass the address of a 'struct curl_slist *' to receive a linked-list of OpenSSL crypto-engines supported.
2821
+ Note that engines are normally implemented in separate dynamic libraries.
2822
+ Hence not all the returned engines may be available at run-time.
2823
+ NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done with it, as libcurl will not free the data for you. (Added in 7.12.3)
2492
2824
  */
2493
2825
 
2494
2826
  /*
@@ -2592,7 +2924,7 @@ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
2592
2924
 
2593
2925
  /*
2594
2926
  * call-seq:
2595
- * easy.num_connects => integer
2927
+ * easy.num_connects => integer
2596
2928
  *
2597
2929
  * Retrieve the number of new connections libcurl had to create to achieve
2598
2930
  * the previous transfer (only the successful connects are counted).
@@ -2637,7 +2969,7 @@ Pass a pointer to a long to receive the last socket used by this curl session. I
2637
2969
 
2638
2970
  /*
2639
2971
  * call-seq:
2640
- * easy.content_type => "content/type" or nil
2972
+ * easy.ftp_entry_path => "C:\ftp\root\" or nil
2641
2973
  *
2642
2974
  * Retrieve the path of the entry path. That is the initial path libcurl ended
2643
2975
  * up in when logging on to the remote FTP server. This returns +nil+ if
@@ -2666,7 +2998,140 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
2666
2998
 
2667
2999
  /*
2668
3000
  * call-seq:
2669
- * easy.inspect => "#<Curl::Easy http://google.com/>"
3001
+ * easy.multi => "#<Curl::Multi>"
3002
+ */
3003
+ static VALUE ruby_curl_easy_multi_get(VALUE self) {
3004
+ ruby_curl_easy *rbce;
3005
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3006
+ return rbce->multi;
3007
+ }
3008
+
3009
+ /*
3010
+ * call-seq:
3011
+ * easy.multi=multi => "#<Curl::Multi>"
3012
+ */
3013
+ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
3014
+ ruby_curl_easy *rbce;
3015
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3016
+ rbce->multi = multi;
3017
+ return rbce->multi;
3018
+ }
3019
+
3020
+ /*
3021
+ * call-seq:
3022
+ * easy.last_result => 0
3023
+ */
3024
+ static VALUE ruby_curl_easy_last_result(VALUE self) {
3025
+ ruby_curl_easy *rbce;
3026
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3027
+ return INT2FIX(rbce->last_result);
3028
+ }
3029
+
3030
+ /*
3031
+ * call-seq:
3032
+ * easy.setopt Fixnum, value => value
3033
+ *
3034
+ * Iniital access to libcurl curl_easy_setopt
3035
+ */
3036
+ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3037
+ ruby_curl_easy *rbce;
3038
+ long option = FIX2LONG(opt);
3039
+
3040
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3041
+
3042
+ switch (option) {
3043
+ /* BEHAVIOR OPTIONS */
3044
+ case CURLOPT_VERBOSE: {
3045
+ VALUE verbose = val;
3046
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, verbose);
3047
+ } break;
3048
+ case CURLOPT_FOLLOWLOCATION: {
3049
+ VALUE follow_location = val;
3050
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, follow_location);
3051
+ } break;
3052
+ /* TODO: CALLBACK OPTIONS */
3053
+ /* TODO: ERROR OPTIONS */
3054
+ /* NETWORK OPTIONS */
3055
+ case CURLOPT_URL: {
3056
+ VALUE url = val;
3057
+ CURB_OBJECT_HSETTER(ruby_curl_easy, url);
3058
+ } break;
3059
+ case CURLOPT_CUSTOMREQUEST:
3060
+ curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, NIL_P(val) ? NULL : StringValueCStr(val));
3061
+ break;
3062
+ case CURLOPT_HTTP_VERSION:
3063
+ curl_easy_setopt(rbce->curl, CURLOPT_HTTP_VERSION, FIX2INT(val));
3064
+ break;
3065
+ case CURLOPT_PROXY: {
3066
+ VALUE proxy_url = val;
3067
+ CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_url);
3068
+ } break;
3069
+ case CURLOPT_INTERFACE: {
3070
+ VALUE interface_hm = val;
3071
+ CURB_OBJECT_HSETTER(ruby_curl_easy, interface_hm);
3072
+ } break;
3073
+ case CURLOPT_HEADER:
3074
+ case CURLOPT_NOPROGRESS:
3075
+ case CURLOPT_NOSIGNAL:
3076
+ case CURLOPT_HTTPGET:
3077
+ case CURLOPT_NOBODY: {
3078
+ int type = rb_type(val);
3079
+ VALUE value;
3080
+ if (type == T_TRUE) {
3081
+ value = rb_int_new(1);
3082
+ } else if (type == T_FALSE) {
3083
+ value = rb_int_new(0);
3084
+ } else {
3085
+ value = rb_funcall(val, rb_intern("to_i"), 0);
3086
+ }
3087
+ curl_easy_setopt(rbce->curl, option, FIX2INT(value));
3088
+ } break;
3089
+ case CURLOPT_USERPWD: {
3090
+ VALUE userpwd = val;
3091
+ CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
3092
+ } break;
3093
+ case CURLOPT_PROXYUSERPWD: {
3094
+ VALUE proxypwd = val;
3095
+ CURB_OBJECT_HSETTER(ruby_curl_easy, proxypwd);
3096
+ } break;
3097
+ case CURLOPT_COOKIE: {
3098
+ VALUE cookies = val;
3099
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookies);
3100
+ } break;
3101
+ case CURLOPT_COOKIEFILE: {
3102
+ VALUE cookiefile = val;
3103
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookiefile);
3104
+ } break;
3105
+ case CURLOPT_COOKIEJAR: {
3106
+ VALUE cookiejar = val;
3107
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
3108
+ } break;
3109
+ case CURLOPT_RESUME_FROM: {
3110
+ curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, FIX2LONG(val));
3111
+ } break;
3112
+ case CURLOPT_FAILONERROR: {
3113
+ curl_easy_setopt(rbce->curl, CURLOPT_FAILONERROR, FIX2LONG(val));
3114
+ } break;
3115
+ default:
3116
+ break;
3117
+ }
3118
+
3119
+ return val;
3120
+ }
3121
+
3122
+ /*
3123
+ * call-seq:
3124
+ * easy.getinfo Fixnum => value
3125
+ *
3126
+ * Iniital access to libcurl curl_easy_getinfo, remember getinfo doesn't return the same values as setopt
3127
+ */
3128
+ static VALUE ruby_curl_easy_get_opt(VALUE self, VALUE opt) {
3129
+ return Qnil;
3130
+ }
3131
+
3132
+ /*
3133
+ * call-seq:
3134
+ * easy.inspect => "#<Curl::Easy http://google.com/>"
2670
3135
  */
2671
3136
  static VALUE ruby_curl_easy_inspect(VALUE self) {
2672
3137
  char buf[64];
@@ -2678,11 +3143,11 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
2678
3143
  size_t len = 13+((RSTRING_LEN(url) > 50) ? 50 : RSTRING_LEN(url));
2679
3144
  /* "#<Net::HTTP http://www.google.com/:80 open=false>" */
2680
3145
  memcpy(buf,"#<Curl::Easy ", 13);
2681
- memcpy(buf+13,RSTRING_PTR(url), (len - 13));
2682
- buf[len-1] = '>';
3146
+ memcpy(buf+13,StringValueCStr(url), (len - 13));
3147
+ buf[len++] = '>';
2683
3148
  return rb_str_new(buf,len);
2684
3149
  }
2685
- return rb_str_new2("#<Curl::Easy");
3150
+ return rb_str_new2("#<Curl::Easy>");
2686
3151
  }
2687
3152
 
2688
3153
 
@@ -2709,9 +3174,9 @@ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
2709
3174
  if( rb_type(str) != T_STRING ) { str = rb_funcall(str,rb_intern("to_s"),0); }
2710
3175
 
2711
3176
  #if (LIBCURL_VERSION_NUM >= 0x070f04)
2712
- result = (char*)curl_easy_escape(rbce->curl, StringValuePtr(str), RSTRING_LEN(str));
3177
+ result = (char*)curl_easy_escape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str));
2713
3178
  #else
2714
- result = (char*)curl_escape(StringValuePtr(str), RSTRING_LEN(str));
3179
+ result = (char*)curl_escape(StringValuePtr(str), (int)RSTRING_LEN(str));
2715
3180
  #endif
2716
3181
 
2717
3182
  rresult = rb_str_new2(result);
@@ -2722,7 +3187,7 @@ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
2722
3187
 
2723
3188
  /*
2724
3189
  * call-seq:
2725
- * easy.unescape("some%20text") => "some text"
3190
+ * easy.unescape("some%20text") => "some text"
2726
3191
  *
2727
3192
  * Convert the given URL encoded input string to a "plain string" and return
2728
3193
  * the result. All input characters that are URL encoded (%XX where XX is a
@@ -2737,7 +3202,7 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
2737
3202
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2738
3203
 
2739
3204
  #if (LIBCURL_VERSION_NUM >= 0x070f04)
2740
- result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), RSTRING_LEN(str), &rlen);
3205
+ result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
2741
3206
  #else
2742
3207
  result = (char*)curl_unescape(StringValuePtr(str), RSTRING_LEN(str));
2743
3208
  rlen = strlen(result);
@@ -2754,114 +3219,14 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
2754
3219
 
2755
3220
  /*
2756
3221
  * call-seq:
2757
- * Curl::Easy.perform(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
2758
- *
2759
- * Convenience method that creates a new Curl::Easy instance with
2760
- * the specified URL and calls the general +perform+ method, before returning
2761
- * the new instance. For HTTP URLs, this is equivalent to calling +http_get+.
2762
- *
2763
- * If a block is supplied, the new instance will be yielded just prior to
2764
- * the +http_get+ call.
2765
- */
2766
- static VALUE ruby_curl_easy_class_perform(int argc, VALUE *argv, VALUE klass) {
2767
- VALUE c = ruby_curl_easy_new(argc, argv, klass);
2768
-
2769
- if (rb_block_given_p()) {
2770
- rb_yield(c);
2771
- }
2772
-
2773
- ruby_curl_easy_perform(c);
2774
- return c;
2775
- }
2776
-
2777
- /*
2778
- * call-seq:
2779
- * Curl::Easy.http_get(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
2780
- *
2781
- * Convenience method that creates a new Curl::Easy instance with
2782
- * the specified URL and calls +http_get+, before returning the new instance.
2783
- *
2784
- * If a block is supplied, the new instance will be yielded just prior to
2785
- * the +http_get+ call.
2786
- */
2787
- static VALUE ruby_curl_easy_class_perform_get(int argc, VALUE *argv, VALUE klass) {
2788
- VALUE c = ruby_curl_easy_new(argc, argv, klass);
2789
-
2790
- ruby_curl_easy_perform_get(c);
2791
- return c;
2792
- }
2793
-
2794
- /*
2795
- * call-seq:
2796
- * Curl::Easy.http_delete(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
2797
- *
2798
- * Convenience method that creates a new Curl::Easy instance with
2799
- * the specified URL and calls +http_delete+, before returning the new instance.
2800
- *
2801
- * If a block is supplied, the new instance will be yielded just prior to
2802
- * the +http_delete+ call.
2803
- */
2804
- static VALUE ruby_curl_easy_class_perform_delete(int argc, VALUE *argv, VALUE klass) {
2805
- VALUE c = ruby_curl_easy_new(argc, argv, klass);
2806
-
2807
- ruby_curl_easy_perform_delete(c);
2808
- return c;
2809
- }
2810
-
2811
- /*
2812
- * call-seq:
2813
- * Curl::Easy.http_head(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
2814
- *
2815
- * Convenience method that creates a new Curl::Easy instance with
2816
- * the specified URL and calls +http_head+, before returning the new instance.
2817
- *
2818
- * If a block is supplied, the new instance will be yielded just prior to
2819
- * the +http_head+ call.
2820
- */
2821
- static VALUE ruby_curl_easy_class_perform_head(int argc, VALUE *argv, VALUE klass) {
2822
- VALUE c = ruby_curl_easy_new(argc, argv, klass);
2823
-
2824
- ruby_curl_easy_perform_head(c);
2825
-
2826
- return c;
2827
- }
2828
-
2829
- // TODO: add convenience method for http_post
2830
-
2831
- /*
2832
- * call-seq:
2833
- * Curl::Easy.http_post(url, "some=urlencoded%20form%20data&and=so%20on") => true
2834
- * Curl::Easy.http_post(url, "some=urlencoded%20form%20data", "and=so%20on", ...) => true
2835
- * Curl::Easy.http_post(url, "some=urlencoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
2836
- * Curl::Easy.http_post(url, Curl::PostField, Curl::PostField ..., Curl::PostField) => true
2837
- *
2838
- * POST the specified formdata to the currently configured URL using
2839
- * the current options set for this Curl::Easy instance. This method
2840
- * always returns true, or raises an exception (defined under
2841
- * Curl::Err) on error.
3222
+ * Curl::Easy.error(code) => String
2842
3223
  *
2843
- * If you wish to use multipart form encoding, you'll need to supply a block
2844
- * in order to set multipart_form_post true. See #http_post for more
2845
- * information.
3224
+ * translate an internal libcurl error to ruby error class
2846
3225
  */
2847
- static VALUE ruby_curl_easy_class_perform_post(int argc, VALUE *argv, VALUE klass) {
2848
- VALUE url, fields;
2849
- VALUE c;
2850
-
2851
- rb_scan_args(argc, argv, "1*", &url, &fields);
2852
-
2853
- c = ruby_curl_easy_new(1, &url, klass);
2854
-
2855
- if (argc > 1) {
2856
- ruby_curl_easy_perform_post(argc - 1, &argv[1], c);
2857
- } else {
2858
- ruby_curl_easy_perform_post(0, NULL, c);
2859
- }
2860
-
2861
- return c;
3226
+ static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
3227
+ return rb_curl_easy_error(FIX2INT(code));
2862
3228
  }
2863
3229
 
2864
-
2865
3230
  /* =================== INIT LIB =====================*/
2866
3231
  void init_curb_easy() {
2867
3232
  idCall = rb_intern("call");
@@ -2874,34 +3239,23 @@ void init_curb_easy() {
2874
3239
 
2875
3240
  /* Class methods */
2876
3241
  rb_define_singleton_method(cCurlEasy, "new", ruby_curl_easy_new, -1);
2877
- rb_define_singleton_method(cCurlEasy, "perform", ruby_curl_easy_class_perform, -1);
2878
- rb_define_singleton_method(cCurlEasy, "http_delete", ruby_curl_easy_class_perform_delete, -1);
2879
- rb_define_singleton_method(cCurlEasy, "http_get", ruby_curl_easy_class_perform_get, -1);
2880
- rb_define_singleton_method(cCurlEasy, "http_post", ruby_curl_easy_class_perform_post, -1);
2881
- rb_define_singleton_method(cCurlEasy, "http_head", ruby_curl_easy_class_perform_head, -1);
2882
- rb_define_singleton_method(cCurlEasy, "http_put", ruby_curl_easy_class_perform_put, 2);
3242
+ rb_define_singleton_method(cCurlEasy, "error", ruby_curl_easy_error_message, 1);
2883
3243
 
2884
3244
  /* Attributes for config next perform */
2885
- rb_define_method(cCurlEasy, "url=", ruby_curl_easy_url_set, 1);
2886
3245
  rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
2887
- rb_define_method(cCurlEasy, "proxy_url=", ruby_curl_easy_proxy_url_set, 1);
2888
3246
  rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
2889
3247
  rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
2890
3248
  rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
2891
- rb_define_method(cCurlEasy, "interface=", ruby_curl_easy_interface_set, 1);
2892
3249
  rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
2893
- rb_define_method(cCurlEasy, "userpwd=", ruby_curl_easy_userpwd_set, 1);
2894
3250
  rb_define_method(cCurlEasy, "userpwd", ruby_curl_easy_userpwd_get, 0);
2895
- rb_define_method(cCurlEasy, "proxypwd=", ruby_curl_easy_proxypwd_set, 1);
2896
3251
  rb_define_method(cCurlEasy, "proxypwd", ruby_curl_easy_proxypwd_get, 0);
2897
- rb_define_method(cCurlEasy, "cookies=", ruby_curl_easy_cookies_set, 1);
2898
3252
  rb_define_method(cCurlEasy, "cookies", ruby_curl_easy_cookies_get, 0);
2899
- rb_define_method(cCurlEasy, "cookiefile=", ruby_curl_easy_cookiefile_set, 1);
2900
3253
  rb_define_method(cCurlEasy, "cookiefile", ruby_curl_easy_cookiefile_get, 0);
2901
- rb_define_method(cCurlEasy, "cookiejar=", ruby_curl_easy_cookiejar_set, 1);
2902
3254
  rb_define_method(cCurlEasy, "cookiejar", ruby_curl_easy_cookiejar_get, 0);
2903
3255
  rb_define_method(cCurlEasy, "cert=", ruby_curl_easy_cert_set, 1);
2904
3256
  rb_define_method(cCurlEasy, "cert", ruby_curl_easy_cert_get, 0);
3257
+ rb_define_method(cCurlEasy, "cert_key=", ruby_curl_easy_cert_key_set, 1);
3258
+ rb_define_method(cCurlEasy, "cert_key", ruby_curl_easy_cert_key_get, 0);
2905
3259
  rb_define_method(cCurlEasy, "cacert=", ruby_curl_easy_cacert_set, 1);
2906
3260
  rb_define_method(cCurlEasy, "cacert", ruby_curl_easy_cacert_get, 0);
2907
3261
  rb_define_method(cCurlEasy, "certpassword=", ruby_curl_easy_certpassword_set, 1);
@@ -2914,6 +3268,8 @@ void init_curb_easy() {
2914
3268
  rb_define_method(cCurlEasy, "post_body=", ruby_curl_easy_post_body_set, 1);
2915
3269
  rb_define_method(cCurlEasy, "post_body", ruby_curl_easy_post_body_get, 0);
2916
3270
  rb_define_method(cCurlEasy, "put_data=", ruby_curl_easy_put_data_set, 1);
3271
+ rb_define_method(cCurlEasy, "ftp_commands=", ruby_curl_easy_ftp_commands_set, 1);
3272
+ rb_define_method(cCurlEasy, "ftp_commands", ruby_curl_easy_ftp_commands_get, 0);
2917
3273
 
2918
3274
  rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
2919
3275
  rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
@@ -2937,6 +3293,16 @@ void init_curb_easy() {
2937
3293
  rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
2938
3294
  rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
2939
3295
  rb_define_method(cCurlEasy, "ftp_response_timeout", ruby_curl_easy_ftp_response_timeout_get, 0);
3296
+ rb_define_method(cCurlEasy, "low_speed_limit=", ruby_curl_easy_low_speed_limit_set, 1);
3297
+ rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
3298
+ rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
3299
+ rb_define_method(cCurlEasy, "low_speed_time", ruby_curl_easy_low_speed_time_get, 0);
3300
+ rb_define_method(cCurlEasy, "ssl_version=", ruby_curl_easy_ssl_version_set, 1);
3301
+ rb_define_method(cCurlEasy, "ssl_version", ruby_curl_easy_ssl_version_get, 0);
3302
+ rb_define_method(cCurlEasy, "use_ssl=", ruby_curl_easy_use_ssl_set, 1);
3303
+ rb_define_method(cCurlEasy, "use_ssl", ruby_curl_easy_use_ssl_get, 0);
3304
+ rb_define_method(cCurlEasy, "ftp_filemethod=", ruby_curl_easy_ftp_filemethod_set, 1);
3305
+ rb_define_method(cCurlEasy, "ftp_filemethod", ruby_curl_easy_ftp_filemethod_get, 0);
2940
3306
 
2941
3307
  rb_define_method(cCurlEasy, "username=", ruby_curl_easy_username_set, 1);
2942
3308
  rb_define_method(cCurlEasy, "username", ruby_curl_easy_username_get, 0);
@@ -2949,14 +3315,14 @@ void init_curb_easy() {
2949
3315
  rb_define_method(cCurlEasy, "fetch_file_time?", ruby_curl_easy_fetch_file_time_q, 0);
2950
3316
  rb_define_method(cCurlEasy, "ssl_verify_peer=", ruby_curl_easy_ssl_verify_peer_set, 1);
2951
3317
  rb_define_method(cCurlEasy, "ssl_verify_peer?", ruby_curl_easy_ssl_verify_peer_q, 0);
2952
- rb_define_method(cCurlEasy, "ssl_verify_host=", ruby_curl_easy_ssl_verify_host_set, 1);
2953
- rb_define_method(cCurlEasy, "ssl_verify_host?", ruby_curl_easy_ssl_verify_host_q, 0);
3318
+ rb_define_method(cCurlEasy, "ssl_verify_host_integer=", ruby_curl_easy_ssl_verify_host_set, 1);
3319
+ rb_define_method(cCurlEasy, "ssl_verify_host", ruby_curl_easy_ssl_verify_host_get, 0);
2954
3320
  rb_define_method(cCurlEasy, "header_in_body=", ruby_curl_easy_header_in_body_set, 1);
2955
3321
  rb_define_method(cCurlEasy, "header_in_body?", ruby_curl_easy_header_in_body_q, 0);
2956
3322
  rb_define_method(cCurlEasy, "use_netrc=", ruby_curl_easy_use_netrc_set, 1);
2957
3323
  rb_define_method(cCurlEasy, "use_netrc?", ruby_curl_easy_use_netrc_q, 0);
2958
- rb_define_method(cCurlEasy, "follow_location=", ruby_curl_easy_follow_location_set, 1);
2959
3324
  rb_define_method(cCurlEasy, "follow_location?", ruby_curl_easy_follow_location_q, 0);
3325
+ rb_define_method(cCurlEasy, "autoreferer=", ruby_curl_easy_autoreferer_set, 1);
2960
3326
  rb_define_method(cCurlEasy, "unrestricted_auth=", ruby_curl_easy_unrestricted_auth_set, 1);
2961
3327
  rb_define_method(cCurlEasy, "unrestricted_auth?", ruby_curl_easy_unrestricted_auth_q, 0);
2962
3328
  rb_define_method(cCurlEasy, "verbose=", ruby_curl_easy_verbose_set, 1);
@@ -2965,6 +3331,10 @@ void init_curb_easy() {
2965
3331
  rb_define_method(cCurlEasy, "multipart_form_post?", ruby_curl_easy_multipart_form_post_q, 0);
2966
3332
  rb_define_method(cCurlEasy, "enable_cookies=", ruby_curl_easy_enable_cookies_set, 1);
2967
3333
  rb_define_method(cCurlEasy, "enable_cookies?", ruby_curl_easy_enable_cookies_q, 0);
3334
+ rb_define_method(cCurlEasy, "ignore_content_length=", ruby_curl_easy_ignore_content_length_set, 1);
3335
+ rb_define_method(cCurlEasy, "ignore_content_length?", ruby_curl_easy_ignore_content_length_q, 0);
3336
+ rb_define_method(cCurlEasy, "resolve_mode", ruby_curl_easy_resolve_mode, 0);
3337
+ rb_define_method(cCurlEasy, "resolve_mode=", ruby_curl_easy_resolve_mode_set, 1);
2968
3338
 
2969
3339
  rb_define_method(cCurlEasy, "on_body", ruby_curl_easy_on_body_set, -1);
2970
3340
  rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
@@ -2972,16 +3342,13 @@ void init_curb_easy() {
2972
3342
  rb_define_method(cCurlEasy, "on_debug", ruby_curl_easy_on_debug_set, -1);
2973
3343
  rb_define_method(cCurlEasy, "on_success", ruby_curl_easy_on_success_set, -1);
2974
3344
  rb_define_method(cCurlEasy, "on_failure", ruby_curl_easy_on_failure_set, -1);
3345
+ rb_define_method(cCurlEasy, "on_missing", ruby_curl_easy_on_missing_set, -1);
3346
+ rb_define_method(cCurlEasy, "on_redirect", ruby_curl_easy_on_redirect_set, -1);
2975
3347
  rb_define_method(cCurlEasy, "on_complete", ruby_curl_easy_on_complete_set, -1);
2976
3348
 
2977
- rb_define_method(cCurlEasy, "perform", ruby_curl_easy_perform, 0);
2978
- rb_define_method(cCurlEasy, "http_delete", ruby_curl_easy_perform_delete, 0);
2979
- rb_define_method(cCurlEasy, "http_get", ruby_curl_easy_perform_get, 0);
3349
+ rb_define_method(cCurlEasy, "http", ruby_curl_easy_perform_verb, 1);
2980
3350
  rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
2981
- rb_define_method(cCurlEasy, "http_head", ruby_curl_easy_perform_head, 0);
2982
3351
  rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 1);
2983
- rb_define_method(cCurlEasy, "head=", ruby_curl_easy_set_head_option, 1);
2984
- rb_define_method(cCurlEasy, "delete=", ruby_curl_easy_set_delete_option, 1);
2985
3352
 
2986
3353
  /* Post-perform info methods */
2987
3354
  rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
@@ -2989,6 +3356,9 @@ void init_curb_easy() {
2989
3356
 
2990
3357
  rb_define_method(cCurlEasy, "last_effective_url", ruby_curl_easy_last_effective_url_get, 0);
2991
3358
  rb_define_method(cCurlEasy, "response_code", ruby_curl_easy_response_code_get, 0);
3359
+ #if defined(HAVE_CURLINFO_PRIMARY_IP)
3360
+ rb_define_method(cCurlEasy, "primary_ip", ruby_curl_easy_primary_ip_get, 0);
3361
+ #endif
2992
3362
  rb_define_method(cCurlEasy, "http_connect_code", ruby_curl_easy_http_connect_code_get, 0);
2993
3363
  rb_define_method(cCurlEasy, "file_time", ruby_curl_easy_file_time_get, 0);
2994
3364
  rb_define_method(cCurlEasy, "total_time", ruby_curl_easy_total_time_get, 0);
@@ -2998,6 +3368,7 @@ void init_curb_easy() {
2998
3368
  rb_define_method(cCurlEasy, "start_transfer_time", ruby_curl_easy_start_transfer_time_get, 0);
2999
3369
  rb_define_method(cCurlEasy, "redirect_time", ruby_curl_easy_redirect_time_get, 0);
3000
3370
  rb_define_method(cCurlEasy, "redirect_count", ruby_curl_easy_redirect_count_get, 0);
3371
+ rb_define_method(cCurlEasy, "redirect_url", ruby_curl_easy_redirect_url_get, 0);
3001
3372
  rb_define_method(cCurlEasy, "downloaded_bytes", ruby_curl_easy_downloaded_bytes_get, 0);
3002
3373
  rb_define_method(cCurlEasy, "uploaded_bytes", ruby_curl_easy_uploaded_bytes_get, 0);
3003
3374
  rb_define_method(cCurlEasy, "download_speed", ruby_curl_easy_download_speed_get, 0);
@@ -3011,7 +3382,9 @@ void init_curb_easy() {
3011
3382
  rb_define_method(cCurlEasy, "os_errno", ruby_curl_easy_os_errno_get, 0);
3012
3383
  rb_define_method(cCurlEasy, "num_connects", ruby_curl_easy_num_connects_get, 0);
3013
3384
  rb_define_method(cCurlEasy, "ftp_entry_path", ruby_curl_easy_ftp_entry_path_get, 0);
3014
- rb_define_method(cCurlEasy, "inspect", ruby_curl_easy_inspect, 0);
3385
+
3386
+ rb_define_method(cCurlEasy, "close", ruby_curl_easy_close, 0);
3387
+ rb_define_method(cCurlEasy, "reset", ruby_curl_easy_reset, 0);
3015
3388
 
3016
3389
  /* Curl utils */
3017
3390
  rb_define_method(cCurlEasy, "escape", ruby_curl_easy_escape, 1);
@@ -3020,4 +3393,12 @@ void init_curb_easy() {
3020
3393
  /* Runtime support */
3021
3394
  rb_define_method(cCurlEasy, "clone", ruby_curl_easy_clone, 0);
3022
3395
  rb_define_alias(cCurlEasy, "dup", "clone");
3396
+ rb_define_method(cCurlEasy, "inspect", ruby_curl_easy_inspect, 0);
3397
+
3398
+ rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
3399
+ rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
3400
+ rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
3401
+
3402
+ rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
3403
+ rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
3023
3404
  }