* Fixed crashes with repeated registering/unregisitering of request methods (noticed...
[m6w6/ext-http] / http_request_body_api.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2007, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_CURL
16 #include "php_http.h"
17
18 #ifdef HTTP_HAVE_CURL
19
20 #include "php_http_api.h"
21 #include "php_http_url_api.h"
22 #include "php_http_request_body_api.h"
23
24 #if defined(HAVE_CURL_GETFORMDATA) && !defined(HAVE_CURL_FORMGET)
25 struct FormData {
26 struct FormData *next;
27 int type;
28 char *line;
29 size_t length;
30 };
31
32 CURLcode Curl_getFormData(struct FormData **, struct curl_httppost *post, curl_off_t *size);
33
34 static char *file_get_contents(char *file, size_t *len TSRMLS_DC)
35 {
36 php_stream *s = NULL;
37 char *buf = NULL;
38
39 if ((s = php_stream_open_wrapper_ex(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT))) {
40 *len = php_stream_copy_to_mem(s, &buf, (size_t) -1, 0);
41 php_stream_close(s);
42 } else {
43 *len = 0;
44 }
45 return buf;
46 }
47
48 static int curl_formget(struct FormData *post, phpstr *str TSRMLS_DC)
49 {
50 int fgc_error = 0;
51 char *fdata;
52 size_t fsize;
53 struct FormData *next, *pptr = post;
54
55 while (pptr) {
56 next = pptr->next;
57
58 if (!fgc_error) {
59 if (pptr->type) {
60 if ((fdata = file_get_contents(pptr->line, &fsize TSRMLS_CC))) {
61 phpstr_append(str, fdata, fsize);
62 efree(fdata);
63 } else {
64 fgc_error = 1;
65 }
66 } else {
67 phpstr_append(str, pptr->line, pptr->length);
68 }
69 }
70
71 curl_free(pptr->line);
72 curl_free(pptr);
73 pptr = next;
74 }
75
76 return fgc_error;
77 }
78 #endif
79
80
81 /* {{{ http_request_body *http_request_body_new() */
82 PHP_HTTP_API http_request_body *_http_request_body_init_ex(http_request_body *body, int type, void *data, size_t size, zend_bool free ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
83 {
84 if (!body) {
85 body = emalloc_rel(sizeof(http_request_body));
86 }
87
88 body->type = type;
89 body->free = free;
90 body->priv = 0;
91 body->data = data;
92 body->size = size;
93
94 return body;
95 }
96 /* }}} */
97
98 /* {{{ http_request_body *http_request_body_fill(http_request_body *body, HashTable *, HashTable *) */
99 PHP_HTTP_API http_request_body *_http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
100 {
101 if (files && (zend_hash_num_elements(files) > 0)) {
102 HashKey key = initHashKey(0);
103 zval **data;
104 HashPosition pos;
105 struct curl_httppost *http_post_data[2] = {NULL, NULL};
106
107 /* normal data */
108 if (fields) {
109 FOREACH_HASH_KEYVAL(pos, fields, key, data) {
110 if (key.type == HASH_KEY_IS_STRING) {
111 CURLcode err;
112 zval *orig = *data;
113
114 convert_to_string_ex(data);
115 err = curl_formadd(&http_post_data[0], &http_post_data[1],
116 CURLFORM_COPYNAME, key.str,
117 CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
118 CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_PP(data),
119 CURLFORM_END
120 );
121
122 if (orig != *data) {
123 zval_ptr_dtor(data);
124 }
125
126 if (CURLE_OK != err) {
127 http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err));
128 curl_formfree(http_post_data[0]);
129 return NULL;
130 }
131 }
132 }
133 }
134
135 /* file data */
136 FOREACH_HASH_VAL(pos, files, data) {
137 zval **file, **type, **name;
138
139 if (Z_TYPE_PP(data) != IS_ARRAY) {
140 http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry");
141 } else if ( SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void *) &name) ||
142 SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void *) &type) ||
143 SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void *) &file)) {
144 http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Post file array entry misses either 'name', 'type' or 'file' entry");
145 } else {
146 CURLcode err;
147 const char *path;
148 zval *ofile = *file, *otype = *type, *oname = *name;
149
150 convert_to_string_ex(file);
151 convert_to_string_ex(type);
152 convert_to_string_ex(name);
153
154 HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_PP(file), curl_formfree(http_post_data[0]); return NULL);
155
156 /* this is blatant but should be sufficient for most cases */
157 if (strncasecmp(Z_STRVAL_PP(file), "file://", lenof("file://"))) {
158 path = Z_STRVAL_PP(file);
159 } else {
160 path = Z_STRVAL_PP(file) + lenof("file://");
161 }
162
163 err = curl_formadd(&http_post_data[0], &http_post_data[1],
164 CURLFORM_COPYNAME, Z_STRVAL_PP(name),
165 CURLFORM_FILE, path,
166 CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
167 CURLFORM_END
168 );
169
170 if (ofile != *file) zval_ptr_dtor(file);
171 if (otype != *type) zval_ptr_dtor(type);
172 if (oname != *name) zval_ptr_dtor(name);
173
174 if (CURLE_OK != err) {
175 http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err));
176 curl_formfree(http_post_data[0]);
177 return NULL;
178 }
179 }
180 }
181
182 return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CURLPOST, http_post_data[0], 0, 1);
183
184 } else if (fields) {
185 char *encoded;
186 size_t encoded_len;
187
188 if (SUCCESS != http_urlencode_hash_ex(fields, 1, NULL, 0, &encoded, &encoded_len)) {
189 http_error(HE_WARNING, HTTP_E_ENCODING, "Could not encode post data");
190 return NULL;
191 }
192
193 return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, encoded, encoded_len, 1);
194 } else {
195 return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, estrndup("", 0), 0, 1);
196 }
197 }
198
199 /* STATUS http_request_body_encode(http_request_body *, char**, size_t *) */
200 PHP_HTTP_API STATUS _http_request_body_encode(http_request_body *body, char **buf, size_t *len TSRMLS_DC)
201 {
202 switch (body->type) {
203 case HTTP_REQUEST_BODY_CURLPOST:
204 {
205 #if defined(HAVE_CURL_FORMGET)
206 phpstr str;
207
208 phpstr_init_ex(&str, 0x8000, 0);
209 if (curl_formget(body->data, &str, (curl_formget_callback) phpstr_append)) {
210 phpstr_dtor(&str);
211 } else {
212 phpstr_fix(&str);
213 *buf = PHPSTR_VAL(&str);
214 *len = PHPSTR_LEN(&str);
215 return SUCCESS;
216 }
217 #elif defined(HAVE_CURL_GETFORMDATA)
218 struct FormData *data;
219 curl_off_t size;
220
221 if (!Curl_getFormData(&data, body->data, &size)) {
222 phpstr str;
223
224 phpstr_init_ex(&str, (size_t) size, 0);
225 if (curl_formget(data, &str TSRMLS_CC)) {
226 phpstr_dtor(&str);
227 } else {
228 phpstr_fix(&str);
229 *buf = PHPSTR_VAL(&str);
230 *len = PHPSTR_LEN(&len);
231 return SUCCESS;
232 }
233 }
234 #endif
235 break;
236 }
237
238 case HTTP_REQUEST_BODY_CSTRING:
239 *buf = estrndup(body->data, *len = body->size);
240 return SUCCESS;
241
242 default:
243 break;
244 }
245 return FAILURE;
246 }
247 /* }}} */
248
249 /* {{{ void http_request_body_dtor(http_request_body *) */
250 PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC)
251 {
252 if (body) {
253 if (body->free) {
254 switch (body->type) {
255 case HTTP_REQUEST_BODY_CSTRING:
256 if (body->data) {
257 efree(body->data);
258 }
259 break;
260
261 case HTTP_REQUEST_BODY_CURLPOST:
262 curl_formfree(body->data);
263 break;
264
265 case HTTP_REQUEST_BODY_UPLOADFILE:
266 php_stream_close(body->data);
267 break;
268 }
269 }
270 memset(body, 0, sizeof(http_request_body));
271 }
272 }
273 /* }}} */
274
275 /* {{{ void http_request_body_free(http_request_body *) */
276 PHP_HTTP_API void _http_request_body_free(http_request_body **body TSRMLS_DC)
277 {
278 if (*body) {
279 http_request_body_dtor(*body);
280 efree(*body);
281 *body = NULL;
282 }
283 }
284 /* }}} */
285
286 #endif /* HTTP_HAVE_CURL */
287
288 /*
289 * Local variables:
290 * tab-width: 4
291 * c-basic-offset: 4
292 * End:
293 * vim600: noet sw=4 ts=4 fdm=marker
294 * vim<600: noet sw=4 ts=4
295 */