codders-curb 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/LICENSE +51 -0
  2. data/README +194 -0
  3. data/Rakefile +320 -0
  4. data/doc.rb +42 -0
  5. data/ext/curb.c +977 -0
  6. data/ext/curb.h +52 -0
  7. data/ext/curb_easy.c +3404 -0
  8. data/ext/curb_easy.h +90 -0
  9. data/ext/curb_errors.c +647 -0
  10. data/ext/curb_errors.h +129 -0
  11. data/ext/curb_macros.h +159 -0
  12. data/ext/curb_multi.c +633 -0
  13. data/ext/curb_multi.h +26 -0
  14. data/ext/curb_postfield.c +523 -0
  15. data/ext/curb_postfield.h +40 -0
  16. data/ext/curb_upload.c +80 -0
  17. data/ext/curb_upload.h +30 -0
  18. data/ext/extconf.rb +399 -0
  19. data/lib/curb.rb +4 -0
  20. data/lib/curl.rb +57 -0
  21. data/lib/curl/easy.rb +468 -0
  22. data/lib/curl/multi.rb +248 -0
  23. data/tests/alltests.rb +3 -0
  24. data/tests/bug_crash_on_debug.rb +39 -0
  25. data/tests/bug_crash_on_progress.rb +33 -0
  26. data/tests/bug_curb_easy_blocks_ruby_threads.rb +52 -0
  27. data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +83 -0
  28. data/tests/bug_instance_post_differs_from_class_post.rb +53 -0
  29. data/tests/bug_multi_segfault.rb +14 -0
  30. data/tests/bug_postfields_crash.rb +26 -0
  31. data/tests/bug_postfields_crash2.rb +57 -0
  32. data/tests/bug_require_last_or_segfault.rb +40 -0
  33. data/tests/bugtests.rb +9 -0
  34. data/tests/helper.rb +199 -0
  35. data/tests/mem_check.rb +65 -0
  36. data/tests/require_last_or_segfault_script.rb +36 -0
  37. data/tests/tc_curl_download.rb +75 -0
  38. data/tests/tc_curl_easy.rb +1011 -0
  39. data/tests/tc_curl_easy_setopt.rb +31 -0
  40. data/tests/tc_curl_multi.rb +485 -0
  41. data/tests/tc_curl_postfield.rb +143 -0
  42. data/tests/timeout.rb +100 -0
  43. data/tests/timeout_server.rb +33 -0
  44. data/tests/unittests.rb +2 -0
  45. metadata +133 -0
data/ext/curb.h ADDED
@@ -0,0 +1,52 @@
1
+ /* Curb - Libcurl(3) bindings for Ruby.
2
+ * Copyright (c)2006 Ross Bamford.
3
+ * Licensed under the Ruby License. See LICENSE for details.
4
+ *
5
+ * $Id: curb.h 39 2006-12-23 15:28:45Z roscopeco $
6
+ */
7
+
8
+ #ifndef __CURB_H
9
+ #define __CURB_H
10
+
11
+ #include <ruby.h>
12
+ #include <curl/curl.h>
13
+
14
+ #include "curb_config.h"
15
+ #include "curb_easy.h"
16
+ #include "curb_errors.h"
17
+ #include "curb_postfield.h"
18
+ #include "curb_multi.h"
19
+
20
+ #include "curb_macros.h"
21
+
22
+ // These should be managed from the Rake 'release' task.
23
+ #define CURB_VERSION "0.8.0"
24
+ #define CURB_VER_NUM 800
25
+ #define CURB_VER_MAJ 0
26
+ #define CURB_VER_MIN 8
27
+ #define CURB_VER_MIC 0
28
+ #define CURB_VER_PATCH 0
29
+
30
+
31
+ // Maybe not yet defined in Ruby
32
+ #ifndef RSTRING_LEN
33
+ #define RSTRING_LEN(x) RSTRING(x)->len
34
+ #endif
35
+
36
+ #ifndef RSTRING_PTR
37
+ #define RSTRING_PTR(x) RSTRING(x)->ptr
38
+ #endif
39
+
40
+ #ifndef RHASH_LEN
41
+ #ifdef HAVE_RUBY19_HASH
42
+ #define RHASH_LEN(hash) RHASH(hash)->ntbl->num_entries
43
+ #else
44
+ #define RHASH_LEN(hash) RHASH(hash)->tbl->num_entries
45
+ #endif
46
+ #endif
47
+
48
+ extern VALUE mCurl;
49
+
50
+ extern void Init_curb_core();
51
+
52
+ #endif
data/ext/curb_easy.c ADDED
@@ -0,0 +1,3404 @@
1
+ /* curb_easy.c - Curl easy mode
2
+ * Copyright (c)2006 Ross Bamford.
3
+ * Licensed under the Ruby License. See LICENSE for details.
4
+ *
5
+ * $Id: curb_easy.c 30 2006-12-09 12:30:24Z roscopeco $
6
+ */
7
+ #include "curb_easy.h"
8
+ #include "curb_errors.h"
9
+ #include "curb_postfield.h"
10
+ #include "curb_upload.h"
11
+ #include "curb_multi.h"
12
+
13
+ #include <errno.h>
14
+ #include <string.h>
15
+
16
+ extern VALUE mCurl;
17
+
18
+ static VALUE idCall;
19
+ static VALUE idJoin;
20
+ static VALUE rbstrAmp;
21
+
22
+ #ifdef RDOC_NEVER_DEFINED
23
+ mCurl = rb_define_module("Curl");
24
+ #endif
25
+
26
+ VALUE cCurlEasy;
27
+
28
+
29
+ /* ================== CURL HANDLER FUNCS ==============*/
30
+
31
+ static VALUE callback_exception(VALUE unused) {
32
+ return Qfalse;
33
+ }
34
+
35
+ /* These handle both body and header data */
36
+ static size_t default_data_handler(char *stream,
37
+ size_t size,
38
+ size_t nmemb,
39
+ VALUE out) {
40
+ rb_str_buf_cat(out, stream, size * nmemb);
41
+ return size * nmemb;
42
+ }
43
+
44
+ // size_t function( void *ptr, size_t size, size_t nmemb, void *stream);
45
+ static size_t read_data_handler(void *ptr,
46
+ size_t size,
47
+ size_t nmemb,
48
+ ruby_curl_easy *rbce) {
49
+ VALUE upload = rb_easy_get("upload");
50
+ size_t read_bytes = (size*nmemb);
51
+ VALUE stream = ruby_curl_upload_stream_get(upload);
52
+
53
+ if (rb_respond_to(stream, rb_intern("read"))) {//if (rb_respond_to(stream, rb_intern("to_s"))) {
54
+ /* copy read_bytes from stream into ptr */
55
+ VALUE str = rb_funcall(stream, rb_intern("read"), 1, rb_int_new(read_bytes) );
56
+ if( str != Qnil ) {
57
+ memcpy(ptr, RSTRING_PTR(str), RSTRING_LEN(str));
58
+ return RSTRING_LEN(str);
59
+ }
60
+ else {
61
+ return 0;
62
+ }
63
+ }
64
+ else if (rb_respond_to(stream, rb_intern("to_s"))) {
65
+ ruby_curl_upload *rbcu;
66
+ VALUE str;
67
+ size_t len;
68
+ size_t remaining;
69
+ char *str_ptr;
70
+ Data_Get_Struct(upload, ruby_curl_upload, rbcu);
71
+ str = rb_funcall(stream, rb_intern("to_s"), 0);
72
+ len = RSTRING_LEN(str);
73
+ remaining = len - rbcu->offset;
74
+ str_ptr = RSTRING_PTR(str);
75
+
76
+ if( remaining < read_bytes ) {
77
+ if( remaining > 0 ) {
78
+ memcpy(ptr, str_ptr+rbcu->offset, remaining);
79
+ read_bytes = remaining;
80
+ rbcu->offset += remaining;
81
+ }
82
+ return remaining;
83
+ }
84
+ else if( remaining > read_bytes ) { // read_bytes <= remaining - send what we can fit in the buffer(ptr)
85
+ memcpy(ptr, str_ptr+rbcu->offset, read_bytes);
86
+ rbcu->offset += read_bytes;
87
+ }
88
+ else { // they're equal
89
+ memcpy(ptr, str_ptr+rbcu->offset, --read_bytes);
90
+ rbcu->offset += read_bytes;
91
+ }
92
+ return read_bytes;
93
+ }
94
+ else {
95
+ return 0;
96
+ }
97
+ }
98
+
99
+ static size_t proc_data_handler(char *stream,
100
+ size_t size,
101
+ size_t nmemb,
102
+ VALUE proc) {
103
+ VALUE procret;
104
+
105
+ procret = rb_funcall(proc, idCall, 1, rb_str_new(stream, size * nmemb));
106
+
107
+ switch (rb_type(procret)) {
108
+ case T_FIXNUM:
109
+ return FIX2LONG(procret);
110
+ case T_BIGNUM:
111
+ return NUM2LONG(procret);
112
+ default:
113
+ rb_warn("Curl data handlers should return the number of bytes read as an Integer");
114
+ return size * nmemb;
115
+ }
116
+ }
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
+
150
+ static int proc_progress_handler(VALUE proc,
151
+ double dltotal,
152
+ double dlnow,
153
+ double ultotal,
154
+ double ulnow) {
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));
163
+
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);
170
+
171
+ return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
172
+ }
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
+ }
179
+ static int proc_debug_handler(CURL *curl,
180
+ curl_infotype type,
181
+ char *data,
182
+ size_t data_len,
183
+ VALUE proc) {
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));
193
+ return 0;
194
+ }
195
+
196
+ /* ================== MARK/FREE FUNC ==================*/
197
+ void curl_easy_mark(ruby_curl_easy *rbce) {
198
+ if (!NIL_P(rbce->opts)) { rb_gc_mark(rbce->opts); }
199
+ if (!NIL_P(rbce->multi)) { rb_gc_mark(rbce->multi); }
200
+ }
201
+
202
+ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
203
+ if (rbce->curl_headers) {
204
+ curl_slist_free_all(rbce->curl_headers);
205
+ }
206
+
207
+ if (rbce->curl_ftp_commands) {
208
+ curl_slist_free_all(rbce->curl_ftp_commands);
209
+ }
210
+
211
+ if (rbce->curl) {
212
+ curl_easy_cleanup(rbce->curl);
213
+ }
214
+ }
215
+
216
+ void curl_easy_free(ruby_curl_easy *rbce) {
217
+ ruby_curl_easy_free(rbce);
218
+ free(rbce);
219
+ }
220
+
221
+
222
+ /* ================= ALLOC METHODS ====================*/
223
+
224
+ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
225
+ rbce->opts = rb_hash_new();
226
+
227
+ rbce->curl_headers = NULL;
228
+ rbce->curl_ftp_commands = NULL;
229
+
230
+ /* various-typed opts */
231
+ rbce->local_port = 0;
232
+ rbce->local_port_range = 0;
233
+ rbce->proxy_port = 0;
234
+ rbce->proxy_type = -1;
235
+ rbce->http_auth_types = 0;
236
+ rbce->proxy_auth_types = 0;
237
+ rbce->max_redirs = -1;
238
+ rbce->timeout = 0;
239
+ rbce->connect_timeout = 0;
240
+ rbce->dns_cache_timeout = 60;
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;
248
+
249
+ /* bool opts */
250
+ rbce->proxy_tunnel = 0;
251
+ rbce->fetch_file_time = 0;
252
+ rbce->ssl_verify_peer = 1;
253
+ rbce->ssl_verify_host = 2;
254
+ rbce->header_in_body = 0;
255
+ rbce->use_netrc = 0;
256
+ rbce->follow_location = 0;
257
+ rbce->unrestricted_auth = 0;
258
+ rbce->verbose = 0;
259
+ rbce->multipart_form_post = 0;
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
+ }
290
+
291
+ new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
292
+
293
+ rbce->multi = Qnil;
294
+ rbce->opts = Qnil;
295
+
296
+ ruby_curl_easy_zero(rbce);
297
+
298
+ rb_easy_set("url", url);
299
+
300
+ /* set the new_curl pointer to the curl handle */
301
+ ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)new_curl);
302
+ if (ecode != CURLE_OK) {
303
+ raise_curl_easy_error_exception(ecode);
304
+ }
305
+
306
+ if (blk != Qnil) {
307
+ rb_funcall(blk, idCall, 1, new_curl);
308
+ }
309
+
310
+ return new_curl;
311
+ }
312
+
313
+ /*
314
+ * call-seq:
315
+ * easy.clone => #&lt;easy clone&gt;
316
+ * easy.dup => #&lt;easy clone&gt;
317
+ *
318
+ * Clone this Curl::Easy instance, creating a new instance.
319
+ * This method duplicates the underlying CURL* handle.
320
+ */
321
+ static VALUE ruby_curl_easy_clone(VALUE self) {
322
+ ruby_curl_easy *rbce, *newrbce;
323
+
324
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
325
+
326
+ newrbce = ALLOC(ruby_curl_easy);
327
+ memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
328
+ newrbce->curl = curl_easy_duphandle(rbce->curl);
329
+ newrbce->curl_headers = NULL;
330
+ newrbce->curl_ftp_commands = NULL;
331
+
332
+ return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
333
+ }
334
+
335
+ /*
336
+ * call-seq:
337
+ * easy.close => nil
338
+ *
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.
342
+ */
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;
372
+ }
373
+
374
+ /*
375
+ * call-seq:
376
+ * easy.reset => Hash
377
+ *
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.
385
+ */
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;
414
+ }
415
+
416
+
417
+ /* ================ OBJ ATTRIBUTES ==================*/
418
+
419
+ /*
420
+ * call-seq:
421
+ * easy.url => string
422
+ *
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);
427
+ }
428
+
429
+ /*
430
+ * call-seq:
431
+ * easy.proxy_url => string
432
+ *
433
+ * Obtain the HTTP Proxy URL that will be used by subsequent calls to +perform+.
434
+ */
435
+ static VALUE ruby_curl_easy_proxy_url_get(VALUE self) {
436
+ CURB_OBJECT_HGETTER(ruby_curl_easy, proxy_url);
437
+ }
438
+
439
+ /*
440
+ * call-seq:
441
+ * easy.headers = "Header: val" => "Header: val"
442
+ * easy.headers = {"Header" => "val" ..., "Header" => "val"} => {"Header: val", ...}
443
+ * easy.headers = ["Header: val" ..., "Header: val"] => ["Header: val", ...]
444
+ *
445
+ * Set custom HTTP headers for following requests. This can be used to add
446
+ * custom headers, or override standard headers used by libcurl. It defaults to a
447
+ * Hash.
448
+ *
449
+ * For example to set a standard or custom header:
450
+ *
451
+ * easy.headers["MyHeader"] = "myval"
452
+ *
453
+ * To remove a standard header (this is useful when removing libcurls default
454
+ * 'Expect: 100-Continue' header when using HTTP form posts):
455
+ *
456
+ * easy.headers["Expect"] = ''
457
+ *
458
+ * Anything passed to libcurl as a header will be converted to a string during
459
+ * the perform step.
460
+ */
461
+ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
462
+ CURB_OBJECT_HSETTER(ruby_curl_easy, headers);
463
+ }
464
+
465
+ /*
466
+ * call-seq:
467
+ * easy.headers => Hash, Array or Str
468
+ *
469
+ * Obtain the custom HTTP headers for following requests.
470
+ */
471
+ static VALUE ruby_curl_easy_headers_get(VALUE self) {
472
+ ruby_curl_easy *rbce;
473
+ VALUE headers;
474
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
475
+ headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
476
+ if (headers == Qnil) { headers = rb_easy_set("headers", rb_hash_new()); }
477
+ return headers;
478
+ }
479
+
480
+ /*
481
+ * call-seq:
482
+ * easy.interface => string
483
+ *
484
+ * Obtain the interface name that is used as the outgoing network interface.
485
+ * The name can be an interface name, an IP address or a host name.
486
+ */
487
+ static VALUE ruby_curl_easy_interface_get(VALUE self) {
488
+ CURB_OBJECT_HGETTER(ruby_curl_easy, interface_hm);
489
+ }
490
+
491
+ /*
492
+ * call-seq:
493
+ * easy.userpwd => string
494
+ *
495
+ * Obtain the username/password string that will be used for subsequent
496
+ * calls to +perform+.
497
+ */
498
+ static VALUE ruby_curl_easy_userpwd_get(VALUE self) {
499
+ CURB_OBJECT_HGETTER(ruby_curl_easy, userpwd);
500
+ }
501
+
502
+ /*
503
+ * call-seq:
504
+ * easy.proxypwd => string
505
+ *
506
+ * Obtain the username/password string that will be used for proxy
507
+ * connection during subsequent calls to +perform+. The supplied string
508
+ * should have the form "username:password"
509
+ */
510
+ static VALUE ruby_curl_easy_proxypwd_get(VALUE self) {
511
+ CURB_OBJECT_HGETTER(ruby_curl_easy, proxypwd);
512
+ }
513
+
514
+ /*
515
+ * call-seq:
516
+ * easy.cookies => "name1=content1; name2=content2;"
517
+ *
518
+ * Obtain the cookies for this Curl::Easy instance.
519
+ */
520
+ static VALUE ruby_curl_easy_cookies_get(VALUE self) {
521
+ CURB_OBJECT_HGETTER(ruby_curl_easy, cookies);
522
+ }
523
+
524
+ /*
525
+ * call-seq:
526
+ * easy.cookiefile => string
527
+ *
528
+ * Obtain the cookiefile file for this Curl::Easy instance.
529
+ */
530
+ static VALUE ruby_curl_easy_cookiefile_get(VALUE self) {
531
+ CURB_OBJECT_HGETTER(ruby_curl_easy, cookiefile);
532
+ }
533
+
534
+ /*
535
+ * call-seq:
536
+ * easy.cookiejar => string
537
+ *
538
+ * Obtain the cookiejar file to use for this Curl::Easy instance.
539
+ */
540
+ static VALUE ruby_curl_easy_cookiejar_get(VALUE self) {
541
+ CURB_OBJECT_HGETTER(ruby_curl_easy, cookiejar);
542
+ }
543
+
544
+ /*
545
+ * call-seq:
546
+ * easy.cert = string => ""
547
+ *
548
+ * Set a cert file to use for this Curl::Easy instance. This file
549
+ * will be used to validate SSL connections.
550
+ *
551
+ */
552
+ static VALUE ruby_curl_easy_cert_set(VALUE self, VALUE cert) {
553
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cert);
554
+ }
555
+
556
+ /*
557
+ * call-seq:
558
+ * easy.cert => string
559
+ *
560
+ * Obtain the cert file to use for this Curl::Easy instance.
561
+ */
562
+ static VALUE ruby_curl_easy_cert_get(VALUE self) {
563
+ CURB_OBJECT_HGETTER(ruby_curl_easy, cert);
564
+ }
565
+
566
+ /*
567
+ * call-seq:
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 => ""
591
+ *
592
+ * Set a cacert bundle to use for this Curl::Easy instance. This file
593
+ * will be used to validate SSL certificates.
594
+ *
595
+ */
596
+ static VALUE ruby_curl_easy_cacert_set(VALUE self, VALUE cacert) {
597
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cacert);
598
+ }
599
+
600
+ /*
601
+ * call-seq:
602
+ * easy.cacert => string
603
+ *
604
+ * Obtain the cacert file to use for this Curl::Easy instance.
605
+ */
606
+ static VALUE ruby_curl_easy_cacert_get(VALUE self) {
607
+ CURB_OBJECT_HGETTER(ruby_curl_easy, cacert);
608
+ }
609
+
610
+ /*
611
+ * call-seq:
612
+ * easy.certpassword = string => ""
613
+ *
614
+ * Set a password used to open the specified cert
615
+ */
616
+ static VALUE ruby_curl_easy_certpassword_set(VALUE self, VALUE certpassword) {
617
+ CURB_OBJECT_HSETTER(ruby_curl_easy, certpassword);
618
+ }
619
+
620
+ /*
621
+ * call-seq:
622
+ * easy.certtype = "PEM|DER" => ""
623
+ *
624
+ * Set a cert type to use for this Curl::Easy instance.
625
+ * Default is PEM
626
+ *
627
+ */
628
+ static VALUE ruby_curl_easy_certtype_set(VALUE self, VALUE certtype) {
629
+ CURB_OBJECT_HSETTER(ruby_curl_easy, certtype);
630
+ }
631
+
632
+ /*
633
+ * call-seq:
634
+ * easy.certtype => string
635
+ *
636
+ * Obtain the cert type used for this Curl::Easy instance
637
+ */
638
+ static VALUE ruby_curl_easy_certtype_get(VALUE self) {
639
+ CURB_OBJECT_HGETTER(ruby_curl_easy, certtype);
640
+ }
641
+
642
+ /*
643
+ * call-seq:
644
+ * easy.encoding = string => string
645
+ *
646
+ * Set the accepted encoding types, curl will handle all of the decompression
647
+ *
648
+ */
649
+ static VALUE ruby_curl_easy_encoding_set(VALUE self, VALUE encoding) {
650
+ CURB_OBJECT_HSETTER(ruby_curl_easy, encoding);
651
+ }
652
+ /*
653
+ * call-seq:
654
+ * easy.encoding => string
655
+ *
656
+ * Get the set encoding types
657
+ *
658
+ */
659
+ static VALUE ruby_curl_easy_encoding_get(VALUE self) {
660
+ CURB_OBJECT_HGETTER(ruby_curl_easy, encoding);
661
+ }
662
+
663
+ /*
664
+ * call-seq:
665
+ * easy.useragent = "Ruby/Curb" => ""
666
+ *
667
+ * Set the user agent string for this Curl::Easy instance
668
+ *
669
+ */
670
+ static VALUE ruby_curl_easy_useragent_set(VALUE self, VALUE useragent) {
671
+ CURB_OBJECT_HSETTER(ruby_curl_easy, useragent);
672
+ }
673
+
674
+ /*
675
+ * call-seq:
676
+ * easy.useragent => "Ruby/Curb"
677
+ *
678
+ * Obtain the user agent string used for this Curl::Easy instance
679
+ */
680
+ static VALUE ruby_curl_easy_useragent_get(VALUE self) {
681
+ CURB_OBJECT_HGETTER(ruby_curl_easy, useragent);
682
+ }
683
+
684
+ /*
685
+ * call-seq:
686
+ * easy.post_body = "some=form%20data&to=send" => string or nil
687
+ *
688
+ * Sets the POST body of this Curl::Easy instance. This is expected to be
689
+ * URL encoded; no additional processing or encoding is done on the string.
690
+ * The content-type header will be set to application/x-www-form-urlencoded.
691
+ *
692
+ * This is handy if you want to perform a POST against a Curl::Multi instance.
693
+ */
694
+ static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
695
+ ruby_curl_easy *rbce;
696
+ CURL *curl;
697
+
698
+ char *data;
699
+ long len;
700
+
701
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
702
+
703
+ curl = rbce->curl;
704
+
705
+ if ( post_body == Qnil ) {
706
+ //rbce->postdata_buffer = Qnil;
707
+ rb_easy_del("postdata_buffer");
708
+
709
+ } else {
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
+ }
722
+
723
+ // Store the string, since it has to hang around for the duration of the
724
+ // request. See CURLOPT_POSTFIELDS in the libcurl docs.
725
+ //rbce->postdata_buffer = post_body;
726
+ rb_easy_set("postdata_buffer", post_body);
727
+
728
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
729
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
730
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
731
+
732
+ return post_body;
733
+ }
734
+
735
+ return Qnil;
736
+ }
737
+
738
+ /*
739
+ * call-seq:
740
+ * easy.post_body => string or nil
741
+ *
742
+ * Obtain the POST body used in this Curl::Easy instance.
743
+ */
744
+ static VALUE ruby_curl_easy_post_body_get(VALUE self) {
745
+ CURB_OBJECT_HGETTER(ruby_curl_easy, postdata_buffer);
746
+ }
747
+
748
+ /*
749
+ * call-seq:
750
+ * easy.put_data = data => ""
751
+ *
752
+ * Points this Curl::Easy instance to data to be uploaded via PUT. This
753
+ * sets the request to a PUT type request - useful if you want to PUT via
754
+ * a multi handle.
755
+ */
756
+ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
757
+ ruby_curl_easy *rbce;
758
+ CURL *curl;
759
+ VALUE upload;
760
+ VALUE headers;
761
+
762
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
763
+
764
+ upload = ruby_curl_upload_new(cCurlUpload);
765
+ ruby_curl_upload_stream_set(upload,data);
766
+
767
+ curl = rbce->curl;
768
+ rb_easy_set("upload", upload); /* keep the upload object alive as long as
769
+ the easy handle is active or until the upload
770
+ is complete or terminated... */
771
+
772
+ curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
773
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
774
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
775
+ curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
776
+
777
+ /*
778
+ * we need to set specific headers for the PUT to work... so
779
+ * convert the internal headers structure to a HASH if one is set
780
+ */
781
+ if (!rb_easy_nil("headers")) {
782
+ if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_STRING)) {
783
+ rb_raise(rb_eRuntimeError, "Must set headers as a HASH to modify the headers in an PUT request");
784
+ }
785
+ }
786
+
787
+ // exit fast if the payload is empty
788
+ if (NIL_P(data)) { return data; }
789
+
790
+ headers = rb_easy_get("headers");
791
+ if( headers == Qnil ) {
792
+ headers = rb_hash_new();
793
+ }
794
+
795
+ if (rb_respond_to(data, rb_intern("read"))) {
796
+ VALUE stat = rb_funcall(data, rb_intern("stat"), 0);
797
+ if( stat && rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil) {
798
+ VALUE size;
799
+ if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
800
+ rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
801
+ }
802
+ size = rb_funcall(stat, rb_intern("size"), 0);
803
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2LONG(size));
804
+ }
805
+ else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil && rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
806
+ rb_hash_aset(headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
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
+ }
812
+ }
813
+ else if (rb_respond_to(data, rb_intern("to_s"))) {
814
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, RSTRING_LEN(data));
815
+ if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
816
+ rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
817
+ }
818
+ }
819
+ else {
820
+ rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
821
+ }
822
+ rb_easy_set("headers",headers);
823
+
824
+ // if we made it this far, all should be well.
825
+ return data;
826
+ }
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
+
846
+ /* ================== IMMED ATTRS ==================*/
847
+
848
+ /*
849
+ * call-seq:
850
+ * easy.local_port = fixnum or nil => fixnum or nil
851
+ *
852
+ * Set the local port that will be used for the following +perform+ calls.
853
+ *
854
+ * Passing +nil+ will return to the default behaviour (no local port
855
+ * preference).
856
+ *
857
+ * This option is ignored if compiled against libcurl < 7.15.2.
858
+ */
859
+ static VALUE ruby_curl_easy_local_port_set(VALUE self, VALUE local_port) {
860
+ CURB_IMMED_PORT_SETTER(ruby_curl_easy, local_port, "port");
861
+ }
862
+
863
+ /*
864
+ * call-seq:
865
+ * easy.local_port => fixnum or nil
866
+ *
867
+ * Obtain the local port that will be used for the following +perform+ calls.
868
+ *
869
+ * This option is ignored if compiled against libcurl < 7.15.2.
870
+ */
871
+ static VALUE ruby_curl_easy_local_port_get(VALUE self) {
872
+ CURB_IMMED_PORT_GETTER(ruby_curl_easy, local_port);
873
+ }
874
+
875
+ /*
876
+ * call-seq:
877
+ * easy.local_port_range = fixnum or nil => fixnum or nil
878
+ *
879
+ * Set the local port range that will be used for the following +perform+
880
+ * calls. This is a number (between 0 and 65535) that determines how far
881
+ * libcurl may deviate from the supplied +local_port+ in order to find
882
+ * an available port.
883
+ *
884
+ * If you set +local_port+ it's also recommended that you set this, since
885
+ * it is fairly likely that your specified port will be unavailable.
886
+ *
887
+ * This option is ignored if compiled against libcurl < 7.15.2.
888
+ */
889
+ static VALUE ruby_curl_easy_local_port_range_set(VALUE self, VALUE local_port_range) {
890
+ CURB_IMMED_PORT_SETTER(ruby_curl_easy, local_port_range, "port range");
891
+ }
892
+
893
+ /*
894
+ * call-seq:
895
+ * easy.local_port_range => fixnum or nil
896
+ *
897
+ * Obtain the local port range that will be used for the following +perform+
898
+ * calls.
899
+ *
900
+ * This option is ignored if compiled against libcurl < 7.15.2.
901
+ */
902
+ static VALUE ruby_curl_easy_local_port_range_get(VALUE self) {
903
+ CURB_IMMED_PORT_GETTER(ruby_curl_easy, local_port_range);
904
+ }
905
+
906
+ /*
907
+ * call-seq:
908
+ * easy.proxy_port = fixnum or nil => fixnum or nil
909
+ *
910
+ * Set the proxy port that will be used for the following +perform+ calls.
911
+ */
912
+ static VALUE ruby_curl_easy_proxy_port_set(VALUE self, VALUE proxy_port) {
913
+ CURB_IMMED_PORT_SETTER(ruby_curl_easy, proxy_port, "port");
914
+ }
915
+
916
+ /*
917
+ * call-seq:
918
+ * easy.proxy_port => fixnum or nil
919
+ *
920
+ * Obtain the proxy port that will be used for the following +perform+ calls.
921
+ */
922
+ static VALUE ruby_curl_easy_proxy_port_get(VALUE self) {
923
+ CURB_IMMED_PORT_GETTER(ruby_curl_easy, proxy_port);
924
+ }
925
+
926
+ /*
927
+ * call-seq:
928
+ * easy.proxy_type = fixnum or nil => fixnum or nil
929
+ *
930
+ * Set the proxy type that will be used for the following +perform+ calls.
931
+ * This should be one of the Curl::CURLPROXY constants.
932
+ */
933
+ static VALUE ruby_curl_easy_proxy_type_set(VALUE self, VALUE proxy_type) {
934
+ CURB_IMMED_SETTER(ruby_curl_easy, proxy_type, -1);
935
+ }
936
+
937
+ /*
938
+ * call-seq:
939
+ * easy.proxy_type => fixnum or nil
940
+ *
941
+ * Obtain the proxy type that will be used for the following +perform+ calls.
942
+ */
943
+ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
944
+ CURB_IMMED_GETTER(ruby_curl_easy, proxy_type, -1);
945
+ }
946
+
947
+ #if defined(HAVE_CURLAUTH_DIGEST_IE)
948
+ #define CURL_HTTPAUTH_STR_TO_NUM(node) \
949
+ (!strncmp("basic",node,5)) ? CURLAUTH_BASIC : \
950
+ (!strncmp("digest_ie",node,9)) ? CURLAUTH_DIGEST_IE : \
951
+ (!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
952
+ (!strncmp("gssnegotiate",node,12)) ? CURLAUTH_GSSNEGOTIATE : \
953
+ (!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
954
+ (!strncmp("any",node,3)) ? CURLAUTH_ANY : \
955
+ (!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : 0
956
+ #else
957
+ #define CURL_HTTPAUTH_STR_TO_NUM(node) \
958
+ (!strncmp("basic",node,5)) ? CURLAUTH_BASIC : \
959
+ (!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
960
+ (!strncmp("gssnegotiate",node,12)) ? CURLAUTH_GSSNEGOTIATE : \
961
+ (!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
962
+ (!strncmp("any",node,3)) ? CURLAUTH_ANY : \
963
+ (!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : 0
964
+ #endif
965
+ /*
966
+ * call-seq:
967
+ * easy.http_auth_types = fixnum or nil => fixnum or nil
968
+ * easy.http_auth_types = [:basic,:digest,:digest_ie,:gssnegotiate, :ntlm, :any, :anysafe]
969
+ *
970
+ * Set the HTTP authentication types that may be used for the following
971
+ * +perform+ calls. This is a bitmap made by ORing together the
972
+ * Curl::CURLAUTH constants.
973
+ */
974
+ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE self) {//VALUE self, VALUE http_auth_types) {
975
+ ruby_curl_easy *rbce;
976
+ VALUE args_ary;
977
+ int i, len;
978
+ char* node = NULL;
979
+ long mask = 0x000000;
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
+
986
+ if (len == 1 && (TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM || rb_ary_entry(args_ary,0) == Qnil)) {
987
+ if (rb_ary_entry(args_ary,0) == Qnil) {
988
+ rbce->http_auth_types = 0;
989
+ }
990
+ else {
991
+ rbce->http_auth_types = NUM2INT(rb_ary_entry(args_ary,0));
992
+ }
993
+ }
994
+ else {
995
+ // we could have multiple values, but they should be symbols
996
+ node = RSTRING_PTR(rb_funcall(rb_ary_entry(args_ary,0),rb_intern("to_s"),0));
997
+ mask = CURL_HTTPAUTH_STR_TO_NUM(node);
998
+ for( i = 1; i < len; ++i ) {
999
+ node = RSTRING_PTR(rb_funcall(rb_ary_entry(args_ary,i),rb_intern("to_s"),0));
1000
+ mask |= CURL_HTTPAUTH_STR_TO_NUM(node);
1001
+ }
1002
+ rbce->http_auth_types = mask;
1003
+ }
1004
+ return INT2NUM(rbce->http_auth_types);
1005
+ }
1006
+
1007
+ /*
1008
+ * call-seq:
1009
+ * easy.http_auth_types => fixnum or nil
1010
+ *
1011
+ * Obtain the HTTP authentication types that may be used for the following
1012
+ * +perform+ calls.
1013
+ */
1014
+ static VALUE ruby_curl_easy_http_auth_types_get(VALUE self) {
1015
+ CURB_IMMED_GETTER(ruby_curl_easy, http_auth_types, 0);
1016
+ }
1017
+
1018
+ /*
1019
+ * call-seq:
1020
+ * easy.proxy_auth_types = fixnum or nil => fixnum or nil
1021
+ *
1022
+ * Set the proxy authentication types that may be used for the following
1023
+ * +perform+ calls. This is a bitmap made by ORing together the
1024
+ * Curl::CURLAUTH constants.
1025
+ */
1026
+ static VALUE ruby_curl_easy_proxy_auth_types_set(VALUE self, VALUE proxy_auth_types) {
1027
+ CURB_IMMED_SETTER(ruby_curl_easy, proxy_auth_types, 0);
1028
+ }
1029
+
1030
+ /*
1031
+ * call-seq:
1032
+ * easy.proxy_auth_types => fixnum or nil
1033
+ *
1034
+ * Obtain the proxy authentication types that may be used for the following
1035
+ * +perform+ calls.
1036
+ */
1037
+ static VALUE ruby_curl_easy_proxy_auth_types_get(VALUE self) {
1038
+ CURB_IMMED_GETTER(ruby_curl_easy, proxy_auth_types, 0);
1039
+ }
1040
+
1041
+ /*
1042
+ * call-seq:
1043
+ * easy.max_redirects = fixnum or nil => fixnum or nil
1044
+ *
1045
+ * Set the maximum number of redirections to follow in the following +perform+
1046
+ * calls. Set to nil or -1 allow an infinite number (the default). Setting this
1047
+ * option only makes sense if +follow_location+ is also set true.
1048
+ *
1049
+ * With libcurl >= 7.15.1, setting this to 0 will cause libcurl to refuse any
1050
+ * redirect.
1051
+ */
1052
+ static VALUE ruby_curl_easy_max_redirects_set(VALUE self, VALUE max_redirs) {
1053
+ CURB_IMMED_SETTER(ruby_curl_easy, max_redirs, -1);
1054
+ }
1055
+
1056
+ /*
1057
+ * call-seq:
1058
+ * easy.max_redirects => fixnum or nil
1059
+ *
1060
+ * Obtain the maximum number of redirections to follow in the following
1061
+ * +perform+ calls.
1062
+ */
1063
+ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
1064
+ CURB_IMMED_GETTER(ruby_curl_easy, max_redirs, -1);
1065
+ }
1066
+
1067
+ /*
1068
+ * call-seq:
1069
+ * easy.timeout = fixnum or nil => fixnum or nil
1070
+ *
1071
+ * Set the maximum time in seconds that you allow the libcurl transfer
1072
+ * operation to take. Normally, name lookups can take a considerable time
1073
+ * and limiting operations to less than a few minutes risk aborting
1074
+ * perfectly normal operations.
1075
+ *
1076
+ * Set to nil (or zero) to disable timeout (it will then only timeout
1077
+ * on the system's internal timeouts).
1078
+ */
1079
+ static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout) {
1080
+ CURB_IMMED_SETTER(ruby_curl_easy, timeout, 0);
1081
+ }
1082
+
1083
+ /*
1084
+ * call-seq:
1085
+ * easy.timeout => fixnum or nil
1086
+ *
1087
+ * Obtain the maximum time in seconds that you allow the libcurl transfer
1088
+ * operation to take.
1089
+ */
1090
+ static VALUE ruby_curl_easy_timeout_get(VALUE self, VALUE timeout) {
1091
+ CURB_IMMED_GETTER(ruby_curl_easy, timeout, 0);
1092
+ }
1093
+
1094
+ /*
1095
+ * call-seq:
1096
+ * easy.connect_timeout = fixnum or nil => fixnum or nil
1097
+ *
1098
+ * Set the maximum time in seconds that you allow the connection to the
1099
+ * server to take. This only limits the connection phase, once it has
1100
+ * connected, this option is of no more use.
1101
+ *
1102
+ * Set to nil (or zero) to disable connection timeout (it will then only
1103
+ * timeout on the system's internal timeouts).
1104
+ */
1105
+ static VALUE ruby_curl_easy_connect_timeout_set(VALUE self, VALUE connect_timeout) {
1106
+ CURB_IMMED_SETTER(ruby_curl_easy, connect_timeout, 0);
1107
+ }
1108
+
1109
+ /*
1110
+ * call-seq:
1111
+ * easy.connect_timeout => fixnum or nil
1112
+ *
1113
+ * Obtain the maximum time in seconds that you allow the connection to the
1114
+ * server to take.
1115
+ */
1116
+ static VALUE ruby_curl_easy_connect_timeout_get(VALUE self, VALUE connect_timeout) {
1117
+ CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout, 0);
1118
+ }
1119
+
1120
+ /*
1121
+ * call-seq:
1122
+ * easy.dns_cache_timeout = fixnum or nil => fixnum or nil
1123
+ *
1124
+ * Set the dns cache timeout in seconds. Name resolves will be kept in
1125
+ * memory for this number of seconds. Set to zero (0) to completely disable
1126
+ * caching, or set to nil (or -1) to make the cached entries remain forever.
1127
+ * By default, libcurl caches this info for 60 seconds.
1128
+ */
1129
+ static VALUE ruby_curl_easy_dns_cache_timeout_set(VALUE self, VALUE dns_cache_timeout) {
1130
+ CURB_IMMED_SETTER(ruby_curl_easy, dns_cache_timeout, -1);
1131
+ }
1132
+
1133
+ /*
1134
+ * call-seq:
1135
+ * easy.dns_cache_timeout => fixnum or nil
1136
+ *
1137
+ * Obtain the dns cache timeout in seconds.
1138
+ */
1139
+ static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self, VALUE dns_cache_timeout) {
1140
+ CURB_IMMED_GETTER(ruby_curl_easy, dns_cache_timeout, -1);
1141
+ }
1142
+
1143
+ /*
1144
+ * call-seq:
1145
+ * easy.ftp_response_timeout = fixnum or nil => fixnum or nil
1146
+ *
1147
+ * Set a timeout period (in seconds) on the amount of time that the server
1148
+ * is allowed to take in order to generate a response message for a command
1149
+ * before the session is considered hung. While curl is waiting for a
1150
+ * response, this value overrides +timeout+. It is recommended that if used
1151
+ * in conjunction with +timeout+, you set +ftp_response_timeout+ to a value
1152
+ * smaller than +timeout+.
1153
+ *
1154
+ * Ignored if libcurl version is < 7.10.8.
1155
+ */
1156
+ static VALUE ruby_curl_easy_ftp_response_timeout_set(VALUE self, VALUE ftp_response_timeout) {
1157
+ CURB_IMMED_SETTER(ruby_curl_easy, ftp_response_timeout, 0);
1158
+ }
1159
+
1160
+ /*
1161
+ * call-seq:
1162
+ * easy.ftp_response_timeout => fixnum or nil
1163
+ *
1164
+ * Obtain the maximum time that libcurl will wait for FTP command responses.
1165
+ */
1166
+ static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self, VALUE ftp_response_timeout) {
1167
+ CURB_IMMED_GETTER(ruby_curl_easy, ftp_response_timeout, 0);
1168
+ }
1169
+
1170
+ /*
1171
+ * call-seq:
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
1218
+ *
1219
+ * Set the HTTP Authentication username.
1220
+ */
1221
+ static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
1222
+ #if HAVE_CURLOPT_USERNAME
1223
+ CURB_OBJECT_HSETTER(ruby_curl_easy, username);
1224
+ #else
1225
+ return Qnil;
1226
+ #endif
1227
+ }
1228
+
1229
+ /*
1230
+ * call-seq:
1231
+ * easy.username => string
1232
+ *
1233
+ * Get the current username
1234
+ */
1235
+ static VALUE ruby_curl_easy_username_get(VALUE self, VALUE username) {
1236
+ #if HAVE_CURLOPT_USERNAME
1237
+ CURB_OBJECT_HGETTER(ruby_curl_easy, username);
1238
+ #else
1239
+ return Qnil;
1240
+ #endif
1241
+ }
1242
+
1243
+ /*
1244
+ * call-seq:
1245
+ * easy.password = string => string
1246
+ *
1247
+ * Set the HTTP Authentication password.
1248
+ */
1249
+ static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
1250
+ #if HAVE_CURLOPT_PASSWORD
1251
+ CURB_OBJECT_HSETTER(ruby_curl_easy, password);
1252
+ #else
1253
+ return Qnil;
1254
+ #endif
1255
+ }
1256
+
1257
+ /*
1258
+ * call-seq:
1259
+ * easy.password => string
1260
+ *
1261
+ * Get the current password
1262
+ */
1263
+ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
1264
+ #if HAVE_CURLOPT_PASSWORD
1265
+ CURB_OBJECT_HGETTER(ruby_curl_easy, password);
1266
+ #else
1267
+ return Qnil;
1268
+ #endif
1269
+ }
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
+
1335
+ /* ================== BOOL ATTRS ===================*/
1336
+
1337
+ /*
1338
+ * call-seq:
1339
+ * easy.proxy_tunnel = boolean => boolean
1340
+ *
1341
+ * Configure whether this Curl instance will use proxy tunneling.
1342
+ */
1343
+ static VALUE ruby_curl_easy_proxy_tunnel_set(VALUE self, VALUE proxy_tunnel) {
1344
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, proxy_tunnel);
1345
+ }
1346
+
1347
+ /*
1348
+ * call-seq:
1349
+ * easy.proxy_tunnel? => boolean
1350
+ *
1351
+ * Determine whether this Curl instance will use proxy tunneling.
1352
+ */
1353
+ static VALUE ruby_curl_easy_proxy_tunnel_q(VALUE self) {
1354
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, proxy_tunnel);
1355
+ }
1356
+
1357
+ /*
1358
+ * call-seq:
1359
+ * easy.fetch_file_time = boolean => boolean
1360
+ *
1361
+ * Configure whether this Curl instance will fetch remote file
1362
+ * times, if available.
1363
+ */
1364
+ static VALUE ruby_curl_easy_fetch_file_time_set(VALUE self, VALUE fetch_file_time) {
1365
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, fetch_file_time);
1366
+ }
1367
+
1368
+ /*
1369
+ * call-seq:
1370
+ * easy.fetch_file_time? => boolean
1371
+ *
1372
+ * Determine whether this Curl instance will fetch remote file
1373
+ * times, if available.
1374
+ */
1375
+ static VALUE ruby_curl_easy_fetch_file_time_q(VALUE self) {
1376
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, fetch_file_time);
1377
+ }
1378
+
1379
+ /*
1380
+ * call-seq:
1381
+ * easy.ssl_verify_peer = boolean => boolean
1382
+ *
1383
+ * Configure whether this Curl instance will verify the SSL peer
1384
+ * certificate. When true (the default), and the verification fails to
1385
+ * prove that the certificate is authentic, the connection fails. When
1386
+ * false, the connection succeeds regardless.
1387
+ *
1388
+ * Authenticating the certificate is not by itself very useful. You
1389
+ * typically want to ensure that the server, as authentically identified
1390
+ * by its certificate, is the server you mean to be talking to.
1391
+ * The ssl_verify_host? options controls that.
1392
+ */
1393
+ static VALUE ruby_curl_easy_ssl_verify_peer_set(VALUE self, VALUE ssl_verify_peer) {
1394
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, ssl_verify_peer);
1395
+ }
1396
+
1397
+ /*
1398
+ * call-seq:
1399
+ * easy.ssl_verify_peer? => boolean
1400
+ *
1401
+ * Determine whether this Curl instance will verify the SSL peer
1402
+ * certificate.
1403
+ */
1404
+ static VALUE ruby_curl_easy_ssl_verify_peer_q(VALUE self) {
1405
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, ssl_verify_peer);
1406
+ }
1407
+
1408
+ /*
1409
+ * call-seq:
1410
+ * easy.ssl_verify_host = [0, 1, 2] => [0, 1, 2]
1411
+ *
1412
+ * Configure whether this Curl instance will verify that the server cert
1413
+ * is for the server it is known as. When true (the default) the server
1414
+ * certificate must indicate that the server is the server to which you
1415
+ * meant to connect, or the connection fails. When false, the connection
1416
+ * will succeed regardless of the names in the certificate.
1417
+ *
1418
+ * this option controls is of the identity that the server claims.
1419
+ * The server could be lying. To control lying, see ssl_verify_peer? .
1420
+ */
1421
+ static VALUE ruby_curl_easy_ssl_verify_host_set(VALUE self, VALUE ssl_verify_host) {
1422
+ CURB_IMMED_SETTER(ruby_curl_easy, ssl_verify_host, 0);
1423
+ }
1424
+
1425
+ /*
1426
+ * call-seq:
1427
+ * easy.ssl_verify_host => number
1428
+ *
1429
+ * Determine whether this Curl instance will verify that the server cert
1430
+ * is for the server it is known as.
1431
+ */
1432
+ static VALUE ruby_curl_easy_ssl_verify_host_get(VALUE self) {
1433
+ CURB_IMMED_GETTER(ruby_curl_easy, ssl_verify_host, 0);
1434
+ }
1435
+
1436
+ /*
1437
+ * call-seq:
1438
+ * easy.header_in_body = boolean => boolean
1439
+ *
1440
+ * Configure whether this Curl instance will return HTTP headers
1441
+ * combined with body data. If this option is set true, both header
1442
+ * and body data will go to +body_str+ (or the configured +on_body+ handler).
1443
+ */
1444
+ static VALUE ruby_curl_easy_header_in_body_set(VALUE self, VALUE header_in_body) {
1445
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, header_in_body);
1446
+ }
1447
+
1448
+ /*
1449
+ * call-seq:
1450
+ * easy.header_in_body? => boolean
1451
+ *
1452
+ * Determine whether this Curl instance will return HTTP headers
1453
+ * combined with body data.
1454
+ */
1455
+ static VALUE ruby_curl_easy_header_in_body_q(VALUE self) {
1456
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, header_in_body);
1457
+ }
1458
+
1459
+ /*
1460
+ * call-seq:
1461
+ * easy.use_netrc = boolean => boolean
1462
+ *
1463
+ * Configure whether this Curl instance will use data from the user's
1464
+ * .netrc file for FTP connections.
1465
+ */
1466
+ static VALUE ruby_curl_easy_use_netrc_set(VALUE self, VALUE use_netrc) {
1467
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, use_netrc);
1468
+ }
1469
+
1470
+ /*
1471
+ * call-seq:
1472
+ * easy.use_netrc? => boolean
1473
+ *
1474
+ * Determine whether this Curl instance will use data from the user's
1475
+ * .netrc file for FTP connections.
1476
+ */
1477
+ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
1478
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, use_netrc);
1479
+ }
1480
+
1481
+ /*
1482
+ * call-seq:
1483
+ *
1484
+ * easy = Curl::Easy.new
1485
+ * easy.autoreferer=true
1486
+ */
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;
1499
+ }
1500
+
1501
+ /*
1502
+ * call-seq:
1503
+ * easy.follow_location? => boolean
1504
+ *
1505
+ * Determine whether this Curl instance will follow Location: headers
1506
+ * in HTTP responses.
1507
+ */
1508
+ static VALUE ruby_curl_easy_follow_location_q(VALUE self) {
1509
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, follow_location);
1510
+ }
1511
+
1512
+ /*
1513
+ * call-seq:
1514
+ * easy.unrestricted_auth = boolean => boolean
1515
+ *
1516
+ * Configure whether this Curl instance may use any HTTP authentication
1517
+ * method available when necessary.
1518
+ */
1519
+ static VALUE ruby_curl_easy_unrestricted_auth_set(VALUE self, VALUE unrestricted_auth) {
1520
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, unrestricted_auth);
1521
+ }
1522
+
1523
+ /*
1524
+ * call-seq:
1525
+ * easy.unrestricted_auth? => boolean
1526
+ *
1527
+ * Determine whether this Curl instance may use any HTTP authentication
1528
+ * method available when necessary.
1529
+ */
1530
+ static VALUE ruby_curl_easy_unrestricted_auth_q(VALUE self) {
1531
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, unrestricted_auth);
1532
+ }
1533
+
1534
+ /*
1535
+ * call-seq:
1536
+ * easy.verbose = boolean => boolean
1537
+ *
1538
+ * Configure whether this Curl instance gives verbose output to STDERR
1539
+ * during transfers. Ignored if this instance has an on_debug handler.
1540
+ */
1541
+ static VALUE ruby_curl_easy_verbose_set(VALUE self, VALUE verbose) {
1542
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, verbose);
1543
+ }
1544
+
1545
+ /*
1546
+ * call-seq:
1547
+ * easy.verbose? => boolean
1548
+ *
1549
+ * Determine whether this Curl instance gives verbose output to STDERR
1550
+ * during transfers.
1551
+ */
1552
+ static VALUE ruby_curl_easy_verbose_q(VALUE self) {
1553
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, verbose);
1554
+ }
1555
+
1556
+ /*
1557
+ * call-seq:
1558
+ * easy.multipart_form_post = boolean => boolean
1559
+ *
1560
+ * Configure whether this Curl instance uses multipart/formdata content
1561
+ * type for HTTP POST requests. If this is false (the default), then the
1562
+ * application/x-www-form-urlencoded content type is used for the form
1563
+ * data.
1564
+ *
1565
+ * If this is set true, you must pass one or more PostField instances
1566
+ * to the http_post method - no support for posting multipart forms from
1567
+ * a string is provided.
1568
+ */
1569
+ static VALUE ruby_curl_easy_multipart_form_post_set(VALUE self, VALUE multipart_form_post)
1570
+ {
1571
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, multipart_form_post);
1572
+ }
1573
+
1574
+ /*
1575
+ * call-seq:
1576
+ * easy.multipart_form_post? => boolean
1577
+ *
1578
+ * Determine whether this Curl instance uses multipart/formdata content
1579
+ * type for HTTP POST requests.
1580
+ */
1581
+ static VALUE ruby_curl_easy_multipart_form_post_q(VALUE self) {
1582
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, multipart_form_post);
1583
+ }
1584
+
1585
+ /*
1586
+ * call-seq:
1587
+ * easy.enable_cookies = boolean => boolean
1588
+ *
1589
+ * Configure whether the libcurl cookie engine is enabled for this Curl::Easy
1590
+ * instance.
1591
+ */
1592
+ static VALUE ruby_curl_easy_enable_cookies_set(VALUE self, VALUE enable_cookies)
1593
+ {
1594
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, enable_cookies);
1595
+ }
1596
+
1597
+ /*
1598
+ * call-seq:
1599
+ * easy.enable_cookies? => boolean
1600
+ *
1601
+ * Determine whether the libcurl cookie engine is enabled for this
1602
+ * Curl::Easy instance.
1603
+ */
1604
+ static VALUE ruby_curl_easy_enable_cookies_q(VALUE self) {
1605
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, enable_cookies);
1606
+ }
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
+
1692
+ /* ================= EVENT PROCS ================== */
1693
+
1694
+ /*
1695
+ * call-seq:
1696
+ * easy.on_body { |body_data| ... } => &lt;old handler&gt;
1697
+ *
1698
+ * Assign or remove the +on_body+ handler for this Curl::Easy instance.
1699
+ * To remove a previously-supplied handler, call this method with no
1700
+ * attached block.
1701
+ *
1702
+ * The +on_body+ handler is called for each chunk of response body passed back
1703
+ * by libcurl during +perform+. It should perform any processing necessary,
1704
+ * and return the actual number of bytes handled. Normally, this will
1705
+ * equal the length of the data string, and CURL will continue processing.
1706
+ * If the returned length does not equal the input length, CURL will abort
1707
+ * the processing with a Curl::Err::AbortedByCallbackError.
1708
+ */
1709
+ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
1710
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, body_proc);
1711
+ }
1712
+
1713
+ /*
1714
+ * call-seq:
1715
+ * easy.on_success { |easy| ... } => &lt;old handler&gt;
1716
+ *
1717
+ * Assign or remove the +on_success+ handler for this Curl::Easy instance.
1718
+ * To remove a previously-supplied handler, call this method with no
1719
+ * attached block.
1720
+ *
1721
+ * The +on_success+ handler is called when the request is finished with a
1722
+ * status of 20x
1723
+ */
1724
+ static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
1725
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, success_proc);
1726
+ }
1727
+
1728
+ /*
1729
+ * call-seq:
1730
+ * easy.on_failure {|easy,code| ... } => &lt;old handler&gt;
1731
+ *
1732
+ * Assign or remove the +on_failure+ handler for this Curl::Easy instance.
1733
+ * To remove a previously-supplied handler, call this method with no
1734
+ * attached block.
1735
+ *
1736
+ * The +on_failure+ handler is called when the request is finished with a
1737
+ * status of 50x
1738
+ */
1739
+ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
1740
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, failure_proc);
1741
+ }
1742
+
1743
+ /*
1744
+ * call-seq:
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;
1776
+ *
1777
+ * Assign or remove the +on_complete+ handler for this Curl::Easy instance.
1778
+ * To remove a previously-supplied handler, call this method with no
1779
+ * attached block.
1780
+ *
1781
+ * The +on_complete+ handler is called when the request is finished.
1782
+ */
1783
+ static VALUE ruby_curl_easy_on_complete_set(int argc, VALUE *argv, VALUE self) {
1784
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, complete_proc);
1785
+ }
1786
+
1787
+ /*
1788
+ * call-seq:
1789
+ * easy.on_header { |header_data| ... } => &lt;old handler&gt;
1790
+ *
1791
+ * Assign or remove the +on_header+ handler for this Curl::Easy instance.
1792
+ * To remove a previously-supplied handler, call this method with no
1793
+ * attached block.
1794
+ *
1795
+ * The +on_header+ handler is called for each chunk of response header passed
1796
+ * back by libcurl during +perform+. The semantics are the same as for the
1797
+ * block supplied to +on_body+.
1798
+ */
1799
+ static VALUE ruby_curl_easy_on_header_set(int argc, VALUE *argv, VALUE self) {
1800
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, header_proc);
1801
+ }
1802
+
1803
+ /*
1804
+ * call-seq:
1805
+ * easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } => &lt;old handler&gt;
1806
+ *
1807
+ * Assign or remove the +on_progress+ handler for this Curl::Easy instance.
1808
+ * To remove a previously-supplied handler, call this method with no
1809
+ * attached block.
1810
+ *
1811
+ * The +on_progress+ handler is called regularly by libcurl (approximately once
1812
+ * per second) during transfers to allow the application to receive progress
1813
+ * information. There is no guarantee that the reported progress will change
1814
+ * between calls.
1815
+ *
1816
+ * The result of the block call determines whether libcurl continues the transfer.
1817
+ * Returning a non-true value (i.e. nil or false) will cause the transfer to abort,
1818
+ * throwing a Curl::Err::AbortedByCallbackError.
1819
+ */
1820
+ static VALUE ruby_curl_easy_on_progress_set(int argc, VALUE *argv, VALUE self) {
1821
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, progress_proc);
1822
+ }
1823
+
1824
+ /*
1825
+ * call-seq:
1826
+ * easy.on_debug { |type, data| ... } => &lt;old handler&gt;
1827
+ *
1828
+ * Assign or remove the +on_debug+ handler for this Curl::Easy instance.
1829
+ * To remove a previously-supplied handler, call this method with no
1830
+ * attached block.
1831
+ *
1832
+ * The +on_debug+ handler, if configured, will receive detailed information
1833
+ * from libcurl during the perform call. This can be useful for debugging.
1834
+ * Setting a debug handler overrides libcurl's internal handler, disabling
1835
+ * any output from +verbose+, if set.
1836
+ *
1837
+ * The type argument will match one of the Curl::Easy::CURLINFO_XXXX
1838
+ * constants, and specifies the kind of information contained in the
1839
+ * data. The data is passed as a String.
1840
+ */
1841
+ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
1842
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, debug_proc);
1843
+ }
1844
+
1845
+
1846
+ /* =================== PERFORM =====================*/
1847
+
1848
+ /***********************************************
1849
+ * This is an rb_iterate callback used to set up http headers.
1850
+ */
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
+
1855
+ VALUE header_str = Qnil;
1856
+
1857
+ //rb_p(header);
1858
+
1859
+ if (rb_type(header) == T_ARRAY) {
1860
+ // we're processing a hash, header is [name, val]
1861
+ VALUE name, value;
1862
+
1863
+ name = rb_obj_as_string(rb_ary_entry(header, 0));
1864
+ value = rb_obj_as_string(rb_ary_entry(header, 1));
1865
+
1866
+ // This is a bit inefficient, but we don't want to be modifying
1867
+ // the actual values in the original hash.
1868
+ header_str = rb_str_plus(name, rb_str_new2(": "));
1869
+ header_str = rb_str_plus(header_str, value);
1870
+ } else {
1871
+ header_str = rb_obj_as_string(header);
1872
+ }
1873
+
1874
+ //rb_p(header_str);
1875
+
1876
+ *list = curl_slist_append(*list, StringValuePtr(header_str));
1877
+ return header_str;
1878
+ }
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
+
1893
+ /***********************************************
1894
+ *
1895
+ * Setup a connection
1896
+ *
1897
+ * Always returns Qtrue, rb_raise on error.
1898
+ */
1899
+ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
1900
+ // TODO this could do with a bit of refactoring...
1901
+ CURL *curl;
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);
1905
+
1906
+ curl = rbce->curl;
1907
+
1908
+ if (_url == Qnil) {
1909
+ rb_raise(eCurlErrError, "No URL supplied");
1910
+ }
1911
+
1912
+ url = rb_check_string_type(_url);
1913
+
1914
+ curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
1915
+
1916
+ // network stuff and auth
1917
+ if (!rb_easy_nil("interface_hm")) {
1918
+ curl_easy_setopt(curl, CURLOPT_INTERFACE, rb_easy_get_str("interface_hm"));
1919
+ } else {
1920
+ curl_easy_setopt(curl, CURLOPT_INTERFACE, NULL);
1921
+ }
1922
+
1923
+ #if HAVE_CURLOPT_USERNAME == 1 && HAVE_CURLOPT_PASSWORD == 1
1924
+ if (!rb_easy_nil("username")) {
1925
+ curl_easy_setopt(curl, CURLOPT_USERNAME, rb_easy_get_str("username"));
1926
+ } else {
1927
+ curl_easy_setopt(curl, CURLOPT_USERNAME, NULL);
1928
+ }
1929
+ if (!rb_easy_nil("password")) {
1930
+ curl_easy_setopt(curl, CURLOPT_PASSWORD, rb_easy_get_str("password"));
1931
+ }
1932
+ else {
1933
+ curl_easy_setopt(curl, CURLOPT_PASSWORD, NULL);
1934
+ }
1935
+ #endif
1936
+
1937
+ if (!rb_easy_nil("userpwd")) {
1938
+ curl_easy_setopt(curl, CURLOPT_USERPWD, rb_easy_get_str("userpwd"));
1939
+ #if HAVE_CURLOPT_USERNAME == 1
1940
+ } else if (rb_easy_nil("username") && rb_easy_nil("password")) { /* don't set this even to NULL if we have set username and password */
1941
+ #else
1942
+ } else {
1943
+ #endif
1944
+ curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
1945
+ }
1946
+
1947
+ if (rb_easy_nil("proxy_url")) {
1948
+ curl_easy_setopt(curl, CURLOPT_PROXY, NULL);
1949
+ } else {
1950
+ curl_easy_setopt(curl, CURLOPT_PROXY, rb_easy_get_str("proxy_url"));
1951
+ }
1952
+
1953
+ if (rb_easy_nil("proxypwd")) {
1954
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
1955
+ } else {
1956
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxypwd"));
1957
+ }
1958
+
1959
+ // body/header procs
1960
+ if (!rb_easy_nil("body_proc")) {
1961
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
1962
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
1963
+ /* clear out the body_data if it was set */
1964
+ rb_easy_del("body_data");
1965
+ } else {
1966
+ VALUE body_buffer = rb_easy_set("body_data", rb_str_buf_new(32768));
1967
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&default_data_handler);
1968
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, body_buffer);
1969
+ }
1970
+
1971
+ if (!rb_easy_nil("header_proc")) {
1972
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler_header);
1973
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce);
1974
+ /* clear out the header_data if it was set */
1975
+ rb_easy_del("header_data");
1976
+ } else {
1977
+ VALUE header_buffer = rb_easy_set("header_data", rb_str_buf_new(16384));
1978
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&default_data_handler);
1979
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, header_buffer);
1980
+ }
1981
+
1982
+ /* encoding */
1983
+ if (!rb_easy_nil("encoding")) {
1984
+ curl_easy_setopt(curl, CURLOPT_ENCODING, rb_easy_get_str("encoding"));
1985
+ }
1986
+
1987
+ // progress and debug procs
1988
+ if (!rb_easy_nil("progress_proc")) {
1989
+ curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&proc_progress_handler);
1990
+ curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, rb_easy_get("progress_proc"));
1991
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
1992
+ } else {
1993
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
1994
+ }
1995
+
1996
+ if (!rb_easy_nil("debug_proc")) {
1997
+ curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, (curl_debug_callback)&proc_debug_handler);
1998
+ curl_easy_setopt(curl, CURLOPT_DEBUGDATA, rb_easy_get("debug_proc"));
1999
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
2000
+ } else {
2001
+ // have to remove handler to re-enable standard verbosity
2002
+ curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, NULL);
2003
+ curl_easy_setopt(curl, CURLOPT_DEBUGDATA, NULL);
2004
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, rbce->verbose);
2005
+ }
2006
+
2007
+ /* general opts */
2008
+
2009
+ curl_easy_setopt(curl, CURLOPT_HEADER, rbce->header_in_body);
2010
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, rbce->follow_location);
2011
+ curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
2012
+
2013
+ curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, rbce->proxy_tunnel);
2014
+ curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
2015
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
2016
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_host);
2017
+
2018
+ if ((rbce->use_netrc != Qnil) && (rbce->use_netrc != Qfalse)) {
2019
+ curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
2020
+ } else {
2021
+ curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
2022
+ }
2023
+
2024
+ curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
2025
+
2026
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, rbce->timeout);
2027
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
2028
+ curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
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
+
2035
+ #if LIBCURL_VERSION_NUM >= 0x070a08
2036
+ curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
2037
+ #else
2038
+ if (rbce->ftp_response_timeout > 0) {
2039
+ rb_warn("Installed libcurl is too old to support ftp_response_timeout");
2040
+ }
2041
+ #endif
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
+
2046
+ // Set up localport / proxy port
2047
+ // FIXME these won't get returned to default if they're unset Ruby
2048
+ if (rbce->proxy_port > 0) {
2049
+ curl_easy_setopt(curl, CURLOPT_PROXYPORT, rbce->proxy_port);
2050
+ }
2051
+
2052
+ if (rbce->local_port > 0) {
2053
+ #if LIBCURL_VERSION_NUM >= 0x070f02
2054
+ curl_easy_setopt(curl, CURLOPT_LOCALPORT, rbce->local_port);
2055
+
2056
+ if (rbce->local_port_range > 0) {
2057
+ curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, rbce->local_port_range);
2058
+ }
2059
+ #else
2060
+ rb_warn("Installed libcurl is too old to support local_port");
2061
+ #endif
2062
+ }
2063
+
2064
+ if (rbce->proxy_type != -1) {
2065
+ #if LIBCURL_VERSION_NUM >= 0x070a00
2066
+ if (rbce->proxy_type == -2) {
2067
+ rb_warn("Installed libcurl is too old to support the selected proxy type");
2068
+ } else {
2069
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, rbce->proxy_type);
2070
+ }
2071
+ } else {
2072
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
2073
+ #else
2074
+ rb_warn("Installed libcurl is too old to support proxy_type");
2075
+ #endif
2076
+ }
2077
+
2078
+ if (rbce->http_auth_types > 0) {
2079
+ #if LIBCURL_VERSION_NUM >= 0x070a06
2080
+ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, rbce->http_auth_types);
2081
+ } else {
2082
+ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
2083
+ #else
2084
+ rb_warn("Installed libcurl is too old to support http_auth_types");
2085
+ #endif
2086
+ }
2087
+
2088
+ if (rbce->proxy_auth_types > 0) {
2089
+ #if LIBCURL_VERSION_NUM >= 0x070a07
2090
+ curl_easy_setopt(curl, CURLOPT_PROXYAUTH, rbce->proxy_auth_types);
2091
+ } else {
2092
+ curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
2093
+ #else
2094
+ rb_warn("Installed libcurl is too old to support proxy_auth_types");
2095
+ #endif
2096
+ }
2097
+
2098
+ /* Set up HTTP cookie handling if necessary
2099
+ FIXME this may not get disabled if it's enabled, the disabled again from ruby.
2100
+ */
2101
+ if (rbce->enable_cookies) {
2102
+ if (!rb_easy_nil("cookiejar")) {
2103
+ curl_easy_setopt(curl, CURLOPT_COOKIEJAR, rb_easy_get_str("cookiejar"));
2104
+ }
2105
+
2106
+ if (!rb_easy_nil("cookiefile")) {
2107
+ curl_easy_setopt(curl, CURLOPT_COOKIEFILE, rb_easy_get_str("cookiefile"));
2108
+ } else {
2109
+ curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); /* "" = magic to just enable */
2110
+ }
2111
+ }
2112
+
2113
+ if (!rb_easy_nil("cookies")) {
2114
+ curl_easy_setopt(curl, CURLOPT_COOKIE, rb_easy_get_str("cookies"));
2115
+ }
2116
+
2117
+ /* Set up HTTPS cert handling if necessary */
2118
+ if (!rb_easy_nil("cert")) {
2119
+ if (!rb_easy_nil("certtype")) {
2120
+ curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, rb_easy_get_str("certtype"));
2121
+ }
2122
+ curl_easy_setopt(curl, CURLOPT_SSLCERT, rb_easy_get_str("cert"));
2123
+ if (!rb_easy_nil("certpassword")) {
2124
+ curl_easy_setopt(curl, CURLOPT_SSLCERTPASSWD, rb_easy_get_str("certpassword"));
2125
+ }
2126
+ if (!rb_easy_nil("cert_key")) {
2127
+ curl_easy_setopt(curl, CURLOPT_SSLKEY, rb_easy_get_str("cert_key"));
2128
+ }
2129
+ }
2130
+
2131
+ if (!rb_easy_nil("cacert")) {
2132
+ curl_easy_setopt(curl, CURLOPT_CAINFO, rb_easy_get_str("cacert"));
2133
+ }
2134
+ #ifdef HAVE_CURL_CONFIG_CA
2135
+ else {
2136
+ curl_easy_setopt(curl, CURLOPT_CAINFO, CURL_CONFIG_CA);
2137
+ }
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);
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
2153
+
2154
+ if (rbce->ftp_filemethod > 0) {
2155
+ curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, rbce->ftp_filemethod);
2156
+ }
2157
+
2158
+ /* Set the user-agent string if specified */
2159
+ if (!rb_easy_nil("useragent")) {
2160
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, rb_easy_get_str("useragent"));
2161
+ }
2162
+
2163
+ /* Setup HTTP headers if necessary */
2164
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
2165
+
2166
+ if (!rb_easy_nil("headers")) {
2167
+ if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_HASH)) {
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);
2170
+ } else {
2171
+ VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
2172
+ *hdrs = curl_slist_append(*hdrs, StringValuePtr(headers_str));
2173
+ }
2174
+
2175
+ if (*hdrs) {
2176
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *hdrs);
2177
+ }
2178
+ }
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
+
2192
+ return Qnil;
2193
+ }
2194
+ /***********************************************
2195
+ *
2196
+ * Clean up a connection
2197
+ *
2198
+ * Always returns Qtrue.
2199
+ */
2200
+ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2201
+
2202
+ CURL *curl = rbce->curl;
2203
+ struct curl_slist *ftp_commands;
2204
+
2205
+ /* Free everything up */
2206
+ if (rbce->curl_headers) {
2207
+ curl_slist_free_all(rbce->curl_headers);
2208
+ rbce->curl_headers = NULL;
2209
+ }
2210
+
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. */
2218
+ if (!rb_easy_nil("upload")) {
2219
+ rb_easy_del("upload"); // set the upload object to Qnil to let the GC clean up
2220
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
2221
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
2222
+ curl_easy_setopt(curl, CURLOPT_READDATA, NULL);
2223
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
2224
+ }
2225
+
2226
+ return Qnil;
2227
+ }
2228
+
2229
+ /*
2230
+ * Common implementation of easy.http(verb) and easy.http_delete
2231
+ */
2232
+ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
2233
+ ruby_curl_easy *rbce;
2234
+ CURL *curl;
2235
+ VALUE retval;
2236
+
2237
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2238
+ curl = rbce->curl;
2239
+
2240
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
2241
+
2242
+ retval = rb_funcall(self, rb_intern("perform"), 0);
2243
+
2244
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2245
+
2246
+ return retval;
2247
+ }
2248
+
2249
+ /*
2250
+ * call-seq:
2251
+ * easy.http(verb)
2252
+ *
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.
2255
+ */
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
+ }
2268
+ }
2269
+
2270
+ /*
2271
+ * call-seq:
2272
+ * easy.http_post("url=encoded%20form%20data;and=so%20on") => true
2273
+ * easy.http_post("url=encoded%20form%20data", "and=so%20on", ...) => true
2274
+ * easy.http_post("url=encoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
2275
+ * easy.http_post(Curl::PostField, Curl::PostField ..., Curl::PostField) => true
2276
+ *
2277
+ * POST the specified formdata to the currently configured URL using
2278
+ * the current options set for this Curl::Easy instance. This method
2279
+ * always returns true, or raises an exception (defined under
2280
+ * Curl::Err) on error.
2281
+ *
2282
+ * The Content-type of the POST is determined by the current setting
2283
+ * of multipart_form_post? , according to the following rules:
2284
+ * * When false (the default): the form will be POSTed with a
2285
+ * content-type of 'application/x-www-form-urlencoded', and any of the
2286
+ * four calling forms may be used.
2287
+ * * When true: the form will be POSTed with a content-type of
2288
+ * 'multipart/formdata'. Only the last calling form may be used,
2289
+ * i.e. only PostField instances may be POSTed. In this mode,
2290
+ * individual fields' content-types are recognised, and file upload
2291
+ * fields are supported.
2292
+ *
2293
+ */
2294
+ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2295
+ ruby_curl_easy *rbce;
2296
+ CURL *curl;
2297
+ int i;
2298
+ VALUE args_ary;
2299
+
2300
+ rb_scan_args(argc, argv, "*", &args_ary);
2301
+
2302
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2303
+ curl = rbce->curl;
2304
+
2305
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2306
+
2307
+ if (rbce->multipart_form_post) {
2308
+ VALUE ret;
2309
+ struct curl_httppost *first = NULL, *last = NULL;
2310
+
2311
+ // Make the multipart form
2312
+ for (i = 0; i < argc; i++) {
2313
+ if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
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
+ }
2326
+ } else {
2327
+ rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
2328
+ return Qnil;
2329
+ }
2330
+ }
2331
+
2332
+ curl_easy_setopt(curl, CURLOPT_POST, 0);
2333
+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
2334
+ ret = rb_funcall(self, rb_intern("perform"), 0);
2335
+ curl_formfree(first);
2336
+
2337
+ return ret;
2338
+ } else {
2339
+ VALUE post_body = Qnil;
2340
+ /* TODO: check for PostField.file and raise error before to_s fails */
2341
+ if ((post_body = rb_funcall(args_ary, idJoin, 1, rbstrAmp)) == Qnil) {
2342
+ rb_raise(eCurlErrError, "Failed to join arguments");
2343
+ return Qnil;
2344
+ } else {
2345
+ /* if the function call above returns an empty string because no additional arguments were passed this makes sure
2346
+ a previously set easy.post_body = "arg=foo&bar=bin" will be honored */
2347
+ if( post_body != Qnil && rb_type(post_body) == T_STRING && RSTRING_LEN(post_body) > 0 ) {
2348
+ ruby_curl_easy_post_body_set(self, post_body);
2349
+ }
2350
+
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
+ }
2355
+
2356
+ return rb_funcall(self, rb_intern("perform"), 0);
2357
+ }
2358
+ }
2359
+ }
2360
+
2361
+ /*
2362
+ * call-seq:
2363
+ * easy.http_put(data) => true
2364
+ *
2365
+ * PUT the supplied data to the currently configured URL using the
2366
+ * current options set for this Curl::Easy instance. This method always
2367
+ * returns true, or raises an exception (defined under Curl::Err) on error.
2368
+ */
2369
+ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
2370
+ ruby_curl_easy *rbce;
2371
+ CURL *curl;
2372
+
2373
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2374
+ curl = rbce->curl;
2375
+
2376
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2377
+ ruby_curl_easy_put_data_set(self, data);
2378
+
2379
+ return rb_funcall(self, rb_intern("perform"), 0);
2380
+ }
2381
+
2382
+
2383
+ /* =================== DATA FUNCS =============== */
2384
+
2385
+ /*
2386
+ * call-seq:
2387
+ * easy.body_str => "response body"
2388
+ *
2389
+ * Return the response body from the previous call to +perform+. This
2390
+ * is populated by the default +on_body+ handler - if you supply
2391
+ * your own body handler, this string will be empty.
2392
+ */
2393
+ static VALUE ruby_curl_easy_body_str_get(VALUE self) {
2394
+ CURB_OBJECT_HGETTER(ruby_curl_easy, body_data);
2395
+ }
2396
+
2397
+ /*
2398
+ * call-seq:
2399
+ * easy.header_str => "response header"
2400
+ *
2401
+ * Return the response header from the previous call to +perform+. This
2402
+ * is populated by the default +on_header+ handler - if you supply
2403
+ * your own header handler, this string will be empty.
2404
+ */
2405
+ static VALUE ruby_curl_easy_header_str_get(VALUE self) {
2406
+ CURB_OBJECT_HGETTER(ruby_curl_easy, header_data);
2407
+ }
2408
+
2409
+
2410
+ /* ============== LASTCONN INFO FUNCS ============ */
2411
+
2412
+ /*
2413
+ * call-seq:
2414
+ * easy.last_effective_url => "http://some.url" or nil
2415
+ *
2416
+ * Retrieve the last effective URL used by this instance.
2417
+ * This is the URL used in the last +perform+ call,
2418
+ * and may differ from the value of easy.url.
2419
+ */
2420
+ static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
2421
+ ruby_curl_easy *rbce;
2422
+ char* url;
2423
+
2424
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2425
+ curl_easy_getinfo(rbce->curl, CURLINFO_EFFECTIVE_URL, &url);
2426
+
2427
+ if (url && url[0]) { // curl returns empty string if none
2428
+ return rb_str_new2(url);
2429
+ } else {
2430
+ return Qnil;
2431
+ }
2432
+ }
2433
+
2434
+ /*
2435
+ * call-seq:
2436
+ * easy.response_code => fixnum
2437
+ *
2438
+ * Retrieve the last received HTTP or FTP code. This will be zero
2439
+ * if no server response code has been received. Note that a proxy's
2440
+ * CONNECT response should be read with +http_connect_code+
2441
+ * and not this method.
2442
+ */
2443
+ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
2444
+ ruby_curl_easy *rbce;
2445
+ long code;
2446
+
2447
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2448
+ #ifdef HAVE_CURLINFO_RESPONSE_CODE
2449
+ curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
2450
+ #else
2451
+ // old libcurl
2452
+ curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CODE, &code);
2453
+ #endif
2454
+
2455
+ return LONG2NUM(code);
2456
+ }
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
+
2482
+ /*
2483
+ * call-seq:
2484
+ * easy.http_connect_code => fixnum
2485
+ *
2486
+ * Retrieve the last received proxy response code to a CONNECT request.
2487
+ */
2488
+ static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
2489
+ ruby_curl_easy *rbce;
2490
+ long code;
2491
+
2492
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2493
+ curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CONNECTCODE, &code);
2494
+
2495
+ return LONG2NUM(code);
2496
+ }
2497
+
2498
+ /*
2499
+ * call-seq:
2500
+ * easy.file_time => fixnum
2501
+ *
2502
+ * Retrieve the remote time of the retrieved document (in number of
2503
+ * seconds since 1 jan 1970 in the GMT/UTC time zone). If you get -1,
2504
+ * it can be because of many reasons (unknown, the server hides it
2505
+ * or the server doesn't support the command that tells document time
2506
+ * etc) and the time of the document is unknown.
2507
+ *
2508
+ * Note that you must tell the server to collect this information
2509
+ * before the transfer is made, by setting +fetch_file_time?+ to true,
2510
+ * or you will unconditionally get a -1 back.
2511
+ *
2512
+ * This requires libcurl 7.5 or higher - otherwise -1 is unconditionally
2513
+ * returned.
2514
+ */
2515
+ static VALUE ruby_curl_easy_file_time_get(VALUE self) {
2516
+ #ifdef HAVE_CURLINFO_FILETIME
2517
+ ruby_curl_easy *rbce;
2518
+ long time;
2519
+
2520
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2521
+ curl_easy_getinfo(rbce->curl, CURLINFO_FILETIME, &time);
2522
+
2523
+ return LONG2NUM(time);
2524
+ #else
2525
+ rb_warn("Installed libcurl is too old to support file_time");
2526
+ return INT2FIX(0);
2527
+ #endif
2528
+ }
2529
+
2530
+ /*
2531
+ * call-seq:
2532
+ * easy.total_time => float
2533
+ *
2534
+ * Retrieve the total time in seconds for the previous transfer,
2535
+ * including name resolving, TCP connect etc.
2536
+ */
2537
+ static VALUE ruby_curl_easy_total_time_get(VALUE self) {
2538
+ ruby_curl_easy *rbce;
2539
+ double time;
2540
+
2541
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2542
+ curl_easy_getinfo(rbce->curl, CURLINFO_TOTAL_TIME, &time);
2543
+
2544
+ return rb_float_new(time);
2545
+ }
2546
+
2547
+ /*
2548
+ * call-seq:
2549
+ * easy.name_lookup_time => float
2550
+ *
2551
+ * Retrieve the time, in seconds, it took from the start until the
2552
+ * name resolving was completed.
2553
+ */
2554
+ static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
2555
+ ruby_curl_easy *rbce;
2556
+ double time;
2557
+
2558
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2559
+ curl_easy_getinfo(rbce->curl, CURLINFO_NAMELOOKUP_TIME, &time);
2560
+
2561
+ return rb_float_new(time);
2562
+ }
2563
+
2564
+ /*
2565
+ * call-seq:
2566
+ * easy.connect_time => float
2567
+ *
2568
+ * Retrieve the time, in seconds, it took from the start until the
2569
+ * connect to the remote host (or proxy) was completed.
2570
+ */
2571
+ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
2572
+ ruby_curl_easy *rbce;
2573
+ double time;
2574
+
2575
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2576
+ curl_easy_getinfo(rbce->curl, CURLINFO_CONNECT_TIME, &time);
2577
+
2578
+ return rb_float_new(time);
2579
+ }
2580
+
2581
+ /*
2582
+ * call-seq:
2583
+ * easy.pre_transfer_time => float
2584
+ *
2585
+ * Retrieve the time, in seconds, it took from the start until the
2586
+ * file transfer is just about to begin. This includes all pre-transfer
2587
+ * commands and negotiations that are specific to the particular protocol(s)
2588
+ * involved.
2589
+ */
2590
+ static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
2591
+ ruby_curl_easy *rbce;
2592
+ double time;
2593
+
2594
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2595
+ curl_easy_getinfo(rbce->curl, CURLINFO_PRETRANSFER_TIME, &time);
2596
+
2597
+ return rb_float_new(time);
2598
+ }
2599
+
2600
+ /*
2601
+ * call-seq:
2602
+ * easy.start_transfer_time => float
2603
+ *
2604
+ * Retrieve the time, in seconds, it took from the start until the first byte
2605
+ * is just about to be transferred. This includes the +pre_transfer_time+ and
2606
+ * also the time the server needs to calculate the result.
2607
+ */
2608
+ static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
2609
+ ruby_curl_easy *rbce;
2610
+ double time;
2611
+
2612
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2613
+ curl_easy_getinfo(rbce->curl, CURLINFO_STARTTRANSFER_TIME, &time);
2614
+
2615
+ return rb_float_new(time);
2616
+ }
2617
+
2618
+ /*
2619
+ * call-seq:
2620
+ * easy.redirect_time => float
2621
+ *
2622
+ * Retrieve the total time, in seconds, it took for all redirection steps
2623
+ * include name lookup, connect, pretransfer and transfer before final
2624
+ * transaction was started. +redirect_time+ contains the complete
2625
+ * execution time for multiple redirections.
2626
+ *
2627
+ * Requires libcurl 7.9.7 or higher, otherwise -1 is always returned.
2628
+ */
2629
+ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
2630
+ #ifdef HAVE_CURLINFO_REDIRECT_TIME
2631
+ ruby_curl_easy *rbce;
2632
+ double time;
2633
+
2634
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2635
+ curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_TIME, &time);
2636
+
2637
+ return rb_float_new(time);
2638
+ #else
2639
+ rb_warn("Installed libcurl is too old to support redirect_time");
2640
+ return rb_float_new(-1);
2641
+ #endif
2642
+ }
2643
+
2644
+ /*
2645
+ * call-seq:
2646
+ * easy.redirect_count => integer
2647
+ *
2648
+ * Retrieve the total number of redirections that were actually followed.
2649
+ *
2650
+ * Requires libcurl 7.9.7 or higher, otherwise -1 is always returned.
2651
+ */
2652
+ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
2653
+ #ifdef HAVE_CURLINFO_REDIRECT_COUNT
2654
+ ruby_curl_easy *rbce;
2655
+ long count;
2656
+
2657
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2658
+ curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_COUNT, &count);
2659
+
2660
+ return LONG2NUM(count);
2661
+ #else
2662
+ rb_warn("Installed libcurl is too old to support redirect_count");
2663
+ return INT2FIX(-1);
2664
+ #endif
2665
+
2666
+ }
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
+
2698
+ /*
2699
+ * call-seq:
2700
+ * easy.uploaded_bytes => float
2701
+ *
2702
+ * Retrieve the total amount of bytes that were uploaded in the
2703
+ * preceeding transfer.
2704
+ */
2705
+ static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
2706
+ ruby_curl_easy *rbce;
2707
+ double bytes;
2708
+
2709
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2710
+ curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
2711
+
2712
+ return rb_float_new(bytes);
2713
+ }
2714
+
2715
+ /*
2716
+ * call-seq:
2717
+ * easy.downloaded_bytes => float
2718
+ *
2719
+ * Retrieve the total amount of bytes that were downloaded in the
2720
+ * preceeding transfer.
2721
+ */
2722
+ static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
2723
+ ruby_curl_easy *rbce;
2724
+ double bytes;
2725
+
2726
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2727
+ curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
2728
+
2729
+ return rb_float_new(bytes);
2730
+ }
2731
+
2732
+ /*
2733
+ * call-seq:
2734
+ * easy.upload_speed => float
2735
+ *
2736
+ * Retrieve the average upload speed that curl measured for the
2737
+ * preceeding complete upload.
2738
+ */
2739
+ static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
2740
+ ruby_curl_easy *rbce;
2741
+ double bytes;
2742
+
2743
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2744
+ curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
2745
+
2746
+ return rb_float_new(bytes);
2747
+ }
2748
+
2749
+ /*
2750
+ * call-seq:
2751
+ * easy.download_speed => float
2752
+ *
2753
+ * Retrieve the average download speed that curl measured for
2754
+ * the preceeding complete download.
2755
+ */
2756
+ static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
2757
+ ruby_curl_easy *rbce;
2758
+ double bytes;
2759
+
2760
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2761
+ curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
2762
+
2763
+ return rb_float_new(bytes);
2764
+ }
2765
+
2766
+ /*
2767
+ * call-seq:
2768
+ * easy.header_size => fixnum
2769
+ *
2770
+ * Retrieve the total size of all the headers received in the
2771
+ * preceeding transfer.
2772
+ */
2773
+ static VALUE ruby_curl_easy_header_size_get(VALUE self) {
2774
+ ruby_curl_easy *rbce;
2775
+ long size;
2776
+
2777
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2778
+ curl_easy_getinfo(rbce->curl, CURLINFO_HEADER_SIZE, &size);
2779
+
2780
+ return LONG2NUM(size);
2781
+ }
2782
+
2783
+ /*
2784
+ * call-seq:
2785
+ * easy.request_size => fixnum
2786
+ *
2787
+ * Retrieve the total size of the issued requests. This is so far
2788
+ * only for HTTP requests. Note that this may be more than one request
2789
+ * if +follow_location?+ is true.
2790
+ */
2791
+ static VALUE ruby_curl_easy_request_size_get(VALUE self) {
2792
+ ruby_curl_easy *rbce;
2793
+ long size;
2794
+
2795
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2796
+ curl_easy_getinfo(rbce->curl, CURLINFO_REQUEST_SIZE, &size);
2797
+
2798
+ return LONG2NUM(size);
2799
+ }
2800
+
2801
+ /*
2802
+ * call-seq:
2803
+ * easy.ssl_verify_result => integer
2804
+ *
2805
+ * Retrieve the result of the certification verification that was requested
2806
+ * (by setting +ssl_verify_peer?+ to +true+).
2807
+ */
2808
+ static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
2809
+ ruby_curl_easy *rbce;
2810
+ long result;
2811
+
2812
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2813
+ curl_easy_getinfo(rbce->curl, CURLINFO_SSL_VERIFYRESULT, &result);
2814
+
2815
+ return LONG2NUM(result);
2816
+ }
2817
+
2818
+ /* TODO CURLINFO_SSL_ENGINES
2819
+
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)
2824
+ */
2825
+
2826
+ /*
2827
+ * call-seq:
2828
+ * easy.downloaded_content_length => float
2829
+ *
2830
+ * Retrieve the content-length of the download. This is the value read
2831
+ * from the Content-Length: field.
2832
+ */
2833
+ static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
2834
+ ruby_curl_easy *rbce;
2835
+ double bytes;
2836
+
2837
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2838
+ curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
2839
+
2840
+ return rb_float_new(bytes);
2841
+ }
2842
+
2843
+ /*
2844
+ * call-seq:
2845
+ * easy.uploaded_content_length => float
2846
+ *
2847
+ * Retrieve the content-length of the upload.
2848
+ */
2849
+ static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
2850
+ ruby_curl_easy *rbce;
2851
+ double bytes;
2852
+
2853
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2854
+ curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
2855
+
2856
+ return rb_float_new(bytes);
2857
+ }
2858
+
2859
+ /*
2860
+ * call-seq:
2861
+ * easy.content_type => "content/type" or nil
2862
+ *
2863
+ * Retrieve the content-type of the downloaded object. This is the value read
2864
+ * from the Content-Type: field. If you get +nil+, it means that the server
2865
+ * didn't send a valid Content-Type header or that the protocol used doesn't
2866
+ * support this.
2867
+ */
2868
+ static VALUE ruby_curl_easy_content_type_get(VALUE self) {
2869
+ ruby_curl_easy *rbce;
2870
+ char* type;
2871
+
2872
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2873
+ curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_TYPE, &type);
2874
+
2875
+ if (type && type[0]) { // curl returns empty string if none
2876
+ return rb_str_new2(type);
2877
+ } else {
2878
+ return Qnil;
2879
+ }
2880
+ }
2881
+
2882
+
2883
+ /* NOT REQUIRED?
2884
+ CURLINFO_PRIVATE
2885
+
2886
+ Pass a pointer to a 'char *' to receive the pointer to the private data associated with the curl handle (set with the CURLOPT_PRIVATE option to curl_easy_setopt(3)). (Added in 7.10.3)
2887
+ */
2888
+
2889
+ /* TODO these will need constants setting up too for checking the bits.
2890
+ *
2891
+ * Alternatively, could return an object that wraps the long, and has
2892
+ * question methods to query the auth types. Could return long from to_i(nt)
2893
+ *
2894
+ CURLINFO_HTTPAUTH_AVAIL
2895
+
2896
+ Pass a pointer to a long to receive a bitmask indicating the authentication method(s) available. The meaning of the bits is explained in the CURLOPT_HTTPAUTH option for curl_easy_setopt(3). (Added in 7.10.8)
2897
+
2898
+ CURLINFO_PROXYAUTH_AVAIL
2899
+
2900
+ Pass a pointer to a long to receive a bitmask indicating the authentication method(s) available for your proxy authentication. (Added in 7.10.8)
2901
+ */
2902
+
2903
+ /*
2904
+ * call-seq:
2905
+ * easy.os_errno => integer
2906
+ *
2907
+ * Retrieve the errno variable from a connect failure (requires
2908
+ * libcurl 7.12.2 or higher, otherwise 0 is always returned).
2909
+ */
2910
+ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
2911
+ #ifdef HAVE_CURLINFO_OS_ERRNO
2912
+ ruby_curl_easy *rbce;
2913
+ long result;
2914
+
2915
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2916
+ curl_easy_getinfo(rbce->curl, CURLINFO_OS_ERRNO, &result);
2917
+
2918
+ return LONG2NUM(result);
2919
+ #else
2920
+ rb_warn("Installed libcurl is too old to support os_errno");
2921
+ return INT2FIX(0);
2922
+ #endif
2923
+ }
2924
+
2925
+ /*
2926
+ * call-seq:
2927
+ * easy.num_connects => integer
2928
+ *
2929
+ * Retrieve the number of new connections libcurl had to create to achieve
2930
+ * the previous transfer (only the successful connects are counted).
2931
+ * Combined with +redirect_count+ you are able to know how many times libcurl
2932
+ * successfully reused existing connection(s) or not.
2933
+ *
2934
+ * See the Connection Options of curl_easy_setopt(3) to see how libcurl tries
2935
+ * to make persistent connections to save time.
2936
+ *
2937
+ * (requires libcurl 7.12.3 or higher, otherwise -1 is always returned).
2938
+ */
2939
+ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
2940
+ #ifdef HAVE_CURLINFO_NUM_CONNECTS
2941
+ ruby_curl_easy *rbce;
2942
+ long result;
2943
+
2944
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2945
+ curl_easy_getinfo(rbce->curl, CURLINFO_NUM_CONNECTS, &result);
2946
+
2947
+ return LONG2NUM(result);
2948
+ #else
2949
+ rb_warn("Installed libcurl is too old to support num_connects");
2950
+ return INT2FIX(-1);
2951
+ #endif
2952
+ }
2953
+
2954
+
2955
+ /* TODO this needs to be implemented.
2956
+
2957
+ CURLINFO_COOKIELIST
2958
+
2959
+ Pass a pointer to a 'struct curl_slist *' to receive a linked-list of all cookies cURL knows (expired ones, too). Don't forget to curl_slist_free_all(3) the list after it has been used. If there are no cookies (cookies for the handle have not been enabled or simply none have been received) 'struct curl_slist *' will be set to point to NULL. (Added in 7.14.1)
2960
+ */
2961
+
2962
+ /* TODO this needs to be implemented. Could probably support CONNECT_ONLY by having this
2963
+ * return an open Socket or something.
2964
+ *
2965
+ CURLINFO_LASTSOCKET
2966
+
2967
+ Pass a pointer to a long to receive the last socket used by this curl session. If the socket is no longer valid, -1 is returned. When you finish working with the socket, you must call curl_easy_cleanup() as usual and let libcurl close the socket and cleanup other resources associated with the handle. This is typically used in combination with CURLOPT_CONNECT_ONLY. (Added in 7.15.2)
2968
+ */
2969
+
2970
+ /*
2971
+ * call-seq:
2972
+ * easy.ftp_entry_path => "C:\ftp\root\" or nil
2973
+ *
2974
+ * Retrieve the path of the entry path. That is the initial path libcurl ended
2975
+ * up in when logging on to the remote FTP server. This returns +nil+ if
2976
+ * something is wrong.
2977
+ *
2978
+ * (requires libcurl 7.15.4 or higher, otherwise +nil+ is always returned).
2979
+ */
2980
+ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
2981
+ #ifdef HAVE_CURLINFO_FTP_ENTRY_PATH
2982
+ ruby_curl_easy *rbce;
2983
+ char* path = NULL;
2984
+
2985
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2986
+ curl_easy_getinfo(rbce->curl, CURLINFO_FTP_ENTRY_PATH, &path);
2987
+
2988
+ if (path && path[0]) { // curl returns NULL or empty string if none
2989
+ return rb_str_new2(path);
2990
+ } else {
2991
+ return Qnil;
2992
+ }
2993
+ #else
2994
+ rb_warn("Installed libcurl is too old to support num_connects");
2995
+ return Qnil;
2996
+ #endif
2997
+ }
2998
+
2999
+ /*
3000
+ * call-seq:
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/>"
3135
+ */
3136
+ static VALUE ruby_curl_easy_inspect(VALUE self) {
3137
+ char buf[64];
3138
+ ruby_curl_easy *rbce;
3139
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3140
+ /* if we don't have a url set... we'll crash... */
3141
+ if( !rb_easy_nil("url") && rb_easy_type_check("url", T_STRING)) {
3142
+ VALUE url = rb_easy_get("url");
3143
+ size_t len = 13+((RSTRING_LEN(url) > 50) ? 50 : RSTRING_LEN(url));
3144
+ /* "#<Net::HTTP http://www.google.com/:80 open=false>" */
3145
+ memcpy(buf,"#<Curl::Easy ", 13);
3146
+ memcpy(buf+13,StringValueCStr(url), (len - 13));
3147
+ buf[len++] = '>';
3148
+ return rb_str_new(buf,len);
3149
+ }
3150
+ return rb_str_new2("#<Curl::Easy>");
3151
+ }
3152
+
3153
+
3154
+ /* ================== ESCAPING FUNCS ==============*/
3155
+
3156
+ /*
3157
+ * call-seq:
3158
+ * easy.escape("some text") => "some%20text"
3159
+ *
3160
+ * Convert the given input string to a URL encoded string and return
3161
+ * the result. All input characters that are not a-z, A-Z or 0-9 are
3162
+ * converted to their "URL escaped" version (%NN where NN is a
3163
+ * two-digit hexadecimal number).
3164
+ */
3165
+ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
3166
+ ruby_curl_easy *rbce;
3167
+ char *result;
3168
+ VALUE rresult;
3169
+ VALUE str = svalue;
3170
+
3171
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3172
+
3173
+ /* NOTE: make sure the value is a string, if not call to_s */
3174
+ if( rb_type(str) != T_STRING ) { str = rb_funcall(str,rb_intern("to_s"),0); }
3175
+
3176
+ #if (LIBCURL_VERSION_NUM >= 0x070f04)
3177
+ result = (char*)curl_easy_escape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str));
3178
+ #else
3179
+ result = (char*)curl_escape(StringValuePtr(str), (int)RSTRING_LEN(str));
3180
+ #endif
3181
+
3182
+ rresult = rb_str_new2(result);
3183
+ curl_free(result);
3184
+
3185
+ return rresult;
3186
+ }
3187
+
3188
+ /*
3189
+ * call-seq:
3190
+ * easy.unescape("some%20text") => "some text"
3191
+ *
3192
+ * Convert the given URL encoded input string to a "plain string" and return
3193
+ * the result. All input characters that are URL encoded (%XX where XX is a
3194
+ * two-digit hexadecimal number) are converted to their binary versions.
3195
+ */
3196
+ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
3197
+ ruby_curl_easy *rbce;
3198
+ int rlen;
3199
+ char *result;
3200
+ VALUE rresult;
3201
+
3202
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3203
+
3204
+ #if (LIBCURL_VERSION_NUM >= 0x070f04)
3205
+ result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
3206
+ #else
3207
+ result = (char*)curl_unescape(StringValuePtr(str), RSTRING_LEN(str));
3208
+ rlen = strlen(result);
3209
+ #endif
3210
+
3211
+ rresult = rb_str_new(result, rlen);
3212
+ curl_free(result);
3213
+
3214
+ return rresult;
3215
+ }
3216
+
3217
+
3218
+ /* ================= CLASS METHODS ==================*/
3219
+
3220
+ /*
3221
+ * call-seq:
3222
+ * Curl::Easy.error(code) => String
3223
+ *
3224
+ * translate an internal libcurl error to ruby error class
3225
+ */
3226
+ static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
3227
+ return rb_curl_easy_error(FIX2INT(code));
3228
+ }
3229
+
3230
+ /* =================== INIT LIB =====================*/
3231
+ void init_curb_easy() {
3232
+ idCall = rb_intern("call");
3233
+ idJoin = rb_intern("join");
3234
+
3235
+ rbstrAmp = rb_str_new2("&");
3236
+ rb_global_variable(&rbstrAmp);
3237
+
3238
+ cCurlEasy = rb_define_class_under(mCurl, "Easy", rb_cObject);
3239
+
3240
+ /* Class methods */
3241
+ rb_define_singleton_method(cCurlEasy, "new", ruby_curl_easy_new, -1);
3242
+ rb_define_singleton_method(cCurlEasy, "error", ruby_curl_easy_error_message, 1);
3243
+
3244
+ /* Attributes for config next perform */
3245
+ rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
3246
+ rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
3247
+ rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
3248
+ rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
3249
+ rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
3250
+ rb_define_method(cCurlEasy, "userpwd", ruby_curl_easy_userpwd_get, 0);
3251
+ rb_define_method(cCurlEasy, "proxypwd", ruby_curl_easy_proxypwd_get, 0);
3252
+ rb_define_method(cCurlEasy, "cookies", ruby_curl_easy_cookies_get, 0);
3253
+ rb_define_method(cCurlEasy, "cookiefile", ruby_curl_easy_cookiefile_get, 0);
3254
+ rb_define_method(cCurlEasy, "cookiejar", ruby_curl_easy_cookiejar_get, 0);
3255
+ rb_define_method(cCurlEasy, "cert=", ruby_curl_easy_cert_set, 1);
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);
3259
+ rb_define_method(cCurlEasy, "cacert=", ruby_curl_easy_cacert_set, 1);
3260
+ rb_define_method(cCurlEasy, "cacert", ruby_curl_easy_cacert_get, 0);
3261
+ rb_define_method(cCurlEasy, "certpassword=", ruby_curl_easy_certpassword_set, 1);
3262
+ rb_define_method(cCurlEasy, "certtype=", ruby_curl_easy_certtype_set, 1);
3263
+ rb_define_method(cCurlEasy, "certtype", ruby_curl_easy_certtype_get, 0);
3264
+ rb_define_method(cCurlEasy, "encoding=", ruby_curl_easy_encoding_set, 1);
3265
+ rb_define_method(cCurlEasy, "encoding", ruby_curl_easy_encoding_get, 0);
3266
+ rb_define_method(cCurlEasy, "useragent=", ruby_curl_easy_useragent_set, 1);
3267
+ rb_define_method(cCurlEasy, "useragent", ruby_curl_easy_useragent_get, 0);
3268
+ rb_define_method(cCurlEasy, "post_body=", ruby_curl_easy_post_body_set, 1);
3269
+ rb_define_method(cCurlEasy, "post_body", ruby_curl_easy_post_body_get, 0);
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);
3273
+
3274
+ rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
3275
+ rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
3276
+ rb_define_method(cCurlEasy, "local_port_range=", ruby_curl_easy_local_port_range_set, 1);
3277
+ rb_define_method(cCurlEasy, "local_port_range", ruby_curl_easy_local_port_range_get, 0);
3278
+ rb_define_method(cCurlEasy, "proxy_port=", ruby_curl_easy_proxy_port_set, 1);
3279
+ rb_define_method(cCurlEasy, "proxy_port", ruby_curl_easy_proxy_port_get, 0);
3280
+ rb_define_method(cCurlEasy, "proxy_type=", ruby_curl_easy_proxy_type_set, 1);
3281
+ rb_define_method(cCurlEasy, "proxy_type", ruby_curl_easy_proxy_type_get, 0);
3282
+ rb_define_method(cCurlEasy, "http_auth_types=", ruby_curl_easy_http_auth_types_set, -1);
3283
+ rb_define_method(cCurlEasy, "http_auth_types", ruby_curl_easy_http_auth_types_get, 0);
3284
+ rb_define_method(cCurlEasy, "proxy_auth_types=", ruby_curl_easy_proxy_auth_types_set, 1);
3285
+ rb_define_method(cCurlEasy, "proxy_auth_types", ruby_curl_easy_proxy_auth_types_get, 0);
3286
+ rb_define_method(cCurlEasy, "max_redirects=", ruby_curl_easy_max_redirects_set, 1);
3287
+ rb_define_method(cCurlEasy, "max_redirects", ruby_curl_easy_max_redirects_get, 0);
3288
+ rb_define_method(cCurlEasy, "timeout=", ruby_curl_easy_timeout_set, 1);
3289
+ rb_define_method(cCurlEasy, "timeout", ruby_curl_easy_timeout_get, 0);
3290
+ rb_define_method(cCurlEasy, "connect_timeout=", ruby_curl_easy_connect_timeout_set, 1);
3291
+ rb_define_method(cCurlEasy, "connect_timeout", ruby_curl_easy_connect_timeout_get, 0);
3292
+ rb_define_method(cCurlEasy, "dns_cache_timeout=", ruby_curl_easy_dns_cache_timeout_set, 1);
3293
+ rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
3294
+ rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
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);
3306
+
3307
+ rb_define_method(cCurlEasy, "username=", ruby_curl_easy_username_set, 1);
3308
+ rb_define_method(cCurlEasy, "username", ruby_curl_easy_username_get, 0);
3309
+ rb_define_method(cCurlEasy, "password=", ruby_curl_easy_password_set, 1);
3310
+ rb_define_method(cCurlEasy, "password", ruby_curl_easy_password_get, 0);
3311
+
3312
+ rb_define_method(cCurlEasy, "proxy_tunnel=", ruby_curl_easy_proxy_tunnel_set, 1);
3313
+ rb_define_method(cCurlEasy, "proxy_tunnel?", ruby_curl_easy_proxy_tunnel_q, 0);
3314
+ rb_define_method(cCurlEasy, "fetch_file_time=", ruby_curl_easy_fetch_file_time_set, 1);
3315
+ rb_define_method(cCurlEasy, "fetch_file_time?", ruby_curl_easy_fetch_file_time_q, 0);
3316
+ rb_define_method(cCurlEasy, "ssl_verify_peer=", ruby_curl_easy_ssl_verify_peer_set, 1);
3317
+ rb_define_method(cCurlEasy, "ssl_verify_peer?", ruby_curl_easy_ssl_verify_peer_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);
3320
+ rb_define_method(cCurlEasy, "header_in_body=", ruby_curl_easy_header_in_body_set, 1);
3321
+ rb_define_method(cCurlEasy, "header_in_body?", ruby_curl_easy_header_in_body_q, 0);
3322
+ rb_define_method(cCurlEasy, "use_netrc=", ruby_curl_easy_use_netrc_set, 1);
3323
+ rb_define_method(cCurlEasy, "use_netrc?", ruby_curl_easy_use_netrc_q, 0);
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);
3326
+ rb_define_method(cCurlEasy, "unrestricted_auth=", ruby_curl_easy_unrestricted_auth_set, 1);
3327
+ rb_define_method(cCurlEasy, "unrestricted_auth?", ruby_curl_easy_unrestricted_auth_q, 0);
3328
+ rb_define_method(cCurlEasy, "verbose=", ruby_curl_easy_verbose_set, 1);
3329
+ rb_define_method(cCurlEasy, "verbose?", ruby_curl_easy_verbose_q, 0);
3330
+ rb_define_method(cCurlEasy, "multipart_form_post=", ruby_curl_easy_multipart_form_post_set, 1);
3331
+ rb_define_method(cCurlEasy, "multipart_form_post?", ruby_curl_easy_multipart_form_post_q, 0);
3332
+ rb_define_method(cCurlEasy, "enable_cookies=", ruby_curl_easy_enable_cookies_set, 1);
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);
3338
+
3339
+ rb_define_method(cCurlEasy, "on_body", ruby_curl_easy_on_body_set, -1);
3340
+ rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
3341
+ rb_define_method(cCurlEasy, "on_progress", ruby_curl_easy_on_progress_set, -1);
3342
+ rb_define_method(cCurlEasy, "on_debug", ruby_curl_easy_on_debug_set, -1);
3343
+ rb_define_method(cCurlEasy, "on_success", ruby_curl_easy_on_success_set, -1);
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);
3347
+ rb_define_method(cCurlEasy, "on_complete", ruby_curl_easy_on_complete_set, -1);
3348
+
3349
+ rb_define_method(cCurlEasy, "http", ruby_curl_easy_perform_verb, 1);
3350
+ rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
3351
+ rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 1);
3352
+
3353
+ /* Post-perform info methods */
3354
+ rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
3355
+ rb_define_method(cCurlEasy, "header_str", ruby_curl_easy_header_str_get, 0);
3356
+
3357
+ rb_define_method(cCurlEasy, "last_effective_url", ruby_curl_easy_last_effective_url_get, 0);
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
3362
+ rb_define_method(cCurlEasy, "http_connect_code", ruby_curl_easy_http_connect_code_get, 0);
3363
+ rb_define_method(cCurlEasy, "file_time", ruby_curl_easy_file_time_get, 0);
3364
+ rb_define_method(cCurlEasy, "total_time", ruby_curl_easy_total_time_get, 0);
3365
+ rb_define_method(cCurlEasy, "name_lookup_time", ruby_curl_easy_name_lookup_time_get, 0);
3366
+ rb_define_method(cCurlEasy, "connect_time", ruby_curl_easy_connect_time_get, 0);
3367
+ rb_define_method(cCurlEasy, "pre_transfer_time", ruby_curl_easy_pre_transfer_time_get, 0);
3368
+ rb_define_method(cCurlEasy, "start_transfer_time", ruby_curl_easy_start_transfer_time_get, 0);
3369
+ rb_define_method(cCurlEasy, "redirect_time", ruby_curl_easy_redirect_time_get, 0);
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);
3372
+ rb_define_method(cCurlEasy, "downloaded_bytes", ruby_curl_easy_downloaded_bytes_get, 0);
3373
+ rb_define_method(cCurlEasy, "uploaded_bytes", ruby_curl_easy_uploaded_bytes_get, 0);
3374
+ rb_define_method(cCurlEasy, "download_speed", ruby_curl_easy_download_speed_get, 0);
3375
+ rb_define_method(cCurlEasy, "upload_speed", ruby_curl_easy_upload_speed_get, 0);
3376
+ rb_define_method(cCurlEasy, "header_size", ruby_curl_easy_header_size_get, 0);
3377
+ rb_define_method(cCurlEasy, "request_size", ruby_curl_easy_request_size_get, 0);
3378
+ rb_define_method(cCurlEasy, "ssl_verify_result", ruby_curl_easy_ssl_verify_result_get, 0);
3379
+ rb_define_method(cCurlEasy, "downloaded_content_length", ruby_curl_easy_downloaded_content_length_get, 0);
3380
+ rb_define_method(cCurlEasy, "uploaded_content_length", ruby_curl_easy_uploaded_content_length_get, 0);
3381
+ rb_define_method(cCurlEasy, "content_type", ruby_curl_easy_content_type_get, 0);
3382
+ rb_define_method(cCurlEasy, "os_errno", ruby_curl_easy_os_errno_get, 0);
3383
+ rb_define_method(cCurlEasy, "num_connects", ruby_curl_easy_num_connects_get, 0);
3384
+ rb_define_method(cCurlEasy, "ftp_entry_path", ruby_curl_easy_ftp_entry_path_get, 0);
3385
+
3386
+ rb_define_method(cCurlEasy, "close", ruby_curl_easy_close, 0);
3387
+ rb_define_method(cCurlEasy, "reset", ruby_curl_easy_reset, 0);
3388
+
3389
+ /* Curl utils */
3390
+ rb_define_method(cCurlEasy, "escape", ruby_curl_easy_escape, 1);
3391
+ rb_define_method(cCurlEasy, "unescape", ruby_curl_easy_unescape, 1);
3392
+
3393
+ /* Runtime support */
3394
+ rb_define_method(cCurlEasy, "clone", ruby_curl_easy_clone, 0);
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);
3404
+ }