taf2-curb 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/ext/curb_easy.c ADDED
@@ -0,0 +1,2540 @@
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
+
11
+ #include <errno.h>
12
+ #include <string.h>
13
+
14
+ extern VALUE mCurl;
15
+
16
+ static VALUE idCall;
17
+ static VALUE idJoin;
18
+ static VALUE rbstrAmp;
19
+
20
+ #ifdef RDOC_NEVER_DEFINED
21
+ mCurl = rb_define_module("Curl");
22
+ #endif
23
+
24
+ VALUE cCurlEasy;
25
+
26
+
27
+ /* ================== CURL HANDLER FUNCS ==============*/
28
+
29
+ /* These handle both body and header data */
30
+ static size_t default_data_handler(char *stream,
31
+ size_t size,
32
+ size_t nmemb,
33
+ VALUE out) {
34
+ rb_str_buf_cat(out, stream, size * nmemb);
35
+ return size * nmemb;
36
+ }
37
+
38
+ static size_t proc_data_handler(char *stream,
39
+ size_t size,
40
+ size_t nmemb,
41
+ VALUE proc) {
42
+ VALUE procret;
43
+
44
+ procret = rb_funcall(proc, idCall, 1, rb_str_new(stream, size * nmemb));
45
+
46
+ switch (rb_type(procret)) {
47
+ case T_FIXNUM:
48
+ return FIX2LONG(procret);
49
+ case T_BIGNUM:
50
+ return NUM2LONG(procret);
51
+ default:
52
+ rb_warn("Curl data handlers should return the number of bytes read as an Integer");
53
+ return size * nmemb;
54
+ }
55
+ }
56
+
57
+ static int proc_progress_handler(VALUE proc,
58
+ double dltotal,
59
+ double dlnow,
60
+ double ultotal,
61
+ double ulnow) {
62
+ VALUE procret;
63
+
64
+ procret = rb_funcall(proc, idCall, 4, rb_float_new(dltotal),
65
+ rb_float_new(dlnow),
66
+ rb_float_new(ultotal),
67
+ rb_float_new(ulnow));
68
+
69
+ return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
70
+ }
71
+
72
+ static int proc_debug_handler(CURL *curl,
73
+ curl_infotype type,
74
+ char *data,
75
+ size_t data_len,
76
+ VALUE proc) {
77
+ rb_funcall(proc, idCall, 2, INT2FIX(type), rb_str_new(data, data_len));
78
+ return 0;
79
+ }
80
+
81
+ /* ================== MARK/FREE FUNC ==================*/
82
+ void curl_easy_mark(ruby_curl_easy *rbce) {
83
+ rb_gc_mark(rbce->url);
84
+ rb_gc_mark(rbce->proxy_url);
85
+ rb_gc_mark(rbce->body_proc);
86
+ rb_gc_mark(rbce->body_data);
87
+ rb_gc_mark(rbce->header_proc);
88
+ rb_gc_mark(rbce->header_data);
89
+ rb_gc_mark(rbce->progress_proc);
90
+ rb_gc_mark(rbce->debug_proc);
91
+ rb_gc_mark(rbce->interface);
92
+ rb_gc_mark(rbce->userpwd);
93
+ rb_gc_mark(rbce->proxypwd);
94
+ rb_gc_mark(rbce->headers);
95
+ rb_gc_mark(rbce->cookiejar);
96
+ rb_gc_mark(rbce->cert);
97
+ rb_gc_mark(rbce->encoding);
98
+ rb_gc_mark(rbce->success_proc);
99
+ rb_gc_mark(rbce->failure_proc);
100
+ rb_gc_mark(rbce->complete_proc);
101
+
102
+ rb_gc_mark(rbce->postdata_buffer);
103
+ rb_gc_mark(rbce->bodybuf);
104
+ rb_gc_mark(rbce->headerbuf);
105
+ }
106
+
107
+ void curl_easy_free(ruby_curl_easy *rbce) {
108
+ if (rbce->curl_headers) {
109
+ curl_slist_free_all(rbce->curl_headers);
110
+ }
111
+ curl_easy_cleanup(rbce->curl);
112
+ free(rbce);
113
+ }
114
+
115
+
116
+ /* ================= ALLOC METHODS ====================*/
117
+
118
+ /*
119
+ * call-seq:
120
+ * Curl::Easy.new => #&lt;Curl::Easy...&gt;
121
+ * Curl::Easy.new(url = nil) => #&lt;Curl::Easy...&gt;
122
+ * Curl::Easy.new(url = nil) { |self| ... } => #&lt;Curl::Easy...&gt;
123
+ *
124
+ * Create a new Curl::Easy instance, optionally supplying the URL.
125
+ * The block form allows further configuration to be supplied before
126
+ * the instance is returned.
127
+ */
128
+ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
129
+ CURLcode ecode;
130
+ VALUE url, blk;
131
+ VALUE new_curl;
132
+
133
+ rb_scan_args(argc, argv, "01&", &url, &blk);
134
+
135
+ ruby_curl_easy *rbce = ALLOC(ruby_curl_easy);
136
+
137
+ /* handler */
138
+ rbce->curl = curl_easy_init();
139
+
140
+ /* assoc objects */
141
+ rbce->url = url;
142
+ rbce->proxy_url = Qnil;
143
+ rbce->body_data = Qnil;
144
+ rbce->body_proc = Qnil;
145
+ rbce->header_data = Qnil;
146
+ rbce->header_proc = Qnil;
147
+ rbce->progress_proc = Qnil;
148
+ rbce->debug_proc = Qnil;
149
+ rbce->interface = Qnil;
150
+ rbce->userpwd = Qnil;
151
+ rbce->proxypwd = Qnil;
152
+ rbce->headers = rb_hash_new();
153
+ rbce->cookiejar = Qnil;
154
+ rbce->cert = Qnil;
155
+ rbce->encoding = Qnil;
156
+ rbce->success_proc = Qnil;
157
+ rbce->failure_proc = Qnil;
158
+ rbce->complete_proc = Qnil;
159
+
160
+ /* various-typed opts */
161
+ rbce->local_port = 0;
162
+ rbce->local_port_range = 0;
163
+ rbce->proxy_port = 0;
164
+ rbce->proxy_type = -1;
165
+ rbce->http_auth_types = 0;
166
+ rbce->proxy_auth_types = 0;
167
+ rbce->max_redirs = -1;
168
+ rbce->timeout = 0;
169
+ rbce->connect_timeout = 0;
170
+ rbce->dns_cache_timeout = 60;
171
+ rbce->ftp_response_timeout = 0;
172
+
173
+ /* bool opts */
174
+ rbce->proxy_tunnel = 0;
175
+ rbce->fetch_file_time = 0;
176
+ rbce->ssl_verify_peer = 1;
177
+ rbce->ssl_verify_host = 1;
178
+ rbce->header_in_body = 0;
179
+ rbce->use_netrc = 0;
180
+ rbce->follow_location = 0;
181
+ rbce->unrestricted_auth = 0;
182
+ rbce->verbose = 0;
183
+ rbce->multipart_form_post = 0;
184
+ rbce->enable_cookies = 0;
185
+
186
+ /* buffers */
187
+ rbce->postdata_buffer = Qnil;
188
+ rbce->bodybuf = Qnil;
189
+ rbce->headerbuf = Qnil;
190
+ rbce->curl_headers = NULL;
191
+
192
+ new_curl = Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, rbce);
193
+
194
+ if (blk != Qnil) {
195
+ rb_funcall(blk, idCall, 1, new_curl);
196
+ }
197
+
198
+ /* set the rbce pointer to the curl handle */
199
+ ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
200
+ if (ecode != CURLE_OK) {
201
+ raise_curl_easy_error_exception(ecode);
202
+ }
203
+
204
+ return new_curl;
205
+ }
206
+
207
+ /*
208
+ * call-seq:
209
+ * easy.clone => #&lt;easy clone&gt;
210
+ * easy.dup => #&lt;easy clone&gt;
211
+ *
212
+ * Clone this Curl::Easy instance, creating a new instance.
213
+ * This method duplicates the underlying CURL* handle.
214
+ */
215
+ static VALUE ruby_curl_easy_clone(VALUE self) {
216
+ ruby_curl_easy *rbce, *newrbce;
217
+
218
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
219
+
220
+ newrbce = ALLOC(ruby_curl_easy);
221
+ memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
222
+ newrbce->curl = curl_easy_duphandle(rbce->curl);
223
+ newrbce->curl_headers = NULL;
224
+
225
+ return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
226
+ }
227
+
228
+
229
+ /* ================ OBJ ATTRIBUTES ==================*/
230
+
231
+ /*
232
+ * call-seq:
233
+ * easy.url = "http://some.url/" => "http://some.url/"
234
+ *
235
+ * Set the URL for subsequent calls to +perform+. It is acceptable
236
+ * (and even recommended) to reuse Curl::Easy instances by reassigning
237
+ * the URL between calls to +perform+.
238
+ */
239
+ static VALUE ruby_curl_easy_url_set(VALUE self, VALUE url) {
240
+ CURB_OBJECT_SETTER(ruby_curl_easy, url);
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * easy.url => "http://some.url/"
246
+ *
247
+ * Obtain the URL that will be used by subsequent calls to +perform+.
248
+ */
249
+ static VALUE ruby_curl_easy_url_get(VALUE self) {
250
+ CURB_OBJECT_GETTER(ruby_curl_easy, url);
251
+ }
252
+
253
+ /*
254
+ * call-seq:
255
+ * easy.proxy_url = "some.url" => "some.url"
256
+ *
257
+ * Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
258
+ * The URL should specify the the host name or dotted IP address. To specify
259
+ * port number in this string, append :[port] to the end of the host name.
260
+ * The proxy string may be prefixed with [protocol]:// since any such prefix
261
+ * will be ignored. The proxy's port number may optionally be specified with
262
+ * the separate option proxy_port .
263
+ *
264
+ * When you tell the library to use an HTTP proxy, libcurl will transparently
265
+ * convert operations to HTTP even if you specify an FTP URL etc. This may have
266
+ * an impact on what other features of the library you can use, such as
267
+ * FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
268
+ * tunneling is activated with proxy_tunnel = true.
269
+ *
270
+ * libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
271
+ * *all_proxy* etc, if any of those is set. The proxy_url option does however
272
+ * override any possibly set environment variables.
273
+ *
274
+ * Starting with libcurl 7.14.1, the proxy host string given in environment
275
+ * variables can be specified the exact same way as the proxy can be set with
276
+ * proxy_url, including protocol prefix (http://) and embedded user + password.
277
+ */
278
+ static VALUE ruby_curl_easy_proxy_url_set(VALUE self, VALUE proxy_url) {
279
+ CURB_OBJECT_SETTER(ruby_curl_easy, proxy_url);
280
+ }
281
+
282
+ /*
283
+ * call-seq:
284
+ * easy.proxy_url => "some.url"
285
+ *
286
+ * Obtain the HTTP Proxy URL that will be used by subsequent calls to +perform+.
287
+ */
288
+ static VALUE ruby_curl_easy_proxy_url_get(VALUE self) {
289
+ CURB_OBJECT_GETTER(ruby_curl_easy, proxy_url);
290
+ }
291
+
292
+ /*
293
+ * call-seq:
294
+ * easy.headers = "Header: val" => ["Header: val", ...]
295
+ * easy.headers = {"Header" => "val" ..., "Header" => "val"} => ["Header: val", ...]
296
+ * easy.headers = ["Header: val" ..., "Header: val"] => ["Header: val", ...]
297
+ *
298
+ * Set custom HTTP headers for following requests. This can be used to add
299
+ * custom headers, or override standard headers used by libcurl. It defaults to a
300
+ * Hash.
301
+ *
302
+ * For example to set a standard or custom header:
303
+ *
304
+ * easy.headers["MyHeader"] = "myval"
305
+ *
306
+ * To remove a standard header (this is useful when removing libcurls default
307
+ * 'Expect: 100-Continue' header when using HTTP form posts):
308
+ *
309
+ * easy.headers["Expect:"] = ''
310
+ *
311
+ * Anything passed to libcurl as a header will be converted to a string during
312
+ * the perform step.
313
+ */
314
+ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
315
+ CURB_OBJECT_SETTER(ruby_curl_easy, headers);
316
+ }
317
+
318
+ /*
319
+ * call-seq:
320
+ * easy.headers => Hash, Array or Str
321
+ *
322
+ * Obtain the custom HTTP headers for following requests.
323
+ */
324
+ static VALUE ruby_curl_easy_headers_get(VALUE self) {
325
+ CURB_OBJECT_GETTER(ruby_curl_easy, headers);
326
+ }
327
+
328
+ /*
329
+ * call-seq:
330
+ * easy.interface = "interface" => "interface"
331
+ *
332
+ * Set the interface name to use as the outgoing network interface.
333
+ * The name can be an interface name, an IP address or a host name.
334
+ */
335
+ static VALUE ruby_curl_easy_interface_set(VALUE self, VALUE interface) {
336
+ CURB_OBJECT_SETTER(ruby_curl_easy, interface);
337
+ }
338
+
339
+ /*
340
+ * call-seq:
341
+ * easy.interface => "interface"
342
+ *
343
+ * Obtain the interface name that is used as the outgoing network interface.
344
+ * The name can be an interface name, an IP address or a host name.
345
+ */
346
+ static VALUE ruby_curl_easy_interface_get(VALUE self) {
347
+ CURB_OBJECT_GETTER(ruby_curl_easy, interface);
348
+ }
349
+
350
+ /*
351
+ * call-seq:
352
+ * easy.userpwd = "pwd string" => "pwd string"
353
+ *
354
+ * Set the username/password string to use for subsequent calls to +perform+.
355
+ * The supplied string should have the form "username:password"
356
+ */
357
+ static VALUE ruby_curl_easy_userpwd_set(VALUE self, VALUE userpwd) {
358
+ CURB_OBJECT_SETTER(ruby_curl_easy, userpwd);
359
+ }
360
+
361
+ /*
362
+ * call-seq:
363
+ * easy.userpwd => "pwd string"
364
+ *
365
+ * Obtain the username/password string that will be used for subsequent
366
+ * calls to +perform+.
367
+ */
368
+ static VALUE ruby_curl_easy_userpwd_get(VALUE self) {
369
+ CURB_OBJECT_GETTER(ruby_curl_easy, userpwd);
370
+ }
371
+
372
+ /*
373
+ * call-seq:
374
+ * easy.proxypwd = "pwd string" => "pwd string"
375
+ *
376
+ * Set the username/password string to use for proxy connection during
377
+ * subsequent calls to +perform+. The supplied string should have the
378
+ * form "username:password"
379
+ */
380
+ static VALUE ruby_curl_easy_proxypwd_set(VALUE self, VALUE proxypwd) {
381
+ CURB_OBJECT_SETTER(ruby_curl_easy, proxypwd);
382
+ }
383
+
384
+ /*
385
+ * call-seq:
386
+ * easy.proxypwd => "pwd string"
387
+ *
388
+ * Obtain the username/password string that will be used for proxy
389
+ * connection during subsequent calls to +perform+. The supplied string
390
+ * should have the form "username:password"
391
+ */
392
+ static VALUE ruby_curl_easy_proxypwd_get(VALUE self) {
393
+ CURB_OBJECT_GETTER(ruby_curl_easy, proxypwd);
394
+ }
395
+
396
+ /*
397
+ * call-seq:
398
+ * easy.cookiejar = "cookiejar.file" => "pwd string"
399
+ *
400
+ * Set a cookiejar file to use for this Curl::Easy instance. This file
401
+ * will be used to persist cookies.
402
+ *
403
+ * *Note* that you must set enable_cookies true to enable the cookie
404
+ * engine, or this option will be ignored.
405
+ */
406
+ static VALUE ruby_curl_easy_cookiejar_set(VALUE self, VALUE cookiejar) {
407
+ CURB_OBJECT_SETTER(ruby_curl_easy, cookiejar);
408
+ }
409
+
410
+ /*
411
+ * call-seq:
412
+ * easy.cookiejar => "cookiejar.file"
413
+ *
414
+ * Obtain the cookiejar file to use for this Curl::Easy instance.
415
+ */
416
+ static VALUE ruby_curl_easy_cookiejar_get(VALUE self) {
417
+ CURB_OBJECT_GETTER(ruby_curl_easy, cookiejar);
418
+ }
419
+
420
+ /*
421
+ * call-seq:
422
+ * easy.cert = "cert.file" => ""
423
+ *
424
+ * Set a cert file to use for this Curl::Easy instance. This file
425
+ * will be used to validate SSL connections.
426
+ *
427
+ */
428
+ static VALUE ruby_curl_easy_cert_set(VALUE self, VALUE cert) {
429
+ CURB_OBJECT_SETTER(ruby_curl_easy, cert);
430
+ }
431
+
432
+ /*
433
+ * call-seq:
434
+ * easy.cert => "cert.file"
435
+ *
436
+ * Obtain the cert file to use for this Curl::Easy instance.
437
+ */
438
+ static VALUE ruby_curl_easy_cert_get(VALUE self) {
439
+ CURB_OBJECT_GETTER(ruby_curl_easy, cert);
440
+ }
441
+
442
+ /*
443
+ * call-seq:
444
+ * easy.encoding= => "string"
445
+ *
446
+ * Set the accepted encoding types, curl will handle all of the decompression
447
+ *
448
+ */
449
+ static VALUE ruby_curl_easy_encoding_set(VALUE self, VALUE encoding) {
450
+ CURB_OBJECT_SETTER(ruby_curl_easy, encoding);
451
+ }
452
+ /*
453
+ * call-seq:
454
+ * easy.encoding => "string"
455
+ *
456
+ * Get the set encoding types
457
+ *
458
+ */
459
+ static VALUE ruby_curl_easy_encoding_get(VALUE self) {
460
+ CURB_OBJECT_GETTER(ruby_curl_easy, encoding);
461
+ }
462
+
463
+ /* ================== IMMED ATTRS ==================*/
464
+
465
+ /*
466
+ * call-seq:
467
+ * easy.local_port = fixnum or nil => fixnum or nil
468
+ *
469
+ * Set the local port that will be used for the following +perform+ calls.
470
+ *
471
+ * Passing +nil+ will return to the default behaviour (no local port
472
+ * preference).
473
+ *
474
+ * This option is ignored if compiled against libcurl < 7.15.2.
475
+ */
476
+ static VALUE ruby_curl_easy_local_port_set(VALUE self, VALUE local_port) {
477
+ CURB_IMMED_PORT_SETTER(ruby_curl_easy, local_port, "port");
478
+ }
479
+
480
+ /*
481
+ * call-seq:
482
+ * easy.local_port => fixnum or nil
483
+ *
484
+ * Obtain the local port that will be used for the following +perform+ calls.
485
+ *
486
+ * This option is ignored if compiled against libcurl < 7.15.2.
487
+ */
488
+ static VALUE ruby_curl_easy_local_port_get(VALUE self) {
489
+ CURB_IMMED_PORT_GETTER(ruby_curl_easy, local_port);
490
+ }
491
+
492
+ /*
493
+ * call-seq:
494
+ * easy.local_port_range = fixnum or nil => fixnum or nil
495
+ *
496
+ * Set the local port range that will be used for the following +perform+
497
+ * calls. This is a number (between 0 and 65535) that determines how far
498
+ * libcurl may deviate from the supplied +local_port+ in order to find
499
+ * an available port.
500
+ *
501
+ * If you set +local_port+ it's also recommended that you set this, since
502
+ * it is fairly likely that your specified port will be unavailable.
503
+ *
504
+ * This option is ignored if compiled against libcurl < 7.15.2.
505
+ */
506
+ static VALUE ruby_curl_easy_local_port_range_set(VALUE self, VALUE local_port_range) {
507
+ CURB_IMMED_PORT_SETTER(ruby_curl_easy, local_port_range, "port range");
508
+ }
509
+
510
+ /*
511
+ * call-seq:
512
+ * easy.local_port_range => fixnum or nil
513
+ *
514
+ * Obtain the local port range that will be used for the following +perform+
515
+ * calls.
516
+ *
517
+ * This option is ignored if compiled against libcurl < 7.15.2.
518
+ */
519
+ static VALUE ruby_curl_easy_local_port_range_get(VALUE self) {
520
+ CURB_IMMED_PORT_GETTER(ruby_curl_easy, local_port_range);
521
+ }
522
+
523
+ /*
524
+ * call-seq:
525
+ * easy.proxy_port = fixnum or nil => fixnum or nil
526
+ *
527
+ * Set the proxy port that will be used for the following +perform+ calls.
528
+ */
529
+ static VALUE ruby_curl_easy_proxy_port_set(VALUE self, VALUE proxy_port) {
530
+ CURB_IMMED_PORT_SETTER(ruby_curl_easy, proxy_port, "port");
531
+ }
532
+
533
+ /*
534
+ * call-seq:
535
+ * easy.proxy_port => fixnum or nil
536
+ *
537
+ * Obtain the proxy port that will be used for the following +perform+ calls.
538
+ */
539
+ static VALUE ruby_curl_easy_proxy_port_get(VALUE self) {
540
+ CURB_IMMED_PORT_GETTER(ruby_curl_easy, proxy_port);
541
+ }
542
+
543
+ /*
544
+ * call-seq:
545
+ * easy.proxy_type = fixnum or nil => fixnum or nil
546
+ *
547
+ * Set the proxy type that will be used for the following +perform+ calls.
548
+ * This should be one of the Curl::CURLPROXY constants.
549
+ */
550
+ static VALUE ruby_curl_easy_proxy_type_set(VALUE self, VALUE proxy_type) {
551
+ CURB_IMMED_SETTER(ruby_curl_easy, proxy_type, -1);
552
+ }
553
+
554
+ /*
555
+ * call-seq:
556
+ * easy.proxy_type => fixnum or nil
557
+ *
558
+ * Obtain the proxy type that will be used for the following +perform+ calls.
559
+ */
560
+ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
561
+ CURB_IMMED_GETTER(ruby_curl_easy, proxy_type, -1);
562
+ }
563
+
564
+ /*
565
+ * call-seq:
566
+ * easy.http_auth_types = fixnum or nil => fixnum or nil
567
+ *
568
+ * Set the HTTP authentication types that may be used for the following
569
+ * +perform+ calls. This is a bitmap made by ORing together the
570
+ * Curl::CURLAUTH constants.
571
+ */
572
+ static VALUE ruby_curl_easy_http_auth_types_set(VALUE self, VALUE http_auth_types) {
573
+ CURB_IMMED_SETTER(ruby_curl_easy, http_auth_types, 0);
574
+ }
575
+
576
+ /*
577
+ * call-seq:
578
+ * easy.http_auth_types => fixnum or nil
579
+ *
580
+ * Obtain the HTTP authentication types that may be used for the following
581
+ * +perform+ calls.
582
+ */
583
+ static VALUE ruby_curl_easy_http_auth_types_get(VALUE self) {
584
+ CURB_IMMED_GETTER(ruby_curl_easy, http_auth_types, 0);
585
+ }
586
+
587
+ /*
588
+ * call-seq:
589
+ * easy.proxy_auth_types = fixnum or nil => fixnum or nil
590
+ *
591
+ * Set the proxy authentication types that may be used for the following
592
+ * +perform+ calls. This is a bitmap made by ORing together the
593
+ * Curl::CURLAUTH constants.
594
+ */
595
+ static VALUE ruby_curl_easy_proxy_auth_types_set(VALUE self, VALUE proxy_auth_types) {
596
+ CURB_IMMED_SETTER(ruby_curl_easy, proxy_auth_types, 0);
597
+ }
598
+
599
+ /*
600
+ * call-seq:
601
+ * easy.proxy_auth_types => fixnum or nil
602
+ *
603
+ * Obtain the proxy authentication types that may be used for the following
604
+ * +perform+ calls.
605
+ */
606
+ static VALUE ruby_curl_easy_proxy_auth_types_get(VALUE self) {
607
+ CURB_IMMED_GETTER(ruby_curl_easy, proxy_auth_types, 0);
608
+ }
609
+
610
+ /*
611
+ * call-seq:
612
+ * easy.max_redirects = fixnum or nil => fixnum or nil
613
+ *
614
+ * Set the maximum number of redirections to follow in the following +perform+
615
+ * calls. Set to nil or -1 allow an infinite number (the default). Setting this
616
+ * option only makes sense if +follow_location+ is also set true.
617
+ *
618
+ * With libcurl >= 7.15.1, setting this to 0 will cause libcurl to refuse any
619
+ * redirect.
620
+ */
621
+ static VALUE ruby_curl_easy_max_redirects_set(VALUE self, VALUE max_redirs) {
622
+ CURB_IMMED_SETTER(ruby_curl_easy, max_redirs, -1);
623
+ }
624
+
625
+ /*
626
+ * call-seq:
627
+ * easy.max_redirects => fixnum or nil
628
+ *
629
+ * Obtain the maximum number of redirections to follow in the following
630
+ * +perform+ calls.
631
+ */
632
+ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
633
+ CURB_IMMED_GETTER(ruby_curl_easy, max_redirs, -1);
634
+ }
635
+
636
+ /*
637
+ * call-seq:
638
+ * easy.timeout = fixnum or nil => fixnum or nil
639
+ *
640
+ * Set the maximum time in seconds that you allow the libcurl transfer
641
+ * operation to take. Normally, name lookups can take a considerable time
642
+ * and limiting operations to less than a few minutes risk aborting
643
+ * perfectly normal operations.
644
+ *
645
+ * Set to nil (or zero) to disable timeout (it will then only timeout
646
+ * on the system's internal timeouts).
647
+ */
648
+ static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout) {
649
+ CURB_IMMED_SETTER(ruby_curl_easy, timeout, 0);
650
+ }
651
+
652
+ /*
653
+ * call-seq:
654
+ * easy.timeout => fixnum or nil
655
+ *
656
+ * Obtain the maximum time in seconds that you allow the libcurl transfer
657
+ * operation to take.
658
+ */
659
+ static VALUE ruby_curl_easy_timeout_get(VALUE self, VALUE timeout) {
660
+ CURB_IMMED_GETTER(ruby_curl_easy, timeout, 0);
661
+ }
662
+
663
+ /*
664
+ * call-seq:
665
+ * easy.connect_timeout = fixnum or nil => fixnum or nil
666
+ *
667
+ * Set the maximum time in seconds that you allow the connection to the
668
+ * server to take. This only limits the connection phase, once it has
669
+ * connected, this option is of no more use.
670
+ *
671
+ * Set to nil (or zero) to disable connection timeout (it will then only
672
+ * timeout on the system's internal timeouts).
673
+ */
674
+ static VALUE ruby_curl_easy_connect_timeout_set(VALUE self, VALUE connect_timeout) {
675
+ CURB_IMMED_SETTER(ruby_curl_easy, connect_timeout, 0);
676
+ }
677
+
678
+ /*
679
+ * call-seq:
680
+ * easy.connect_timeout => fixnum or nil
681
+ *
682
+ * Obtain the maximum time in seconds that you allow the connection to the
683
+ * server to take.
684
+ */
685
+ static VALUE ruby_curl_easy_connect_timeout_get(VALUE self, VALUE connect_timeout) {
686
+ CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout, 0);
687
+ }
688
+
689
+ /*
690
+ * call-seq:
691
+ * easy.dns_cache_timeout = fixnum or nil => fixnum or nil
692
+ *
693
+ * Set the dns cache timeout in seconds. Name resolves will be kept in
694
+ * memory for this number of seconds. Set to zero (0) to completely disable
695
+ * caching, or set to nil (or -1) to make the cached entries remain forever.
696
+ * By default, libcurl caches this info for 60 seconds.
697
+ */
698
+ static VALUE ruby_curl_easy_dns_cache_timeout_set(VALUE self, VALUE dns_cache_timeout) {
699
+ CURB_IMMED_SETTER(ruby_curl_easy, dns_cache_timeout, -1);
700
+ }
701
+
702
+ /*
703
+ * call-seq:
704
+ * easy.dns_cache_timeout => fixnum or nil
705
+ *
706
+ * Obtain the dns cache timeout in seconds.
707
+ */
708
+ static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self, VALUE dns_cache_timeout) {
709
+ CURB_IMMED_GETTER(ruby_curl_easy, dns_cache_timeout, -1);
710
+ }
711
+
712
+ /*
713
+ * call-seq:
714
+ * easy.ftp_response_timeout = fixnum or nil => fixnum or nil
715
+ *
716
+ * Set a timeout period (in seconds) on the amount of time that the server
717
+ * is allowed to take in order to generate a response message for a command
718
+ * before the session is considered hung. While curl is waiting for a
719
+ * response, this value overrides +timeout+. It is recommended that if used
720
+ * in conjunction with +timeout+, you set +ftp_response_timeout+ to a value
721
+ * smaller than +timeout+.
722
+ *
723
+ * Ignored if libcurl version is < 7.10.8.
724
+ */
725
+ static VALUE ruby_curl_easy_ftp_response_timeout_set(VALUE self, VALUE ftp_response_timeout) {
726
+ CURB_IMMED_SETTER(ruby_curl_easy, ftp_response_timeout, 0);
727
+ }
728
+
729
+ /*
730
+ * call-seq:
731
+ * easy.ftp_response_timeout => fixnum or nil
732
+ *
733
+ * Obtain the maximum time that libcurl will wait for FTP command responses.
734
+ */
735
+ static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self, VALUE ftp_response_timeout) {
736
+ CURB_IMMED_GETTER(ruby_curl_easy, ftp_response_timeout, 0);
737
+ }
738
+
739
+ /* ================== BOOL ATTRS ===================*/
740
+
741
+ /*
742
+ * call-seq:
743
+ * proxy_tunnel = boolean => boolean
744
+ *
745
+ * Configure whether this Curl instance will use proxy tunneling.
746
+ */
747
+ static VALUE ruby_curl_easy_proxy_tunnel_set(VALUE self, VALUE proxy_tunnel) {
748
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, proxy_tunnel);
749
+ }
750
+
751
+ /*
752
+ * call-seq:
753
+ * proxy_tunnel? => boolean
754
+ *
755
+ * Determine whether this Curl instance will use proxy tunneling.
756
+ */
757
+ static VALUE ruby_curl_easy_proxy_tunnel_q(VALUE self) {
758
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, proxy_tunnel);
759
+ }
760
+
761
+ /*
762
+ * call-seq:
763
+ * fetch_file_time = boolean => boolean
764
+ *
765
+ * Configure whether this Curl instance will fetch remote file
766
+ * times, if available.
767
+ */
768
+ static VALUE ruby_curl_easy_fetch_file_time_set(VALUE self, VALUE fetch_file_time) {
769
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, fetch_file_time);
770
+ }
771
+
772
+ /*
773
+ * call-seq:
774
+ * fetch_file_time? => boolean
775
+ *
776
+ * Determine whether this Curl instance will fetch remote file
777
+ * times, if available.
778
+ */
779
+ static VALUE ruby_curl_easy_fetch_file_time_q(VALUE self) {
780
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, fetch_file_time);
781
+ }
782
+
783
+ /*
784
+ * call-seq:
785
+ * ssl_verify_peer = boolean => boolean
786
+ *
787
+ * Configure whether this Curl instance will verify the SSL peer
788
+ * certificate. When true (the default), and the verification fails to
789
+ * prove that the certificate is authentic, the connection fails. When
790
+ * false, the connection succeeds regardless.
791
+ *
792
+ * Authenticating the certificate is not by itself very useful. You
793
+ * typically want to ensure that the server, as authentically identified
794
+ * by its certificate, is the server you mean to be talking to.
795
+ * The ssl_verify_host? options controls that.
796
+ */
797
+ static VALUE ruby_curl_easy_ssl_verify_peer_set(VALUE self, VALUE ssl_verify_peer) {
798
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, ssl_verify_peer);
799
+ }
800
+
801
+ /*
802
+ * call-seq:
803
+ * ssl_verify_peer? => boolean
804
+ *
805
+ * Determine whether this Curl instance will verify the SSL peer
806
+ * certificate.
807
+ */
808
+ static VALUE ruby_curl_easy_ssl_verify_peer_q(VALUE self) {
809
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, ssl_verify_peer);
810
+ }
811
+
812
+ /*
813
+ * call-seq:
814
+ * ssl_verify_host = boolean => boolean
815
+ *
816
+ * Configure whether this Curl instance will verify that the server cert
817
+ * is for the server it is known as. When true (the default) the server
818
+ * certificate must indicate that the server is the server to which you
819
+ * meant to connect, or the connection fails. When false, the connection
820
+ * will succeed regardless of the names in the certificate.
821
+ *
822
+ * this option controls is of the identity that the server claims.
823
+ * The server could be lying. To control lying, see ssl_verify_peer? .
824
+ */
825
+ static VALUE ruby_curl_easy_ssl_verify_host_set(VALUE self, VALUE ssl_verify_host) {
826
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, ssl_verify_host);
827
+ }
828
+
829
+ /*
830
+ * call-seq:
831
+ * ssl_verify_host? => boolean
832
+ *
833
+ * Determine whether this Curl instance will verify that the server cert
834
+ * is for the server it is known as.
835
+ */
836
+ static VALUE ruby_curl_easy_ssl_verify_host_q(VALUE self) {
837
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, ssl_verify_host);
838
+ }
839
+
840
+ /*
841
+ * call-seq:
842
+ * header_in_body = boolean => boolean
843
+ *
844
+ * Configure whether this Curl instance will return HTTP headers
845
+ * combined with body data. If this option is set true, both header
846
+ * and body data will go to +body_str+ (or the configured +on_body+ handler).
847
+ */
848
+ static VALUE ruby_curl_easy_header_in_body_set(VALUE self, VALUE header_in_body) {
849
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, header_in_body);
850
+ }
851
+
852
+ /*
853
+ * call-seq:
854
+ * header_in_body? => boolean
855
+ *
856
+ * Determine whether this Curl instance will verify the SSL peer
857
+ * certificate.
858
+ */
859
+ static VALUE ruby_curl_easy_header_in_body_q(VALUE self) {
860
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, header_in_body);
861
+ }
862
+
863
+ /*
864
+ * call-seq:
865
+ * use_netrc = boolean => boolean
866
+ *
867
+ * Configure whether this Curl instance will use data from the user's
868
+ * .netrc file for FTP connections.
869
+ */
870
+ static VALUE ruby_curl_easy_use_netrc_set(VALUE self, VALUE use_netrc) {
871
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, use_netrc);
872
+ }
873
+
874
+ /*
875
+ * call-seq:
876
+ * use_netrc? => boolean
877
+ *
878
+ * Determine whether this Curl instance will use data from the user's
879
+ * .netrc file for FTP connections.
880
+ */
881
+ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
882
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, use_netrc);
883
+ }
884
+
885
+ /*
886
+ * call-seq:
887
+ * follow_location = boolean => boolean
888
+ *
889
+ * Configure whether this Curl instance will follow Location: headers
890
+ * in HTTP responses. Redirects will only be followed to the extent
891
+ * specified by +max_redirects+.
892
+ */
893
+ static VALUE ruby_curl_easy_follow_location_set(VALUE self, VALUE follow_location) {
894
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, follow_location);
895
+ }
896
+
897
+ /*
898
+ * call-seq:
899
+ * follow_location? => boolean
900
+ *
901
+ * Determine whether this Curl instance will follow Location: headers
902
+ * in HTTP responses.
903
+ */
904
+ static VALUE ruby_curl_easy_follow_location_q(VALUE self) {
905
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, follow_location);
906
+ }
907
+
908
+ /*
909
+ * call-seq:
910
+ * unrestricted_auth = boolean => boolean
911
+ *
912
+ * Configure whether this Curl instance may use any HTTP authentication
913
+ * method available when necessary.
914
+ */
915
+ static VALUE ruby_curl_easy_unrestricted_auth_set(VALUE self, VALUE unrestricted_auth) {
916
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, unrestricted_auth);
917
+ }
918
+
919
+ /*
920
+ * call-seq:
921
+ * unrestricted_auth? => boolean
922
+ *
923
+ * Determine whether this Curl instance may use any HTTP authentication
924
+ * method available when necessary.
925
+ */
926
+ static VALUE ruby_curl_easy_unrestricted_auth_q(VALUE self) {
927
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, unrestricted_auth);
928
+ }
929
+
930
+ /*
931
+ * call-seq:
932
+ * easy.verbose = boolean => boolean
933
+ *
934
+ * Configure whether this Curl instance gives verbose output to STDERR
935
+ * during transfers. Ignored if this instance has an on_debug handler.
936
+ */
937
+ static VALUE ruby_curl_easy_verbose_set(VALUE self, VALUE verbose) {
938
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, verbose);
939
+ }
940
+
941
+ /*
942
+ * call-seq:
943
+ * easy.verbose? => boolean
944
+ *
945
+ * Determine whether this Curl instance gives verbose output to STDERR
946
+ * during transfers.
947
+ */
948
+ static VALUE ruby_curl_easy_verbose_q(VALUE self) {
949
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, verbose);
950
+ }
951
+
952
+ /*
953
+ * call-seq:
954
+ * easy.multipart_form_post = boolean => boolean
955
+ *
956
+ * Configure whether this Curl instance uses multipart/formdata content
957
+ * type for HTTP POST requests. If this is false (the default), then the
958
+ * application/x-www-form-urlencoded content type is used for the form
959
+ * data.
960
+ *
961
+ * If this is set true, you must pass one or more PostField instances
962
+ * to the http_post method - no support for posting multipart forms from
963
+ * a string is provided.
964
+ */
965
+ static VALUE ruby_curl_easy_multipart_form_post_set(VALUE self, VALUE multipart_form_post)
966
+ {
967
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, multipart_form_post);
968
+ }
969
+
970
+ /*
971
+ * call-seq:
972
+ * easy.multipart_form_post? => boolean
973
+ *
974
+ * Determine whether this Curl instance uses multipart/formdata content
975
+ * type for HTTP POST requests.
976
+ */
977
+ static VALUE ruby_curl_easy_multipart_form_post_q(VALUE self) {
978
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, multipart_form_post);
979
+ }
980
+
981
+ /*
982
+ * call-seq:
983
+ * easy.enable_cookies = boolean => boolean
984
+ *
985
+ * Configure whether the libcurl cookie engine is enabled for this Curl::Easy
986
+ * instance.
987
+ */
988
+ static VALUE ruby_curl_easy_enable_cookies_set(VALUE self, VALUE enable_cookies)
989
+ {
990
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, enable_cookies);
991
+ }
992
+
993
+ /*
994
+ * call-seq:
995
+ * easy.enable_cookies? => boolean
996
+ *
997
+ * Determine whether the libcurl cookie engine is enabled for this
998
+ * Curl::Easy instance.
999
+ */
1000
+ static VALUE ruby_curl_easy_enable_cookies_q(VALUE self) {
1001
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, enable_cookies);
1002
+ }
1003
+
1004
+ /* ================= EVENT PROCS ================== */
1005
+
1006
+ /*
1007
+ * call-seq:
1008
+ * easy.on_body { |body_data| ... } => &lt;old handler&gt;
1009
+ *
1010
+ * Assign or remove the +on_body+ handler for this Curl::Easy instance.
1011
+ * To remove a previously-supplied handler, call this method with no
1012
+ * attached block.
1013
+ *
1014
+ * The +on_body+ handler is called for each chunk of response body passed back
1015
+ * by libcurl during +perform+. It should perform any processing necessary,
1016
+ * and return the actual number of bytes handled. Normally, this will
1017
+ * equal the length of the data string, and CURL will continue processing.
1018
+ * If the returned length does not equal the input length, CURL will abort
1019
+ * the processing with a Curl::Err::AbortedByCallbackError.
1020
+ */
1021
+ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
1022
+ CURB_HANDLER_PROC_SETTER(ruby_curl_easy, body_proc);
1023
+ }
1024
+
1025
+ /*
1026
+ * call-seq:
1027
+ * easy.on_success { ... } => &lt;old handler&gt;
1028
+ *
1029
+ * Assign or remove the +on_success+ handler for this Curl::Easy instance.
1030
+ * To remove a previously-supplied handler, call this method with no
1031
+ * attached block.
1032
+ *
1033
+ * The +on_success+ handler is called when the request is finished with a
1034
+ * status of 20x
1035
+ */
1036
+ static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
1037
+ CURB_HANDLER_PROC_SETTER(ruby_curl_easy, success_proc);
1038
+ }
1039
+
1040
+ /*
1041
+ * call-seq:
1042
+ * easy.on_failure { ... } => &lt;old handler&gt;
1043
+ *
1044
+ * Assign or remove the +on_failure+ handler for this Curl::Easy instance.
1045
+ * To remove a previously-supplied handler, call this method with no
1046
+ * attached block.
1047
+ *
1048
+ * The +on_failure+ handler is called when the request is finished with a
1049
+ * status of 50x
1050
+ */
1051
+ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
1052
+ CURB_HANDLER_PROC_SETTER(ruby_curl_easy, failure_proc);
1053
+ }
1054
+
1055
+ /*
1056
+ * call-seq:
1057
+ * easy.on_complete { ... } => &lt;old handler&gt;
1058
+ *
1059
+ * Assign or remove the +on_complete+ handler for this Curl::Easy instance.
1060
+ * To remove a previously-supplied handler, call this method with no
1061
+ * attached block.
1062
+ *
1063
+ * The +on_complete+ handler is called when the request is finished.
1064
+ */
1065
+ static VALUE ruby_curl_easy_on_complete_set(int argc, VALUE *argv, VALUE self) {
1066
+ CURB_HANDLER_PROC_SETTER(ruby_curl_easy, complete_proc);
1067
+ }
1068
+
1069
+ /*
1070
+ * call-seq:
1071
+ * easy.on_header { |header_data| ... } => &lt;old handler&gt;
1072
+ *
1073
+ * Assign or remove the +on_header+ handler for this Curl::Easy instance.
1074
+ * To remove a previously-supplied handler, call this method with no
1075
+ * attached block.
1076
+ *
1077
+ * The +on_header+ handler is called for each chunk of response header passed
1078
+ * back by libcurl during +perform+. The semantics are the same as for the
1079
+ * block supplied to +on_body+.
1080
+ */
1081
+ static VALUE ruby_curl_easy_on_header_set(int argc, VALUE *argv, VALUE self) {
1082
+ CURB_HANDLER_PROC_SETTER(ruby_curl_easy, header_proc);
1083
+ }
1084
+
1085
+ /*
1086
+ * call-seq:
1087
+ * easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } => &lt;old handler&gt;
1088
+ *
1089
+ * Assign or remove the +on_progress+ handler for this Curl::Easy instance.
1090
+ * To remove a previously-supplied handler, call this method with no
1091
+ * attached block.
1092
+ *
1093
+ * The +on_progress+ handler is called regularly by libcurl (approximately once
1094
+ * per second) during transfers to allow the application to receive progress
1095
+ * information. There is no guarantee that the reported progress will change
1096
+ * between calls.
1097
+ *
1098
+ * The result of the block call determines whether libcurl continues the transfer.
1099
+ * Returning a non-true value (i.e. nil or false) will cause the transfer to abort,
1100
+ * throwing a Curl::Err::AbortedByCallbackError.
1101
+ */
1102
+ static VALUE ruby_curl_easy_on_progress_set(int argc, VALUE *argv, VALUE self) {
1103
+ CURB_HANDLER_PROC_SETTER(ruby_curl_easy, progress_proc);
1104
+ }
1105
+
1106
+ /*
1107
+ * call-seq:
1108
+ * easy.on_debug { |type, data| ... } => &lt;old handler&gt;
1109
+ *
1110
+ * Assign or remove the +on_debug+ handler for this Curl::Easy instance.
1111
+ * To remove a previously-supplied handler, call this method with no
1112
+ * attached block.
1113
+ *
1114
+ * The +on_debug+ handler, if configured, will receive detailed information
1115
+ * from libcurl during the perform call. This can be useful for debugging.
1116
+ * Setting a debug handler overrides libcurl's internal handler, disabling
1117
+ * any output from +verbose+, if set.
1118
+ *
1119
+ * The type argument will match one of the Curl::Easy::CURLINFO_XXXX
1120
+ * constants, and specifies the kind of information contained in the
1121
+ * data. The data is passed as a String.
1122
+ */
1123
+ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
1124
+ CURB_HANDLER_PROC_SETTER(ruby_curl_easy, debug_proc);
1125
+ }
1126
+
1127
+
1128
+ /* =================== PERFORM =====================*/
1129
+
1130
+ /***********************************************
1131
+ * This is an rb_iterate callback used to set up http headers.
1132
+ */
1133
+ static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
1134
+ VALUE header_str = Qnil;
1135
+
1136
+ //rb_p(header);
1137
+
1138
+ if (rb_type(header) == T_ARRAY) {
1139
+ // we're processing a hash, header is [name, val]
1140
+ VALUE name, value;
1141
+
1142
+ name = rb_obj_as_string(rb_ary_entry(header, 0));
1143
+ value = rb_obj_as_string(rb_ary_entry(header, 1));
1144
+
1145
+ // This is a bit inefficient, but we don't want to be modifying
1146
+ // the actual values in the original hash.
1147
+ header_str = rb_str_plus(name, rb_str_new2(": "));
1148
+ header_str = rb_str_plus(header_str, value);
1149
+ } else {
1150
+ header_str = rb_obj_as_string(header);
1151
+ }
1152
+
1153
+ //rb_p(header_str);
1154
+
1155
+ *list = curl_slist_append(*list, StringValuePtr(header_str));
1156
+ return header_str;
1157
+ }
1158
+
1159
+ /***********************************************
1160
+ *
1161
+ * Setup a connection
1162
+ *
1163
+ * Always returns Qtrue, rb_raise on error.
1164
+ */
1165
+ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, VALUE *body_buffer, VALUE *header_buffer, struct curl_slist **hdrs ) {
1166
+ // TODO this could do with a bit of refactoring...
1167
+ CURL *curl;
1168
+
1169
+ curl = rbce->curl;
1170
+
1171
+ if (rbce->url == Qnil) {
1172
+ rb_raise(eCurlErrError, "No URL supplied");
1173
+ }
1174
+
1175
+ VALUE url = rb_check_string_type(rbce->url);
1176
+
1177
+ // Need to configure the handler as per settings in rbce
1178
+ curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
1179
+
1180
+ // network stuff and auth
1181
+ if (rbce->interface != Qnil) {
1182
+ curl_easy_setopt(curl, CURLOPT_INTERFACE, StringValuePtr(rbce->interface));
1183
+ } else {
1184
+ curl_easy_setopt(curl, CURLOPT_INTERFACE, NULL);
1185
+ }
1186
+
1187
+ if (rbce->userpwd != Qnil) {
1188
+ curl_easy_setopt(curl, CURLOPT_USERPWD, StringValuePtr(rbce->userpwd));
1189
+ } else {
1190
+ curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
1191
+ }
1192
+
1193
+ if (rbce->proxy_url != Qnil) {
1194
+ curl_easy_setopt(curl, CURLOPT_PROXY, StringValuePtr(rbce->proxy_url));
1195
+ } else {
1196
+ curl_easy_setopt(curl, CURLOPT_PROXY, NULL);
1197
+ }
1198
+
1199
+ if (rbce->proxypwd != Qnil) {
1200
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, StringValuePtr(rbce->proxypwd));
1201
+ } else {
1202
+ curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
1203
+ }
1204
+
1205
+ // body/header procs
1206
+ if (rbce->body_proc != Qnil) {
1207
+ *body_buffer = Qnil;
1208
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler);
1209
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce->body_proc);
1210
+ } else {
1211
+ *body_buffer = rb_str_buf_new(32768);
1212
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&default_data_handler);
1213
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, *body_buffer);
1214
+ }
1215
+
1216
+ if (rbce->header_proc != Qnil) {
1217
+ *header_buffer = Qnil;
1218
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler);
1219
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce->header_proc);
1220
+ } else {
1221
+ *header_buffer = rb_str_buf_new(32768);
1222
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&default_data_handler);
1223
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, *header_buffer);
1224
+ }
1225
+
1226
+ /* encoding */
1227
+ if (rbce->encoding != Qnil) {
1228
+ curl_easy_setopt(curl, CURLOPT_ENCODING, StringValuePtr(rbce->encoding));
1229
+ }
1230
+
1231
+ // progress and debug procs
1232
+ if (rbce->progress_proc != Qnil) {
1233
+ curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&proc_progress_handler);
1234
+ curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, rbce->progress_proc);
1235
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
1236
+ } else {
1237
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
1238
+ }
1239
+
1240
+ if (rbce->debug_proc != Qnil) {
1241
+ curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, (curl_debug_callback)&proc_debug_handler);
1242
+ curl_easy_setopt(curl, CURLOPT_DEBUGDATA, rbce->debug_proc);
1243
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
1244
+ } else {
1245
+ // have to remove handler to re-enable standard verbosity
1246
+ curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, NULL);
1247
+ curl_easy_setopt(curl, CURLOPT_DEBUGDATA, NULL);
1248
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, rbce->verbose);
1249
+ }
1250
+
1251
+ /* general opts */
1252
+
1253
+ curl_easy_setopt(curl, CURLOPT_HEADER, rbce->header_in_body);
1254
+
1255
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, rbce->follow_location);
1256
+ curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
1257
+
1258
+ curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, rbce->proxy_tunnel);
1259
+ curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
1260
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
1261
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_peer);
1262
+
1263
+ if ((rbce->use_netrc != Qnil) && (rbce->use_netrc != Qfalse)) {
1264
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_OPTIONAL);
1265
+ } else {
1266
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_IGNORED);
1267
+ }
1268
+
1269
+ curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
1270
+
1271
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, rbce->timeout);
1272
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
1273
+ curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
1274
+
1275
+ #if LIBCURL_VERSION_NUM >= 0x070a08
1276
+ curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
1277
+ #else
1278
+ if (rbce->ftp_response_timeout > 0) {
1279
+ rb_warn("Installed libcurl is too old to support ftp_response_timeout");
1280
+ }
1281
+ #endif
1282
+
1283
+ // Set up localport / proxy port
1284
+ // FIXME these won't get returned to default if they're unset Ruby
1285
+ if (rbce->proxy_port > 0) {
1286
+ curl_easy_setopt(curl, CURLOPT_PROXYPORT, rbce->proxy_port);
1287
+ }
1288
+
1289
+ if (rbce->local_port > 0) {
1290
+ #if LIBCURL_VERSION_NUM >= 0x070f02
1291
+ curl_easy_setopt(curl, CURLOPT_LOCALPORT, rbce->local_port);
1292
+
1293
+ if (rbce->local_port_range > 0) {
1294
+ curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, rbce->local_port_range);
1295
+ }
1296
+ #else
1297
+ rb_warn("Installed libcurl is too old to support local_port");
1298
+ #endif
1299
+ }
1300
+
1301
+ if (rbce->proxy_type != -1) {
1302
+ #if LIBCURL_VERSION_NUM >= 0x070a00
1303
+ if (rbce->proxy_type == -2) {
1304
+ rb_warn("Installed libcurl is too old to support the selected proxy type");
1305
+ } else {
1306
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, rbce->proxy_type);
1307
+ }
1308
+ } else {
1309
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
1310
+ #else
1311
+ rb_warn("Installed libcurl is too old to support proxy_type");
1312
+ #endif
1313
+ }
1314
+
1315
+ if (rbce->http_auth_types > 0) {
1316
+ #if LIBCURL_VERSION_NUM >= 0x070a06
1317
+ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, rbce->http_auth_types);
1318
+ } else {
1319
+ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
1320
+ #else
1321
+ rb_warn("Installed libcurl is too old to support http_auth_types");
1322
+ #endif
1323
+ }
1324
+
1325
+ if (rbce->proxy_auth_types > 0) {
1326
+ #if LIBCURL_VERSION_NUM >= 0x070a07
1327
+ curl_easy_setopt(curl, CURLOPT_PROXYAUTH, rbce->proxy_auth_types);
1328
+ } else {
1329
+ curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
1330
+ #else
1331
+ rb_warn("Installed libcurl is too old to support proxy_auth_types");
1332
+ #endif
1333
+ }
1334
+
1335
+ /* Set up HTTP cookie handling if necessary
1336
+ FIXME this may not get disabled if it's enabled, the disabled again from ruby.
1337
+ */
1338
+ if (rbce->enable_cookies) {
1339
+ if (rbce->cookiejar != Qnil) {
1340
+ curl_easy_setopt(curl, CURLOPT_COOKIEJAR, StringValuePtr(rbce->cookiejar));
1341
+ } else {
1342
+ curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); /* "" = magic to just enable */
1343
+ }
1344
+ }
1345
+
1346
+ /* Set up HTTPS cert handling if necessary */
1347
+ if (rbce->cert != Qnil) {
1348
+ curl_easy_setopt(curl, CURLOPT_SSLCERT, StringValuePtr(rbce->cert));
1349
+ curl_easy_setopt(curl, CURLOPT_CAINFO, "/usr/local/share/curl/curl-ca-bundle.crt");
1350
+ }
1351
+
1352
+ /* Setup HTTP headers if necessary */
1353
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); // clear
1354
+
1355
+ if (rbce->headers != Qnil) {
1356
+ if ((rb_type(rbce->headers) == T_ARRAY) || (rb_type(rbce->headers) == T_HASH)) {
1357
+ rb_iterate(rb_each, rbce->headers, cb_each_http_header, (VALUE)hdrs);
1358
+ } else {
1359
+ VALUE headers_str = rb_obj_as_string(rbce->headers);
1360
+ *hdrs = curl_slist_append(*hdrs, StringValuePtr(headers_str));
1361
+ }
1362
+
1363
+ if (*hdrs) {
1364
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *hdrs);
1365
+ }
1366
+ }
1367
+
1368
+ return Qnil;
1369
+ }
1370
+ /***********************************************
1371
+ *
1372
+ * Clean up a connection
1373
+ *
1374
+ * Always returns Qtrue.
1375
+ */
1376
+ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce, VALUE bodybuf, VALUE headerbuf, struct curl_slist *headers ) {
1377
+
1378
+ // Free everything up
1379
+ if (headers) {
1380
+ curl_slist_free_all(headers);
1381
+ rbce->curl_headers = NULL;
1382
+ }
1383
+
1384
+ // Sort out the built-in body/header data.
1385
+ if (bodybuf != Qnil) {
1386
+ rbce->body_data = rb_str_to_str(bodybuf);
1387
+ } else {
1388
+ rbce->body_data = Qnil;
1389
+ }
1390
+
1391
+ if (headerbuf != Qnil) {
1392
+ rbce->header_data = rb_str_to_str(headerbuf);
1393
+ } else {
1394
+ rbce->header_data = Qnil;
1395
+ }
1396
+
1397
+ return Qnil;
1398
+ }
1399
+
1400
+ /***********************************************
1401
+ *
1402
+ * This is the main worker for the perform methods (get, post, head, put).
1403
+ * It's not surfaced as a Ruby method - instead, the individual request
1404
+ * methods are responsible for setting up stuff specific to that type,
1405
+ * then calling this to handle common stuff and do the perform.
1406
+ *
1407
+ * Always returns Qtrue, rb_raise on error.
1408
+ *
1409
+ */
1410
+ static VALUE handle_perform(VALUE self, ruby_curl_easy *rbce) {
1411
+
1412
+ int msgs;
1413
+ int still_running = 1;
1414
+ CURLcode result = -1;
1415
+ CURLMcode mcode = -1;
1416
+ CURLM *multi_handle = curl_multi_init();
1417
+ struct curl_slist *headers = NULL;
1418
+ VALUE bodybuf = Qnil, headerbuf = Qnil;
1419
+ // char errors[CURL_ERROR_SIZE*2];
1420
+
1421
+ ruby_curl_easy_setup(rbce, &bodybuf, &headerbuf, &headers);
1422
+ // curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, errors);
1423
+ // curl_easy_setopt(rbce->curl, CURLOPT_VERBOSE, 1);
1424
+
1425
+ // if( rb_thread_alone() ) {
1426
+ // result = curl_easy_perform(rbce->curl);
1427
+ // }
1428
+ // else {
1429
+
1430
+ /* NOTE:
1431
+ * We create an Curl multi handle here and use rb_thread_select allowing other ruby threads to
1432
+ * perform actions... ideally we'd have just 1 shared multi handle per all curl easy handles globally
1433
+ */
1434
+ mcode = curl_multi_add_handle(multi_handle, rbce->curl);
1435
+ if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
1436
+ raise_curl_multi_error_exception(mcode);
1437
+ }
1438
+
1439
+ while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &still_running)) ) ;
1440
+
1441
+ if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
1442
+ raise_curl_multi_error_exception(mcode);
1443
+ }
1444
+
1445
+ while(still_running) {
1446
+ struct timeval timeout;
1447
+ int rc; /* select() return code */
1448
+ int maxfd;
1449
+
1450
+ fd_set fdread;
1451
+ fd_set fdwrite;
1452
+ fd_set fdexcep;
1453
+
1454
+ FD_ZERO(&fdread);
1455
+ FD_ZERO(&fdwrite);
1456
+ FD_ZERO(&fdexcep);
1457
+
1458
+ /* set a suitable timeout to play around with */
1459
+ timeout.tv_sec = 1;
1460
+ timeout.tv_usec = 0;
1461
+ /* get file descriptors from the transfers */
1462
+ mcode = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
1463
+ if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
1464
+ raise_curl_multi_error_exception(mcode);
1465
+ }
1466
+
1467
+ rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
1468
+ if (rc < 0) {
1469
+ rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
1470
+ }
1471
+
1472
+ switch(rc) {
1473
+ case 0:
1474
+ default:
1475
+ /* timeout or readable/writable sockets */
1476
+ while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &still_running)) );
1477
+ break;
1478
+ }
1479
+
1480
+ if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
1481
+ raise_curl_multi_error_exception(mcode);
1482
+ }
1483
+
1484
+ }
1485
+
1486
+ /* check for errors */
1487
+ CURLMsg *msg = curl_multi_info_read(multi_handle, &msgs);
1488
+ if (msg && msg->msg == CURLMSG_DONE) {
1489
+ result = msg->data.result;
1490
+ }
1491
+
1492
+ curl_multi_remove_handle(multi_handle, rbce->curl);
1493
+ curl_multi_cleanup(multi_handle);
1494
+ // }
1495
+
1496
+ ruby_curl_easy_cleanup(self, rbce, bodybuf, headerbuf, headers);
1497
+
1498
+ if (rbce->complete_proc != Qnil) {
1499
+ rb_funcall( rbce->complete_proc, idCall, 1, self );
1500
+ }
1501
+
1502
+ /* check the request status and determine if on_success or on_failure should be called */
1503
+ long response_code = -1;
1504
+ curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &response_code);
1505
+ if (result != 0) {
1506
+ // printf("error: %s\n", errors);
1507
+ if (rbce->failure_proc != Qnil) {
1508
+ rb_funcall( rbce->failure_proc, idCall, 1, self );
1509
+ } else {
1510
+ raise_curl_easy_error_exception(result);
1511
+ }
1512
+ }
1513
+ else if (rbce->success_proc != Qnil &&
1514
+ /* NOTE: we allow response_code == 0, in the case the file is being read from disk */
1515
+ ((response_code >= 200 && response_code < 300) || response_code == 0)) {
1516
+ rb_funcall( rbce->success_proc, idCall, 1, self );
1517
+ }
1518
+ else if (rbce->failure_proc != Qnil &&
1519
+ (response_code >= 300 && response_code < 600)) {
1520
+ rb_funcall( rbce->failure_proc, idCall, 1, self );
1521
+ }
1522
+
1523
+ return Qtrue;
1524
+ }
1525
+
1526
+ /*
1527
+ * call-seq:
1528
+ * easy.http_get => true
1529
+ *
1530
+ * GET the currently configured URL using the current options set for
1531
+ * this Curl::Easy instance. This method always returns true, or raises
1532
+ * an exception (defined under Curl::Err) on error.
1533
+ */
1534
+ static VALUE ruby_curl_easy_perform_get(VALUE self) {
1535
+ ruby_curl_easy *rbce;
1536
+ CURL *curl;
1537
+
1538
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1539
+ curl = rbce->curl;
1540
+
1541
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
1542
+
1543
+ return handle_perform(self,rbce);
1544
+ }
1545
+
1546
+ /*
1547
+ * call-seq:
1548
+ * easy.http_delete
1549
+ *
1550
+ * DELETE the currently configured URL using the current options set for
1551
+ * this Curl::Easy instance. This method always returns true, or raises
1552
+ * an exception (defined under Curl::Err) on error.
1553
+ */
1554
+ static VALUE ruby_curl_easy_perform_delete(VALUE self) {
1555
+ ruby_curl_easy *rbce;
1556
+ CURL *curl;
1557
+
1558
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1559
+ curl = rbce->curl;
1560
+
1561
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
1562
+ // curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
1563
+
1564
+ return handle_perform(self,rbce);
1565
+ }
1566
+
1567
+ /*
1568
+ * call-seq:
1569
+ * easy.perform => true
1570
+ *
1571
+ * Transfer the currently configured URL using the options set for this
1572
+ * Curl::Easy instance. If this is an HTTP URL, it will be transferred via
1573
+ * the GET request method (i.e. this method is a synonym for +http_get+
1574
+ * when using HTTP URLs).
1575
+ */
1576
+ static VALUE ruby_curl_easy_perform(VALUE self) {
1577
+ return ruby_curl_easy_perform_get(self);
1578
+ }
1579
+
1580
+ /*
1581
+ * call-seq:
1582
+ * easy.http_post("url=encoded%20form%20data;and=so%20on") => true
1583
+ * easy.http_post("url=encoded%20form%20data", "and=so%20on", ...) => true
1584
+ * easy.http_post("url=encoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
1585
+ * easy.http_post(Curl::PostField, Curl::PostField ..., Curl::PostField) => true
1586
+ *
1587
+ * POST the specified formdata to the currently configured URL using
1588
+ * the current options set for this Curl::Easy instance. This method
1589
+ * always returns true, or raises an exception (defined under
1590
+ * Curl::Err) on error.
1591
+ *
1592
+ * The Content-type of the POST is determined by the current setting
1593
+ * of multipart_form_post? , according to the following rules:
1594
+ * * When false (the default): the form will be POSTed with a
1595
+ * content-type of 'application/x-www-form-urlencoded', and any of the
1596
+ * four calling forms may be used.
1597
+ * * When true: the form will be POSTed with a content-type of
1598
+ * 'multipart/formdata'. Only the last calling form may be used,
1599
+ * i.e. only PostField instances may be POSTed. In this mode,
1600
+ * individual fields' content-types are recognised, and file upload
1601
+ * fields are supported.
1602
+ *
1603
+ */
1604
+ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
1605
+ ruby_curl_easy *rbce;
1606
+ CURL *curl;
1607
+ int i;
1608
+ VALUE args_ary;
1609
+
1610
+ rb_scan_args(argc, argv, "*", &args_ary);
1611
+
1612
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1613
+ curl = curl_easy_duphandle(rbce->curl);
1614
+ curl_easy_cleanup(rbce->curl);
1615
+ rbce->curl = curl;
1616
+
1617
+ if (rbce->multipart_form_post) {
1618
+ VALUE ret;
1619
+ struct curl_httppost *first = NULL, *last = NULL;
1620
+
1621
+ // Make the multipart form
1622
+ for (i = 0; i < argc; i++) {
1623
+ if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
1624
+ append_to_form(argv[i], &first, &last);
1625
+ } else {
1626
+ rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
1627
+ return Qnil;
1628
+ }
1629
+ }
1630
+
1631
+ curl_easy_setopt(curl, CURLOPT_POST, 0);
1632
+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
1633
+ ret = handle_perform(self,rbce);
1634
+ curl_formfree(first);
1635
+
1636
+ return ret;
1637
+ } else {
1638
+ long len;
1639
+ char *data;
1640
+
1641
+ if ((rbce->postdata_buffer = rb_funcall(args_ary, idJoin, 1, rbstrAmp)) == Qnil) {
1642
+ rb_raise(eCurlErrError, "Failed to join arguments");
1643
+ return Qnil;
1644
+ } else {
1645
+ data = StringValuePtr(rbce->postdata_buffer);
1646
+ len = RSTRING_LEN(rbce->postdata_buffer);
1647
+
1648
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
1649
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
1650
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
1651
+
1652
+ return handle_perform(self,rbce);
1653
+ }
1654
+ }
1655
+ }
1656
+
1657
+ /*
1658
+ * call-seq:
1659
+ * easy.http_head => true
1660
+ *
1661
+ * Request headers from the currently configured URL using the HEAD
1662
+ * method and current options set for this Curl::Easy instance. This
1663
+ * method always returns true, or raises an exception (defined under
1664
+ * Curl::Err) on error.
1665
+ *
1666
+ * TODO Not yet implemented
1667
+ */
1668
+ static VALUE ruby_curl_easy_perform_head(VALUE self) {
1669
+ rb_raise(eCurlErrError, "Not yet implemented");
1670
+ }
1671
+
1672
+ /*
1673
+ * call-seq:
1674
+ * easy.http_put(data) => true
1675
+ *
1676
+ * PUT the supplied data to the currently configured URL using the
1677
+ * current options set for this Curl::Easy instance. This method always
1678
+ * returns true, or raises an exception (defined under Curl::Err) on error.
1679
+ *
1680
+ * TODO Not yet implemented
1681
+ */
1682
+ static VALUE ruby_curl_easy_perform_put(VALUE self) {
1683
+ rb_raise(eCurlErrError, "Not yet implemented");
1684
+ }
1685
+
1686
+ /* =================== DATA FUNCS =============== */
1687
+
1688
+ /*
1689
+ * call-seq:
1690
+ * easy.body_str => "response body"
1691
+ *
1692
+ * Return the response body from the previous call to +perform+. This
1693
+ * is populated by the default +on_body+ handler - if you supply
1694
+ * your own body handler, this string will be empty.
1695
+ */
1696
+ static VALUE ruby_curl_easy_body_str_get(VALUE self) {
1697
+ CURB_OBJECT_GETTER(ruby_curl_easy, body_data);
1698
+ }
1699
+
1700
+ /*
1701
+ * call-seq:
1702
+ * easy.header_str => "response header"
1703
+ *
1704
+ * Return the response header from the previous call to +perform+. This
1705
+ * is populated by the default +on_header+ handler - if you supply
1706
+ * your own header handler, this string will be empty.
1707
+ */
1708
+ static VALUE ruby_curl_easy_header_str_get(VALUE self) {
1709
+ CURB_OBJECT_GETTER(ruby_curl_easy, header_data);
1710
+ }
1711
+
1712
+
1713
+ /* ============== LASTCONN INFO FUNCS ============ */
1714
+
1715
+ /*
1716
+ * call-seq:
1717
+ * easy.last_effective_url => "http://some.url" or nil
1718
+ *
1719
+ * Retrieve the last effective URL used by this instance.
1720
+ * This is the URL used in the last +perform+ call,
1721
+ * and may differ from the value of easy.url.
1722
+ */
1723
+ static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
1724
+ ruby_curl_easy *rbce;
1725
+ char* url;
1726
+
1727
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1728
+ curl_easy_getinfo(rbce->curl, CURLINFO_EFFECTIVE_URL, &url);
1729
+
1730
+ if (url && url[0]) { // curl returns empty string if none
1731
+ return rb_str_new2(url);
1732
+ } else {
1733
+ return Qnil;
1734
+ }
1735
+ }
1736
+
1737
+ /*
1738
+ * call-seq:
1739
+ * easy.response_code => fixnum
1740
+ *
1741
+ * Retrieve the last received HTTP or FTP code. This will be zero
1742
+ * if no server response code has been received. Note that a proxy's
1743
+ * CONNECT response should be read with +http_connect_code+
1744
+ * and not this method.
1745
+ */
1746
+ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
1747
+ ruby_curl_easy *rbce;
1748
+ long code;
1749
+
1750
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1751
+ #ifdef CURLINFO_RESPONSE_CODE
1752
+ curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
1753
+ #else
1754
+ // old libcurl
1755
+ curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CODE, &code);
1756
+ #endif
1757
+
1758
+ return LONG2NUM(code);
1759
+ }
1760
+
1761
+ /*
1762
+ * call-seq:
1763
+ * easy.http_connect_code => fixnum
1764
+ *
1765
+ * Retrieve the last received proxy response code to a CONNECT request.
1766
+ */
1767
+ static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
1768
+ ruby_curl_easy *rbce;
1769
+ long code;
1770
+
1771
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1772
+ curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CONNECTCODE, &code);
1773
+
1774
+ return LONG2NUM(code);
1775
+ }
1776
+
1777
+ /*
1778
+ * call-seq:
1779
+ * easy.file_time => fixnum
1780
+ *
1781
+ * Retrieve the remote time of the retrieved document (in number of
1782
+ * seconds since 1 jan 1970 in the GMT/UTC time zone). If you get -1,
1783
+ * it can be because of many reasons (unknown, the server hides it
1784
+ * or the server doesn't support the command that tells document time
1785
+ * etc) and the time of the document is unknown.
1786
+ *
1787
+ * Note that you must tell the server to collect this information
1788
+ * before the transfer is made, by setting +fetch_file_time?+ to true,
1789
+ * or you will unconditionally get a -1 back.
1790
+ *
1791
+ * This requires libcurl 7.5 or higher - otherwise -1 is unconditionally
1792
+ * returned.
1793
+ */
1794
+ static VALUE ruby_curl_easy_file_time_get(VALUE self) {
1795
+ #ifdef CURLINFO_FILETIME
1796
+ ruby_curl_easy *rbce;
1797
+ long time;
1798
+
1799
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1800
+ curl_easy_getinfo(rbce->curl, CURLINFO_FILETIME, &time);
1801
+
1802
+ return LONG2NUM(time);
1803
+ #else
1804
+ rb_warn("Installed libcurl is too old to support file_time");
1805
+ return INT2FIX(0);
1806
+ #endif
1807
+ }
1808
+
1809
+ /*
1810
+ * call-seq:
1811
+ * easy.total_time => float
1812
+ *
1813
+ * Retrieve the total time in seconds for the previous transfer,
1814
+ * including name resolving, TCP connect etc.
1815
+ */
1816
+ static VALUE ruby_curl_easy_total_time_get(VALUE self) {
1817
+ ruby_curl_easy *rbce;
1818
+ double time;
1819
+
1820
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1821
+ curl_easy_getinfo(rbce->curl, CURLINFO_TOTAL_TIME, &time);
1822
+
1823
+ return rb_float_new(time);
1824
+ }
1825
+
1826
+ /*
1827
+ * call-seq:
1828
+ * easy.name_lookup_time => float
1829
+ *
1830
+ * Retrieve the time, in seconds, it took from the start until the
1831
+ * name resolving was completed.
1832
+ */
1833
+ static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
1834
+ ruby_curl_easy *rbce;
1835
+ double time;
1836
+
1837
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1838
+ curl_easy_getinfo(rbce->curl, CURLINFO_NAMELOOKUP_TIME, &time);
1839
+
1840
+ return rb_float_new(time);
1841
+ }
1842
+
1843
+ /*
1844
+ * call-seq:
1845
+ * easy.connect_time => float
1846
+ *
1847
+ * Retrieve the time, in seconds, it took from the start until the
1848
+ * connect to the remote host (or proxy) was completed.
1849
+ */
1850
+ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
1851
+ ruby_curl_easy *rbce;
1852
+ double time;
1853
+
1854
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1855
+ curl_easy_getinfo(rbce->curl, CURLINFO_CONNECT_TIME, &time);
1856
+
1857
+ return rb_float_new(time);
1858
+ }
1859
+
1860
+ /*
1861
+ * call-seq:
1862
+ * easy.pre_transfer_time => float
1863
+ *
1864
+ * Retrieve the time, in seconds, it took from the start until the
1865
+ * file transfer is just about to begin. This includes all pre-transfer
1866
+ * commands and negotiations that are specific to the particular protocol(s)
1867
+ * involved.
1868
+ */
1869
+ static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
1870
+ ruby_curl_easy *rbce;
1871
+ double time;
1872
+
1873
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1874
+ curl_easy_getinfo(rbce->curl, CURLINFO_PRETRANSFER_TIME, &time);
1875
+
1876
+ return rb_float_new(time);
1877
+ }
1878
+
1879
+ /*
1880
+ * call-seq:
1881
+ * easy.start_transfer_time => float
1882
+ *
1883
+ * Retrieve the time, in seconds, it took from the start until the first byte
1884
+ * is just about to be transferred. This includes the +pre_transfer_time+ and
1885
+ * also the time the server needs to calculate the result.
1886
+ */
1887
+ static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
1888
+ ruby_curl_easy *rbce;
1889
+ double time;
1890
+
1891
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1892
+ curl_easy_getinfo(rbce->curl, CURLINFO_STARTTRANSFER_TIME, &time);
1893
+
1894
+ return rb_float_new(time);
1895
+ }
1896
+
1897
+ /*
1898
+ * call-seq:
1899
+ * easy.redirect_time => float
1900
+ *
1901
+ * Retrieve the total time, in seconds, it took for all redirection steps
1902
+ * include name lookup, connect, pretransfer and transfer before final
1903
+ * transaction was started. +redirect_time+ contains the complete
1904
+ * execution time for multiple redirections.
1905
+ *
1906
+ * Requires libcurl 7.9.7 or higher, otherwise -1 is always returned.
1907
+ */
1908
+ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
1909
+ #ifdef CURLINFO_REDIRECT_TIME
1910
+ ruby_curl_easy *rbce;
1911
+ double time;
1912
+
1913
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1914
+ curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_TIME, &time);
1915
+
1916
+ return rb_float_new(time);
1917
+ #else
1918
+ rb_warn("Installed libcurl is too old to support redirect_time");
1919
+ return rb_float_new(-1);
1920
+ #endif
1921
+ }
1922
+
1923
+ /*
1924
+ * call-seq:
1925
+ * easy.redirect_count => integer
1926
+ *
1927
+ * Retrieve the total number of redirections that were actually followed.
1928
+ *
1929
+ * Requires libcurl 7.9.7 or higher, otherwise -1 is always returned.
1930
+ */
1931
+ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
1932
+ #ifdef CURLINFO_REDIRECT_COUNT
1933
+ ruby_curl_easy *rbce;
1934
+ long count;
1935
+
1936
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1937
+ curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_COUNT, &count);
1938
+
1939
+ return LONG2NUM(count);
1940
+ #else
1941
+ rb_warn("Installed libcurl is too old to support redirect_count");
1942
+ return INT2FIX(-1);
1943
+ #endif
1944
+
1945
+ }
1946
+
1947
+ /*
1948
+ * call-seq:
1949
+ * easy.uploaded_bytes => float
1950
+ *
1951
+ * Retrieve the total amount of bytes that were uploaded in the
1952
+ * preceeding transfer.
1953
+ */
1954
+ static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
1955
+ ruby_curl_easy *rbce;
1956
+ double bytes;
1957
+
1958
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1959
+ curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
1960
+
1961
+ return rb_float_new(bytes);
1962
+ }
1963
+
1964
+ /*
1965
+ * call-seq:
1966
+ * easy.downloaded_bytes => float
1967
+ *
1968
+ * Retrieve the total amount of bytes that were downloaded in the
1969
+ * preceeding transfer.
1970
+ */
1971
+ static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
1972
+ ruby_curl_easy *rbce;
1973
+ double bytes;
1974
+
1975
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1976
+ curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
1977
+
1978
+ return rb_float_new(bytes);
1979
+ }
1980
+
1981
+ /*
1982
+ * call-seq:
1983
+ * easy.upload_speed => float
1984
+ *
1985
+ * Retrieve the average upload speed that curl measured for the
1986
+ * preceeding complete upload.
1987
+ */
1988
+ static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
1989
+ ruby_curl_easy *rbce;
1990
+ double bytes;
1991
+
1992
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1993
+ curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
1994
+
1995
+ return rb_float_new(bytes);
1996
+ }
1997
+
1998
+ /*
1999
+ * call-seq:
2000
+ * easy.download_speed => float
2001
+ *
2002
+ * Retrieve the average download speed that curl measured for
2003
+ * the preceeding complete download.
2004
+ */
2005
+ static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
2006
+ ruby_curl_easy *rbce;
2007
+ double bytes;
2008
+
2009
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2010
+ curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
2011
+
2012
+ return rb_float_new(bytes);
2013
+ }
2014
+
2015
+ /*
2016
+ * call-seq:
2017
+ * easy.header_size => fixnum
2018
+ *
2019
+ * Retrieve the total size of all the headers received in the
2020
+ * preceeding transfer.
2021
+ */
2022
+ static VALUE ruby_curl_easy_header_size_get(VALUE self) {
2023
+ ruby_curl_easy *rbce;
2024
+ long size;
2025
+
2026
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2027
+ curl_easy_getinfo(rbce->curl, CURLINFO_HEADER_SIZE, &size);
2028
+
2029
+ return LONG2NUM(size);
2030
+ }
2031
+
2032
+ /*
2033
+ * call-seq:
2034
+ * easy.request_size => fixnum
2035
+ *
2036
+ * Retrieve the total size of the issued requests. This is so far
2037
+ * only for HTTP requests. Note that this may be more than one request
2038
+ * if +follow_location?+ is true.
2039
+ */
2040
+ static VALUE ruby_curl_easy_request_size_get(VALUE self) {
2041
+ ruby_curl_easy *rbce;
2042
+ long size;
2043
+
2044
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2045
+ curl_easy_getinfo(rbce->curl, CURLINFO_REQUEST_SIZE, &size);
2046
+
2047
+ return LONG2NUM(size);
2048
+ }
2049
+
2050
+ /*
2051
+ * call-seq:
2052
+ * easy.ssl_verify_result => integer
2053
+ *
2054
+ * Retrieve the result of the certification verification that was requested
2055
+ * (by setting +ssl_verify_peer?+ to +true+).
2056
+ */
2057
+ static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
2058
+ ruby_curl_easy *rbce;
2059
+ long result;
2060
+
2061
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2062
+ curl_easy_getinfo(rbce->curl, CURLINFO_SSL_VERIFYRESULT, &result);
2063
+
2064
+ return LONG2NUM(result);
2065
+ }
2066
+
2067
+ /* TODO CURLINFO_SSL_ENGINES
2068
+
2069
+ Pass the address of a 'struct curl_slist *' to receive a linked-list of OpenSSL crypto-engines supported. Note that engines are normally implemented in separate dynamic libraries. Hence not all the returned engines may be available at run-time. NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done with it, as libcurl will not free the data for you. (Added in 7.12.3)
2070
+ */
2071
+
2072
+ /*
2073
+ * call-seq:
2074
+ * easy.downloaded_content_length => float
2075
+ *
2076
+ * Retrieve the content-length of the download. This is the value read
2077
+ * from the Content-Length: field.
2078
+ */
2079
+ static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
2080
+ ruby_curl_easy *rbce;
2081
+ double bytes;
2082
+
2083
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2084
+ curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
2085
+
2086
+ return rb_float_new(bytes);
2087
+ }
2088
+
2089
+ /*
2090
+ * call-seq:
2091
+ * easy.uploaded_content_length => float
2092
+ *
2093
+ * Retrieve the content-length of the upload.
2094
+ */
2095
+ static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
2096
+ ruby_curl_easy *rbce;
2097
+ double bytes;
2098
+
2099
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2100
+ curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
2101
+
2102
+ return rb_float_new(bytes);
2103
+ }
2104
+
2105
+ /*
2106
+ * call-seq:
2107
+ * easy.content_type => "content/type" or nil
2108
+ *
2109
+ * Retrieve the content-type of the downloaded object. This is the value read
2110
+ * from the Content-Type: field. If you get +nil+, it means that the server
2111
+ * didn't send a valid Content-Type header or that the protocol used doesn't
2112
+ * support this.
2113
+ */
2114
+ static VALUE ruby_curl_easy_content_type_get(VALUE self) {
2115
+ ruby_curl_easy *rbce;
2116
+ char* type;
2117
+
2118
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2119
+ curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_TYPE, &type);
2120
+
2121
+ if (type && type[0]) { // curl returns empty string if none
2122
+ return rb_str_new2(type);
2123
+ } else {
2124
+ return Qnil;
2125
+ }
2126
+ }
2127
+
2128
+
2129
+ /* NOT REQUIRED?
2130
+ CURLINFO_PRIVATE
2131
+
2132
+ 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)
2133
+ */
2134
+
2135
+ /* TODO these will need constants setting up too for checking the bits.
2136
+ *
2137
+ * Alternatively, could return an object that wraps the long, and has
2138
+ * question methods to query the auth types. Could return long from to_i(nt)
2139
+ *
2140
+ CURLINFO_HTTPAUTH_AVAIL
2141
+
2142
+ 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)
2143
+
2144
+ CURLINFO_PROXYAUTH_AVAIL
2145
+
2146
+ 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)
2147
+ */
2148
+
2149
+ /*
2150
+ * call-seq:
2151
+ * easy.os_errno => integer
2152
+ *
2153
+ * Retrieve the errno variable from a connect failure (requires
2154
+ * libcurl 7.12.2 or higher, otherwise 0 is always returned).
2155
+ */
2156
+ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
2157
+ #ifdef CURLINFO_OS_ERRNO
2158
+ ruby_curl_easy *rbce;
2159
+ long result;
2160
+
2161
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2162
+ curl_easy_getinfo(rbce->curl, CURLINFO_OS_ERRNO, &result);
2163
+
2164
+ return LONG2NUM(result);
2165
+ #else
2166
+ rb_warn("Installed libcurl is too old to support os_errno");
2167
+ return INT2FIX(0);
2168
+ #endif
2169
+ }
2170
+
2171
+ /*
2172
+ * call-seq:
2173
+ * easy.num_connects => integer
2174
+ *
2175
+ * Retrieve the number of new connections libcurl had to create to achieve
2176
+ * the previous transfer (only the successful connects are counted).
2177
+ * Combined with +redirect_count+ you are able to know how many times libcurl
2178
+ * successfully reused existing connection(s) or not.
2179
+ *
2180
+ * See the Connection Options of curl_easy_setopt(3) to see how libcurl tries
2181
+ * to make persistent connections to save time.
2182
+ *
2183
+ * (requires libcurl 7.12.3 or higher, otherwise -1 is always returned).
2184
+ */
2185
+ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
2186
+ #ifdef CURLINFO_NUM_CONNECTS
2187
+ ruby_curl_easy *rbce;
2188
+ long result;
2189
+
2190
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2191
+ curl_easy_getinfo(rbce->curl, CURLINFO_NUM_CONNECTS, &result);
2192
+
2193
+ return LONG2NUM(result);
2194
+ #else
2195
+ rb_warn("Installed libcurl is too old to support num_connects");
2196
+ return INT2FIX(-1);
2197
+ #endif
2198
+ }
2199
+
2200
+
2201
+ /* TODO this needs to be implemented.
2202
+
2203
+ CURLINFO_COOKIELIST
2204
+
2205
+ 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)
2206
+ */
2207
+
2208
+ /* TODO this needs to be implemented. Could probably support CONNECT_ONLY by having this
2209
+ * return an open Socket or something.
2210
+ *
2211
+ CURLINFO_LASTSOCKET
2212
+
2213
+ 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)
2214
+ */
2215
+
2216
+ /*
2217
+ * call-seq:
2218
+ * easy.content_type => "content/type" or nil
2219
+ *
2220
+ * Retrieve the path of the entry path. That is the initial path libcurl ended
2221
+ * up in when logging on to the remote FTP server. This returns +nil+ if
2222
+ * something is wrong.
2223
+ *
2224
+ * (requires libcurl 7.15.4 or higher, otherwise +nil+ is always returned).
2225
+ */
2226
+ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
2227
+ #ifdef CURLINFO_FTP_ENTRY_PATH
2228
+ ruby_curl_easy *rbce;
2229
+ char* path;
2230
+
2231
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2232
+ curl_easy_getinfo(rbce->curl, CURLINFO_FTP_ENTRY_PATH, &path);
2233
+
2234
+ if (type && type[0]) { // curl returns NULL or empty string if none
2235
+ return rb_str_new2(path);
2236
+ } else {
2237
+ return Qnil;
2238
+ }
2239
+ #else
2240
+ rb_warn("Installed libcurl is too old to support num_connects");
2241
+ return Qnil;
2242
+ #endif
2243
+ }
2244
+
2245
+
2246
+ /* ================== ESCAPING FUNCS ==============*/
2247
+
2248
+ /*
2249
+ * call-seq:
2250
+ * easy.escape("some text") => "some%20text"
2251
+ *
2252
+ * Convert the given input string to a URL encoded string and return
2253
+ * the result. All input characters that are not a-z, A-Z or 0-9 are
2254
+ * converted to their "URL escaped" version (%NN where NN is a
2255
+ * two-digit hexadecimal number).
2256
+ */
2257
+ static VALUE ruby_curl_easy_escape(VALUE self, VALUE str) {
2258
+ ruby_curl_easy *rbce;
2259
+ char *result;
2260
+ VALUE rresult;
2261
+
2262
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2263
+
2264
+ #if (LIBCURL_VERSION_NUM >= 0x070f04)
2265
+ result = (char*)curl_easy_escape(rbce->curl, StringValuePtr(str), RSTRING_LEN(str));
2266
+ #else
2267
+ result = (char*)curl_escape(StringValuePtr(str), RSTRING_LEN(str));
2268
+ #endif
2269
+
2270
+ rresult = rb_str_new2(result);
2271
+ curl_free(result);
2272
+
2273
+ return rresult;
2274
+ }
2275
+
2276
+ /*
2277
+ * call-seq:
2278
+ * easy.unescape("some text") => "some%20text"
2279
+ *
2280
+ * Convert the given URL encoded input string to a "plain string" and return
2281
+ * the result. All input characters that are URL encoded (%XX where XX is a
2282
+ * two-digit hexadecimal number) are converted to their binary versions.
2283
+ */
2284
+ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
2285
+ ruby_curl_easy *rbce;
2286
+ int rlen;
2287
+ char *result;
2288
+ VALUE rresult;
2289
+
2290
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2291
+
2292
+ #if (LIBCURL_VERSION_NUM >= 0x070f04)
2293
+ result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), RSTRING_LEN(str), &rlen);
2294
+ #else
2295
+ result = (char*)curl_unescape(StringValuePtr(str), RSTRING_LEN(str));
2296
+ rlen = strlen(result);
2297
+ #endif
2298
+
2299
+ rresult = rb_str_new(result, rlen);
2300
+ curl_free(result);
2301
+
2302
+ return rresult;
2303
+ }
2304
+
2305
+
2306
+ /* ================= CLASS METHODS ==================*/
2307
+
2308
+ /*
2309
+ * call-seq:
2310
+ * Curl::Easy.perform(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
2311
+ *
2312
+ * Convenience method that creates a new Curl::Easy instance with
2313
+ * the specified URL and calls the general +perform+ method, before returning
2314
+ * the new instance. For HTTP URLs, this is equivalent to calling +http_get+.
2315
+ *
2316
+ * If a block is supplied, the new instance will be yielded just prior to
2317
+ * the +http_get+ call.
2318
+ */
2319
+ static VALUE ruby_curl_easy_class_perform(int argc, VALUE *argv, VALUE klass) {
2320
+ VALUE c = ruby_curl_easy_new(argc, argv, klass);
2321
+
2322
+ if (rb_block_given_p()) {
2323
+ rb_yield(c);
2324
+ }
2325
+
2326
+ ruby_curl_easy_perform(c);
2327
+ return c;
2328
+ }
2329
+
2330
+ /*
2331
+ * call-seq:
2332
+ * Curl::Easy.http_get(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
2333
+ *
2334
+ * Convenience method that creates a new Curl::Easy instance with
2335
+ * the specified URL and calls +http_get+, before returning the new instance.
2336
+ *
2337
+ * If a block is supplied, the new instance will be yielded just prior to
2338
+ * the +http_get+ call.
2339
+ */
2340
+ static VALUE ruby_curl_easy_class_perform_get(int argc, VALUE *argv, VALUE klass) {
2341
+ VALUE c = ruby_curl_easy_new(argc, argv, klass);
2342
+
2343
+ if (rb_block_given_p()) {
2344
+ rb_yield(c);
2345
+ }
2346
+
2347
+ ruby_curl_easy_perform_get(c);
2348
+ return c;
2349
+ }
2350
+
2351
+ /*
2352
+ * call-seq:
2353
+ * Curl::Easy.http_delete(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
2354
+ *
2355
+ * Convenience method that creates a new Curl::Easy instance with
2356
+ * the specified URL and calls +http_delete+, before returning the new instance.
2357
+ *
2358
+ * If a block is supplied, the new instance will be yielded just prior to
2359
+ * the +http_delete+ call.
2360
+ */
2361
+ static VALUE ruby_curl_easy_class_perform_delete(int argc, VALUE *argv, VALUE klass) {
2362
+ VALUE c = ruby_curl_easy_new(argc, argv, klass);
2363
+
2364
+ if (rb_block_given_p()) {
2365
+ rb_yield(c);
2366
+ }
2367
+
2368
+ ruby_curl_easy_perform_delete(c);
2369
+ return c;
2370
+ }
2371
+
2372
+ /*
2373
+ * call-seq:
2374
+ * Curl::Easy.http_post(url, "some=urlencoded%20form%20data&and=so%20on") => true
2375
+ * Curl::Easy.http_post(url, "some=urlencoded%20form%20data", "and=so%20on", ...) => true
2376
+ * Curl::Easy.http_post(url, "some=urlencoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
2377
+ * Curl::Easy.http_post(url, Curl::PostField, Curl::PostField ..., Curl::PostField) => true
2378
+ *
2379
+ * POST the specified formdata to the currently configured URL using
2380
+ * the current options set for this Curl::Easy instance. This method
2381
+ * always returns true, or raises an exception (defined under
2382
+ * Curl::Err) on error.
2383
+ *
2384
+ * If you wish to use multipart form encoding, you'll need to supply a block
2385
+ * in order to set multipart_form_post true. See #http_post for more
2386
+ * information.
2387
+ */
2388
+ static VALUE ruby_curl_easy_class_perform_post(int argc, VALUE *argv, VALUE klass) {
2389
+ VALUE url, fields;
2390
+
2391
+ rb_scan_args(argc, argv, "1*", &url, &fields);
2392
+
2393
+ VALUE c = ruby_curl_easy_new(1, &url, klass);
2394
+
2395
+ if (argc > 1) {
2396
+ ruby_curl_easy_perform_post(argc - 1, &argv[1], c);
2397
+ } else {
2398
+ ruby_curl_easy_perform_post(0, NULL, c);
2399
+ }
2400
+
2401
+ return c;
2402
+ }
2403
+
2404
+
2405
+ /* =================== INIT LIB =====================*/
2406
+ void init_curb_easy() {
2407
+ idCall = rb_intern("call");
2408
+ idJoin = rb_intern("join");
2409
+
2410
+ rbstrAmp = rb_str_new2("&");
2411
+ rb_global_variable(&rbstrAmp);
2412
+
2413
+ cCurlEasy = rb_define_class_under(mCurl, "Easy", rb_cObject);
2414
+
2415
+ /* Class methods */
2416
+ rb_define_singleton_method(cCurlEasy, "new", ruby_curl_easy_new, -1);
2417
+ rb_define_singleton_method(cCurlEasy, "perform", ruby_curl_easy_class_perform, -1);
2418
+ rb_define_singleton_method(cCurlEasy, "http_delete", ruby_curl_easy_class_perform_delete, -1);
2419
+ rb_define_singleton_method(cCurlEasy, "http_get", ruby_curl_easy_class_perform_get, -1);
2420
+ rb_define_singleton_method(cCurlEasy, "http_post", ruby_curl_easy_class_perform_post, -1);
2421
+
2422
+ /* Attributes for config next perform */
2423
+ rb_define_method(cCurlEasy, "url=", ruby_curl_easy_url_set, 1);
2424
+ rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
2425
+ rb_define_method(cCurlEasy, "proxy_url=", ruby_curl_easy_proxy_url_set, 1);
2426
+ rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
2427
+ rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
2428
+ rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
2429
+ rb_define_method(cCurlEasy, "interface=", ruby_curl_easy_interface_set, 1);
2430
+ rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
2431
+ rb_define_method(cCurlEasy, "userpwd=", ruby_curl_easy_userpwd_set, 1);
2432
+ rb_define_method(cCurlEasy, "userpwd", ruby_curl_easy_userpwd_get, 0);
2433
+ rb_define_method(cCurlEasy, "proxypwd=", ruby_curl_easy_proxypwd_set, 1);
2434
+ rb_define_method(cCurlEasy, "proxypwd", ruby_curl_easy_proxypwd_get, 0);
2435
+ rb_define_method(cCurlEasy, "cookiejar=", ruby_curl_easy_cookiejar_set, 1);
2436
+ rb_define_method(cCurlEasy, "cookiejar", ruby_curl_easy_cookiejar_get, 0);
2437
+ rb_define_method(cCurlEasy, "cert=", ruby_curl_easy_cert_set, 1);
2438
+ rb_define_method(cCurlEasy, "cert", ruby_curl_easy_cert_get, 0);
2439
+ rb_define_method(cCurlEasy, "encoding=", ruby_curl_easy_encoding_set, 1);
2440
+ rb_define_method(cCurlEasy, "encoding", ruby_curl_easy_encoding_get, 0);
2441
+
2442
+ rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
2443
+ rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
2444
+ rb_define_method(cCurlEasy, "local_port_range=", ruby_curl_easy_local_port_range_set, 1);
2445
+ rb_define_method(cCurlEasy, "local_port_range", ruby_curl_easy_local_port_range_get, 0);
2446
+ rb_define_method(cCurlEasy, "proxy_port=", ruby_curl_easy_proxy_port_set, 1);
2447
+ rb_define_method(cCurlEasy, "proxy_port", ruby_curl_easy_proxy_port_get, 0);
2448
+ rb_define_method(cCurlEasy, "proxy_type=", ruby_curl_easy_proxy_type_set, 1);
2449
+ rb_define_method(cCurlEasy, "proxy_type", ruby_curl_easy_proxy_type_get, 0);
2450
+ rb_define_method(cCurlEasy, "http_auth_types=", ruby_curl_easy_http_auth_types_set, 1);
2451
+ rb_define_method(cCurlEasy, "http_auth_types", ruby_curl_easy_http_auth_types_get, 0);
2452
+ rb_define_method(cCurlEasy, "proxy_auth_types=", ruby_curl_easy_proxy_auth_types_set, 1);
2453
+ rb_define_method(cCurlEasy, "proxy_auth_types", ruby_curl_easy_proxy_auth_types_get, 0);
2454
+ rb_define_method(cCurlEasy, "max_redirects=", ruby_curl_easy_max_redirects_set, 1);
2455
+ rb_define_method(cCurlEasy, "max_redirects", ruby_curl_easy_max_redirects_get, 0);
2456
+ rb_define_method(cCurlEasy, "timeout=", ruby_curl_easy_timeout_set, 1);
2457
+ rb_define_method(cCurlEasy, "timeout", ruby_curl_easy_timeout_get, 0);
2458
+ rb_define_method(cCurlEasy, "connect_timeout=", ruby_curl_easy_connect_timeout_set, 1);
2459
+ rb_define_method(cCurlEasy, "connect_timeout", ruby_curl_easy_connect_timeout_get, 0);
2460
+ rb_define_method(cCurlEasy, "dns_cache_timeout=", ruby_curl_easy_dns_cache_timeout_set, 1);
2461
+ rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
2462
+ rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
2463
+ rb_define_method(cCurlEasy, "ftp_response_timeout", ruby_curl_easy_ftp_response_timeout_get, 0);
2464
+
2465
+ rb_define_method(cCurlEasy, "proxy_tunnel=", ruby_curl_easy_proxy_tunnel_set, 1);
2466
+ rb_define_method(cCurlEasy, "proxy_tunnel?", ruby_curl_easy_proxy_tunnel_q, 0);
2467
+ rb_define_method(cCurlEasy, "fetch_file_time=", ruby_curl_easy_fetch_file_time_set, 1);
2468
+ rb_define_method(cCurlEasy, "fetch_file_time?", ruby_curl_easy_fetch_file_time_q, 0);
2469
+ rb_define_method(cCurlEasy, "ssl_verify_peer=", ruby_curl_easy_ssl_verify_peer_set, 1);
2470
+ rb_define_method(cCurlEasy, "ssl_verify_peer?", ruby_curl_easy_ssl_verify_peer_q, 0);
2471
+ rb_define_method(cCurlEasy, "ssl_verify_host=", ruby_curl_easy_ssl_verify_host_set, 1);
2472
+ rb_define_method(cCurlEasy, "ssl_verify_host?", ruby_curl_easy_ssl_verify_host_q, 0);
2473
+ rb_define_method(cCurlEasy, "header_in_body=", ruby_curl_easy_header_in_body_set, 1);
2474
+ rb_define_method(cCurlEasy, "header_in_body?", ruby_curl_easy_header_in_body_q, 0);
2475
+ rb_define_method(cCurlEasy, "use_netrc=", ruby_curl_easy_use_netrc_set, 1);
2476
+ rb_define_method(cCurlEasy, "use_netrc?", ruby_curl_easy_use_netrc_q, 0);
2477
+ rb_define_method(cCurlEasy, "follow_location=", ruby_curl_easy_follow_location_set, 1);
2478
+ rb_define_method(cCurlEasy, "follow_location?", ruby_curl_easy_follow_location_q, 0);
2479
+ rb_define_method(cCurlEasy, "unrestricted_auth=", ruby_curl_easy_unrestricted_auth_set, 1);
2480
+ rb_define_method(cCurlEasy, "unrestricted_auth?", ruby_curl_easy_unrestricted_auth_q, 0);
2481
+ rb_define_method(cCurlEasy, "verbose=", ruby_curl_easy_verbose_set, 1);
2482
+ rb_define_method(cCurlEasy, "verbose?", ruby_curl_easy_verbose_q, 0);
2483
+ rb_define_method(cCurlEasy, "multipart_form_post=", ruby_curl_easy_multipart_form_post_set, 1);
2484
+ rb_define_method(cCurlEasy, "multipart_form_post?", ruby_curl_easy_multipart_form_post_q, 0);
2485
+ rb_define_method(cCurlEasy, "enable_cookies=", ruby_curl_easy_enable_cookies_set, 1);
2486
+ rb_define_method(cCurlEasy, "enable_cookies?", ruby_curl_easy_enable_cookies_q, 0);
2487
+
2488
+ rb_define_method(cCurlEasy, "on_body", ruby_curl_easy_on_body_set, -1);
2489
+ rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
2490
+ rb_define_method(cCurlEasy, "on_progress", ruby_curl_easy_on_progress_set, -1);
2491
+ rb_define_method(cCurlEasy, "on_debug", ruby_curl_easy_on_debug_set, -1);
2492
+ rb_define_method(cCurlEasy, "on_success", ruby_curl_easy_on_success_set, -1);
2493
+ rb_define_method(cCurlEasy, "on_failure", ruby_curl_easy_on_failure_set, -1);
2494
+ rb_define_method(cCurlEasy, "on_complete", ruby_curl_easy_on_complete_set, -1);
2495
+
2496
+ rb_define_method(cCurlEasy, "perform", ruby_curl_easy_perform, 0);
2497
+ rb_define_method(cCurlEasy, "http_delete", ruby_curl_easy_perform_delete, 0);
2498
+ rb_define_method(cCurlEasy, "http_get", ruby_curl_easy_perform_get, 0);
2499
+ rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
2500
+ rb_define_method(cCurlEasy, "http_head", ruby_curl_easy_perform_head, 0);
2501
+ rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 0);
2502
+
2503
+ /* Post-perform info methods */
2504
+ rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
2505
+ rb_define_method(cCurlEasy, "header_str", ruby_curl_easy_header_str_get, 0);
2506
+
2507
+ rb_define_method(cCurlEasy, "last_effective_url", ruby_curl_easy_last_effective_url_get, 0);
2508
+ rb_define_method(cCurlEasy, "response_code", ruby_curl_easy_response_code_get, 0);
2509
+ rb_define_method(cCurlEasy, "http_connect_code", ruby_curl_easy_http_connect_code_get, 0);
2510
+ rb_define_method(cCurlEasy, "file_time", ruby_curl_easy_file_time_get, 0);
2511
+ rb_define_method(cCurlEasy, "total_time", ruby_curl_easy_total_time_get, 0);
2512
+ rb_define_method(cCurlEasy, "total_time", ruby_curl_easy_total_time_get, 0);
2513
+ rb_define_method(cCurlEasy, "name_lookup_time", ruby_curl_easy_name_lookup_time_get, 0);
2514
+ rb_define_method(cCurlEasy, "connect_time", ruby_curl_easy_connect_time_get, 0);
2515
+ rb_define_method(cCurlEasy, "pre_transfer_time", ruby_curl_easy_pre_transfer_time_get, 0);
2516
+ rb_define_method(cCurlEasy, "start_transfer_time", ruby_curl_easy_start_transfer_time_get, 0);
2517
+ rb_define_method(cCurlEasy, "redirect_time", ruby_curl_easy_redirect_time_get, 0);
2518
+ rb_define_method(cCurlEasy, "redirect_count", ruby_curl_easy_redirect_count_get, 0);
2519
+ rb_define_method(cCurlEasy, "downloaded_bytes", ruby_curl_easy_downloaded_bytes_get, 0);
2520
+ rb_define_method(cCurlEasy, "uploaded_bytes", ruby_curl_easy_uploaded_bytes_get, 0);
2521
+ rb_define_method(cCurlEasy, "download_speed", ruby_curl_easy_download_speed_get, 0);
2522
+ rb_define_method(cCurlEasy, "upload_speed", ruby_curl_easy_upload_speed_get, 0);
2523
+ rb_define_method(cCurlEasy, "header_size", ruby_curl_easy_header_size_get, 0);
2524
+ rb_define_method(cCurlEasy, "request_size", ruby_curl_easy_request_size_get, 0);
2525
+ rb_define_method(cCurlEasy, "ssl_verify_result", ruby_curl_easy_ssl_verify_result_get, 0);
2526
+ rb_define_method(cCurlEasy, "downloaded_content_length", ruby_curl_easy_downloaded_content_length_get, 0);
2527
+ rb_define_method(cCurlEasy, "uploaded_content_length", ruby_curl_easy_uploaded_content_length_get, 0);
2528
+ rb_define_method(cCurlEasy, "content_type", ruby_curl_easy_content_type_get, 0);
2529
+ rb_define_method(cCurlEasy, "os_errno", ruby_curl_easy_os_errno_get, 0);
2530
+ rb_define_method(cCurlEasy, "num_connects", ruby_curl_easy_num_connects_get, 0);
2531
+ rb_define_method(cCurlEasy, "ftp_entry_path", ruby_curl_easy_ftp_entry_path_get, 0);
2532
+
2533
+ /* Curl utils */
2534
+ rb_define_method(cCurlEasy, "escape", ruby_curl_easy_escape, 1);
2535
+ rb_define_method(cCurlEasy, "unescape", ruby_curl_easy_unescape, 1);
2536
+
2537
+ /* Runtime support */
2538
+ rb_define_method(cCurlEasy, "clone", ruby_curl_easy_clone, 0);
2539
+ rb_define_alias(cCurlEasy, "dup", "clone");
2540
+ }