- enable dns data sharing for the global request datashare by default
[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-2006, 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 char *key = NULL;
103 ulong idx;
104 zval **data;
105 HashPosition pos;
106 struct curl_httppost *http_post_data[2] = {NULL, NULL};
107
108 /* normal data */
109 if (fields) {
110 FOREACH_HASH_KEYVAL(pos, fields, key, idx, data) {
111 if (key) {
112 CURLcode err;
113 zval *orig = *data;
114
115 convert_to_string_ex(data);
116 err = curl_formadd(&http_post_data[0], &http_post_data[1],
117 CURLFORM_COPYNAME, key,
118 CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
119 CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_PP(data),
120 CURLFORM_END
121 );
122
123 if (orig != *data) {
124 zval_ptr_dtor(data);
125 }
126
127 if (CURLE_OK != err) {
128 http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err));
129 curl_formfree(http_post_data[0]);
130 return NULL;
131 }
132
133 /* reset */
134 key = NULL;
135 }
136 }
137 }
138
139 /* file data */
140 FOREACH_HASH_VAL(pos, files, data) {
141 zval **file, **type, **name;
142
143 if (Z_TYPE_PP(data) != IS_ARRAY) {
144 http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry");
145 } else if ( SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void *) &name) ||
146 SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void *) &type) ||
147 SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void *) &file)) {
148 http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Post file array entry misses either 'name', 'type' or 'file' entry");
149 } else {
150 CURLcode err;
151 const char *path;
152 zval *ofile = *file, *otype = *type, *oname = *name;
153
154 convert_to_string_ex(file);
155 convert_to_string_ex(type);
156 convert_to_string_ex(name);
157
158 HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_PP(file), curl_formfree(http_post_data[0]); return NULL);
159
160 /* this is blatant but should be sufficient for most cases */
161 if (strncasecmp(Z_STRVAL_PP(file), "file://", lenof("file://"))) {
162 path = Z_STRVAL_PP(file);
163 } else {
164 path = Z_STRVAL_PP(file) + lenof("file://");
165 }
166
167 err = curl_formadd(&http_post_data[0], &http_post_data[1],
168 CURLFORM_COPYNAME, Z_STRVAL_PP(name),
169 CURLFORM_FILE, path,
170 CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
171 CURLFORM_END
172 );
173
174 if (ofile != *file) zval_ptr_dtor(file);
175 if (otype != *type) zval_ptr_dtor(type);
176 if (oname != *name) zval_ptr_dtor(name);
177
178 if (CURLE_OK != err) {
179 http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err));
180 curl_formfree(http_post_data[0]);
181 return NULL;
182 }
183 }
184 }
185
186 return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CURLPOST, http_post_data[0], 0, 1);
187
188 } else if (fields) {
189 char *encoded;
190 size_t encoded_len;
191
192 if (SUCCESS != http_urlencode_hash_ex(fields, 1, NULL, 0, &encoded, &encoded_len)) {
193 http_error(HE_WARNING, HTTP_E_ENCODING, "Could not encode post data");
194 return NULL;
195 }
196
197 return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, encoded, encoded_len, 1);
198 } else {
199 return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, estrndup("", 0), 0, 1);
200 }
201 }
202
203 /* STATUS http_request_body_encode(http_request_body *, char**, size_t *) */
204 PHP_HTTP_API STATUS _http_request_body_encode(http_request_body *body, char **buf, size_t *len TSRMLS_DC)
205 {
206 switch (body->type) {
207 case HTTP_REQUEST_BODY_CURLPOST:
208 {
209 #if defined(HAVE_CURL_FORMGET)
210 phpstr str;
211
212 phpstr_init_ex(&str, 0x8000, 0);
213 if (curl_formget(body->data, &str, (curl_formget_callback) phpstr_append)) {
214 phpstr_dtor(&str);
215 } else {
216 phpstr_fix(&str);
217 *buf = PHPSTR_VAL(&str);
218 *len = PHPSTR_LEN(&str);
219 return SUCCESS;
220 }
221 #elif defined(HAVE_CURL_GETFORMDATA)
222 struct FormData *data;
223 curl_off_t size;
224
225 if (!Curl_getFormData(&data, body->data, &size)) {
226 phpstr str;
227
228 phpstr_init_ex(&str, (size_t) size, 0);
229 if (curl_formget(data, &str TSRMLS_CC)) {
230 phpstr_dtor(&str);
231 } else {
232 phpstr_fix(&str);
233 *buf = PHPSTR_VAL(&str);
234 *len = PHPSTR_LEN(&len);
235 return SUCCESS;
236 }
237 }
238 #endif
239 break;
240 }
241
242 case HTTP_REQUEST_BODY_CSTRING:
243 *buf = estrndup(body->data, *len = body->size);
244 return SUCCESS;
245
246 default:
247 break;
248 }
249 return FAILURE;
250 }
251 /* }}} */
252
253 /* {{{ void http_request_body_dtor(http_request_body *) */
254 PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC)
255 {
256 if (body) {
257 if (body->free) {
258 switch (body->type) {
259 case HTTP_REQUEST_BODY_CSTRING:
260 if (body->data) {
261 efree(body->data);
262 }
263 break;
264
265 case HTTP_REQUEST_BODY_CURLPOST:
266 curl_formfree(body->data);
267 break;
268
269 case HTTP_REQUEST_BODY_UPLOADFILE:
270 php_stream_close(body->data);
271 break;
272 }
273 }
274 memset(body, 0, sizeof(http_request_body));
275 }
276 }
277 /* }}} */
278
279 /* {{{ void http_request_body_free(http_request_body *) */
280 PHP_HTTP_API void _http_request_body_free(http_request_body **body TSRMLS_DC)
281 {
282 if (*body) {
283 http_request_body_dtor(*body);
284 efree(*body);
285 *body = NULL;
286 }
287 }
288 /* }}} */
289
290 #endif /* HTTP_HAVE_CURL */
291
292 /*
293 * Local variables:
294 * tab-width: 4
295 * c-basic-offset: 4
296 * End:
297 * vim600: noet sw=4 ts=4 fdm=marker
298 * vim<600: noet sw=4 ts=4
299 */