ghazel-curb 0.5.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,511 @@
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, 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, 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) => #<Curl::PostField...>
199
+ * Curl::PostField.content(name, content, content_type = nil) => #<Curl::PostField...>
200
+ * Curl::PostField.content(name, content_type = nil) { |field| ... } => #<Curl::PostField...>
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) => #<Curl::PostField...>
245
+ * Curl::PostField.file(name, local_file_name, remote_file_name = local_file_name) => #<Curl::PostField...>
246
+ * Curl::PostField.file(name, remote_file_name) { |field| ... } => #<Curl::PostField...>
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| ... } => <old proc>
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
+
428
+ Data_Get_Struct(self, ruby_curl_postfield, rbcpf);
429
+
430
+ if ((rbcpf->local_file == Qnil) && (rbcpf->remote_file == Qnil)) {
431
+ if (rbcpf->name != Qnil) {
432
+
433
+ char *tmpchrs = curl_escape(RSTRING_PTR(rbcpf->name), RSTRING_LEN(rbcpf->name));
434
+
435
+ if (!tmpchrs) {
436
+ rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name `%s'", tmpchrs);
437
+ } else {
438
+ VALUE tmpcontent = Qnil;
439
+ VALUE escd_name = rb_str_new2(tmpchrs);
440
+ curl_free(tmpchrs);
441
+
442
+ if (rbcpf->content_proc != Qnil) {
443
+ tmpcontent = rb_funcall(rbcpf->content_proc, idCall, 1, self);
444
+ } else if (rbcpf->content != Qnil) {
445
+ tmpcontent = rbcpf->content;
446
+ } else {
447
+ tmpcontent = rb_str_new2("");
448
+ }
449
+ if (TYPE(tmpcontent) != T_STRING) {
450
+ if (rb_respond_to(tmpcontent, rb_intern("to_s"))) {
451
+ tmpcontent = rb_funcall(tmpcontent, rb_intern("to_s"), 0);
452
+ }
453
+ else {
454
+ rb_raise(rb_eRuntimeError, "postfield(%s) is not a string and does not respond_to to_s", RSTRING_PTR(escd_name) );
455
+ }
456
+ }
457
+ //fprintf(stderr, "encoding content: %ld - %s\n", RSTRING_LEN(tmpcontent), RSTRING_PTR(tmpcontent) );
458
+ tmpchrs = curl_escape(RSTRING_PTR(tmpcontent), RSTRING_LEN(tmpcontent));
459
+ if (!tmpchrs) {
460
+ rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content `%s'", tmpchrs);
461
+ } else {
462
+ VALUE escd_content = rb_str_new2(tmpchrs);
463
+ curl_free(tmpchrs);
464
+
465
+ result = escd_name;
466
+ rb_str_cat(result, "=", 1);
467
+ rb_str_concat(result, escd_content);
468
+ }
469
+ }
470
+ } else {
471
+ rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string");
472
+ }
473
+ } else {
474
+ rb_raise(eCurlErrInvalidPostField, "Cannot convert non-content field to string");
475
+ }
476
+
477
+ return result;
478
+ }
479
+
480
+
481
+ /* =================== INIT LIB =====================*/
482
+ void init_curb_postfield() {
483
+ VALUE sc;
484
+
485
+ idCall = rb_intern("call");
486
+
487
+ cCurlPostField = rb_define_class_under(mCurl, "PostField", rb_cObject);
488
+
489
+ /* Class methods */
490
+ rb_define_singleton_method(cCurlPostField, "content", ruby_curl_postfield_new_content, -1);
491
+ rb_define_singleton_method(cCurlPostField, "file", ruby_curl_postfield_new_file, -1);
492
+
493
+ sc = rb_singleton_class(cCurlPostField);
494
+ rb_undef(sc, rb_intern("new"));
495
+
496
+ rb_define_method(cCurlPostField, "name=", ruby_curl_postfield_name_set, 1);
497
+ rb_define_method(cCurlPostField, "name", ruby_curl_postfield_name_get, 0);
498
+ rb_define_method(cCurlPostField, "content=", ruby_curl_postfield_content_set, 1);
499
+ rb_define_method(cCurlPostField, "content", ruby_curl_postfield_content_get, 0);
500
+ rb_define_method(cCurlPostField, "content_type=", ruby_curl_postfield_content_type_set, 1);
501
+ rb_define_method(cCurlPostField, "content_type", ruby_curl_postfield_content_type_get, 0);
502
+ rb_define_method(cCurlPostField, "local_file=", ruby_curl_postfield_local_file_set, 1);
503
+ rb_define_method(cCurlPostField, "local_file", ruby_curl_postfield_local_file_get, 0);
504
+ rb_define_method(cCurlPostField, "remote_file=", ruby_curl_postfield_remote_file_set, 1);
505
+ rb_define_method(cCurlPostField, "remote_file", ruby_curl_postfield_remote_file_get, 0);
506
+
507
+ rb_define_method(cCurlPostField, "set_content_proc", ruby_curl_postfield_content_proc_set, -1);
508
+
509
+ rb_define_method(cCurlPostField, "to_str", ruby_curl_postfield_to_str, 0);
510
+ rb_define_alias(cCurlPostField, "to_s", "to_str");
511
+ }
@@ -0,0 +1,40 @@
1
+ /* curb_postfield.h - 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.h 4 2006-11-17 18:35:31Z roscopeco $
6
+ */
7
+ #ifndef __CURB_POSTFIELD_H
8
+ #define __CURB_POSTFIELD_H
9
+
10
+ #include "curb.h"
11
+
12
+ /*
13
+ * postfield doesn't actually wrap a curl_httppost - instead,
14
+ * it just holds together some ruby objects and has a C-side
15
+ * method to add it to a given form list during the perform.
16
+ */
17
+ typedef struct {
18
+ /* Objects we associate */
19
+ VALUE name;
20
+ VALUE content;
21
+ VALUE content_type;
22
+ VALUE content_proc;
23
+ VALUE local_file;
24
+ VALUE remote_file;
25
+
26
+ /* this will sometimes hold a string, which is the result
27
+ * of the content_proc invocation. We need it to hang around.
28
+ */
29
+ VALUE buffer_str;
30
+ } ruby_curl_postfield;
31
+
32
+ extern VALUE cCurlPostField;
33
+
34
+ void append_to_form(VALUE self,
35
+ struct curl_httppost **first,
36
+ struct curl_httppost **last);
37
+
38
+ void init_curb_postfield();
39
+
40
+ #endif
data/ext/curb_upload.c ADDED
@@ -0,0 +1,80 @@
1
+ /* curb_upload.c - Curl upload handle
2
+ * Copyright (c)2009 Todd A Fisher.
3
+ * Licensed under the Ruby License. See LICENSE for details.
4
+ */
5
+ #include "curb_upload.h"
6
+ extern VALUE mCurl;
7
+ VALUE cCurlUpload;
8
+
9
+ #ifdef RDOC_NEVER_DEFINED
10
+ mCurl = rb_define_module("Curl");
11
+ #endif
12
+
13
+ static void curl_upload_mark(ruby_curl_upload *rbcu) {
14
+ if (rbcu->stream) rb_gc_mark(rbcu->stream);
15
+ }
16
+ static void curl_upload_free(ruby_curl_upload *rbcu) {
17
+ free(rbcu);
18
+ }
19
+
20
+ /*
21
+ * call-seq:
22
+ * internal class for sending large file uploads
23
+ */
24
+ VALUE ruby_curl_upload_new(VALUE klass) {
25
+ VALUE upload;
26
+ ruby_curl_upload *rbcu = ALLOC(ruby_curl_upload);
27
+ rbcu->stream = Qnil;
28
+ rbcu->offset = 0;
29
+ upload = Data_Wrap_Struct(klass, curl_upload_mark, curl_upload_free, rbcu);
30
+ return upload;
31
+ }
32
+
33
+ /*
34
+ * call-seq:
35
+ * internal class for sending large file uploads
36
+ */
37
+ VALUE ruby_curl_upload_stream_set(VALUE self, VALUE stream) {
38
+ ruby_curl_upload *rbcu;
39
+ Data_Get_Struct(self, ruby_curl_upload, rbcu);
40
+ rbcu->stream = stream;
41
+ return stream;
42
+ }
43
+ /*
44
+ * call-seq:
45
+ * internal class for sending large file uploads
46
+ */
47
+ VALUE ruby_curl_upload_stream_get(VALUE self) {
48
+ ruby_curl_upload *rbcu;
49
+ Data_Get_Struct(self, ruby_curl_upload, rbcu);
50
+ return rbcu->stream;
51
+ }
52
+ /*
53
+ * call-seq:
54
+ * internal class for sending large file uploads
55
+ */
56
+ VALUE ruby_curl_upload_offset_set(VALUE self, VALUE offset) {
57
+ ruby_curl_upload *rbcu;
58
+ Data_Get_Struct(self, ruby_curl_upload, rbcu);
59
+ rbcu->offset = FIX2INT(offset);
60
+ return offset;
61
+ }
62
+ /*
63
+ * call-seq:
64
+ * internal class for sending large file uploads
65
+ */
66
+ VALUE ruby_curl_upload_offset_get(VALUE self) {
67
+ ruby_curl_upload *rbcu;
68
+ Data_Get_Struct(self, ruby_curl_upload, rbcu);
69
+ return INT2FIX(rbcu->offset);
70
+ }
71
+
72
+ /* =================== INIT LIB =====================*/
73
+ void init_curb_upload() {
74
+ cCurlUpload = rb_define_class_under(mCurl, "Upload", rb_cObject);
75
+ rb_define_singleton_method(cCurlUpload, "new", ruby_curl_upload_new, 0);
76
+ rb_define_method(cCurlUpload, "stream=", ruby_curl_upload_stream_set, 1);
77
+ rb_define_method(cCurlUpload, "stream", ruby_curl_upload_stream_get, 0);
78
+ rb_define_method(cCurlUpload, "offset=", ruby_curl_upload_offset_set, 1);
79
+ rb_define_method(cCurlUpload, "offset", ruby_curl_upload_offset_get, 0);
80
+ }
data/ext/curb_upload.h ADDED
@@ -0,0 +1,30 @@
1
+ /* curb_upload.h - Curl upload handle
2
+ * Copyright (c)2009 Todd A Fisher.
3
+ * Licensed under the Ruby License. See LICENSE for details.
4
+ */
5
+ #ifndef __CURB_UPLOAD_H
6
+ #define __CURB_UPLOAD_H
7
+
8
+ #include "curb.h"
9
+
10
+ #include <curl/easy.h>
11
+
12
+ /*
13
+ * Maintain the state of an upload e.g. for putting large streams with very little memory
14
+ * out to a server. via PUT requests
15
+ */
16
+ typedef struct {
17
+ VALUE stream;
18
+ size_t offset;
19
+ } ruby_curl_upload;
20
+
21
+ extern VALUE cCurlUpload;
22
+ void init_curb_upload();
23
+
24
+ VALUE ruby_curl_upload_new(VALUE klass);
25
+ VALUE ruby_curl_upload_stream_set(VALUE self, VALUE stream);
26
+ VALUE ruby_curl_upload_stream_get(VALUE self);
27
+ VALUE ruby_curl_upload_offset_set(VALUE self, VALUE offset);
28
+ VALUE ruby_curl_upload_offset_get(VALUE self);
29
+
30
+ #endif