- simplify http_send_header API
[m6w6/ext-http] / http_request_object.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 #include "php.h"
23
24 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
25
26 #include "php_http_std_defs.h"
27 #include "php_http_request_object.h"
28 #include "php_http_request_api.h"
29 #include "php_http_request_pool_api.h"
30 #include "php_http.h"
31 #include "php_http_api.h"
32 #include "php_http_url_api.h"
33 #include "php_http_message_api.h"
34 #include "php_http_message_object.h"
35 #include "php_http_exception_object.h"
36
37 #ifdef PHP_WIN32
38 # include <winsock2.h>
39 #endif
40 #include <curl/curl.h>
41
42 ZEND_EXTERN_MODULE_GLOBALS(http);
43
44 #define HTTP_BEGIN_ARGS(method, ret_ref, req_args) HTTP_BEGIN_ARGS_EX(HttpRequest, method, ret_ref, req_args)
45 #define HTTP_EMPTY_ARGS(method, ret_ref) HTTP_EMPTY_ARGS_EX(HttpRequest, method, ret_ref)
46 #define HTTP_REQUEST_ME(method, visibility) PHP_ME(HttpRequest, method, HTTP_ARGS(HttpRequest, method), visibility)
47 #define HTTP_REQUEST_ALIAS(method, func) HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpRequest, method))
48
49 HTTP_EMPTY_ARGS(__destruct, 0);
50 HTTP_BEGIN_ARGS(__construct, 0, 0)
51 HTTP_ARG_VAL(url, 0)
52 HTTP_ARG_VAL(method, 0)
53 HTTP_END_ARGS;
54
55 HTTP_EMPTY_ARGS(getOptions, 0);
56 HTTP_EMPTY_ARGS(unsetOptions, 0);
57 HTTP_BEGIN_ARGS(setOptions, 0, 1)
58 HTTP_ARG_VAL(options, 0)
59 HTTP_END_ARGS;
60
61 HTTP_EMPTY_ARGS(getSslOptions, 0);
62 HTTP_EMPTY_ARGS(unsetSslOptions, 0);
63 HTTP_BEGIN_ARGS(setSslOptions, 0, 1)
64 HTTP_ARG_VAL(ssl_options, 0)
65 HTTP_END_ARGS;
66
67 HTTP_EMPTY_ARGS(getHeaders, 0);
68 HTTP_EMPTY_ARGS(unsetHeaders, 0);
69 HTTP_BEGIN_ARGS(addHeaders, 0, 1)
70 HTTP_ARG_VAL(headers, 0)
71 HTTP_END_ARGS;
72
73 HTTP_EMPTY_ARGS(getCookies, 0);
74 HTTP_EMPTY_ARGS(unsetCookies, 0);
75 HTTP_BEGIN_ARGS(addCookies, 0, 1)
76 HTTP_ARG_VAL(cookies, 0)
77 HTTP_END_ARGS;
78
79 HTTP_EMPTY_ARGS(getUrl, 0);
80 HTTP_BEGIN_ARGS(setUrl, 0, 1)
81 HTTP_ARG_VAL(url, 0)
82 HTTP_END_ARGS;
83
84 HTTP_EMPTY_ARGS(getMethod, 0);
85 HTTP_BEGIN_ARGS(setMethod, 0, 1)
86 HTTP_ARG_VAL(request_method, 0)
87 HTTP_END_ARGS;
88
89 HTTP_EMPTY_ARGS(getContentType, 0);
90 HTTP_BEGIN_ARGS(setContentType, 0, 1)
91 HTTP_ARG_VAL(content_type, 0)
92 HTTP_END_ARGS;
93
94 HTTP_EMPTY_ARGS(getQueryData, 0);
95 HTTP_EMPTY_ARGS(unsetQueryData, 0);
96 HTTP_BEGIN_ARGS(setQueryData, 0, 1)
97 HTTP_ARG_VAL(query_data, 0)
98 HTTP_END_ARGS;
99
100 HTTP_BEGIN_ARGS(addQueryData, 0, 1)
101 HTTP_ARG_VAL(query_data, 0)
102 HTTP_END_ARGS;
103
104 HTTP_EMPTY_ARGS(getPostFields, 0);
105 HTTP_EMPTY_ARGS(unsetPostFields, 0);
106 HTTP_BEGIN_ARGS(setPostFields, 0, 1)
107 HTTP_ARG_VAL(post_fields, 0)
108 HTTP_END_ARGS;
109
110 HTTP_BEGIN_ARGS(addPostFields, 0, 1)
111 HTTP_ARG_VAL(post_fields, 0)
112 HTTP_END_ARGS;
113
114 HTTP_EMPTY_ARGS(getPostFiles, 0);
115 HTTP_EMPTY_ARGS(unsetPostFiles, 0);
116 HTTP_BEGIN_ARGS(setPostFiles, 0, 1)
117 HTTP_ARG_VAL(post_files, 0)
118 HTTP_END_ARGS;
119
120 HTTP_BEGIN_ARGS(addPostFile, 0, 2)
121 HTTP_ARG_VAL(formname, 0)
122 HTTP_ARG_VAL(filename, 0)
123 HTTP_ARG_VAL(content_type, 0)
124 HTTP_END_ARGS;
125
126 HTTP_EMPTY_ARGS(getPutFile, 0);
127 HTTP_EMPTY_ARGS(unsetPutFile, 0);
128 HTTP_BEGIN_ARGS(setPutFile, 0, 1)
129 HTTP_ARG_VAL(filename, 0)
130 HTTP_END_ARGS;
131
132 HTTP_EMPTY_ARGS(getResponseData, 0);
133 HTTP_BEGIN_ARGS(getResponseHeader, 0, 0)
134 HTTP_ARG_VAL(name, 0)
135 HTTP_END_ARGS;
136
137 HTTP_BEGIN_ARGS(getResponseCookie, 0, 0)
138 HTTP_ARG_VAL(name, 0)
139 HTTP_END_ARGS;
140
141 HTTP_EMPTY_ARGS(getResponseBody, 0);
142 HTTP_EMPTY_ARGS(getResponseCode, 0);
143 HTTP_BEGIN_ARGS(getResponseInfo, 0, 0)
144 HTTP_ARG_VAL(name, 0)
145 HTTP_END_ARGS;
146
147 HTTP_EMPTY_ARGS(getResponseMessage, 1);
148 HTTP_EMPTY_ARGS(getRequestMessage, 1);
149 HTTP_EMPTY_ARGS(getHistory, 1);
150 HTTP_EMPTY_ARGS(send, 0);
151
152 HTTP_BEGIN_ARGS(get, 0, 1)
153 HTTP_ARG_VAL(url, 0)
154 HTTP_ARG_VAL(options, 0)
155 HTTP_ARG_VAL(info, 1)
156 HTTP_END_ARGS;
157
158 HTTP_BEGIN_ARGS(head, 0, 1)
159 HTTP_ARG_VAL(url, 0)
160 HTTP_ARG_VAL(options, 0)
161 HTTP_ARG_VAL(info, 1)
162 HTTP_END_ARGS;
163
164 HTTP_BEGIN_ARGS(postData, 0, 2)
165 HTTP_ARG_VAL(url, 0)
166 HTTP_ARG_VAL(data, 0)
167 HTTP_ARG_VAL(options, 0)
168 HTTP_ARG_VAL(info, 1)
169 HTTP_END_ARGS;
170
171 HTTP_BEGIN_ARGS(postFields, 0, 2)
172 HTTP_ARG_VAL(url, 0)
173 HTTP_ARG_VAL(data, 0)
174 HTTP_ARG_VAL(options, 0)
175 HTTP_ARG_VAL(info, 1)
176 HTTP_END_ARGS;
177
178 HTTP_BEGIN_ARGS(putFile, 0, 2)
179 HTTP_ARG_VAL(url, 0)
180 HTTP_ARG_VAL(file, 0)
181 HTTP_ARG_VAL(options, 0)
182 HTTP_ARG_VAL(info, 1)
183 HTTP_END_ARGS;
184
185 HTTP_BEGIN_ARGS(putStream, 0, 2)
186 HTTP_ARG_VAL(url, 0)
187 HTTP_ARG_VAL(stream, 0)
188 HTTP_ARG_VAL(options, 0)
189 HTTP_ARG_VAL(info, 1)
190 HTTP_END_ARGS;
191
192 HTTP_BEGIN_ARGS(methodRegister, 0, 1)
193 HTTP_ARG_VAL(method_name, 0)
194 HTTP_END_ARGS;
195
196 HTTP_BEGIN_ARGS(methodUnregister, 0, 1)
197 HTTP_ARG_VAL(method, 0)
198 HTTP_END_ARGS;
199
200 HTTP_BEGIN_ARGS(methodName, 0, 1)
201 HTTP_ARG_VAL(method_id, 0)
202 HTTP_END_ARGS;
203
204 HTTP_BEGIN_ARGS(methodExists, 0, 1)
205 HTTP_ARG_VAL(method, 0)
206 HTTP_END_ARGS;
207
208 #define http_request_object_declare_default_properties() _http_request_object_declare_default_properties(TSRMLS_C)
209 static inline void _http_request_object_declare_default_properties(TSRMLS_D);
210
211 zend_class_entry *http_request_object_ce;
212 zend_function_entry http_request_object_fe[] = {
213 HTTP_REQUEST_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
214 HTTP_REQUEST_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
215
216 HTTP_REQUEST_ME(setOptions, ZEND_ACC_PUBLIC)
217 HTTP_REQUEST_ME(getOptions, ZEND_ACC_PUBLIC)
218 HTTP_REQUEST_ME(unsetOptions, ZEND_ACC_PUBLIC)
219 HTTP_REQUEST_ME(setSslOptions, ZEND_ACC_PUBLIC)
220 HTTP_REQUEST_ME(getSslOptions, ZEND_ACC_PUBLIC)
221 HTTP_REQUEST_ME(unsetSslOptions, ZEND_ACC_PUBLIC)
222
223 HTTP_REQUEST_ME(addHeaders, ZEND_ACC_PUBLIC)
224 HTTP_REQUEST_ME(getHeaders, ZEND_ACC_PUBLIC)
225 HTTP_REQUEST_ME(unsetHeaders, ZEND_ACC_PUBLIC)
226 HTTP_REQUEST_ME(addCookies, ZEND_ACC_PUBLIC)
227 HTTP_REQUEST_ME(getCookies, ZEND_ACC_PUBLIC)
228 HTTP_REQUEST_ME(unsetCookies, ZEND_ACC_PUBLIC)
229
230 HTTP_REQUEST_ME(setMethod, ZEND_ACC_PUBLIC)
231 HTTP_REQUEST_ME(getMethod, ZEND_ACC_PUBLIC)
232
233 HTTP_REQUEST_ME(setUrl, ZEND_ACC_PUBLIC)
234 HTTP_REQUEST_ME(getUrl, ZEND_ACC_PUBLIC)
235
236 HTTP_REQUEST_ME(setContentType, ZEND_ACC_PUBLIC)
237 HTTP_REQUEST_ME(getContentType, ZEND_ACC_PUBLIC)
238
239 HTTP_REQUEST_ME(setQueryData, ZEND_ACC_PUBLIC)
240 HTTP_REQUEST_ME(getQueryData, ZEND_ACC_PUBLIC)
241 HTTP_REQUEST_ME(addQueryData, ZEND_ACC_PUBLIC)
242 HTTP_REQUEST_ME(unsetQueryData, ZEND_ACC_PUBLIC)
243
244 HTTP_REQUEST_ME(setPostFields, ZEND_ACC_PUBLIC)
245 HTTP_REQUEST_ME(getPostFields, ZEND_ACC_PUBLIC)
246 HTTP_REQUEST_ME(addPostFields, ZEND_ACC_PUBLIC)
247 HTTP_REQUEST_ME(unsetPostFields, ZEND_ACC_PUBLIC)
248
249 HTTP_REQUEST_ME(setPostFiles, ZEND_ACC_PUBLIC)
250 HTTP_REQUEST_ME(addPostFile, ZEND_ACC_PUBLIC)
251 HTTP_REQUEST_ME(getPostFiles, ZEND_ACC_PUBLIC)
252 HTTP_REQUEST_ME(unsetPostFiles, ZEND_ACC_PUBLIC)
253
254 HTTP_REQUEST_ME(setPutFile, ZEND_ACC_PUBLIC)
255 HTTP_REQUEST_ME(getPutFile, ZEND_ACC_PUBLIC)
256 HTTP_REQUEST_ME(unsetPutFile, ZEND_ACC_PUBLIC)
257
258 HTTP_REQUEST_ME(send, ZEND_ACC_PUBLIC)
259
260 HTTP_REQUEST_ME(getResponseData, ZEND_ACC_PUBLIC)
261 HTTP_REQUEST_ME(getResponseHeader, ZEND_ACC_PUBLIC)
262 HTTP_REQUEST_ME(getResponseCookie, ZEND_ACC_PUBLIC)
263 HTTP_REQUEST_ME(getResponseCode, ZEND_ACC_PUBLIC)
264 HTTP_REQUEST_ME(getResponseBody, ZEND_ACC_PUBLIC)
265 HTTP_REQUEST_ME(getResponseInfo, ZEND_ACC_PUBLIC)
266 HTTP_REQUEST_ME(getResponseMessage, ZEND_ACC_PUBLIC)
267 HTTP_REQUEST_ME(getRequestMessage, ZEND_ACC_PUBLIC)
268 HTTP_REQUEST_ME(getHistory, ZEND_ACC_PUBLIC)
269
270 HTTP_REQUEST_ALIAS(get, http_get)
271 HTTP_REQUEST_ALIAS(head, http_head)
272 HTTP_REQUEST_ALIAS(postData, http_post_data)
273 HTTP_REQUEST_ALIAS(postFields, http_post_fields)
274 HTTP_REQUEST_ALIAS(putFile, http_put_file)
275 HTTP_REQUEST_ALIAS(putStream, http_put_stream)
276
277 HTTP_REQUEST_ALIAS(methodRegister, http_request_method_register)
278 HTTP_REQUEST_ALIAS(methodUnregister, http_request_method_unregister)
279 HTTP_REQUEST_ALIAS(methodName, http_request_method_name)
280 HTTP_REQUEST_ALIAS(methodExists, http_request_method_exists)
281
282 {NULL, NULL, NULL}
283 };
284 static zend_object_handlers http_request_object_handlers;
285
286 void _http_request_object_init(INIT_FUNC_ARGS)
287 {
288 HTTP_REGISTER_CLASS_EX(HttpRequest, http_request_object, NULL, 0);
289
290 /* HTTP/1.1 */
291 HTTP_LONG_CONSTANT("HTTP_GET", HTTP_GET);
292 HTTP_LONG_CONSTANT("HTTP_HEAD", HTTP_HEAD);
293 HTTP_LONG_CONSTANT("HTTP_POST", HTTP_POST);
294 HTTP_LONG_CONSTANT("HTTP_PUT", HTTP_PUT);
295 HTTP_LONG_CONSTANT("HTTP_DELETE", HTTP_DELETE);
296 HTTP_LONG_CONSTANT("HTTP_OPTIONS", HTTP_OPTIONS);
297 HTTP_LONG_CONSTANT("HTTP_TRACE", HTTP_TRACE);
298 HTTP_LONG_CONSTANT("HTTP_CONNECT", HTTP_CONNECT);
299 /* WebDAV - RFC 2518 */
300 HTTP_LONG_CONSTANT("HTTP_PROPFIND", HTTP_PROPFIND);
301 HTTP_LONG_CONSTANT("HTTP_PROPPATCH", HTTP_PROPPATCH);
302 HTTP_LONG_CONSTANT("HTTP_MKCOL", HTTP_MKCOL);
303 HTTP_LONG_CONSTANT("HTTP_COPY", HTTP_COPY);
304 HTTP_LONG_CONSTANT("HTTP_MOVE", HTTP_MOVE);
305 HTTP_LONG_CONSTANT("HTTP_LOCK", HTTP_LOCK);
306 HTTP_LONG_CONSTANT("HTTP_UNLOCK", HTTP_UNLOCK);
307 /* WebDAV Versioning - RFC 3253 */
308 HTTP_LONG_CONSTANT("HTTP_VERSION_CONTROL", HTTP_VERSION_CONTROL);
309 HTTP_LONG_CONSTANT("HTTP_REPORT", HTTP_REPORT);
310 HTTP_LONG_CONSTANT("HTTP_CHECKOUT", HTTP_CHECKOUT);
311 HTTP_LONG_CONSTANT("HTTP_CHECKIN", HTTP_CHECKIN);
312 HTTP_LONG_CONSTANT("HTTP_UNCHECKOUT", HTTP_UNCHECKOUT);
313 HTTP_LONG_CONSTANT("HTTP_MKWORKSPACE", HTTP_MKWORKSPACE);
314 HTTP_LONG_CONSTANT("HTTP_UPDATE", HTTP_UPDATE);
315 HTTP_LONG_CONSTANT("HTTP_LABEL", HTTP_LABEL);
316 HTTP_LONG_CONSTANT("HTTP_MERGE", HTTP_MERGE);
317 HTTP_LONG_CONSTANT("HTTP_BASELINE_CONTROL", HTTP_BASELINE_CONTROL);
318 HTTP_LONG_CONSTANT("HTTP_MKACTIVITY", HTTP_MKACTIVITY);
319 /* WebDAV Access Control - RFC 3744 */
320 HTTP_LONG_CONSTANT("HTTP_ACL", HTTP_ACL);
321
322
323 # if LIBCURL_VERSION_NUM >= 0x070a05
324 HTTP_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC);
325 HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST);
326 HTTP_LONG_CONSTANT("HTTP_AUTH_NTLM", CURLAUTH_NTLM);
327 # endif /* LIBCURL_VERSION_NUM */
328 }
329
330 zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC)
331 {
332 zend_object_value ov;
333 http_request_object *o;
334
335 o = ecalloc(1, sizeof(http_request_object));
336 o->zo.ce = ce;
337 o->ch = curl_easy_init();
338 o->pool = NULL;
339
340 phpstr_init(&o->history);
341 phpstr_init(&o->request);
342 phpstr_init_ex(&o->response, HTTP_CURLBUF_SIZE, 0);
343
344 ALLOC_HASHTABLE(OBJ_PROP(o));
345 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
346 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
347
348 ov.handle = putObject(http_request_object, o);
349 ov.handlers = &http_request_object_handlers;
350
351 return ov;
352 }
353
354 static inline void _http_request_object_declare_default_properties(TSRMLS_D)
355 {
356 zend_class_entry *ce = http_request_object_ce;
357
358 DCL_PROP_N(PROTECTED, options);
359 DCL_PROP_N(PROTECTED, responseInfo);
360 DCL_PROP_N(PROTECTED, responseData);
361 DCL_PROP_N(PROTECTED, responseCode);
362 DCL_PROP_N(PROTECTED, responseMessage);
363 DCL_PROP_N(PROTECTED, postFields);
364 DCL_PROP_N(PROTECTED, postFiles);
365
366 DCL_PROP(PROTECTED, long, method, HTTP_GET);
367
368 DCL_PROP(PROTECTED, string, url, "");
369 DCL_PROP(PROTECTED, string, contentType, "");
370 DCL_PROP(PROTECTED, string, queryData, "");
371 DCL_PROP(PROTECTED, string, putFile, "");
372
373 DCL_PROP(PUBLIC, bool, recordHistory, 1);
374 }
375
376 void _http_request_object_free(zend_object *object TSRMLS_DC)
377 {
378 http_request_object *o = (http_request_object *) object;
379
380 if (OBJ_PROP(o)) {
381 zend_hash_destroy(OBJ_PROP(o));
382 FREE_HASHTABLE(OBJ_PROP(o));
383 }
384 if (o->ch) {
385 /* avoid nasty segfaults with already cleaned up callbacks */
386 curl_easy_setopt(o->ch, CURLOPT_NOPROGRESS, 1);
387 curl_easy_setopt(o->ch, CURLOPT_PROGRESSFUNCTION, NULL);
388 curl_easy_setopt(o->ch, CURLOPT_VERBOSE, 0);
389 curl_easy_setopt(o->ch, CURLOPT_DEBUGFUNCTION, NULL);
390 curl_easy_cleanup(o->ch);
391 }
392 phpstr_dtor(&o->response);
393 phpstr_dtor(&o->request);
394 phpstr_dtor(&o->history);
395 efree(o);
396 }
397
398 STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr, http_request_body *body TSRMLS_DC)
399 {
400 zval *meth, *URL, *qdata, *opts;
401 char *request_uri;
402 STATUS status;
403
404 if (!body) {
405 return FAILURE;
406 }
407 if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
408 http_error(HE_WARNING, HTTP_E_REQUEST, "Could not initilaize curl");
409 return FAILURE;
410 }
411
412 meth = GET_PROP(obj, method);
413 URL = GET_PROP(obj, url);
414 qdata = GET_PROP(obj, queryData);
415 opts = GET_PROP(obj, options);
416
417 // HTTP_URI_MAXLEN+1 long char *
418 if (!(request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0))) {
419 return FAILURE;
420 }
421
422 if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
423 if (!strchr(request_uri, '?')) {
424 strcat(request_uri, "?");
425 } else {
426 strcat(request_uri, "&");
427 }
428 strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
429 }
430
431 switch (Z_LVAL_P(meth))
432 {
433 case HTTP_GET:
434 case HTTP_HEAD:
435 body->type = -1;
436 status = http_request_init(obj->ch, Z_LVAL_P(meth), request_uri, NULL, Z_ARRVAL_P(opts));
437 break;
438
439 case HTTP_PUT:
440 {
441 php_stream *stream;
442 php_stream_statbuf ssb;
443 zval *file = GET_PROP(obj, putFile);
444
445 if ( (stream = php_stream_open_wrapper(Z_STRVAL_P(file), "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL)) &&
446 !php_stream_stat(stream, &ssb)) {
447 body->type = HTTP_REQUEST_BODY_UPLOADFILE;
448 body->data = stream;
449 body->size = ssb.sb.st_size;
450
451 status = http_request_init(obj->ch, HTTP_PUT, request_uri, body, Z_ARRVAL_P(opts));
452 } else {
453 status = FAILURE;
454 }
455 }
456 break;
457
458 case HTTP_POST:
459 {
460 zval *fields = GET_PROP(obj, postFields), *files = GET_PROP(obj, postFiles);
461
462 if (SUCCESS == (status = http_request_body_fill(body, Z_ARRVAL_P(fields), Z_ARRVAL_P(files)))) {
463 status = http_request_init(obj->ch, HTTP_POST, request_uri, body, Z_ARRVAL_P(opts));
464 }
465 }
466 break;
467
468 default:
469 {
470 zval *post = GET_PROP(obj, postData);
471
472 body->type = HTTP_REQUEST_BODY_CSTRING;
473 body->data = Z_STRVAL_P(post);
474 body->size = Z_STRLEN_P(post);
475
476 status = http_request_init(obj->ch, Z_LVAL_P(meth), request_uri, body, Z_ARRVAL_P(opts));
477 }
478 break;
479 }
480
481 /* clean previous response */
482 phpstr_dtor(&obj->response);
483 /* clean previous request */
484 phpstr_dtor(&obj->request);
485
486 efree(request_uri);
487 return status;
488 }
489
490 STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr TSRMLS_DC)
491 {
492 http_message *msg;
493
494 phpstr_fix(&obj->request);
495 phpstr_fix(&obj->response);
496
497 if (msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response))) {
498 char *body;
499 size_t body_len;
500 zval *headers, *message,
501 *resp = GET_PROP(obj, responseData),
502 *info = GET_PROP(obj, responseInfo),
503 *hist = GET_PROP(obj, recordHistory);
504
505 /* should we record history? */
506 if (Z_TYPE_P(hist) != IS_BOOL) {
507 convert_to_boolean_ex(&hist);
508 }
509 if (Z_LVAL_P(hist)) {
510 /* we need to act like a zipper, as we'll receive
511 * the requests and the responses in separate chains
512 * for redirects
513 */
514 http_message *response = msg, *request = http_message_parse(PHPSTR_VAL(&obj->request), PHPSTR_LEN(&obj->request));
515 http_message *free_msg = request;
516
517 do {
518 char *message;
519 size_t msglen;
520
521 http_message_tostring(response, &message, &msglen);
522 phpstr_append(&obj->history, message, msglen);
523 efree(message);
524
525 http_message_tostring(request, &message, &msglen);
526 phpstr_append(&obj->history, message, msglen);
527 efree(message);
528
529 } while ((response = response->parent) && (request = request->parent));
530
531 http_message_free(free_msg);
532 phpstr_fix(&obj->history);
533 }
534
535 UPD_PROP(obj, long, responseCode, msg->info.response.code);
536
537 MAKE_STD_ZVAL(headers)
538 array_init(headers);
539
540 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
541 phpstr_data(PHPSTR(msg), &body, &body_len);
542
543 add_assoc_zval(resp, "headers", headers);
544 add_assoc_stringl(resp, "body", body, body_len, 0);
545
546 MAKE_STD_ZVAL(message);
547 message->type = IS_OBJECT;
548 message->is_ref = 1;
549 message->value.obj = http_message_object_from_msg(msg);
550 SET_PROP(obj, responseMessage, message);
551 zval_ptr_dtor(&message);
552
553 http_request_info(obj->ch, Z_ARRVAL_P(info));
554 SET_PROP(obj, responseInfo, info);
555
556 return SUCCESS;
557 }
558 return FAILURE;
559 }
560
561 /* ### USERLAND ### */
562
563 /* {{{ proto void HttpRequest::__construct([string url[, long request_method = HTTP_GET]])
564 *
565 * Instantiate a new HttpRequest object which can be used to issue HEAD, GET
566 * and POST (including posting files) HTTP requests.
567 */
568 PHP_METHOD(HttpRequest, __construct)
569 {
570 char *URL = NULL;
571 int URL_len;
572 long meth = -1;
573 getObject(http_request_object, obj);
574
575 SET_EH_THROW_HTTP();
576 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &URL, &URL_len, &meth)) {
577 INIT_PARR(obj, options);
578 INIT_PARR(obj, responseInfo);
579 INIT_PARR(obj, responseData);
580 INIT_PARR(obj, postFields);
581 INIT_PARR(obj, postFiles);
582
583 if (URL) {
584 UPD_PROP(obj, string, url, URL);
585 }
586 if (meth > -1) {
587 UPD_PROP(obj, long, method, meth);
588 }
589 }
590 SET_EH_NORMAL();
591 }
592 /* }}} */
593
594 /* {{{ proto void HttpRequest::__destruct()
595 *
596 * Destroys the HttpRequest object.
597 */
598 PHP_METHOD(HttpRequest, __destruct)
599 {
600 getObject(http_request_object, obj);
601
602 NO_ARGS;
603
604 FREE_PARR(obj, options);
605 FREE_PARR(obj, responseInfo);
606 FREE_PARR(obj, responseData);
607 FREE_PARR(obj, postFields);
608 FREE_PARR(obj, postFiles);
609 }
610 /* }}} */
611
612 /* {{{ proto bool HttpRequest::setOptions(array options)
613 *
614 * Set the request options to use. See http_get() for a full list of available options.
615 */
616 PHP_METHOD(HttpRequest, setOptions)
617 {
618 char *key = NULL;
619 ulong idx = 0;
620 zval *opts, *old_opts, **opt;
621 getObject(http_request_object, obj);
622
623 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
624 RETURN_FALSE;
625 }
626
627 old_opts = GET_PROP(obj, options);
628
629 /* some options need extra attention -- thus cannot use array_merge() directly */
630 FOREACH_KEYVAL(opts, key, idx, opt) {
631 if (key) {
632 if (!strcmp(key, "headers")) {
633 zval **headers;
634 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
635 array_merge(*opt, *headers);
636 continue;
637 }
638 } else if (!strcmp(key, "cookies")) {
639 zval **cookies;
640 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
641 array_merge(*opt, *cookies);
642 continue;
643 }
644 } else if (!strcmp(key, "ssl")) {
645 zval **ssl;
646 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "ssl", sizeof("ssl"), (void **) &ssl)) {
647 array_merge(*opt, *ssl);
648 continue;
649 }
650 }else if ((!strcasecmp(key, "url")) || (!strcasecmp(key, "uri"))) {
651 if (Z_TYPE_PP(opt) != IS_STRING) {
652 convert_to_string_ex(opt);
653 }
654 UPD_PROP(obj, string, url, Z_STRVAL_PP(opt));
655 continue;
656 } else if (!strcmp(key, "method")) {
657 if (Z_TYPE_PP(opt) != IS_LONG) {
658 convert_to_long_ex(opt);
659 }
660 UPD_PROP(obj, long, method, Z_LVAL_PP(opt));
661 continue;
662 }
663
664 zval_add_ref(opt);
665 add_assoc_zval(old_opts, key, *opt);
666
667 /* reset */
668 key = NULL;
669 }
670 }
671
672 RETURN_TRUE;
673 }
674 /* }}} */
675
676 /* {{{ proto array HttpRequest::getOptions()
677 *
678 * Get current set options.
679 */
680 PHP_METHOD(HttpRequest, getOptions)
681 {
682 NO_ARGS;
683
684 IF_RETVAL_USED {
685 zval *opts;
686 getObject(http_request_object, obj);
687
688 opts = GET_PROP(obj, options);
689 array_init(return_value);
690 array_copy(opts, return_value);
691 }
692 }
693 /* }}} */
694
695 /* {{{ proto void HttpRequest::unsetOptions()
696 *
697 * Unset all options/headers/cookies.
698 */
699 PHP_METHOD(HttpRequest, unsetOptions)
700 {
701 getObject(http_request_object, obj);
702
703 NO_ARGS;
704
705 FREE_PARR(obj, options);
706 INIT_PARR(obj, options);
707 }
708 /* }}} */
709
710 /* {{{ proto bool HttpRequest::setSslOptions(array options)
711 *
712 * Set additional SSL options.
713 */
714 PHP_METHOD(HttpRequest, setSslOptions)
715 {
716 zval *opts, *old_opts, **ssl_options;
717 getObject(http_request_object, obj);
718
719 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
720 RETURN_FALSE;
721 }
722
723 old_opts = GET_PROP(obj, options);
724
725 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
726 array_merge(opts, *ssl_options);
727 } else {
728 zval_add_ref(&opts);
729 add_assoc_zval(old_opts, "ssl", opts);
730 }
731
732 RETURN_TRUE;
733 }
734 /* }}} */
735
736 /* {{{ proto array HttpRequest::getSslOtpions()
737 *
738 * Get previously set SSL options.
739 */
740 PHP_METHOD(HttpRequest, getSslOptions)
741 {
742 NO_ARGS;
743
744 IF_RETVAL_USED {
745 zval *opts, **ssl_options;
746 getObject(http_request_object, obj);
747
748 opts = GET_PROP(obj, options);
749
750 array_init(return_value);
751
752 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
753 array_copy(*ssl_options, return_value);
754 }
755 }
756 }
757 /* }}} */
758
759 /* {{{ proto void HttpRequest::unsetSslOptions()
760 *
761 * Unset previously set SSL options.
762 */
763 PHP_METHOD(HttpRequest, unsetSslOptions)
764 {
765 zval *opts;
766 getObject(http_request_object, obj);
767
768 NO_ARGS;
769
770 opts = GET_PROP(obj, options);
771 zend_hash_del(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"));
772 }
773 /* }}} */
774
775 /* {{{ proto bool HttpRequest::addHeaders(array headers)
776 *
777 * Add request header name/value pairs.
778 */
779 PHP_METHOD(HttpRequest, addHeaders)
780 {
781 zval *opts, **headers, *new_headers;
782 getObject(http_request_object, obj);
783
784 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
785 RETURN_FALSE;
786 }
787
788 opts = GET_PROP(obj, options);
789
790 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
791 array_merge(new_headers, *headers);
792 } else {
793 zval_add_ref(&new_headers);
794 add_assoc_zval(opts, "headers", new_headers);
795 }
796
797 RETURN_TRUE;
798 }
799 /* }}} */
800
801 /* {{{ proto array HttpRequest::getHeaders()
802 *
803 * Get previously set request headers.
804 */
805 PHP_METHOD(HttpRequest, getHeaders)
806 {
807 NO_ARGS;
808
809 IF_RETVAL_USED {
810 zval *opts, **headers;
811 getObject(http_request_object, obj);
812
813 opts = GET_PROP(obj, options);
814
815 array_init(return_value);
816
817 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
818 array_copy(*headers, return_value);
819 }
820 }
821 }
822 /* }}} */
823
824 /* {{{ proto void HttpRequest::unsetHeaders()
825 *
826 * Unset previously set request headers.
827 */
828 PHP_METHOD(HttpRequest, unsetHeaders)
829 {
830 zval *opts;
831 getObject(http_request_object, obj);
832
833 NO_ARGS;
834
835 opts = GET_PROP(obj, options);
836 zend_hash_del(Z_ARRVAL_P(opts), "headers", sizeof("headers"));
837 }
838 /* }}} */
839
840 /* {{{ proto bool HttpRequest::addCookies(array cookies)
841 *
842 * Add cookies.
843 */
844 PHP_METHOD(HttpRequest, addCookies)
845 {
846 zval *opts, **cookies, *new_cookies;
847 getObject(http_request_object, obj);
848
849 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_cookies)) {
850 RETURN_FALSE;
851 }
852
853 opts = GET_PROP(obj, options);
854
855 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
856 array_merge(new_cookies, *cookies);
857 } else {
858 zval_add_ref(&new_cookies);
859 add_assoc_zval(opts, "cookies", new_cookies);
860 }
861
862 RETURN_TRUE;
863 }
864 /* }}} */
865
866 /* {{{ proto array HttpRequest::getCookies()
867 *
868 * Get previously set cookies.
869 */
870 PHP_METHOD(HttpRequest, getCookies)
871 {
872 NO_ARGS;
873
874 IF_RETVAL_USED {
875 zval *opts, **cookies;
876 getObject(http_request_object, obj);
877
878 opts = GET_PROP(obj, options);
879
880 array_init(return_value);
881
882 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
883 array_copy(*cookies, return_value);
884 }
885 }
886 }
887 /* }}} */
888
889 /* {{{ proto void HttpRequest::unsetCookies()
890 *
891 */
892 PHP_METHOD(HttpRequest, unsetCookies)
893 {
894 zval *opts;
895 getObject(http_request_object, obj);
896
897 NO_ARGS;
898
899 opts = GET_PROP(obj, options);
900 zend_hash_del(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"));
901 }
902 /* }}} */
903
904 /* {{{ proto bool HttpRequest::setUrl(string url)
905 *
906 * Set the request URL.
907 */
908 PHP_METHOD(HttpRequest, setUrl)
909 {
910 char *URL = NULL;
911 int URL_len;
912 getObject(http_request_object, obj);
913
914 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
915 RETURN_FALSE;
916 }
917
918 UPD_PROP(obj, string, url, URL);
919 RETURN_TRUE;
920 }
921 /* }}} */
922
923 /* {{{ proto string HttpRequest::getUrl()
924 *
925 * Get the previously set request URL.
926 */
927 PHP_METHOD(HttpRequest, getUrl)
928 {
929 NO_ARGS;
930
931 IF_RETVAL_USED {
932 zval *URL;
933 getObject(http_request_object, obj);
934
935 URL = GET_PROP(obj, url);
936 RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1);
937 }
938 }
939 /* }}} */
940
941 /* {{{ proto bool HttpRequest::setMethod(long request_method)
942 *
943 * Set the request methods; one of the <tt>HTTP_HEAD</tt>, <tt>HTTP_GET</tt> or
944 * <tt>HTTP_POST</tt> constants.
945 */
946 PHP_METHOD(HttpRequest, setMethod)
947 {
948 long meth;
949 getObject(http_request_object, obj);
950
951 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
952 RETURN_FALSE;
953 }
954
955 UPD_PROP(obj, long, method, meth);
956 RETURN_TRUE;
957 }
958 /* }}} */
959
960 /* {{{ proto long HttpRequest::getMethod()
961 *
962 * Get the previously set request method.
963 */
964 PHP_METHOD(HttpRequest, getMethod)
965 {
966 NO_ARGS;
967
968 IF_RETVAL_USED {
969 zval *meth;
970 getObject(http_request_object, obj);
971
972 meth = GET_PROP(obj, method);
973 RETURN_LONG(Z_LVAL_P(meth));
974 }
975 }
976 /* }}} */
977
978 /* {{{ proto bool HttpRequest::setContentType(string content_type)
979 *
980 * Set the content type the post request should have.
981 * Use this only if you know what you're doing.
982 */
983 PHP_METHOD(HttpRequest, setContentType)
984 {
985 char *ctype;
986 int ct_len;
987 getObject(http_request_object, obj);
988
989 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
990 RETURN_FALSE;
991 }
992
993 if (!strchr(ctype, '/')) {
994 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", ctype);
995 RETURN_FALSE;
996 }
997
998 UPD_PROP(obj, string, contentType, ctype);
999 RETURN_TRUE;
1000 }
1001 /* }}} */
1002
1003 /* {{{ proto string HttpRequest::getContentType()
1004 *
1005 * Get the previously content type.
1006 */
1007 PHP_METHOD(HttpRequest, getContentType)
1008 {
1009 NO_ARGS;
1010
1011 IF_RETVAL_USED {
1012 zval *ctype;
1013 getObject(http_request_object, obj);
1014
1015 ctype = GET_PROP(obj, contentType);
1016 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
1017 }
1018 }
1019 /* }}} */
1020
1021 /* {{{ proto bool HttpRequest::setQueryData(mixed query_data)
1022 *
1023 * Set the URL query parameters to use.
1024 * Overwrites previously set query parameters.
1025 * Affects any request types.
1026 */
1027 PHP_METHOD(HttpRequest, setQueryData)
1028 {
1029 zval *qdata;
1030 char *query_data = NULL;
1031 getObject(http_request_object, obj);
1032
1033 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata)) {
1034 RETURN_FALSE;
1035 }
1036
1037 if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1038 if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
1039 RETURN_FALSE;
1040 }
1041 UPD_PROP(obj, string, queryData, query_data);
1042 efree(query_data);
1043 RETURN_TRUE;
1044 }
1045
1046 convert_to_string(qdata);
1047 UPD_PROP(obj, string, queryData, Z_STRVAL_P(qdata));
1048 RETURN_TRUE;
1049 }
1050 /* }}} */
1051
1052 /* {{{ proto string HttpRequest::getQueryData()
1053 *
1054 * Get the current query data in form of an urlencoded query string.
1055 */
1056 PHP_METHOD(HttpRequest, getQueryData)
1057 {
1058 NO_ARGS;
1059
1060 IF_RETVAL_USED {
1061 zval *qdata;
1062 getObject(http_request_object, obj);
1063
1064 qdata = GET_PROP(obj, queryData);
1065 RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1);
1066 }
1067 }
1068 /* }}} */
1069
1070 /* {{{ proto bool HttpRequest::addQueryData(array query_params)
1071 *
1072 * Add parameters to the query parameter list.
1073 * Affects any request type.
1074 */
1075 PHP_METHOD(HttpRequest, addQueryData)
1076 {
1077 zval *qdata, *old_qdata;
1078 char *query_data = NULL;
1079 getObject(http_request_object, obj);
1080
1081 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1082 RETURN_FALSE;
1083 }
1084
1085 old_qdata = GET_PROP(obj, queryData);
1086
1087 if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, NULL)) {
1088 RETURN_FALSE;
1089 }
1090
1091 UPD_PROP(obj, string, queryData, query_data);
1092 efree(query_data);
1093
1094 RETURN_TRUE;
1095 }
1096 /* }}} */
1097
1098 /* {{{ proto void HttpRequest::unsetQueryData()
1099 *
1100 * Clean the query parameters.
1101 * Affects any request type.
1102 */
1103 PHP_METHOD(HttpRequest, unsetQueryData)
1104 {
1105 getObject(http_request_object, obj);
1106
1107 NO_ARGS;
1108
1109 UPD_PROP(obj, string, queryData, "");
1110 }
1111 /* }}} */
1112
1113 /* {{{ proto bool HttpRequest::addPostFields(array post_data)
1114 *
1115 * Adds POST data entries.
1116 * Affects only POST requests.
1117 */
1118 PHP_METHOD(HttpRequest, addPostFields)
1119 {
1120 zval *post, *post_data;
1121 getObject(http_request_object, obj);
1122
1123 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1124 RETURN_FALSE;
1125 }
1126
1127 post = GET_PROP(obj, postFields);
1128 array_merge(post_data, post);
1129
1130 RETURN_TRUE;
1131 }
1132 /* }}} */
1133
1134 /* {{{ proto bool HttpRequest::setPostFields(array post_data)
1135 *
1136 * Set the POST data entries.
1137 * Overwrites previously set POST data.
1138 * Affects only POST requests.
1139 */
1140 PHP_METHOD(HttpRequest, setPostFields)
1141 {
1142 zval *post, *post_data;
1143 getObject(http_request_object, obj);
1144
1145 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1146 RETURN_FALSE;
1147 }
1148
1149 post = GET_PROP(obj, postFields);
1150 zend_hash_clean(Z_ARRVAL_P(post));
1151 array_copy(post_data, post);
1152
1153 RETURN_TRUE;
1154 }
1155 /* }}}*/
1156
1157 /* {{{ proto array HttpRequest::getPostFields()
1158 *
1159 * Get previously set POST data.
1160 */
1161 PHP_METHOD(HttpRequest, getPostFields)
1162 {
1163 NO_ARGS;
1164
1165 IF_RETVAL_USED {
1166 zval *post_data;
1167 getObject(http_request_object, obj);
1168
1169 post_data = GET_PROP(obj, postFields);
1170 array_init(return_value);
1171 array_copy(post_data, return_value);
1172 }
1173 }
1174 /* }}} */
1175
1176 /* {{{ proto void HttpRequest::unsetPostFields()
1177 *
1178 * Clean POST data entires.
1179 * Affects only POST requests.
1180 */
1181 PHP_METHOD(HttpRequest, unsetPostFields)
1182 {
1183 zval *post_data;
1184 getObject(http_request_object, obj);
1185
1186 NO_ARGS;
1187
1188 post_data = GET_PROP(obj, postFields);
1189 zend_hash_clean(Z_ARRVAL_P(post_data));
1190 }
1191 /* }}} */
1192
1193 /* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1194 *
1195 * Add a file to the POST request.
1196 * Affects only POST requests.
1197 */
1198 PHP_METHOD(HttpRequest, addPostFile)
1199 {
1200 zval *files, *entry;
1201 char *name, *file, *type = NULL;
1202 int name_len, file_len, type_len = 0;
1203 getObject(http_request_object, obj);
1204
1205 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1206 RETURN_FALSE;
1207 }
1208
1209 if (type_len) {
1210 if (!strchr(type, '/')) {
1211 http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type);
1212 RETURN_FALSE;
1213 }
1214 } else {
1215 type = "application/x-octetstream";
1216 type_len = sizeof("application/x-octetstream") - 1;
1217 }
1218
1219 MAKE_STD_ZVAL(entry);
1220 array_init(entry);
1221
1222 add_assoc_stringl(entry, "name", name, name_len, 1);
1223 add_assoc_stringl(entry, "type", type, type_len, 1);
1224 add_assoc_stringl(entry, "file", file, file_len, 1);
1225
1226 files = GET_PROP(obj, postFiles);
1227 add_next_index_zval(files, entry);
1228
1229 RETURN_TRUE;
1230 }
1231 /* }}} */
1232
1233 /* {{{ proto bool HttpRequest::setPostFiles(array post_files)
1234 *
1235 * Set files to post.
1236 * Overwrites previously set post files.
1237 * Affects only POST requests.
1238 */
1239 PHP_METHOD(HttpRequest, setPostFiles)
1240 {
1241 zval *files, *pFiles;
1242 getObject(http_request_object, obj);
1243
1244 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &files)) {
1245 RETURN_FALSE;
1246 }
1247
1248 pFiles = GET_PROP(obj, postFiles);
1249 zend_hash_clean(Z_ARRVAL_P(pFiles));
1250 array_copy(files, pFiles);
1251
1252 RETURN_TRUE;
1253 }
1254 /* }}} */
1255
1256 /* {{{ proto array HttpRequest::getPostFiles()
1257 *
1258 * Get all previously added POST files.
1259 */
1260 PHP_METHOD(HttpRequest, getPostFiles)
1261 {
1262 NO_ARGS;
1263
1264 IF_RETVAL_USED {
1265 zval *files;
1266 getObject(http_request_object, obj);
1267
1268 files = GET_PROP(obj, postFiles);
1269
1270 array_init(return_value);
1271 array_copy(files, return_value);
1272 }
1273 }
1274 /* }}} */
1275
1276 /* {{{ proto void HttpRequest::unsetPostFiles()
1277 *
1278 * Unset the POST files list.
1279 * Affects only POST requests.
1280 */
1281 PHP_METHOD(HttpRequest, unsetPostFiles)
1282 {
1283 zval *files;
1284 getObject(http_request_object, obj);
1285
1286 NO_ARGS;
1287
1288 files = GET_PROP(obj, postFiles);
1289 zend_hash_clean(Z_ARRVAL_P(files));
1290 }
1291 /* }}} */
1292
1293 /* {{{ proto bool HttpRequest::SetPutFile(string file)
1294 *
1295 * Set file to put.
1296 * Affects only PUT requests.
1297 */
1298 PHP_METHOD(HttpRequest, setPutFile)
1299 {
1300 char *file;
1301 int file_len;
1302 getObject(http_request_object, obj);
1303
1304 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &file_len)) {
1305 RETURN_FALSE;
1306 }
1307
1308 UPD_PROP(obj, string, putFile, file);
1309 RETURN_TRUE;
1310 }
1311 /* }}} */
1312
1313 /* {{{ proto string HttpRequest::getPutFile()
1314 *
1315 * Get previously set put file.
1316 */
1317 PHP_METHOD(HttpRequest, getPutFile)
1318 {
1319 NO_ARGS;
1320
1321 IF_RETVAL_USED {
1322 zval *putfile;
1323 getObject(http_request_object, obj);
1324
1325 putfile = GET_PROP(obj, putFile);
1326 RETVAL_STRINGL(Z_STRVAL_P(putfile), Z_STRLEN_P(putfile), 1);
1327 }
1328 }
1329 /* }}} */
1330
1331 /* {{{ proto void HttpRequest::unsetPutFile()
1332 *
1333 * Unset file to put.
1334 * Affects only PUT requests.
1335 */
1336 PHP_METHOD(HttpRequest, unsetPutFile)
1337 {
1338 getObject(http_request_object, obj);
1339
1340 NO_ARGS;
1341
1342 UPD_PROP(obj, string, putFile, "");
1343 }
1344 /* }}} */
1345
1346 /* {{{ proto array HttpRequest::getResponseData()
1347 *
1348 * Get all response data after the request has been sent.
1349 */
1350 PHP_METHOD(HttpRequest, getResponseData)
1351 {
1352 NO_ARGS;
1353
1354 IF_RETVAL_USED {
1355 zval *data;
1356 getObject(http_request_object, obj);
1357
1358 data = GET_PROP(obj, responseData);
1359 array_init(return_value);
1360 array_copy(data, return_value);
1361 }
1362 }
1363 /* }}} */
1364
1365 /* {{{ proto mixed HttpRequest::getResponseHeader([string name])
1366 *
1367 * Get response header(s) after the request has been sent.
1368 */
1369 PHP_METHOD(HttpRequest, getResponseHeader)
1370 {
1371 IF_RETVAL_USED {
1372 zval *data, **headers, **header;
1373 char *header_name = NULL;
1374 int header_len = 0;
1375 getObject(http_request_object, obj);
1376
1377 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
1378 RETURN_FALSE;
1379 }
1380
1381 data = GET_PROP(obj, responseData);
1382 if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1383 RETURN_FALSE;
1384 }
1385
1386 if (!header_len || !header_name) {
1387 array_init(return_value);
1388 array_copy(*headers, return_value);
1389 } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) {
1390 RETURN_STRINGL(Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1);
1391 } else {
1392 RETURN_FALSE;
1393 }
1394 }
1395 }
1396 /* }}} */
1397
1398 /* {{{ proto array HttpRequest::getResponseCookie([string name])
1399 *
1400 * Get response cookie(s) after the request has been sent.
1401 */
1402 PHP_METHOD(HttpRequest, getResponseCookie)
1403 {
1404 IF_RETVAL_USED {
1405 zval *data, **headers;
1406 char *cookie_name = NULL;
1407 int cookie_len = 0;
1408 getObject(http_request_object, obj);
1409
1410 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) {
1411 RETURN_FALSE;
1412 }
1413
1414 array_init(return_value);
1415
1416 data = GET_PROP(obj, responseData);
1417 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1418 ulong idx = 0;
1419 char *key = NULL;
1420 zval **header = NULL;
1421
1422 FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) {
1423 if (key && !strcasecmp(key, "Set-Cookie")) {
1424 /* several cookies? */
1425 if (Z_TYPE_PP(header) == IS_ARRAY) {
1426 zval **cookie;
1427
1428 FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) {
1429 zval *cookie_hash;
1430 MAKE_STD_ZVAL(cookie_hash);
1431 array_init(cookie_hash);
1432
1433 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) {
1434 if (!cookie_len) {
1435 add_next_index_zval(return_value, cookie_hash);
1436 } else {
1437 zval **name;
1438
1439 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1440 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1441 add_next_index_zval(return_value, cookie_hash);
1442 return; /* <<< FOUND >>> */
1443 } else {
1444 zval_dtor(cookie_hash);
1445 efree(cookie_hash);
1446 }
1447 }
1448 } else {
1449 zval_dtor(cookie_hash);
1450 efree(cookie_hash);
1451 }
1452 }
1453 } else {
1454 zval *cookie_hash;
1455 MAKE_STD_ZVAL(cookie_hash);
1456 array_init(cookie_hash);
1457
1458 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) {
1459 if (!cookie_len) {
1460 add_next_index_zval(return_value, cookie_hash);
1461 } else {
1462 zval **name;
1463
1464 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1465 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1466 add_next_index_zval(return_value, cookie_hash);
1467 } else {
1468 zval_dtor(cookie_hash);
1469 efree(cookie_hash);
1470 }
1471 }
1472 } else {
1473 zval_dtor(cookie_hash);
1474 efree(cookie_hash);
1475 }
1476 }
1477 break;
1478 }
1479 /* reset key */
1480 key = NULL;
1481 }
1482 }
1483 }
1484 }
1485 /* }}} */
1486
1487 /* {{{ proto string HttpRequest::getResponseBody()
1488 *
1489 * Get the response body after the request has been sent.
1490 */
1491 PHP_METHOD(HttpRequest, getResponseBody)
1492 {
1493 NO_ARGS;
1494
1495 IF_RETVAL_USED {
1496 zval *data, **body;
1497 getObject(http_request_object, obj);
1498
1499 data = GET_PROP(obj, responseData);
1500 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1501 RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1);
1502 } else {
1503 RETURN_FALSE;
1504 }
1505 }
1506 }
1507 /* }}} */
1508
1509 /* {{{ proto int HttpRequest::getResponseCode()
1510 *
1511 * Get the response code after the request has been sent.
1512 */
1513 PHP_METHOD(HttpRequest, getResponseCode)
1514 {
1515 NO_ARGS;
1516
1517 IF_RETVAL_USED {
1518 zval *code;
1519 getObject(http_request_object, obj);
1520
1521 code = GET_PROP(obj, responseCode);
1522 RETURN_LONG(Z_LVAL_P(code));
1523 }
1524 }
1525 /* }}} */
1526
1527 /* {{{ proto array HttpRequest::getResponseInfo([string name])
1528 *
1529 * Get response info after the request has been sent.
1530 * See http_get() for a full list of returned info.
1531 */
1532 PHP_METHOD(HttpRequest, getResponseInfo)
1533 {
1534 IF_RETVAL_USED {
1535 zval *info, **infop;
1536 char *info_name = NULL;
1537 int info_len = 0;
1538 getObject(http_request_object, obj);
1539
1540 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
1541 RETURN_FALSE;
1542 }
1543
1544 info = GET_PROP(obj, responseInfo);
1545
1546 if (info_len && info_name) {
1547 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) {
1548 RETURN_ZVAL(*infop, 1, ZVAL_PTR_DTOR);
1549 } else {
1550 http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Could not find response info named %s", info_name);
1551 RETURN_FALSE;
1552 }
1553 } else {
1554 array_init(return_value);
1555 array_copy(info, return_value);
1556 }
1557 }
1558 }
1559 /* }}}*/
1560
1561 /* {{{ proto HttpMessage HttpRequest::getResponseMessage()
1562 *
1563 * Get the full response as HttpMessage object.
1564 */
1565 PHP_METHOD(HttpRequest, getResponseMessage)
1566 {
1567 NO_ARGS;
1568
1569 IF_RETVAL_USED {
1570 zval *message;
1571 getObject(http_request_object, obj);
1572
1573 SET_EH_THROW_HTTP();
1574 message = GET_PROP(obj, responseMessage);
1575 if (Z_TYPE_P(message) == IS_OBJECT) {
1576 RETVAL_OBJECT(message);
1577 } else {
1578 RETVAL_NULL();
1579 }
1580 SET_EH_NORMAL();
1581 }
1582 }
1583 /* }}} */
1584
1585 /* {{{ proto HttpMessage HttpRequest::getRequestMessage()
1586 *
1587 * Get sent HTTP message.
1588 */
1589 PHP_METHOD(HttpRequest, getRequestMessage)
1590 {
1591 NO_ARGS;
1592
1593 IF_RETVAL_USED {
1594 http_message *msg;
1595 getObject(http_request_object, obj);
1596
1597 SET_EH_THROW_HTTP();
1598 if (msg = http_message_parse(PHPSTR_VAL(&obj->request), PHPSTR_LEN(&obj->request))) {
1599 RETVAL_OBJVAL(http_message_object_from_msg(msg));
1600 }
1601 SET_EH_NORMAL();
1602 }
1603 }
1604 /* }}} */
1605
1606 PHP_METHOD(HttpRequest, getHistory)
1607 {
1608 NO_ARGS;
1609
1610 IF_RETVAL_USED {
1611 http_message *msg;
1612 getObject(http_request_object, obj);
1613
1614 SET_EH_THROW_HTTP();
1615 if (msg = http_message_parse(PHPSTR_VAL(&obj->history), PHPSTR_LEN(&obj->history))) {
1616 RETVAL_OBJVAL(http_message_object_from_msg(msg));
1617 }
1618 SET_EH_NORMAL();
1619 }
1620 }
1621
1622 /* {{{ proto bool HttpRequest::send()
1623 *
1624 * Send the HTTP request.
1625 *
1626 * GET example:
1627 * <pre>
1628 * <?php
1629 * $r = new HttpRequest('http://example.com/feed.rss', HTTP_GET);
1630 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
1631 * $r->addQueryData(array('category' => 3));
1632 * try {
1633 * $r->send();
1634 * if ($r->getResponseCode() == 200) {
1635 * file_put_contents('local.rss', $r->getResponseBody());
1636 * }
1637 * } catch (HttpException $ex) {
1638 * echo $ex;
1639 * }
1640 * ?>
1641 * </pre>
1642 *
1643 * POST example:
1644 * <pre>
1645 * <?php
1646 * $r = new HttpRequest('http://example.com/form.php', HTTP_POST);
1647 * $r->setOptions(array('cookies' => array('lang' => 'de')));
1648 * $r->addpostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));
1649 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
1650 * if ($r->send()) {
1651 * echo $r->getResponseBody();
1652 * }
1653 * ?>
1654 * </pre>
1655 */
1656 PHP_METHOD(HttpRequest, send)
1657 {
1658 STATUS status = FAILURE;
1659 http_request_body body = {0, NULL, 0};
1660 getObject(http_request_object, obj);
1661
1662 NO_ARGS;
1663
1664 SET_EH_THROW_HTTP();
1665
1666 if (obj->pool) {
1667 http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot perform HttpRequest::send() while attached to an HttpRequestPool");
1668 SET_EH_NORMAL();
1669 RETURN_FALSE;
1670 }
1671
1672 if (SUCCESS == (status = http_request_object_requesthandler(obj, getThis(), &body))) {
1673 status = http_request_exec(obj->ch, NULL, &obj->response, &obj->request);
1674 }
1675 http_request_body_dtor(&body);
1676
1677 /* final data handling */
1678 if (SUCCESS == status) {
1679 status = http_request_object_responsehandler(obj, getThis());
1680 }
1681
1682 SET_EH_NORMAL();
1683 RETURN_SUCCESS(status);
1684 }
1685 /* }}} */
1686
1687 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
1688
1689 /*
1690 * Local variables:
1691 * tab-width: 4
1692 * c-basic-offset: 4
1693 * End:
1694 * vim600: noet sw=4 ts=4 fdm=marker
1695 * vim<600: noet sw=4 ts=4
1696 */
1697