codders-curb 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/LICENSE +51 -0
  2. data/README +194 -0
  3. data/Rakefile +320 -0
  4. data/doc.rb +42 -0
  5. data/ext/curb.c +977 -0
  6. data/ext/curb.h +52 -0
  7. data/ext/curb_easy.c +3404 -0
  8. data/ext/curb_easy.h +90 -0
  9. data/ext/curb_errors.c +647 -0
  10. data/ext/curb_errors.h +129 -0
  11. data/ext/curb_macros.h +159 -0
  12. data/ext/curb_multi.c +633 -0
  13. data/ext/curb_multi.h +26 -0
  14. data/ext/curb_postfield.c +523 -0
  15. data/ext/curb_postfield.h +40 -0
  16. data/ext/curb_upload.c +80 -0
  17. data/ext/curb_upload.h +30 -0
  18. data/ext/extconf.rb +399 -0
  19. data/lib/curb.rb +4 -0
  20. data/lib/curl.rb +57 -0
  21. data/lib/curl/easy.rb +468 -0
  22. data/lib/curl/multi.rb +248 -0
  23. data/tests/alltests.rb +3 -0
  24. data/tests/bug_crash_on_debug.rb +39 -0
  25. data/tests/bug_crash_on_progress.rb +33 -0
  26. data/tests/bug_curb_easy_blocks_ruby_threads.rb +52 -0
  27. data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +83 -0
  28. data/tests/bug_instance_post_differs_from_class_post.rb +53 -0
  29. data/tests/bug_multi_segfault.rb +14 -0
  30. data/tests/bug_postfields_crash.rb +26 -0
  31. data/tests/bug_postfields_crash2.rb +57 -0
  32. data/tests/bug_require_last_or_segfault.rb +40 -0
  33. data/tests/bugtests.rb +9 -0
  34. data/tests/helper.rb +199 -0
  35. data/tests/mem_check.rb +65 -0
  36. data/tests/require_last_or_segfault_script.rb +36 -0
  37. data/tests/tc_curl_download.rb +75 -0
  38. data/tests/tc_curl_easy.rb +1011 -0
  39. data/tests/tc_curl_easy_setopt.rb +31 -0
  40. data/tests/tc_curl_multi.rb +485 -0
  41. data/tests/tc_curl_postfield.rb +143 -0
  42. data/tests/timeout.rb +100 -0
  43. data/tests/timeout_server.rb +33 -0
  44. data/tests/unittests.rb +2 -0
  45. metadata +133 -0
data/ext/curb_multi.h ADDED
@@ -0,0 +1,26 @@
1
+ /* curb_multi.h - Curl easy mode
2
+ * Copyright (c)2008 Todd A. Fisher.
3
+ * Licensed under the Ruby License. See LICENSE for details.
4
+ *
5
+ * $Id$
6
+ */
7
+ #ifndef __CURB_MULTI_H
8
+ #define __CURB_MULTI_H
9
+
10
+ #include "curb.h"
11
+ #include "curb_easy.h"
12
+ #include <curl/multi.h>
13
+
14
+ typedef struct {
15
+ int active;
16
+ int running;
17
+ VALUE requests; /* hash of handles currently added */
18
+ CURLM *handle;
19
+ } ruby_curl_multi;
20
+
21
+ extern VALUE cCurlMulti;
22
+ void init_curb_multi();
23
+ VALUE ruby_curl_multi_new(VALUE klass);
24
+
25
+
26
+ #endif
@@ -0,0 +1,523 @@
1
+ /* curb_postfield.c - Field class for POST method
2
+ * Copyright (c)2006 Ross Bamford.
3
+ * Licensed under the Ruby License. See LICENSE for details.
4
+ *
5
+ * $Id: curb_postfield.c 30 2006-12-09 12:30:24Z roscopeco $
6
+ */
7
+ #include "curb_postfield.h"
8
+ #include "curb_errors.h"
9
+
10
+ extern VALUE mCurl;
11
+
12
+ static VALUE idCall;
13
+
14
+ #ifdef RDOC_NEVER_DEFINED
15
+ mCurl = rb_define_module("Curl");
16
+ #endif
17
+
18
+ VALUE cCurlPostField;
19
+
20
+
21
+ /* ================= APPEND FORM FUNC ================ */
22
+
23
+ /* This gets called by the post method on Curl::Easy for each postfield
24
+ * supplied in the arguments. It's job is to add the supplied field to
25
+ * the list that's being built for a perform.
26
+ *
27
+ * THIS FUNC MODIFIES ITS ARGUMENTS. See curl_formadd(3) for details.
28
+ */
29
+ void append_to_form(VALUE self,
30
+ struct curl_httppost **first,
31
+ struct curl_httppost **last) {
32
+ ruby_curl_postfield *rbcpf;
33
+ CURLFORMcode result = -1;
34
+
35
+ Data_Get_Struct(self, ruby_curl_postfield, rbcpf);
36
+
37
+ if (rbcpf->name == Qnil) {
38
+ rb_raise(eCurlErrInvalidPostField, "Cannot post unnamed field");
39
+ } else {
40
+ if ((rbcpf->local_file != Qnil) || (rbcpf->remote_file != Qnil)) {
41
+ // is a file upload field
42
+ if (rbcpf->content_proc != Qnil) {
43
+ // with content proc
44
+ rbcpf->buffer_str = rb_funcall(rbcpf->content_proc, idCall, 1, self);
45
+
46
+ if (rbcpf->remote_file == Qnil) {
47
+ rb_raise(eCurlErrInvalidPostField, "Cannot post file upload field with no filename");
48
+ } else {
49
+ if (rbcpf->content_type == Qnil) {
50
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
51
+ CURLFORM_BUFFER, StringValuePtr(rbcpf->remote_file),
52
+ CURLFORM_BUFFERPTR, StringValuePtr(rbcpf->buffer_str),
53
+ CURLFORM_BUFFERLENGTH, RSTRING_LEN(rbcpf->buffer_str),
54
+ CURLFORM_END);
55
+ } else {
56
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
57
+ CURLFORM_BUFFER, StringValuePtr(rbcpf->remote_file),
58
+ CURLFORM_BUFFERPTR, StringValuePtr(rbcpf->buffer_str),
59
+ CURLFORM_BUFFERLENGTH, RSTRING_LEN(rbcpf->buffer_str),
60
+ CURLFORM_CONTENTTYPE, StringValuePtr(rbcpf->content_type),
61
+ CURLFORM_END);
62
+ }
63
+ }
64
+ } else if (rbcpf->content != Qnil) {
65
+ // with content
66
+ if (rbcpf->remote_file == Qnil) {
67
+ rb_raise(eCurlErrInvalidPostField, "Cannot post file upload field with no filename");
68
+ } else {
69
+ if (rbcpf->content_type == Qnil) {
70
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
71
+ CURLFORM_BUFFER, StringValuePtr(rbcpf->remote_file),
72
+ CURLFORM_BUFFERPTR, StringValuePtr(rbcpf->content),
73
+ CURLFORM_BUFFERLENGTH, RSTRING_LEN(rbcpf->content),
74
+ CURLFORM_END);
75
+ } else {
76
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
77
+ CURLFORM_BUFFER, StringValuePtr(rbcpf->remote_file),
78
+ CURLFORM_BUFFERPTR, StringValuePtr(rbcpf->content),
79
+ CURLFORM_BUFFERLENGTH, RSTRING_LEN(rbcpf->content),
80
+ CURLFORM_CONTENTTYPE, StringValuePtr(rbcpf->content_type),
81
+ CURLFORM_END);
82
+ }
83
+ }
84
+ } else if (rbcpf->local_file != Qnil) {
85
+ // with local filename
86
+ if (rbcpf->local_file == Qnil) {
87
+ rb_raise(eCurlErrInvalidPostField, "Cannot post file upload field no filename");
88
+ } else {
89
+ if (rbcpf->remote_file == Qnil) {
90
+ rbcpf->remote_file = rbcpf->local_file;
91
+ }
92
+
93
+ if (rbcpf->content_type == Qnil) {
94
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
95
+ CURLFORM_FILE, StringValuePtr(rbcpf->local_file),
96
+ CURLFORM_FILENAME, StringValuePtr(rbcpf->remote_file),
97
+ CURLFORM_END);
98
+ } else {
99
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
100
+ CURLFORM_FILE, StringValuePtr(rbcpf->local_file),
101
+ CURLFORM_FILENAME, StringValuePtr(rbcpf->remote_file),
102
+ CURLFORM_CONTENTTYPE, StringValuePtr(rbcpf->content_type),
103
+ CURLFORM_END);
104
+ }
105
+ }
106
+ } else {
107
+ rb_raise(eCurlErrInvalidPostField, "Cannot post file upload field with no data");
108
+ }
109
+ } else {
110
+ // is a content field
111
+ if (rbcpf->content_proc != Qnil) {
112
+ rbcpf->buffer_str = rb_funcall(rbcpf->content_proc, idCall, 1, self);
113
+
114
+ if (rbcpf->content_type == Qnil) {
115
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
116
+ CURLFORM_PTRCONTENTS, StringValuePtr(rbcpf->buffer_str),
117
+ CURLFORM_CONTENTSLENGTH, RSTRING_LEN(rbcpf->buffer_str),
118
+ CURLFORM_END);
119
+ } else {
120
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
121
+ CURLFORM_PTRCONTENTS, StringValuePtr(rbcpf->buffer_str),
122
+ CURLFORM_CONTENTSLENGTH, RSTRING_LEN(rbcpf->buffer_str),
123
+ CURLFORM_CONTENTTYPE, StringValuePtr(rbcpf->content_type),
124
+ CURLFORM_END);
125
+ }
126
+ } else if (rbcpf->content != Qnil) {
127
+ if (rbcpf->content_type == Qnil) {
128
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
129
+ CURLFORM_PTRCONTENTS, StringValuePtr(rbcpf->content),
130
+ CURLFORM_CONTENTSLENGTH, RSTRING_LEN(rbcpf->content),
131
+ CURLFORM_END);
132
+ } else {
133
+ result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
134
+ CURLFORM_PTRCONTENTS, StringValuePtr(rbcpf->content),
135
+ CURLFORM_CONTENTSLENGTH, RSTRING_LEN(rbcpf->content),
136
+ CURLFORM_CONTENTTYPE, StringValuePtr(rbcpf->content_type),
137
+ CURLFORM_END);
138
+ }
139
+ } else {
140
+ rb_raise(eCurlErrInvalidPostField, "Cannot post content field with no data");
141
+ }
142
+ }
143
+ }
144
+
145
+ if (result != 0) {
146
+ const char *reason = NULL;
147
+
148
+ switch (result) {
149
+ case CURL_FORMADD_MEMORY:
150
+ reason = "Memory allocation failed";
151
+ break;
152
+ case CURL_FORMADD_OPTION_TWICE:
153
+ reason = "Duplicate option";
154
+ break;
155
+ case CURL_FORMADD_NULL:
156
+ reason = "Unexpected NULL string";
157
+ break;
158
+ case CURL_FORMADD_UNKNOWN_OPTION:
159
+ reason = "Unknown option";
160
+ break;
161
+ case CURL_FORMADD_INCOMPLETE:
162
+ reason = "Incomplete form data";
163
+ break;
164
+ case CURL_FORMADD_ILLEGAL_ARRAY:
165
+ reason = "Illegal array [BINDING BUG]";
166
+ break;
167
+ case CURL_FORMADD_DISABLED:
168
+ reason = "Installed libcurl cannot support requested feature(s)";
169
+ break;
170
+ default:
171
+ reason = "Unknown error";
172
+ }
173
+
174
+ rb_raise(eCurlErrInvalidPostField, "Failed to add field (%s)", reason);
175
+ }
176
+ }
177
+
178
+
179
+ /* ================== MARK/FREE FUNC ==================*/
180
+ void curl_postfield_mark(ruby_curl_postfield *rbcpf) {
181
+ rb_gc_mark(rbcpf->name);
182
+ rb_gc_mark(rbcpf->content);
183
+ rb_gc_mark(rbcpf->content_type);
184
+ rb_gc_mark(rbcpf->local_file);
185
+ rb_gc_mark(rbcpf->remote_file);
186
+ rb_gc_mark(rbcpf->buffer_str);
187
+ }
188
+
189
+ void curl_postfield_free(ruby_curl_postfield *rbcpf) {
190
+ free(rbcpf);
191
+ }
192
+
193
+
194
+ /* ================= ALLOC METHODS ====================*/
195
+
196
+ /*
197
+ * call-seq:
198
+ * Curl::PostField.content(name, content) => #&lt;Curl::PostField...&gt;
199
+ * Curl::PostField.content(name, content, content_type = nil) => #&lt;Curl::PostField...&gt;
200
+ * Curl::PostField.content(name, content_type = nil) { |field| ... } => #&lt;Curl::PostField...&gt;
201
+ *
202
+ * Create a new Curl::PostField, supplying the field name, content,
203
+ * and, optionally, Content-type (curl will attempt to determine this if
204
+ * not specified).
205
+ *
206
+ * The block form allows a block to supply the content for this field, called
207
+ * during the perform. The block should return a ruby string with the field
208
+ * data.
209
+ */
210
+ static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass) {
211
+ ruby_curl_postfield *rbcpf = ALLOC(ruby_curl_postfield);
212
+
213
+ // wierdness - we actually require two args, unless a block is provided, but
214
+ // we have to work that out below.
215
+ rb_scan_args(argc, argv, "12&", &rbcpf->name, &rbcpf->content, &rbcpf->content_type, &rbcpf->content_proc);
216
+
217
+ // special handling if theres a block, second arg is actually content_type
218
+ if (rbcpf->content_proc != Qnil) {
219
+ if (rbcpf->content != Qnil) {
220
+ // we were given a content-type
221
+ rbcpf->content_type = rbcpf->content;
222
+ rbcpf->content = Qnil;
223
+ } else {
224
+ // default content type
225
+ rbcpf->content_type = Qnil;
226
+ }
227
+ } else {
228
+ // no block, so make sure content was provided
229
+ if (rbcpf->content == Qnil) {
230
+ rb_raise(rb_eArgError, "Incorrect number of arguments (expected 2 or 3)");
231
+ }
232
+ }
233
+
234
+ /* assoc objects */
235
+ rbcpf->local_file = Qnil;
236
+ rbcpf->remote_file = Qnil;
237
+ rbcpf->buffer_str = Qnil;
238
+
239
+ return Data_Wrap_Struct(cCurlPostField, curl_postfield_mark, curl_postfield_free, rbcpf);
240
+ }
241
+
242
+ /*
243
+ * call-seq:
244
+ * Curl::PostField.file(name, local_file_name) => #&lt;Curl::PostField...&gt;
245
+ * Curl::PostField.file(name, local_file_name, remote_file_name = local_file_name) => #&lt;Curl::PostField...&gt;
246
+ * Curl::PostField.file(name, remote_file_name) { |field| ... } => #&lt;Curl::PostField...&gt;
247
+ *
248
+ * Create a new Curl::PostField for a file upload field, supplying the local filename
249
+ * to read from, and optionally the remote filename (defaults to the local name).
250
+ *
251
+ * The block form allows a block to supply the content for this field, called
252
+ * during the perform. The block should return a ruby string with the field
253
+ * data.
254
+ */
255
+ static VALUE ruby_curl_postfield_new_file(int argc, VALUE *argv, VALUE klass) {
256
+ // TODO needs to handle content-type too
257
+ ruby_curl_postfield *rbcpf = ALLOC(ruby_curl_postfield);
258
+
259
+ rb_scan_args(argc, argv, "21&", &rbcpf->name, &rbcpf->local_file, &rbcpf->remote_file, &rbcpf->content_proc);
260
+
261
+ // special handling if theres a block, second arg is actually remote name.
262
+ if (rbcpf->content_proc != Qnil) {
263
+ if (rbcpf->local_file != Qnil) {
264
+ // we were given a local file
265
+ if (rbcpf->remote_file == Qnil) {
266
+ // we weren't given a remote, so local is actually remote
267
+ // (correct block call form)
268
+ rbcpf->remote_file = rbcpf->local_file;
269
+ }
270
+
271
+ // Shouldn't get a local file, so can ignore it.
272
+ rbcpf->local_file = Qnil;
273
+ }
274
+ } else {
275
+ if (rbcpf->remote_file == Qnil) {
276
+ rbcpf->remote_file = rbcpf->local_file;
277
+ }
278
+ }
279
+
280
+ /* assoc objects */
281
+ rbcpf->content = Qnil;
282
+ rbcpf->content_type = Qnil;
283
+ rbcpf->buffer_str = Qnil;
284
+
285
+ return Data_Wrap_Struct(cCurlPostField, curl_postfield_mark, curl_postfield_free, rbcpf);
286
+ }
287
+
288
+ /* ================= ATTRIBUTES ====================*/
289
+
290
+ /*
291
+ * call-seq:
292
+ * field.name = "name" => "name"
293
+ *
294
+ * Set the POST field name for this PostField.
295
+ */
296
+ static VALUE ruby_curl_postfield_name_set(VALUE self, VALUE name) {
297
+ CURB_OBJECT_SETTER(ruby_curl_postfield, name);
298
+ }
299
+
300
+ /*
301
+ * call-seq:
302
+ * field.name => "name"
303
+ *
304
+ * Obtain the POST field name for this PostField.
305
+ */
306
+ static VALUE ruby_curl_postfield_name_get(VALUE self) {
307
+ CURB_OBJECT_GETTER(ruby_curl_postfield, name);
308
+ }
309
+
310
+ /*
311
+ * call-seq:
312
+ * field.content = "content" => "content"
313
+ *
314
+ * Set the POST field content for this PostField. Ignored when a
315
+ * content_proc is supplied via either +Curl::PostField.file+ or
316
+ * +set_content_proc+.
317
+ */
318
+ static VALUE ruby_curl_postfield_content_set(VALUE self, VALUE content) {
319
+ CURB_OBJECT_SETTER(ruby_curl_postfield, content);
320
+ }
321
+
322
+ /*
323
+ * call-seq:
324
+ * field.content => "content"
325
+ *
326
+ * Obtain the POST field content for this PostField.
327
+ */
328
+ static VALUE ruby_curl_postfield_content_get(VALUE self) {
329
+ CURB_OBJECT_GETTER(ruby_curl_postfield, content);
330
+ }
331
+
332
+ /*
333
+ * call-seq:
334
+ * field.content_type = "content_type" => "content_type"
335
+ *
336
+ * Set the POST field Content-type for this PostField.
337
+ */
338
+ static VALUE ruby_curl_postfield_content_type_set(VALUE self, VALUE content_type) {
339
+ CURB_OBJECT_SETTER(ruby_curl_postfield, content_type);
340
+ }
341
+
342
+ /*
343
+ * call-seq:
344
+ * field.content_type => "content_type"
345
+ *
346
+ * Get the POST field Content-type for this PostField.
347
+ */
348
+ static VALUE ruby_curl_postfield_content_type_get(VALUE self) {
349
+ CURB_OBJECT_GETTER(ruby_curl_postfield, content_type);
350
+ }
351
+
352
+ /*
353
+ * call-seq:
354
+ * field.local_file = "filename" => "filename"
355
+ *
356
+ * Set the POST field local filename for this PostField (when performing
357
+ * a file upload). Ignored when a content_proc is supplied via either
358
+ * +Curl::PostField.file+ or +set_content_proc+.
359
+ */
360
+ static VALUE ruby_curl_postfield_local_file_set(VALUE self, VALUE local_file) {
361
+ CURB_OBJECT_SETTER(ruby_curl_postfield, local_file);
362
+ }
363
+
364
+ /*
365
+ * call-seq:
366
+ * field.local_file => "filename"
367
+ *
368
+ * Get the POST field local filename for this PostField (when performing
369
+ * a file upload).
370
+ */
371
+ static VALUE ruby_curl_postfield_local_file_get(VALUE self) {
372
+ CURB_OBJECT_GETTER(ruby_curl_postfield, local_file);
373
+ }
374
+
375
+ /*
376
+ * call-seq:
377
+ * field.remote_file = "filename" => "filename"
378
+ *
379
+ * Set the POST field remote filename for this PostField (when performing
380
+ * a file upload). If no remote filename is provided, and no content_proc
381
+ * is supplied, the local filename is used. If no remote filename is
382
+ * specified when a content_proc is used, an exception will be raised
383
+ * during the perform.
384
+ */
385
+ static VALUE ruby_curl_postfield_remote_file_set(VALUE self, VALUE remote_file) {
386
+ CURB_OBJECT_SETTER(ruby_curl_postfield, remote_file);
387
+ }
388
+
389
+ /*
390
+ * call-seq:
391
+ * field.local_file => "filename"
392
+ *
393
+ * Get the POST field remote filename for this PostField (when performing
394
+ * a file upload).
395
+ */
396
+ static VALUE ruby_curl_postfield_remote_file_get(VALUE self) {
397
+ CURB_OBJECT_GETTER(ruby_curl_postfield, remote_file);
398
+ }
399
+
400
+ /*
401
+ * call-seq:
402
+ * field.set_content_proc { |field| ... } => &lt;old proc&gt;
403
+ *
404
+ * Set a content proc for this field. This proc will be called during the
405
+ * perform to supply the content for this field, overriding any setting
406
+ * of +content+ or +local_file+.
407
+ */
408
+ static VALUE ruby_curl_postfield_content_proc_set(int argc, VALUE *argv, VALUE self) {
409
+ CURB_HANDLER_PROC_SETTER(ruby_curl_postfield, content_proc);
410
+ }
411
+
412
+ /*
413
+ * call-seq:
414
+ * field.to_str => "name=value"
415
+ * field.to_s => "name=value"
416
+ *
417
+ * Obtain a String representation of this PostField in url-encoded
418
+ * format. This is used to construct the post data for non-multipart
419
+ * POSTs.
420
+ *
421
+ * Only content fields may be converted to strings.
422
+ */
423
+ static VALUE ruby_curl_postfield_to_str(VALUE self) {
424
+ // FIXME This is using the deprecated curl_escape func
425
+ ruby_curl_postfield *rbcpf;
426
+ VALUE result = Qnil;
427
+ VALUE name = Qnil;
428
+ char *tmpchrs;
429
+
430
+ Data_Get_Struct(self, ruby_curl_postfield, rbcpf);
431
+
432
+ if (rbcpf->name != Qnil) {
433
+ name = rbcpf->name;
434
+ if (rb_type(name) == T_STRING) {
435
+ name = rbcpf->name;
436
+ } else if (rb_respond_to(name,rb_intern("to_s"))) {
437
+ name = rb_funcall(name, rb_intern("to_s"), 0);
438
+ }
439
+ else {
440
+ name = Qnil; // we can't handle this object
441
+ }
442
+ }
443
+ if (name == Qnil) {
444
+ rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string %s:%d, make sure your field name responds_to :to_s", __FILE__, __LINE__);
445
+ }
446
+
447
+ tmpchrs = curl_escape(StringValuePtr(name), (int)RSTRING_LEN(name));
448
+
449
+ if (!tmpchrs) {
450
+ rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name `%s'", tmpchrs);
451
+ } else {
452
+ VALUE tmpcontent = Qnil;
453
+ VALUE escd_name = rb_str_new2(tmpchrs);
454
+ curl_free(tmpchrs);
455
+
456
+ if (rbcpf->content_proc != Qnil) {
457
+ tmpcontent = rb_funcall(rbcpf->content_proc, idCall, 1, self);
458
+ } else if (rbcpf->content != Qnil) {
459
+ tmpcontent = rbcpf->content;
460
+ } else if (rbcpf->local_file != Qnil) {
461
+ tmpcontent = rbcpf->local_file;
462
+ } else if (rbcpf->remote_file != Qnil) {
463
+ tmpcontent = rbcpf->remote_file;
464
+ } else {
465
+ tmpcontent = rb_str_new2("");
466
+ }
467
+ if (TYPE(tmpcontent) != T_STRING) {
468
+ if (rb_respond_to(tmpcontent, rb_intern("to_s"))) {
469
+ tmpcontent = rb_funcall(tmpcontent, rb_intern("to_s"), 0);
470
+ }
471
+ else {
472
+ rb_raise(rb_eRuntimeError, "postfield(%s) is not a string and does not respond_to to_s", RSTRING_PTR(escd_name) );
473
+ }
474
+ }
475
+ //fprintf(stderr, "encoding content: %ld - %s\n", RSTRING_LEN(tmpcontent), RSTRING_PTR(tmpcontent) );
476
+ tmpchrs = curl_escape(RSTRING_PTR(tmpcontent), (int)RSTRING_LEN(tmpcontent));
477
+ if (!tmpchrs) {
478
+ rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content `%s'", tmpchrs);
479
+ } else {
480
+ VALUE escd_content = rb_str_new2(tmpchrs);
481
+ curl_free(tmpchrs);
482
+
483
+ result = escd_name;
484
+ rb_str_cat(result, "=", 1);
485
+ rb_str_concat(result, escd_content);
486
+ }
487
+ }
488
+
489
+ return result;
490
+ }
491
+
492
+
493
+ /* =================== INIT LIB =====================*/
494
+ void init_curb_postfield() {
495
+ VALUE sc;
496
+
497
+ idCall = rb_intern("call");
498
+
499
+ cCurlPostField = rb_define_class_under(mCurl, "PostField", rb_cObject);
500
+
501
+ /* Class methods */
502
+ rb_define_singleton_method(cCurlPostField, "content", ruby_curl_postfield_new_content, -1);
503
+ rb_define_singleton_method(cCurlPostField, "file", ruby_curl_postfield_new_file, -1);
504
+
505
+ sc = rb_singleton_class(cCurlPostField);
506
+ rb_undef(sc, rb_intern("new"));
507
+
508
+ rb_define_method(cCurlPostField, "name=", ruby_curl_postfield_name_set, 1);
509
+ rb_define_method(cCurlPostField, "name", ruby_curl_postfield_name_get, 0);
510
+ rb_define_method(cCurlPostField, "content=", ruby_curl_postfield_content_set, 1);
511
+ rb_define_method(cCurlPostField, "content", ruby_curl_postfield_content_get, 0);
512
+ rb_define_method(cCurlPostField, "content_type=", ruby_curl_postfield_content_type_set, 1);
513
+ rb_define_method(cCurlPostField, "content_type", ruby_curl_postfield_content_type_get, 0);
514
+ rb_define_method(cCurlPostField, "local_file=", ruby_curl_postfield_local_file_set, 1);
515
+ rb_define_method(cCurlPostField, "local_file", ruby_curl_postfield_local_file_get, 0);
516
+ rb_define_method(cCurlPostField, "remote_file=", ruby_curl_postfield_remote_file_set, 1);
517
+ rb_define_method(cCurlPostField, "remote_file", ruby_curl_postfield_remote_file_get, 0);
518
+
519
+ rb_define_method(cCurlPostField, "set_content_proc", ruby_curl_postfield_content_proc_set, -1);
520
+
521
+ rb_define_method(cCurlPostField, "to_str", ruby_curl_postfield_to_str, 0);
522
+ rb_define_alias(cCurlPostField, "to_s", "to_str");
523
+ }