curb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of curb might be problematic. Click here for more details.
- data/LICENSE +51 -0
- data/README +106 -0
- data/Rakefile +302 -0
- data/doc.rb +42 -0
- data/ext/curb.c +333 -0
- data/ext/curb.h +39 -0
- data/ext/curb.rb +46 -0
- data/ext/curb_easy.c +2138 -0
- data/ext/curb_easy.h +73 -0
- data/ext/curb_errors.c +471 -0
- data/ext/curb_errors.h +106 -0
- data/ext/curb_macros.h +114 -0
- data/ext/curb_postfield.c +499 -0
- data/ext/curb_postfield.h +40 -0
- data/ext/curl.rb +2 -0
- data/ext/extconf.rb +24 -0
- data/samples/gmail.rb +46 -0
- data/tests/alltests.rb +3 -0
- data/tests/bug_instance_post_differs_from_class_post.rb +53 -0
- data/tests/bug_require_last_or_segfault.rb +40 -0
- data/tests/helper.rb +15 -0
- data/tests/require_last_or_segfault_script.rb +36 -0
- data/tests/tc_curl_easy.rb +415 -0
- data/tests/tc_curl_postfield.rb +141 -0
- data/tests/unittests.rb +2 -0
- metadata +80 -0
data/ext/curb_errors.h
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
/* curb_errors.h - Ruby exception types for curl errors
|
2
|
+
* Copyright (c)2006 Ross Bamford.
|
3
|
+
* Licensed under the Ruby License. See LICENSE for details.
|
4
|
+
*
|
5
|
+
* $Id: curb_errors.h 4 2006-11-17 18:35:31Z roscopeco $
|
6
|
+
*/
|
7
|
+
#ifndef __CURB_ERRORS_H
|
8
|
+
#define __CURB_ERRORS_H
|
9
|
+
|
10
|
+
#include "curb.h"
|
11
|
+
|
12
|
+
/* base errors */
|
13
|
+
extern VALUE cCurlErr;
|
14
|
+
|
15
|
+
extern VALUE mCurlErr;
|
16
|
+
extern VALUE eCurlErrError;
|
17
|
+
extern VALUE eCurlErrFTPError;
|
18
|
+
extern VALUE eCurlErrHTTPError;
|
19
|
+
extern VALUE eCurlErrFileError;
|
20
|
+
extern VALUE eCurlErrLDAPError;
|
21
|
+
extern VALUE eCurlErrTelnetError;
|
22
|
+
extern VALUE eCurlErrTFTPError;
|
23
|
+
|
24
|
+
/* libcurl errors */
|
25
|
+
extern VALUE eCurlErrUnsupportedProtocol;
|
26
|
+
extern VALUE eCurlErrFailedInit;
|
27
|
+
extern VALUE eCurlErrMalformedURL;
|
28
|
+
extern VALUE eCurlErrMalformedURLUser;
|
29
|
+
extern VALUE eCurlErrProxyResolution;
|
30
|
+
extern VALUE eCurlErrHostResolution;
|
31
|
+
extern VALUE eCurlErrConnectFailed;
|
32
|
+
extern VALUE eCurlErrFTPWierdReply;
|
33
|
+
extern VALUE eCurlErrFTPAccessDenied;
|
34
|
+
extern VALUE eCurlErrFTPBadPassword;
|
35
|
+
extern VALUE eCurlErrFTPWierdPassReply;
|
36
|
+
extern VALUE eCurlErrFTPWierdUserReply;
|
37
|
+
extern VALUE eCurlErrFTPWierdPasvReply;
|
38
|
+
extern VALUE eCurlErrFTPWierd227Format;
|
39
|
+
extern VALUE eCurlErrFTPCantGetHost;
|
40
|
+
extern VALUE eCurlErrFTPCantReconnect;
|
41
|
+
extern VALUE eCurlErrFTPCouldntSetBinary;
|
42
|
+
extern VALUE eCurlErrPartialFile;
|
43
|
+
extern VALUE eCurlErrFTPCouldntRetrFile;
|
44
|
+
extern VALUE eCurlErrFTPWrite;
|
45
|
+
extern VALUE eCurlErrFTPQuote;
|
46
|
+
extern VALUE eCurlErrHTTPFailed;
|
47
|
+
extern VALUE eCurlErrWriteError;
|
48
|
+
extern VALUE eCurlErrMalformedUser;
|
49
|
+
extern VALUE eCurlErrFTPCouldntStorFile;
|
50
|
+
extern VALUE eCurlErrReadError;
|
51
|
+
extern VALUE eCurlErrOutOfMemory;
|
52
|
+
extern VALUE eCurlErrTimeout;
|
53
|
+
extern VALUE eCurlErrFTPCouldntSetASCII;
|
54
|
+
extern VALUE eCurlErrFTPPortFailed;
|
55
|
+
extern VALUE eCurlErrFTPCouldntUseRest;
|
56
|
+
extern VALUE eCurlErrFTPCouldntGetSize;
|
57
|
+
extern VALUE eCurlErrHTTPRange;
|
58
|
+
extern VALUE eCurlErrHTTPPost;
|
59
|
+
extern VALUE eCurlErrSSLConnectError;
|
60
|
+
extern VALUE eCurlErrBadResume;
|
61
|
+
extern VALUE eCurlErrFileCouldntRead;
|
62
|
+
extern VALUE eCurlErrLDAPCouldntBind;
|
63
|
+
extern VALUE eCurlErrLDAPSearchFailed;
|
64
|
+
extern VALUE eCurlErrLibraryNotFound;
|
65
|
+
extern VALUE eCurlErrFunctionNotFound;
|
66
|
+
extern VALUE eCurlErrAbortedByCallback;
|
67
|
+
extern VALUE eCurlErrBadFunctionArgument;
|
68
|
+
extern VALUE eCurlErrBadCallingOrder;
|
69
|
+
extern VALUE eCurlErrInterfaceFailed;
|
70
|
+
extern VALUE eCurlErrBadPasswordEntered;
|
71
|
+
extern VALUE eCurlErrTooManyRedirects;
|
72
|
+
extern VALUE eCurlErrTelnetUnknownOption;
|
73
|
+
extern VALUE eCurlErrTelnetBadOptionSyntax;
|
74
|
+
extern VALUE eCurlErrObsolete;
|
75
|
+
extern VALUE eCurlErrSSLPeerCertificate;
|
76
|
+
extern VALUE eCurlErrGotNothing;
|
77
|
+
extern VALUE eCurlErrSSLEngineNotFound;
|
78
|
+
extern VALUE eCurlErrSSLEngineSetFailed;
|
79
|
+
extern VALUE eCurlErrSendError;
|
80
|
+
extern VALUE eCurlErrRecvError;
|
81
|
+
extern VALUE eCurlErrShareInUse;
|
82
|
+
extern VALUE eCurlErrSSLCertificate;
|
83
|
+
extern VALUE eCurlErrSSLCipher;
|
84
|
+
extern VALUE eCurlErrSSLCACertificate;
|
85
|
+
extern VALUE eCurlErrBadContentEncoding;
|
86
|
+
extern VALUE eCurlErrLDAPInvalidURL;
|
87
|
+
extern VALUE eCurlErrFileSizeExceeded;
|
88
|
+
extern VALUE eCurlErrFTPSSLFailed;
|
89
|
+
extern VALUE eCurlErrSendFailedRewind;
|
90
|
+
extern VALUE eCurlErrSSLEngineInitFailed;
|
91
|
+
extern VALUE eCurlErrLoginDenied;
|
92
|
+
extern VALUE eCurlErrTFTPNotFound;
|
93
|
+
extern VALUE eCurlErrTFTPPermission;
|
94
|
+
extern VALUE eCurlErrTFTPDiskFull;
|
95
|
+
extern VALUE eCurlErrTFTPIllegalOperation;
|
96
|
+
extern VALUE eCurlErrTFTPUnknownID;
|
97
|
+
extern VALUE eCurlErrTFTPFileExists;
|
98
|
+
extern VALUE eCurlErrTFTPNoSuchUser;
|
99
|
+
|
100
|
+
/* binding errors */
|
101
|
+
extern VALUE eCurlErrInvalidPostField;
|
102
|
+
|
103
|
+
void init_curb_errors();
|
104
|
+
void raise_curl_easy_error_exception(CURLcode code);
|
105
|
+
|
106
|
+
#endif
|
data/ext/curb_macros.h
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
/* Curb - helper macros for ruby integration
|
2
|
+
* Copyright (c)2006 Ross Bamford.
|
3
|
+
* Licensed under the Ruby License. See LICENSE for details.
|
4
|
+
*
|
5
|
+
* $Id: curb_macros.h 13 2006-11-23 23:54:25Z roscopeco $
|
6
|
+
*/
|
7
|
+
|
8
|
+
#ifndef __CURB_MACROS_H
|
9
|
+
#define __CURB_MACROS_H
|
10
|
+
|
11
|
+
/* getter/setter macros for various things */
|
12
|
+
/* setter for anything that stores a ruby VALUE in the struct */
|
13
|
+
#define CURB_OBJECT_SETTER(type, attr) \
|
14
|
+
type *ptr; \
|
15
|
+
\
|
16
|
+
Data_Get_Struct(self, type, ptr); \
|
17
|
+
ptr->attr = attr; \
|
18
|
+
\
|
19
|
+
return attr;
|
20
|
+
|
21
|
+
/* getter for anything that stores a ruby VALUE */
|
22
|
+
#define CURB_OBJECT_GETTER(type, attr) \
|
23
|
+
type *ptr; \
|
24
|
+
\
|
25
|
+
Data_Get_Struct(self, type, ptr); \
|
26
|
+
return ptr->attr;
|
27
|
+
|
28
|
+
/* setter for bool flags */
|
29
|
+
#define CURB_BOOLEAN_SETTER(type, attr) \
|
30
|
+
type *ptr; \
|
31
|
+
Data_Get_Struct(self, type, ptr); \
|
32
|
+
\
|
33
|
+
if (attr == Qnil || attr == Qfalse) { \
|
34
|
+
ptr->attr = 0; \
|
35
|
+
} else { \
|
36
|
+
ptr->attr = 1; \
|
37
|
+
} \
|
38
|
+
\
|
39
|
+
return attr;
|
40
|
+
|
41
|
+
/* getter for bool flags */
|
42
|
+
#define CURB_BOOLEAN_GETTER(type, attr) \
|
43
|
+
type *ptr; \
|
44
|
+
Data_Get_Struct(self, type, ptr); \
|
45
|
+
\
|
46
|
+
return((ptr->attr) ? Qtrue : Qfalse);
|
47
|
+
|
48
|
+
/* special setter for on_event handlers that take a block */
|
49
|
+
#define CURB_HANDLER_PROC_SETTER(type, handler) \
|
50
|
+
type *ptr; \
|
51
|
+
VALUE oldproc; \
|
52
|
+
\
|
53
|
+
Data_Get_Struct(self, type, ptr); \
|
54
|
+
\
|
55
|
+
oldproc = ptr->handler; \
|
56
|
+
rb_scan_args(argc, argv, "0&", &ptr->handler); \
|
57
|
+
\
|
58
|
+
return oldproc; \
|
59
|
+
|
60
|
+
/* setter for numerics that are kept in c ints */
|
61
|
+
#define CURB_IMMED_SETTER(type, attr, nilval) \
|
62
|
+
type *ptr; \
|
63
|
+
\
|
64
|
+
Data_Get_Struct(self, type, ptr); \
|
65
|
+
if (attr == Qnil) { \
|
66
|
+
ptr->attr = nilval; \
|
67
|
+
} else { \
|
68
|
+
ptr->attr = NUM2INT(attr); \
|
69
|
+
} \
|
70
|
+
\
|
71
|
+
return attr; \
|
72
|
+
|
73
|
+
/* setter for numerics that are kept in c ints */
|
74
|
+
#define CURB_IMMED_GETTER(type, attr, nilval) \
|
75
|
+
type *ptr; \
|
76
|
+
\
|
77
|
+
Data_Get_Struct(self, type, ptr); \
|
78
|
+
if (ptr->attr == nilval) { \
|
79
|
+
return Qnil; \
|
80
|
+
} else { \
|
81
|
+
return INT2NUM(ptr->attr); \
|
82
|
+
}
|
83
|
+
|
84
|
+
/* special setter for port / port ranges */
|
85
|
+
#define CURB_IMMED_PORT_SETTER(type, attr, msg) \
|
86
|
+
type *ptr; \
|
87
|
+
\
|
88
|
+
Data_Get_Struct(self, type, ptr); \
|
89
|
+
if (attr == Qnil) { \
|
90
|
+
ptr->attr = 0; \
|
91
|
+
} else { \
|
92
|
+
int port = FIX2INT(attr); \
|
93
|
+
\
|
94
|
+
if ((port) && ((port & 0xFFFF) == port)) { \
|
95
|
+
ptr->attr = port; \
|
96
|
+
} else { \
|
97
|
+
rb_raise(rb_eArgError, "Invalid " msg " %d (expected between 1 and 65535)", port); \
|
98
|
+
} \
|
99
|
+
} \
|
100
|
+
\
|
101
|
+
return attr; \
|
102
|
+
|
103
|
+
/* special getter for port / port ranges */
|
104
|
+
#define CURB_IMMED_PORT_GETTER(type, attr) \
|
105
|
+
type *ptr; \
|
106
|
+
\
|
107
|
+
Data_Get_Struct(self, type, ptr); \
|
108
|
+
if (ptr->attr == 0) { \
|
109
|
+
return Qnil; \
|
110
|
+
} else { \
|
111
|
+
return INT2FIX(ptr->attr); \
|
112
|
+
}
|
113
|
+
|
114
|
+
#endif
|
@@ -0,0 +1,499 @@
|
|
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
|
+
char *reason;
|
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
|
+
char *tmpchrs;
|
433
|
+
|
434
|
+
if ((tmpchrs = curl_escape(StringValuePtr(rbcpf->name), RSTRING_LEN(rbcpf->name))) == NULL) {
|
435
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name `%s'", tmpchrs);
|
436
|
+
} else {
|
437
|
+
VALUE tmpcontent = Qnil;
|
438
|
+
VALUE escd_name = rb_str_new2(tmpchrs);
|
439
|
+
curl_free(tmpchrs);
|
440
|
+
|
441
|
+
if (rbcpf->content_proc != Qnil) {
|
442
|
+
tmpcontent = rb_funcall(rbcpf->content_proc, idCall, 1, self);
|
443
|
+
} else if (rbcpf->content != Qnil) {
|
444
|
+
tmpcontent = rbcpf->content;
|
445
|
+
} else {
|
446
|
+
tmpcontent = rb_str_new2("");
|
447
|
+
}
|
448
|
+
|
449
|
+
if ((tmpchrs = curl_escape(StringValuePtr(tmpcontent), RSTRING_LEN(tmpcontent))) == NULL) {
|
450
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content `%s'", tmpchrs);
|
451
|
+
} else {
|
452
|
+
VALUE escd_content = rb_str_new2(tmpchrs);
|
453
|
+
curl_free(tmpchrs);
|
454
|
+
|
455
|
+
result = escd_name;
|
456
|
+
rb_str_cat(result, "=", 1);
|
457
|
+
rb_str_concat(result, escd_content);
|
458
|
+
}
|
459
|
+
}
|
460
|
+
} else {
|
461
|
+
rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string");
|
462
|
+
}
|
463
|
+
} else {
|
464
|
+
rb_raise(eCurlErrInvalidPostField, "Cannot convert non-content field to string");
|
465
|
+
}
|
466
|
+
|
467
|
+
return result;
|
468
|
+
}
|
469
|
+
|
470
|
+
|
471
|
+
/* =================== INIT LIB =====================*/
|
472
|
+
void init_curb_postfield() {
|
473
|
+
idCall = rb_intern("call");
|
474
|
+
|
475
|
+
cCurlPostField = rb_define_class_under(mCurl, "PostField", rb_cObject);
|
476
|
+
|
477
|
+
/* Class methods */
|
478
|
+
rb_define_singleton_method(cCurlPostField, "content", ruby_curl_postfield_new_content, -1);
|
479
|
+
rb_define_singleton_method(cCurlPostField, "file", ruby_curl_postfield_new_file, -1);
|
480
|
+
|
481
|
+
VALUE sc = rb_singleton_class(cCurlPostField);
|
482
|
+
rb_undef(sc, rb_intern("new"));
|
483
|
+
|
484
|
+
rb_define_method(cCurlPostField, "name=", ruby_curl_postfield_name_set, 1);
|
485
|
+
rb_define_method(cCurlPostField, "name", ruby_curl_postfield_name_get, 0);
|
486
|
+
rb_define_method(cCurlPostField, "content=", ruby_curl_postfield_content_set, 1);
|
487
|
+
rb_define_method(cCurlPostField, "content", ruby_curl_postfield_content_get, 0);
|
488
|
+
rb_define_method(cCurlPostField, "content_type=", ruby_curl_postfield_content_type_set, 1);
|
489
|
+
rb_define_method(cCurlPostField, "content_type", ruby_curl_postfield_content_type_get, 0);
|
490
|
+
rb_define_method(cCurlPostField, "local_file=", ruby_curl_postfield_local_file_set, 1);
|
491
|
+
rb_define_method(cCurlPostField, "local_file", ruby_curl_postfield_local_file_get, 0);
|
492
|
+
rb_define_method(cCurlPostField, "remote_file=", ruby_curl_postfield_remote_file_set, 1);
|
493
|
+
rb_define_method(cCurlPostField, "remote_file", ruby_curl_postfield_remote_file_get, 0);
|
494
|
+
|
495
|
+
rb_define_method(cCurlPostField, "set_content_proc", ruby_curl_postfield_content_proc_set, -1);
|
496
|
+
|
497
|
+
rb_define_method(cCurlPostField, "to_str", ruby_curl_postfield_to_str, 0);
|
498
|
+
rb_define_alias(cCurlPostField, "to_s", "to_str");
|
499
|
+
}
|