- start thinking about cloning
[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 "zend_interfaces.h"
27
28 #include "php_http_std_defs.h"
29 #include "php_http_request_object.h"
30 #include "php_http_request_api.h"
31 #include "php_http_request_pool_api.h"
32 #include "php_http.h"
33 #include "php_http_api.h"
34 #include "php_http_url_api.h"
35 #include "php_http_message_api.h"
36 #include "php_http_message_object.h"
37 #include "php_http_exception_object.h"
38
39 #include "missing.h"
40
41 #ifdef PHP_WIN32
42 # include <winsock2.h>
43 #endif
44 #include <curl/curl.h>
45
46 ZEND_EXTERN_MODULE_GLOBALS(http);
47
48 #define HTTP_BEGIN_ARGS(method, ret_ref, req_args) HTTP_BEGIN_ARGS_EX(HttpRequest, method, ret_ref, req_args)
49 #define HTTP_EMPTY_ARGS(method, ret_ref) HTTP_EMPTY_ARGS_EX(HttpRequest, method, ret_ref)
50 #define HTTP_REQUEST_ME(method, visibility) PHP_ME(HttpRequest, method, HTTP_ARGS(HttpRequest, method), visibility)
51 #define HTTP_REQUEST_ALIAS(method, func) HTTP_STATIC_ME_ALIAS(method, func, HTTP_ARGS(HttpRequest, method))
52
53 HTTP_EMPTY_ARGS(__destruct, 0);
54 HTTP_BEGIN_ARGS(__construct, 0, 0)
55 HTTP_ARG_VAL(url, 0)
56 HTTP_ARG_VAL(method, 0)
57 HTTP_ARG_VAL(options, 0)
58 HTTP_END_ARGS;
59
60 HTTP_EMPTY_ARGS(getOptions, 0);
61 HTTP_BEGIN_ARGS(setOptions, 0, 0)
62 HTTP_ARG_VAL(options, 0)
63 HTTP_END_ARGS;
64
65 HTTP_EMPTY_ARGS(getSslOptions, 0);
66 HTTP_BEGIN_ARGS(setSslOptions, 0, 0)
67 HTTP_ARG_VAL(ssl_options, 0)
68 HTTP_END_ARGS;
69
70 HTTP_EMPTY_ARGS(getHeaders, 0);
71 HTTP_BEGIN_ARGS(setHeaders, 0, 0)
72 HTTP_ARG_VAL(headers, 0)
73 HTTP_END_ARGS;
74
75 HTTP_BEGIN_ARGS(addHeaders, 0, 1)
76 HTTP_ARG_VAL(headers, 0)
77 HTTP_END_ARGS;
78
79 HTTP_EMPTY_ARGS(getCookies, 0);
80 HTTP_BEGIN_ARGS(setCookies, 0, 0)
81 HTTP_ARG_VAL(cookies, 0)
82 HTTP_END_ARGS;
83
84 HTTP_BEGIN_ARGS(addCookies, 0, 1)
85 HTTP_ARG_VAL(cookies, 0)
86 HTTP_END_ARGS;
87
88 HTTP_EMPTY_ARGS(getUrl, 0);
89 HTTP_BEGIN_ARGS(setUrl, 0, 1)
90 HTTP_ARG_VAL(url, 0)
91 HTTP_END_ARGS;
92
93 HTTP_EMPTY_ARGS(getMethod, 0);
94 HTTP_BEGIN_ARGS(setMethod, 0, 1)
95 HTTP_ARG_VAL(request_method, 0)
96 HTTP_END_ARGS;
97
98 HTTP_EMPTY_ARGS(getContentType, 0);
99 HTTP_BEGIN_ARGS(setContentType, 0, 1)
100 HTTP_ARG_VAL(content_type, 0)
101 HTTP_END_ARGS;
102
103 HTTP_EMPTY_ARGS(getQueryData, 0);
104 HTTP_BEGIN_ARGS(setQueryData, 0, 0)
105 HTTP_ARG_VAL(query_data, 0)
106 HTTP_END_ARGS;
107
108 HTTP_BEGIN_ARGS(addQueryData, 0, 1)
109 HTTP_ARG_VAL(query_data, 0)
110 HTTP_END_ARGS;
111
112 HTTP_EMPTY_ARGS(getPostFields, 0);
113 HTTP_BEGIN_ARGS(setPostFields, 0, 0)
114 HTTP_ARG_VAL(post_fields, 0)
115 HTTP_END_ARGS;
116
117 HTTP_BEGIN_ARGS(addPostFields, 0, 1)
118 HTTP_ARG_VAL(post_fields, 0)
119 HTTP_END_ARGS;
120
121 HTTP_EMPTY_ARGS(getPostFiles, 0);
122 HTTP_BEGIN_ARGS(setPostFiles, 0, 0)
123 HTTP_ARG_VAL(post_files, 0)
124 HTTP_END_ARGS;
125
126 HTTP_BEGIN_ARGS(addPostFile, 0, 2)
127 HTTP_ARG_VAL(formname, 0)
128 HTTP_ARG_VAL(filename, 0)
129 HTTP_ARG_VAL(content_type, 0)
130 HTTP_END_ARGS;
131
132 HTTP_EMPTY_ARGS(getRawPostData, 0);
133 HTTP_BEGIN_ARGS(setRawPostData, 0, 0)
134 HTTP_ARG_VAL(raw_post_data, 0)
135 HTTP_END_ARGS;
136
137 HTTP_BEGIN_ARGS(addRawPostData, 0, 1)
138 HTTP_ARG_VAL(raw_post_data, 0)
139 HTTP_END_ARGS;
140
141 HTTP_EMPTY_ARGS(getPutFile, 0);
142 HTTP_BEGIN_ARGS(setPutFile, 0, 0)
143 HTTP_ARG_VAL(filename, 0)
144 HTTP_END_ARGS;
145
146 HTTP_EMPTY_ARGS(getResponseData, 0);
147 HTTP_BEGIN_ARGS(getResponseHeader, 0, 0)
148 HTTP_ARG_VAL(name, 0)
149 HTTP_END_ARGS;
150
151 HTTP_BEGIN_ARGS(getResponseCookie, 0, 0)
152 HTTP_ARG_VAL(name, 0)
153 HTTP_END_ARGS;
154
155 HTTP_EMPTY_ARGS(getResponseBody, 0);
156 HTTP_EMPTY_ARGS(getResponseCode, 0);
157 HTTP_BEGIN_ARGS(getResponseInfo, 0, 0)
158 HTTP_ARG_VAL(name, 0)
159 HTTP_END_ARGS;
160
161 HTTP_EMPTY_ARGS(getResponseMessage, 1);
162 HTTP_EMPTY_ARGS(getRequestMessage, 1);
163 HTTP_EMPTY_ARGS(getHistory, 1);
164 HTTP_EMPTY_ARGS(clearHistory, 0);
165 HTTP_EMPTY_ARGS(send, 1);
166
167 HTTP_BEGIN_ARGS(get, 0, 1)
168 HTTP_ARG_VAL(url, 0)
169 HTTP_ARG_VAL(options, 0)
170 HTTP_ARG_VAL(info, 1)
171 HTTP_END_ARGS;
172
173 HTTP_BEGIN_ARGS(head, 0, 1)
174 HTTP_ARG_VAL(url, 0)
175 HTTP_ARG_VAL(options, 0)
176 HTTP_ARG_VAL(info, 1)
177 HTTP_END_ARGS;
178
179 HTTP_BEGIN_ARGS(postData, 0, 2)
180 HTTP_ARG_VAL(url, 0)
181 HTTP_ARG_VAL(data, 0)
182 HTTP_ARG_VAL(options, 0)
183 HTTP_ARG_VAL(info, 1)
184 HTTP_END_ARGS;
185
186 HTTP_BEGIN_ARGS(postFields, 0, 2)
187 HTTP_ARG_VAL(url, 0)
188 HTTP_ARG_VAL(data, 0)
189 HTTP_ARG_VAL(options, 0)
190 HTTP_ARG_VAL(info, 1)
191 HTTP_END_ARGS;
192
193 HTTP_BEGIN_ARGS(putFile, 0, 2)
194 HTTP_ARG_VAL(url, 0)
195 HTTP_ARG_VAL(file, 0)
196 HTTP_ARG_VAL(options, 0)
197 HTTP_ARG_VAL(info, 1)
198 HTTP_END_ARGS;
199
200 HTTP_BEGIN_ARGS(putStream, 0, 2)
201 HTTP_ARG_VAL(url, 0)
202 HTTP_ARG_VAL(stream, 0)
203 HTTP_ARG_VAL(options, 0)
204 HTTP_ARG_VAL(info, 1)
205 HTTP_END_ARGS;
206
207 HTTP_BEGIN_ARGS(methodRegister, 0, 1)
208 HTTP_ARG_VAL(method_name, 0)
209 HTTP_END_ARGS;
210
211 HTTP_BEGIN_ARGS(methodUnregister, 0, 1)
212 HTTP_ARG_VAL(method, 0)
213 HTTP_END_ARGS;
214
215 HTTP_BEGIN_ARGS(methodName, 0, 1)
216 HTTP_ARG_VAL(method_id, 0)
217 HTTP_END_ARGS;
218
219 HTTP_BEGIN_ARGS(methodExists, 0, 1)
220 HTTP_ARG_VAL(method, 0)
221 HTTP_END_ARGS;
222
223 #define http_request_object_declare_default_properties() _http_request_object_declare_default_properties(TSRMLS_C)
224 static inline void _http_request_object_declare_default_properties(TSRMLS_D);
225 #define http_request_object_clone_obj _http_request_object_clone_obj
226 static inline zend_object_value _http_request_object_clone_obj(zval *object TSRMLS_DC);
227
228 zend_class_entry *http_request_object_ce;
229 zend_function_entry http_request_object_fe[] = {
230 HTTP_REQUEST_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
231 HTTP_REQUEST_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
232
233 HTTP_REQUEST_ME(setOptions, ZEND_ACC_PUBLIC)
234 HTTP_REQUEST_ME(getOptions, ZEND_ACC_PUBLIC)
235 HTTP_REQUEST_ME(setSslOptions, ZEND_ACC_PUBLIC)
236 HTTP_REQUEST_ME(getSslOptions, ZEND_ACC_PUBLIC)
237
238 HTTP_REQUEST_ME(addHeaders, ZEND_ACC_PUBLIC)
239 HTTP_REQUEST_ME(getHeaders, ZEND_ACC_PUBLIC)
240 HTTP_REQUEST_ME(setHeaders, ZEND_ACC_PUBLIC)
241
242 HTTP_REQUEST_ME(addCookies, ZEND_ACC_PUBLIC)
243 HTTP_REQUEST_ME(getCookies, ZEND_ACC_PUBLIC)
244 HTTP_REQUEST_ME(setCookies, ZEND_ACC_PUBLIC)
245
246 HTTP_REQUEST_ME(setMethod, ZEND_ACC_PUBLIC)
247 HTTP_REQUEST_ME(getMethod, ZEND_ACC_PUBLIC)
248
249 HTTP_REQUEST_ME(setUrl, ZEND_ACC_PUBLIC)
250 HTTP_REQUEST_ME(getUrl, ZEND_ACC_PUBLIC)
251
252 HTTP_REQUEST_ME(setContentType, ZEND_ACC_PUBLIC)
253 HTTP_REQUEST_ME(getContentType, ZEND_ACC_PUBLIC)
254
255 HTTP_REQUEST_ME(setQueryData, ZEND_ACC_PUBLIC)
256 HTTP_REQUEST_ME(getQueryData, ZEND_ACC_PUBLIC)
257 HTTP_REQUEST_ME(addQueryData, ZEND_ACC_PUBLIC)
258
259 HTTP_REQUEST_ME(setPostFields, ZEND_ACC_PUBLIC)
260 HTTP_REQUEST_ME(getPostFields, ZEND_ACC_PUBLIC)
261 HTTP_REQUEST_ME(addPostFields, ZEND_ACC_PUBLIC)
262
263 HTTP_REQUEST_ME(setRawPostData, ZEND_ACC_PUBLIC)
264 HTTP_REQUEST_ME(getRawPostData, ZEND_ACC_PUBLIC)
265 HTTP_REQUEST_ME(addRawPostData, ZEND_ACC_PUBLIC)
266
267 HTTP_REQUEST_ME(setPostFiles, ZEND_ACC_PUBLIC)
268 HTTP_REQUEST_ME(addPostFile, ZEND_ACC_PUBLIC)
269 HTTP_REQUEST_ME(getPostFiles, ZEND_ACC_PUBLIC)
270
271 HTTP_REQUEST_ME(setPutFile, ZEND_ACC_PUBLIC)
272 HTTP_REQUEST_ME(getPutFile, ZEND_ACC_PUBLIC)
273
274 HTTP_REQUEST_ME(send, ZEND_ACC_PUBLIC)
275
276 HTTP_REQUEST_ME(getResponseData, ZEND_ACC_PUBLIC)
277 HTTP_REQUEST_ME(getResponseHeader, ZEND_ACC_PUBLIC)
278 HTTP_REQUEST_ME(getResponseCookie, ZEND_ACC_PUBLIC)
279 HTTP_REQUEST_ME(getResponseCode, ZEND_ACC_PUBLIC)
280 HTTP_REQUEST_ME(getResponseBody, ZEND_ACC_PUBLIC)
281 HTTP_REQUEST_ME(getResponseInfo, ZEND_ACC_PUBLIC)
282 HTTP_REQUEST_ME(getResponseMessage, ZEND_ACC_PUBLIC)
283 HTTP_REQUEST_ME(getRequestMessage, ZEND_ACC_PUBLIC)
284 HTTP_REQUEST_ME(getHistory, ZEND_ACC_PUBLIC)
285 HTTP_REQUEST_ME(clearHistory, ZEND_ACC_PUBLIC)
286
287 HTTP_REQUEST_ALIAS(get, http_get)
288 HTTP_REQUEST_ALIAS(head, http_head)
289 HTTP_REQUEST_ALIAS(postData, http_post_data)
290 HTTP_REQUEST_ALIAS(postFields, http_post_fields)
291 HTTP_REQUEST_ALIAS(putFile, http_put_file)
292 HTTP_REQUEST_ALIAS(putStream, http_put_stream)
293
294 HTTP_REQUEST_ALIAS(methodRegister, http_request_method_register)
295 HTTP_REQUEST_ALIAS(methodUnregister, http_request_method_unregister)
296 HTTP_REQUEST_ALIAS(methodName, http_request_method_name)
297 HTTP_REQUEST_ALIAS(methodExists, http_request_method_exists)
298
299 EMPTY_FUNCTION_ENTRY
300 };
301 static zend_object_handlers http_request_object_handlers;
302
303 PHP_MINIT_FUNCTION(http_request_object)
304 {
305 HTTP_REGISTER_CLASS_EX(HttpRequest, http_request_object, NULL, 0);
306 http_request_object_handlers.clone_obj = NULL; /* http_request_object_clone_obj; */
307 return SUCCESS;
308 }
309
310 zend_object_value _http_request_object_new(zend_class_entry *ce TSRMLS_DC)
311 {
312 return http_request_object_new_ex(ce, NULL);
313 }
314
315 zend_object_value _http_request_object_new_ex(zend_class_entry *ce, CURL* ch TSRMLS_DC)
316 {
317 zend_object_value ov;
318 http_request_object *o;
319
320 o = ecalloc(1, sizeof(http_request_object));
321 o->zo.ce = ce;
322
323 if (ch) {
324 o->ch = ch;
325 } else {
326 o->ch = curl_easy_init();
327 }
328
329 phpstr_init(&o->history);
330 phpstr_init(&o->request);
331 phpstr_init_ex(&o->response, HTTP_CURLBUF_SIZE, 0);
332
333 ALLOC_HASHTABLE(OBJ_PROP(o));
334 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
335 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
336
337 ov.handle = putObject(http_request_object, o);
338 ov.handlers = &http_request_object_handlers;
339
340 return ov;
341 }
342
343 zend_object_value _http_request_object_clone(zval *object TSRMLS_DC)
344 {
345 return http_request_object_clone_obj(object TSRMLS_CC);
346 }
347
348 static inline zend_object_value _http_request_object_clone_obj(zval *object TSRMLS_DC)
349 {
350 zval clone;
351 getObjectEx(http_request_object, obj, object);
352
353 INIT_PZVAL(&clone);
354 clone.value.obj = http_request_object_new_ex(Z_OBJCE_P(object), curl_easy_duphandle(obj->ch));
355 {
356 getObjectEx(http_request_object, cobj, &clone);
357
358 /* copy history */
359 phpstr_append(&cobj->history, PHPSTR_VAL(&obj->history), PHPSTR_LEN(&obj->history));
360 /*
361 phpstr_append(&cobj->request, PHPSTR_VAL(&obj->request), PHPSTR_LEN(&obj->request));
362 phpstr_append(&obj->response, PHPSTR_VAL(&obj->response), PHPSTR_ÖEN(&obj->response));
363 */
364 /* copy properties */
365 zend_hash_copy(OBJ_PROP(cobj), OBJ_PROP(obj), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
366
367 /* attach to pool */
368 if (obj->pool) {
369 http_request_pool_attach(obj->pool, &clone);
370 }
371 }
372
373 return clone.value.obj;
374 }
375
376 static inline void _http_request_object_declare_default_properties(TSRMLS_D)
377 {
378 zend_class_entry *ce = http_request_object_ce;
379
380 DCL_PROP_N(PROTECTED, options);
381 DCL_PROP_N(PROTECTED, responseInfo);
382 DCL_PROP_N(PROTECTED, responseData);
383 DCL_PROP_N(PROTECTED, responseCode);
384 DCL_PROP_N(PROTECTED, responseMessage);
385 DCL_PROP_N(PROTECTED, postFields);
386 DCL_PROP_N(PROTECTED, postFiles);
387
388 DCL_PROP(PROTECTED, long, method, HTTP_GET);
389
390 DCL_PROP(PROTECTED, string, url, "");
391 DCL_PROP(PROTECTED, string, contentType, "");
392 DCL_PROP(PROTECTED, string, rawPostData, "");
393 DCL_PROP(PROTECTED, string, queryData, "");
394 DCL_PROP(PROTECTED, string, putFile, "");
395
396 DCL_PROP(PUBLIC, bool, recordHistory, 1);
397
398 #ifndef WONKY
399 /*
400 * Request Method Constants
401 */
402 /* HTTP/1.1 */
403 DCL_CONST(long, "METH_GET", HTTP_GET);
404 DCL_CONST(long, "METH_HEAD", HTTP_HEAD);
405 DCL_CONST(long, "METH_POST", HTTP_POST);
406 DCL_CONST(long, "METH_PUT", HTTP_PUT);
407 DCL_CONST(long, "METH_DELETE", HTTP_DELETE);
408 DCL_CONST(long, "METH_OPTIONS", HTTP_OPTIONS);
409 DCL_CONST(long, "METH_TRACE", HTTP_TRACE);
410 DCL_CONST(long, "METH_CONNECT", HTTP_CONNECT);
411 /* WebDAV - RFC 2518 */
412 DCL_CONST(long, "METH_PROPFIND", HTTP_PROPFIND);
413 DCL_CONST(long, "METH_PROPPATCH", HTTP_PROPPATCH);
414 DCL_CONST(long, "METH_MKCOL", HTTP_MKCOL);
415 DCL_CONST(long, "METH_COPY", HTTP_COPY);
416 DCL_CONST(long, "METH_MOVE", HTTP_MOVE);
417 DCL_CONST(long, "METH_LOCK", HTTP_LOCK);
418 DCL_CONST(long, "METH_UNLOCK", HTTP_UNLOCK);
419 /* WebDAV Versioning - RFC 3253 */
420 DCL_CONST(long, "METH_VERSION_CONTROL", HTTP_VERSION_CONTROL);
421 DCL_CONST(long, "METH_REPORT", HTTP_REPORT);
422 DCL_CONST(long, "METH_CHECKOUT", HTTP_CHECKOUT);
423 DCL_CONST(long, "METH_CHECKIN", HTTP_CHECKIN);
424 DCL_CONST(long, "METH_UNCHECKOUT", HTTP_UNCHECKOUT);
425 DCL_CONST(long, "METH_MKWORKSPACE", HTTP_MKWORKSPACE);
426 DCL_CONST(long, "METH_UPDATE", HTTP_UPDATE);
427 DCL_CONST(long, "METH_LABEL", HTTP_LABEL);
428 DCL_CONST(long, "METH_MERGE", HTTP_MERGE);
429 DCL_CONST(long, "METH_BASELINE_CONTROL", HTTP_BASELINE_CONTROL);
430 DCL_CONST(long, "METH_MKACTIVITY", HTTP_MKACTIVITY);
431 /* WebDAV Access Control - RFC 3744 */
432 DCL_CONST(long, "METH_ACL", HTTP_ACL);
433
434 /*
435 * Auth Constants
436 */
437 # if LIBCURL_VERSION_NUM >= 0x070a05
438 DCL_CONST(long, "AUTH_BASIC", CURLAUTH_BASIC);
439 DCL_CONST(long, "AUTH_DIGEST", CURLAUTH_DIGEST);
440 DCL_CONST(long, "AUTH_NTLM", CURLAUTH_NTLM);
441 DCL_CONST(long, "AUTH_ANY", CURLAUTH_ANY);
442 # endif /* LIBCURL_VERSION_NUM */
443 #endif /* WONKY */
444 }
445
446 void _http_request_object_free(zend_object *object TSRMLS_DC)
447 {
448 http_request_object *o = (http_request_object *) object;
449
450 if (OBJ_PROP(o)) {
451 zend_hash_destroy(OBJ_PROP(o));
452 FREE_HASHTABLE(OBJ_PROP(o));
453 }
454 if (o->ch) {
455 /* avoid nasty segfaults with already cleaned up callbacks */
456 curl_easy_setopt(o->ch, CURLOPT_NOPROGRESS, 1);
457 curl_easy_setopt(o->ch, CURLOPT_PROGRESSFUNCTION, NULL);
458 curl_easy_setopt(o->ch, CURLOPT_VERBOSE, 0);
459 curl_easy_setopt(o->ch, CURLOPT_DEBUGFUNCTION, NULL);
460 curl_easy_cleanup(o->ch);
461 }
462 phpstr_dtor(&o->response);
463 phpstr_dtor(&o->request);
464 phpstr_dtor(&o->history);
465 efree(o);
466 }
467
468 STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ptr, http_request_body *body TSRMLS_DC)
469 {
470 zval *meth, *URL;
471 char *request_uri;
472 STATUS status = SUCCESS;
473
474 if (!body) {
475 return FAILURE;
476 }
477 HTTP_CHECK_CURL_INIT(obj->ch, curl_easy_init(), return FAILURE);
478
479 URL = convert_to_type_ex(IS_STRING, GET_PROP(obj, url));
480 // HTTP_URI_MAXLEN+1 long char *
481 if (!(request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0))) {
482 return FAILURE;
483 }
484
485 meth = convert_to_type_ex(IS_LONG, GET_PROP(obj, method));
486 switch (Z_LVAL_P(meth))
487 {
488 case HTTP_GET:
489 case HTTP_HEAD:
490 body->type = -1;
491 body = NULL;
492 break;
493
494 case HTTP_PUT:
495 {
496 php_stream_statbuf ssb;
497 php_stream *stream = php_stream_open_wrapper(Z_STRVAL_P(GET_PROP(obj, putFile)), "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
498
499 if (stream && !php_stream_stat(stream, &ssb)) {
500 body->type = HTTP_REQUEST_BODY_UPLOADFILE;
501 body->data = stream;
502 body->size = ssb.sb.st_size;
503 } else {
504 status = FAILURE;
505 }
506 }
507 break;
508
509 case HTTP_POST:
510 default:
511 {
512 /* check for raw post data */
513 zval *raw_data = convert_to_type_ex(IS_STRING, GET_PROP(obj, rawPostData));
514
515 if (Z_STRLEN_P(raw_data)) {
516 zval *ctype = convert_to_type_ex(IS_STRING, GET_PROP(obj, contentType));
517
518 if (Z_STRLEN_P(ctype)) {
519 zval **headers, *opts = GET_PROP(obj, options);
520
521 convert_to_array(opts);
522
523 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
524 zval **ct_header;
525
526 convert_to_array(*headers);
527 /* only override if not already set */
528 if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(headers), "Content-Type", sizeof("Content-Type"), (void **) &ct_header)) {
529 add_assoc_stringl(*headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
530 }
531 } else {
532 zval *headers;
533
534 MAKE_STD_ZVAL(headers);
535 array_init(headers);
536 add_assoc_stringl(headers, "Content-Type", Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
537 add_assoc_zval(opts, "headers", headers);
538 }
539 }
540
541 body->type = HTTP_REQUEST_BODY_CSTRING;
542 body->data = estrndup(Z_STRVAL_P(raw_data), Z_STRLEN_P(raw_data));
543 body->size = Z_STRLEN_P(raw_data);
544 } else {
545 status = http_request_body_fill(body, Z_ARRVAL_P(GET_PROP(obj, postFields)), Z_ARRVAL_P(GET_PROP(obj, postFiles)));
546 }
547 }
548 break;
549 }
550
551 if (status == SUCCESS) {
552 zval *qdata = convert_to_type_ex(IS_STRING, GET_PROP(obj, queryData));
553
554 if (Z_STRLEN_P(qdata)) {
555 if (!strchr(request_uri, '?')) {
556 strlcat(request_uri, "?", HTTP_URI_MAXLEN);
557 } else {
558 strlcat(request_uri, "&", HTTP_URI_MAXLEN);
559 }
560 strlcat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN);
561 }
562
563 status = http_request_init(obj->ch, Z_LVAL_P(meth), request_uri, body, Z_ARRVAL_P(GET_PROP(obj, options)));
564 }
565 efree(request_uri);
566
567 /* clean previous response */
568 phpstr_dtor(&obj->response);
569 /* clean previous request */
570 phpstr_dtor(&obj->request);
571
572 return status;
573 }
574
575 STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this_ptr TSRMLS_DC)
576 {
577 http_message *msg;
578
579 phpstr_fix(&obj->request);
580 phpstr_fix(&obj->response);
581
582 msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response));
583
584 if (!msg) {
585 return FAILURE;
586 } else {
587 char *body;
588 size_t body_len;
589 zval *headers, *message,
590 *resp = convert_to_type(IS_ARRAY, GET_PROP(obj, responseData)),
591 *info = convert_to_type(IS_ARRAY, GET_PROP(obj, responseInfo));
592
593 if (zval_is_true(GET_PROP(obj, recordHistory))) {
594 /* we need to act like a zipper, as we'll receive
595 * the requests and the responses in separate chains
596 * for redirects
597 */
598 http_message *response = msg, *request = http_message_parse(PHPSTR_VAL(&obj->request), PHPSTR_LEN(&obj->request));
599 http_message *free_msg = request;
600
601 do {
602 char *message;
603 size_t msglen;
604
605 http_message_tostring(response, &message, &msglen);
606 phpstr_append(&obj->history, message, msglen);
607 efree(message);
608
609 http_message_tostring(request, &message, &msglen);
610 phpstr_append(&obj->history, message, msglen);
611 efree(message);
612
613 } while ((response = response->parent) && (request = request->parent));
614
615 http_message_free(&free_msg);
616 phpstr_fix(&obj->history);
617 }
618
619 UPD_PROP(obj, long, responseCode, msg->http.info.response.code);
620
621 MAKE_STD_ZVAL(headers)
622 array_init(headers);
623
624 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
625 phpstr_data(PHPSTR(msg), &body, &body_len);
626
627 add_assoc_zval(resp, "headers", headers);
628 add_assoc_stringl(resp, "body", body, body_len, 0);
629
630 MAKE_STD_ZVAL(message);
631 ZVAL_OBJVAL(message, http_message_object_from_msg(msg));
632 SET_PROP(obj, responseMessage, message);
633 zval_ptr_dtor(&message);
634
635 http_request_info(obj->ch, Z_ARRVAL_P(info));
636 SET_PROP(obj, responseInfo, info);
637
638 return SUCCESS;
639 }
640 }
641
642 #define http_request_object_set_options_subr(key, ow) \
643 _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, (key), sizeof(key), (ow))
644 static inline void _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len, int overwrite)
645 {
646 zval *opts, **options, *new_options = NULL;
647 getObject(http_request_object, obj);
648
649 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &new_options)) {
650 RETURN_FALSE;
651 }
652
653 opts = convert_to_type(IS_ARRAY, GET_PROP(obj, options));
654
655 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), key, len, (void **) &options)) {
656 convert_to_array(*options);
657 if (overwrite) {
658 zend_hash_clean(Z_ARRVAL_PP(options));
659 }
660 if (new_options && zend_hash_num_elements(Z_ARRVAL_P(new_options))) {
661 if (overwrite) {
662 array_copy(new_options, *options);
663 } else {
664 array_merge(new_options, *options);
665 }
666 }
667 } else if (new_options && zend_hash_num_elements(Z_ARRVAL_P(new_options))) {
668 zval_add_ref(&new_options);
669 add_assoc_zval(opts, key, new_options);
670 }
671
672 RETURN_TRUE;
673 }
674
675 #define http_request_object_get_options_subr(key) \
676 _http_request_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU, (key), sizeof(key))
677 static inline void _http_request_get_options_subr(INTERNAL_FUNCTION_PARAMETERS, char *key, size_t len)
678 {
679 NO_ARGS;
680
681 IF_RETVAL_USED {
682 zval *opts, **options;
683 getObject(http_request_object, obj);
684
685 opts = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, options));
686
687 array_init(return_value);
688
689 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), key, len, (void **) &options)) {
690 convert_to_array(*options);
691 array_copy(*options, return_value);
692 }
693 }
694 }
695
696
697 /* ### USERLAND ### */
698
699 /* {{{ proto void HttpRequest::__construct([string url[, int request_method = HTTP_METH_GET[, array options]]])
700 *
701 * Instantiate a new HttpRequest object.
702 *
703 * Accepts a string as optional parameter containing the target request url.
704 * Additianally accepts an optional int parameter specifying the request method
705 * to use and an associative array as optional third parameter which will be
706 * passed to HttpRequest::setOptions().
707 *
708 * Throws HttpException.
709 */
710 PHP_METHOD(HttpRequest, __construct)
711 {
712 char *URL = NULL;
713 int URL_len;
714 long meth = -1;
715 zval *options = NULL;
716 getObject(http_request_object, obj);
717
718 SET_EH_THROW_HTTP();
719 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sla", &URL, &URL_len, &meth, &options)) {
720 INIT_PARR(obj, options);
721 INIT_PARR(obj, responseInfo);
722 INIT_PARR(obj, responseData);
723 INIT_PARR(obj, postFields);
724 INIT_PARR(obj, postFiles);
725
726 if (URL) {
727 UPD_STRL(obj, url, URL, URL_len);
728 }
729 if (meth > -1) {
730 UPD_PROP(obj, long, method, meth);
731 }
732 if (options) {
733 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setoptions", NULL, options);
734 }
735 }
736 SET_EH_NORMAL();
737 }
738 /* }}} */
739
740 /* {{{ proto void HttpRequest::__destruct()
741 *
742 * Destroys the HttpRequest object.
743 */
744 PHP_METHOD(HttpRequest, __destruct)
745 {
746 getObject(http_request_object, obj);
747
748 NO_ARGS;
749
750 FREE_PARR(obj, options);
751 FREE_PARR(obj, responseInfo);
752 FREE_PARR(obj, responseData);
753 FREE_PARR(obj, postFields);
754 FREE_PARR(obj, postFiles);
755 }
756 /* }}} */
757
758 /* {{{ proto bool HttpRequest::setOptions([array options])
759 *
760 * Set the request options to use. See http_get() for a full list of available options.
761 *
762 * Accepts an array as optional parameters, wich values will overwrite the
763 * currently set request options. If the parameter is empty or mitted,
764 * the optoions of the HttpRequest object will be reset.
765 *
766 * Returns TRUE on success, or FALSE on failure.
767 */
768 PHP_METHOD(HttpRequest, setOptions)
769 {
770 char *key = NULL;
771 ulong idx = 0;
772 zval *opts = NULL, *old_opts, **opt;
773 getObject(http_request_object, obj);
774
775 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a/!", &opts)) {
776 RETURN_FALSE;
777 }
778
779 old_opts = convert_to_type(IS_ARRAY, GET_PROP(obj, options));
780
781 if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
782 zend_hash_clean(Z_ARRVAL_P(old_opts));
783 RETURN_TRUE;
784 }
785
786 /* some options need extra attention -- thus cannot use array_merge() directly */
787 FOREACH_KEYVAL(opts, key, idx, opt) {
788 if (key) {
789 if (!strcmp(key, "headers")) {
790 zval **headers;
791 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
792 convert_to_array(*opt);
793 convert_to_array(*headers);
794 array_merge(*opt, *headers);
795 continue;
796 }
797 } else if (!strcmp(key, "cookies")) {
798 zval **cookies;
799 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
800 convert_to_array(*opt);
801 convert_to_array(*cookies);
802 array_merge(*opt, *cookies);
803 continue;
804 }
805 } else if (!strcmp(key, "ssl")) {
806 zval **ssl;
807 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "ssl", sizeof("ssl"), (void **) &ssl)) {
808 convert_to_array(*opt);
809 convert_to_array(*ssl);
810 array_merge(*opt, *ssl);
811 continue;
812 }
813 } else if ((!strcasecmp(key, "url")) || (!strcasecmp(key, "uri"))) {
814 if (Z_TYPE_PP(opt) != IS_STRING) {
815 convert_to_string_ex(opt);
816 }
817 UPD_STRL(obj, url, Z_STRVAL_PP(opt), Z_STRLEN_PP(opt));
818 continue;
819 } else if (!strcmp(key, "method")) {
820 if (Z_TYPE_PP(opt) != IS_LONG) {
821 convert_to_long_ex(opt);
822 }
823 UPD_PROP(obj, long, method, Z_LVAL_PP(opt));
824 continue;
825 }
826
827 zval_add_ref(opt);
828 add_assoc_zval(old_opts, key, *opt);
829
830 /* reset */
831 key = NULL;
832 }
833 }
834
835 RETURN_TRUE;
836 }
837 /* }}} */
838
839 /* {{{ proto array HttpRequest::getOptions()
840 *
841 * Get currently set options.
842 *
843 * Returns an associative array containing currently set options.
844 */
845 PHP_METHOD(HttpRequest, getOptions)
846 {
847 NO_ARGS;
848
849 IF_RETVAL_USED {
850 zval *opts;
851 getObject(http_request_object, obj);
852
853 opts = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, options));
854 array_init(return_value);
855 array_copy(opts, return_value);
856 }
857 }
858 /* }}} */
859
860 /* {{{ proto bool HttpRequest::setSslOptions([array options])
861 *
862 * Set SSL options.
863 *
864 * Accepts an associative array as parameter containing any SSL specific options.
865 * If the parameter is empty or omitted, the SSL options will be reset.
866 *
867 * Returns TRUE on success, or FALSE on failure.
868 */
869 PHP_METHOD(HttpRequest, setSslOptions)
870 {
871 http_request_object_set_options_subr("ssl", 1);
872 }
873 /* }}} */
874
875 /* {{{ proto bool HttpRequest::addSslOptions(array options)
876 *
877 * Set additional SSL options.
878 *
879 * Expects an associative array as parameter containing additional SSL specific options.
880 *
881 * Returns TRUE on success, or FALSE on failure.
882 */
883 PHP_METHOD(HttpRequest, addSslOptions)
884 {
885 http_request_object_set_options_subr("ssl", 0);
886 }
887 /* }}} */
888
889 /* {{{ proto array HttpRequest::getSslOtpions()
890 *
891 * Get previously set SSL options.
892 *
893 * Returns an associative array containing any previously set SSL options.
894 */
895 PHP_METHOD(HttpRequest, getSslOptions)
896 {
897 http_request_object_get_options_subr("ssl");
898 }
899 /* }}} */
900
901 /* {{{ proto bool HttpRequest::addHeaders(array headers)
902 *
903 * Add request header name/value pairs.
904 *
905 * Expects an ssociative array as parameter containing additional header
906 * name/value pairs.
907 *
908 * Returns TRUE on success, or FALSE on failure.
909 */
910 PHP_METHOD(HttpRequest, addHeaders)
911 {
912 http_request_object_set_options_subr("headers", 0);
913 }
914
915 /* {{{ proto bool HttpRequest::setHeaders([array headers])
916 *
917 * Set request header name/value pairs.
918 *
919 * Accepts an associative array as parameter containing header name/value pairs.
920 * If the parameter is empty or omitted, all previously set headers will be unset.
921 *
922 * Returns TRUE on success, or FALSE on failure.
923 */
924 PHP_METHOD(HttpRequest, setHeaders)
925 {
926 http_request_object_set_options_subr("headers", 1);
927 }
928 /* }}} */
929
930 /* {{{ proto array HttpRequest::getHeaders()
931 *
932 * Get previously set request headers.
933 *
934 * Returns an associative array containing all currently set headers.
935 */
936 PHP_METHOD(HttpRequest, getHeaders)
937 {
938 http_request_object_get_options_subr("headers");
939 }
940 /* }}} */
941
942 /* {{{ proto bool HttpRequest::setCookies([array cookies])
943 *
944 * Set cookies.
945 *
946 * Accepts an associative array as parameter containing cookie name/value pairs.
947 * If the parameter is empty or omitted, all previously set cookies will be unset.
948 *
949 * Returns TRUE on success, or FALSE on failure.
950 */
951 PHP_METHOD(HttpRequest, setCookies)
952 {
953 http_request_object_set_options_subr("cookies", 1);
954 }
955 /* }}} */
956
957 /* {{{ proto bool HttpRequest::addCookies(array cookies)
958 *
959 * Add cookies.
960 *
961 * Expects an associative array as parameter containing any cookie name/value
962 * pairs to add.
963 *
964 * Returns TRUE on success, or FALSE on failure.
965 */
966 PHP_METHOD(HttpRequest, addCookies)
967 {
968 http_request_object_set_options_subr("cookies", 0);
969 }
970 /* }}} */
971
972 /* {{{ proto array HttpRequest::getCookies()
973 *
974 * Get previously set cookies.
975 *
976 * Returns an associative array containing any previously set cookies.
977 */
978 PHP_METHOD(HttpRequest, getCookies)
979 {
980 http_request_object_get_options_subr("cookies");
981 }
982 /* }}} */
983
984 /* {{{ proto bool HttpRequest::setUrl(string url)
985 *
986 * Set the request URL.
987 *
988 * Expects a string as parameter specifying the request url.
989 *
990 * Returns TRUE on success, or FALSE on failure.
991 */
992 PHP_METHOD(HttpRequest, setUrl)
993 {
994 char *URL = NULL;
995 int URL_len;
996 getObject(http_request_object, obj);
997
998 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
999 RETURN_FALSE;
1000 }
1001
1002 UPD_STRL(obj, url, URL, URL_len);
1003 RETURN_TRUE;
1004 }
1005 /* }}} */
1006
1007 /* {{{ proto string HttpRequest::getUrl()
1008 *
1009 * Get the previously set request URL.
1010 *
1011 * Returns the currently set request url as string.
1012 */
1013 PHP_METHOD(HttpRequest, getUrl)
1014 {
1015 NO_ARGS;
1016
1017 IF_RETVAL_USED {
1018 getObject(http_request_object, obj);
1019 zval *URL = GET_PROP(obj, url);
1020
1021 RETURN_ZVAL(URL, 1, 0);
1022 }
1023 }
1024 /* }}} */
1025
1026 /* {{{ proto bool HttpRequest::setMethod(int request_method)
1027 *
1028 * Set the request method.
1029 *
1030 * Expects an int as parameter specifying the request method to use.
1031 * In PHP 5.1+ HttpRequest::METH, otherwise the HTTP_METH constants can be used.
1032 *
1033 * Returns TRUE on success, or FALSE on failure.
1034 */
1035 PHP_METHOD(HttpRequest, setMethod)
1036 {
1037 long meth;
1038 getObject(http_request_object, obj);
1039
1040 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
1041 RETURN_FALSE;
1042 }
1043
1044 UPD_PROP(obj, long, method, meth);
1045 RETURN_TRUE;
1046 }
1047 /* }}} */
1048
1049 /* {{{ proto int HttpRequest::getMethod()
1050 *
1051 * Get the previously set request method.
1052 *
1053 * Returns the currently set request method.
1054 */
1055 PHP_METHOD(HttpRequest, getMethod)
1056 {
1057 NO_ARGS;
1058
1059 IF_RETVAL_USED {
1060 getObject(http_request_object, obj);
1061 zval *meth = GET_PROP(obj, method);
1062
1063 RETURN_ZVAL(meth, 1, 0);
1064 }
1065 }
1066 /* }}} */
1067
1068 /* {{{ proto bool HttpRequest::setContentType(string content_type)
1069 *
1070 * Set the content type the post request should have.
1071 *
1072 * Expects a string as parameters containing the content type of the request
1073 * (primary/secondary).
1074 *
1075 * Returns TRUE on success, or FALSE if the content type does not seem to
1076 * contain a primary and a secondary part.
1077 */
1078 PHP_METHOD(HttpRequest, setContentType)
1079 {
1080 char *ctype;
1081 int ct_len;
1082 getObject(http_request_object, obj);
1083
1084 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
1085 RETURN_FALSE;
1086 }
1087
1088 HTTP_CHECK_CONTENT_TYPE(ctype, RETURN_FALSE);
1089 UPD_STRL(obj, contentType, ctype, ct_len);
1090 RETURN_TRUE;
1091 }
1092 /* }}} */
1093
1094 /* {{{ proto string HttpRequest::getContentType()
1095 *
1096 * Get the previously content type.
1097 *
1098 * Returns the previously set content type as string.
1099 */
1100 PHP_METHOD(HttpRequest, getContentType)
1101 {
1102 NO_ARGS;
1103
1104 IF_RETVAL_USED {
1105 getObject(http_request_object, obj);
1106 zval *ctype = GET_PROP(obj, contentType);
1107
1108 RETURN_ZVAL(ctype, 1, 0);
1109 }
1110 }
1111 /* }}} */
1112
1113 /* {{{ proto bool HttpRequest::setQueryData([mixed query_data])
1114 *
1115 * Set the URL query parameters to use, overwriting previously set query parameters.
1116 * Affects any request types.
1117 *
1118 * Accepts a string or associative array parameter containing the pre-encoded
1119 * query string or to be encoded query fields. If the parameter is empty or
1120 * omitted, the query data will be unset.
1121 *
1122 * Returns TRUE on success, or FALSE on failure.
1123 */
1124 PHP_METHOD(HttpRequest, setQueryData)
1125 {
1126 zval *qdata = NULL;
1127 getObject(http_request_object, obj);
1128
1129 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!", &qdata)) {
1130 RETURN_FALSE;
1131 }
1132
1133 if ((!qdata) || Z_TYPE_P(qdata) == IS_NULL) {
1134 UPD_STRL(obj, queryData, "", 0);
1135 } else if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1136 char *query_data = NULL;
1137
1138 if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
1139 RETURN_FALSE;
1140 }
1141
1142 UPD_PROP(obj, string, queryData, query_data);
1143 efree(query_data);
1144 } else {
1145 convert_to_string_ex(&qdata);
1146 UPD_STRL(obj, queryData, Z_STRVAL_P(qdata), Z_STRLEN_P(qdata));
1147 }
1148 RETURN_TRUE;
1149 }
1150 /* }}} */
1151
1152 /* {{{ proto string HttpRequest::getQueryData()
1153 *
1154 * Get the current query data in form of an urlencoded query string.
1155 *
1156 * Returns a string containing the urlencoded query.
1157 */
1158 PHP_METHOD(HttpRequest, getQueryData)
1159 {
1160 NO_ARGS;
1161
1162 IF_RETVAL_USED {
1163 getObject(http_request_object, obj);
1164 zval *qdata = convert_to_type_ex(IS_STRING, GET_PROP(obj, queryData));
1165
1166 RETURN_ZVAL(qdata, 1, 0);
1167 }
1168 }
1169 /* }}} */
1170
1171 /* {{{ proto bool HttpRequest::addQueryData(array query_params)
1172 *
1173 * Add parameters to the query parameter list, leaving previously set unchanged.
1174 * Affects any request type.
1175 *
1176 * Expects an associative array as parameter containing the query fields to add.
1177 *
1178 * Returns TRUE on success, or FALSE on failure.
1179 */
1180 PHP_METHOD(HttpRequest, addQueryData)
1181 {
1182 zval *qdata, *old_qdata;
1183 char *query_data = NULL;
1184 size_t query_data_len = 0;
1185 getObject(http_request_object, obj);
1186
1187 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1188 RETURN_FALSE;
1189 }
1190
1191 old_qdata = convert_to_type_ex(IS_STRING, GET_PROP(obj, queryData));
1192
1193 if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, &query_data_len)) {
1194 RETURN_FALSE;
1195 }
1196
1197 UPD_STRL(obj, queryData, query_data, query_data_len);
1198 efree(query_data);
1199
1200 RETURN_TRUE;
1201 }
1202 /* }}} */
1203
1204 /* {{{ proto bool HttpRequest::addPostFields(array post_data)
1205 *
1206 * Adds POST data entries, leaving previously set unchanged, unless a
1207 * post entry with the same name already exists.
1208 * Affects only POST and custom requests.
1209 *
1210 * Expects an associative array as parameter containing the post fields.
1211 *
1212 * Returns TRUE on success, or FALSE on failure.
1213 */
1214 PHP_METHOD(HttpRequest, addPostFields)
1215 {
1216 zval *post, *post_data;
1217 getObject(http_request_object, obj);
1218
1219 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1220 RETURN_FALSE;
1221 }
1222
1223 post = convert_to_type(IS_ARRAY, GET_PROP(obj, postFields));
1224 array_merge(post_data, post);
1225
1226 RETURN_TRUE;
1227 }
1228 /* }}} */
1229
1230 /* {{{ proto bool HttpRequest::setPostFields([array post_data])
1231 *
1232 * Set the POST data entries, overwriting previously set POST data.
1233 * Affects only POST and custom requests.
1234 *
1235 * Accepts an associative array as parameter containing the post fields.
1236 * If the parameter is empty or omitted, the post data will be unset.
1237 *
1238 * Returns TRUE on success, or FALSE on failure.
1239 */
1240 PHP_METHOD(HttpRequest, setPostFields)
1241 {
1242 zval *post, *post_data = NULL;
1243 getObject(http_request_object, obj);
1244
1245 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!", &post_data)) {
1246 RETURN_FALSE;
1247 }
1248
1249 post = convert_to_type(IS_ARRAY, GET_PROP(obj, postFields));
1250 zend_hash_clean(Z_ARRVAL_P(post));
1251
1252 if (post_data && zend_hash_num_elements(Z_ARRVAL_P(post_data))) {
1253 array_copy(post_data, post);
1254 }
1255
1256 RETURN_TRUE;
1257 }
1258 /* }}}*/
1259
1260 /* {{{ proto array HttpRequest::getPostFields()
1261 *
1262 * Get previously set POST data.
1263 *
1264 * Returns the currently set post fields as associative array.
1265 */
1266 PHP_METHOD(HttpRequest, getPostFields)
1267 {
1268 NO_ARGS;
1269
1270 IF_RETVAL_USED {
1271 getObject(http_request_object, obj);
1272 zval *post_data = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, postFields));
1273
1274 array_init(return_value);
1275 array_copy(post_data, return_value);
1276 }
1277 }
1278 /* }}} */
1279
1280 /* {{{ proto bool HttpRequest::setRawPostData([string raw_post_data])
1281 *
1282 * Set raw post data to send, overwriting previously set raw post data. Don't
1283 * forget to specify a content type. Affects only POST and custom requests.
1284 * Only either post fields or raw post data can be used for each request.
1285 * Raw post data has higher precedence and will be used even if post fields
1286 * are set.
1287 *
1288 * Accepts a string as parameter containing the *raw* post data.
1289 *
1290 * Returns TRUE on success, or FALSE on failure.
1291 */
1292 PHP_METHOD(HttpRequest, setRawPostData)
1293 {
1294 char *raw_data = NULL;
1295 int data_len = 0;
1296 getObject(http_request_object, obj);
1297
1298 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &raw_data, &data_len)) {
1299 RETURN_FALSE;
1300 }
1301
1302 if (!raw_data) {
1303 raw_data = "";
1304 }
1305
1306 UPD_STRL(obj, rawPostData, raw_data, data_len);
1307 RETURN_TRUE;
1308 }
1309 /* }}} */
1310
1311 /* {{{ proto bool HttpRequest::addRawPostData(string raw_post_data)
1312 *
1313 * Add raw post data, leaving previously set raw post data unchanged.
1314 * Affects only POST and custom requests.
1315 *
1316 * Expects a string as parameter containing the raw post data to concatenate.
1317 *
1318 * Returns TRUE on success, or FALSE on failure.
1319 */
1320 PHP_METHOD(HttpRequest, addRawPostData)
1321 {
1322 char *raw_data, *new_data;
1323 int data_len;
1324 getObject(http_request_object, obj);
1325
1326 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &raw_data, &data_len)) {
1327 RETURN_FALSE;
1328 }
1329
1330 if (data_len) {
1331 zval *zdata = convert_to_type_ex(IS_STRING, GET_PROP(obj, rawPostData));
1332
1333 new_data = emalloc(Z_STRLEN_P(zdata) + data_len + 1);
1334 new_data[Z_STRLEN_P(zdata) + data_len] = '\0';
1335
1336 if (Z_STRLEN_P(zdata)) {
1337 memcpy(new_data, Z_STRVAL_P(zdata), Z_STRLEN_P(zdata));
1338 }
1339
1340 memcpy(new_data + Z_STRLEN_P(zdata), raw_data, data_len);
1341 UPD_STRL(obj, rawPostData, new_data, Z_STRLEN_P(zdata) + data_len);
1342 }
1343
1344 RETURN_TRUE;
1345 }
1346 /* }}} */
1347
1348 /* {{{ proto string HttpRequest::getRawPostData()
1349 *
1350 * Get previously set raw post data.
1351 *
1352 * Returns a string containing the currently set raw post data.
1353 */
1354 PHP_METHOD(HttpRequest, getRawPostData)
1355 {
1356 NO_ARGS;
1357
1358 IF_RETVAL_USED {
1359 getObject(http_request_object, obj);
1360 zval *raw_data = convert_to_type_ex(IS_STRING, GET_PROP(obj, rawPostData));
1361
1362 RETURN_ZVAL(raw_data, 1, 0);
1363 }
1364 }
1365 /* }}} */
1366
1367 /* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1368 *
1369 * Add a file to the POST request, leaving prefiously set files unchanged.
1370 * Affects only POST and custom requests. Cannot be used with raw post data.
1371 *
1372 * Expects a string parameter containing the form element name, and a string
1373 * paremeter containing the path to the file which should be uploaded.
1374 * Additionally accepts an optional string parameter which chould contain
1375 * the content type of the file.
1376 *
1377 * Returns TRUE on success, or FALSE if the content type seems not to contain a
1378 * primary and a secondary content type part.
1379 */
1380 PHP_METHOD(HttpRequest, addPostFile)
1381 {
1382 zval *files, *entry;
1383 char *name, *file, *type = NULL;
1384 int name_len, file_len, type_len = 0;
1385 getObject(http_request_object, obj);
1386
1387 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1388 RETURN_FALSE;
1389 }
1390
1391 if (type_len) {
1392 HTTP_CHECK_CONTENT_TYPE(type, RETURN_FALSE);
1393 } else {
1394 type = "application/x-octetstream";
1395 type_len = sizeof("application/x-octetstream") - 1;
1396 }
1397
1398 MAKE_STD_ZVAL(entry);
1399 array_init(entry);
1400
1401 add_assoc_stringl(entry, "name", name, name_len, 1);
1402 add_assoc_stringl(entry, "type", type, type_len, 1);
1403 add_assoc_stringl(entry, "file", file, file_len, 1);
1404
1405 files = convert_to_type(IS_ARRAY, GET_PROP(obj, postFiles));
1406 add_next_index_zval(files, entry);
1407
1408 RETURN_TRUE;
1409 }
1410 /* }}} */
1411
1412 /* {{{ proto bool HttpRequest::setPostFiles([array post_files])
1413 *
1414 * Set files to post, overwriting previously set post files.
1415 * Affects only POST and requests. Cannot be used with raw post data.
1416 *
1417 * Accepts an array containing the files to post. Each entry should be an
1418 * associative array with "name", "file" and "type" keys. If the parameter
1419 * is empty or omitted the post files will be unset.
1420 *
1421 * Returns TRUE on success, or FALSE on failure.
1422 */
1423 PHP_METHOD(HttpRequest, setPostFiles)
1424 {
1425 zval *files, *pFiles;
1426 getObject(http_request_object, obj);
1427
1428 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &files)) {
1429 RETURN_FALSE;
1430 }
1431
1432 pFiles = convert_to_type(IS_ARRAY, GET_PROP(obj, postFiles));
1433 zend_hash_clean(Z_ARRVAL_P(pFiles));
1434
1435 if (files && zend_hash_num_elements(Z_ARRVAL_P(files))) {
1436 array_copy(files, pFiles);
1437 }
1438
1439 RETURN_TRUE;
1440 }
1441 /* }}} */
1442
1443 /* {{{ proto array HttpRequest::getPostFiles()
1444 *
1445 * Get all previously added POST files.
1446 *
1447 * Returns an array containing currently set post files.
1448 */
1449 PHP_METHOD(HttpRequest, getPostFiles)
1450 {
1451 NO_ARGS;
1452
1453 IF_RETVAL_USED {
1454 getObject(http_request_object, obj);
1455 zval *files = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, postFiles));
1456
1457 array_init(return_value);
1458 array_copy(files, return_value);
1459 }
1460 }
1461 /* }}} */
1462
1463 /* {{{ proto bool HttpRequest::setPutFile([string file])
1464 *
1465 * Set file to put. Affects only PUT requests.
1466 *
1467 * Accepts a string as parameter referencing the path to file.
1468 * If the parameter is empty or omitted the put file will be unset.
1469 *
1470 * Returns TRUE on success, or FALSE on failure.
1471 */
1472 PHP_METHOD(HttpRequest, setPutFile)
1473 {
1474 char *file = "";
1475 int file_len = 0;
1476 getObject(http_request_object, obj);
1477
1478 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &file, &file_len)) {
1479 RETURN_FALSE;
1480 }
1481
1482 UPD_STRL(obj, putFile, file, file_len);
1483 RETURN_TRUE;
1484 }
1485 /* }}} */
1486
1487 /* {{{ proto string HttpRequest::getPutFile()
1488 *
1489 * Get previously set put file.
1490 *
1491 * Returns a string containing the path to the currently set put file.
1492 */
1493 PHP_METHOD(HttpRequest, getPutFile)
1494 {
1495 NO_ARGS;
1496
1497 IF_RETVAL_USED {
1498 getObject(http_request_object, obj);
1499 zval *putfile = convert_to_type_ex(IS_STRING, GET_PROP(obj, putFile));
1500
1501 RETURN_ZVAL(putfile, 1, 0);
1502 }
1503 }
1504 /* }}} */
1505
1506 /* {{{ proto array HttpRequest::getResponseData()
1507 *
1508 * Get all response data after the request has been sent.
1509 *
1510 * Returns an associative array with the key "headers" containing an associative
1511 * array holding all response headers, as well as the ley "body" containing a
1512 * string with the response body.
1513 *
1514 * If redirects were allowed and several responses were received, the data
1515 * references the last received response.
1516 */
1517 PHP_METHOD(HttpRequest, getResponseData)
1518 {
1519 NO_ARGS;
1520
1521 IF_RETVAL_USED {
1522 getObject(http_request_object, obj);
1523 zval *data = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, responseData));
1524
1525 array_init(return_value);
1526 array_copy(data, return_value);
1527 }
1528 }
1529 /* }}} */
1530
1531 /* {{{ proto mixed HttpRequest::getResponseHeader([string name])
1532 *
1533 * Get response header(s) after the request has been sent.
1534 *
1535 * Accepts an string as optional parameter specifying a certain header to read.
1536 * If the parameter is empty or omitted all response headers will be returned.
1537 *
1538 * Returns either a string with the value of the header matching name if requested,
1539 * FALSE on failure, or an associative array containing all reponse headers.
1540 *
1541 * If redirects were allowed and several responses were received, the data
1542 * references the last received response.
1543 */
1544 PHP_METHOD(HttpRequest, getResponseHeader)
1545 {
1546 IF_RETVAL_USED {
1547 zval *data, **headers, **header;
1548 char *header_name = NULL;
1549 int header_len = 0;
1550 getObject(http_request_object, obj);
1551
1552 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
1553 RETURN_FALSE;
1554 }
1555
1556 data = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, responseData));
1557 if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1558 RETURN_FALSE;
1559 }
1560 convert_to_array_ex(headers);
1561 if (!header_len || !header_name) {
1562 array_init(return_value);
1563 array_copy(*headers, return_value);
1564 } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) {
1565 RETURN_ZVAL(*header, 1, 0);
1566 } else {
1567 RETURN_FALSE;
1568 }
1569 }
1570 }
1571 /* }}} */
1572
1573 /* {{{ proto array HttpRequest::getResponseCookie([string name])
1574 *
1575 * Get response cookie(s) after the request has been sent.
1576 *
1577 * Accepts a string as optional parameter specifying the name of the cookie to read.
1578 * If the parameter is empty or omitted, an associative array with all received
1579 * cookies will be returned.
1580 *
1581 * Returns either an associative array with the cookie's name, value and any
1582 * additional params of the cookie matching name if requested, FALSE on failure,
1583 * or an array containing all received cookies as arrays.
1584 *
1585 * If redirects were allowed and several responses were received, the data
1586 * references the last received response.
1587 */
1588 PHP_METHOD(HttpRequest, getResponseCookie)
1589 {
1590 IF_RETVAL_USED {
1591 zval *data, **headers;
1592 char *cookie_name = NULL;
1593 int cookie_len = 0;
1594 getObject(http_request_object, obj);
1595
1596 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) {
1597 RETURN_FALSE;
1598 }
1599
1600 array_init(return_value);
1601
1602 data = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, responseData));
1603 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1604 ulong idx = 0;
1605 char *key = NULL;
1606 zval **header = NULL;
1607
1608 convert_to_array_ex(headers);
1609 FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) {
1610 if (key && !strcasecmp(key, "Set-Cookie")) {
1611 /* several cookies? */
1612 if (Z_TYPE_PP(header) == IS_ARRAY) {
1613 zval **cookie;
1614
1615 FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) {
1616 zval *cookie_hash;
1617 MAKE_STD_ZVAL(cookie_hash);
1618 array_init(cookie_hash);
1619
1620 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) {
1621 if (!cookie_len) {
1622 add_next_index_zval(return_value, cookie_hash);
1623 } else {
1624 zval **name;
1625
1626 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1627 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1628 add_next_index_zval(return_value, cookie_hash);
1629 return; /* <<< FOUND >>> */
1630 } else {
1631 zval_dtor(cookie_hash);
1632 efree(cookie_hash);
1633 }
1634 }
1635 } else {
1636 zval_dtor(cookie_hash);
1637 efree(cookie_hash);
1638 }
1639 }
1640 } else {
1641 zval *cookie_hash;
1642
1643 MAKE_STD_ZVAL(cookie_hash);
1644 array_init(cookie_hash);
1645 convert_to_string_ex(header);
1646
1647 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) {
1648 if (!cookie_len) {
1649 add_next_index_zval(return_value, cookie_hash);
1650 } else {
1651 zval **name;
1652
1653 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1654 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1655 add_next_index_zval(return_value, cookie_hash);
1656 } else {
1657 zval_dtor(cookie_hash);
1658 efree(cookie_hash);
1659 }
1660 }
1661 } else {
1662 zval_dtor(cookie_hash);
1663 efree(cookie_hash);
1664 }
1665 }
1666 break;
1667 }
1668 /* reset key */
1669 key = NULL;
1670 }
1671 }
1672 }
1673 }
1674 /* }}} */
1675
1676 /* {{{ proto string HttpRequest::getResponseBody()
1677 *
1678 * Get the response body after the request has been sent.
1679 *
1680 * Returns a string containing the response body.
1681 *
1682 * If redirects were allowed and several responses were received, the data
1683 * references the last received response.
1684 */
1685 PHP_METHOD(HttpRequest, getResponseBody)
1686 {
1687 NO_ARGS;
1688
1689 IF_RETVAL_USED {
1690 zval **body;
1691 getObject(http_request_object, obj);
1692 zval *data = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, responseData));
1693
1694 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1695 convert_to_string_ex(body);
1696 RETURN_ZVAL(*body, 1, 0);
1697 } else {
1698 RETURN_FALSE;
1699 }
1700 }
1701 }
1702 /* }}} */
1703
1704 /* {{{ proto int HttpRequest::getResponseCode()
1705 *
1706 * Get the response code after the request has been sent.
1707 *
1708 * Returns an int representing the response code.
1709 *
1710 * If redirects were allowed and several responses were received, the data
1711 * references the last received response.
1712 */
1713 PHP_METHOD(HttpRequest, getResponseCode)
1714 {
1715 NO_ARGS;
1716
1717 IF_RETVAL_USED {
1718 getObject(http_request_object, obj);
1719 zval *code = convert_to_type_ex(IS_LONG, GET_PROP(obj, responseCode));
1720
1721 RETURN_ZVAL(code, 1, 0);
1722 }
1723 }
1724 /* }}} */
1725
1726 /* {{{ proto mixed HttpRequest::getResponseInfo([string name])
1727 *
1728 * Get response info after the request has been sent.
1729 * See http_get() for a full list of returned info.
1730 *
1731 * Accepts a string as optional parameter specifying the info to read.
1732 * If the parameter is empty or omitted, an associative array containing
1733 * all available info will be returned.
1734 *
1735 * Returns either a scalar containing the value of the info matching name if
1736 * requested, FALSE on failure, or an associative array containing all
1737 * available info.
1738 *
1739 * If redirects were allowed and several responses were received, the data
1740 * references the last received response.
1741 */
1742 PHP_METHOD(HttpRequest, getResponseInfo)
1743 {
1744 IF_RETVAL_USED {
1745 zval *info, **infop;
1746 char *info_name = NULL;
1747 int info_len = 0;
1748 getObject(http_request_object, obj);
1749
1750 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
1751 RETURN_FALSE;
1752 }
1753
1754 info = convert_to_type_ex(IS_ARRAY, GET_PROP(obj, responseInfo));
1755
1756 if (info_len && info_name) {
1757 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) {
1758 RETURN_ZVAL(*infop, 1, 0);
1759 } else {
1760 http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Could not find response info named %s", info_name);
1761 RETURN_FALSE;
1762 }
1763 } else {
1764 array_init(return_value);
1765 array_copy(info, return_value);
1766 }
1767 }
1768 }
1769 /* }}}*/
1770
1771 /* {{{ proto HttpMessage HttpRequest::getResponseMessage()
1772 *
1773 * Get the full response as HttpMessage object after the request has been sent.
1774 *
1775 * Returns an HttpMessage object of the response.
1776 *
1777 * If redirects were allowed and several responses were received, the data
1778 * references the last received response. Use HttpMessage::getParentMessage()
1779 * to access the data of previously received responses whithin this request
1780 * cycle.
1781 *
1782 * Throws HttpException.
1783 */
1784 PHP_METHOD(HttpRequest, getResponseMessage)
1785 {
1786 NO_ARGS;
1787
1788 IF_RETVAL_USED {
1789 zval *message;
1790 getObject(http_request_object, obj);
1791
1792 SET_EH_THROW_HTTP();
1793 message = GET_PROP(obj, responseMessage);
1794 if (Z_TYPE_P(message) == IS_OBJECT) {
1795 RETVAL_OBJECT(message);
1796 } else {
1797 RETVAL_NULL();
1798 }
1799 SET_EH_NORMAL();
1800 }
1801 }
1802 /* }}} */
1803
1804 /* {{{ proto HttpMessage HttpRequest::getRequestMessage()
1805 *
1806 * Get sent HTTP message.
1807 *
1808 * Returns an HttpMessage object representing the sent request.
1809 *
1810 * If redirects were allowed and several responses were received, the data
1811 * references the last received response. Use HttpMessage::getParentMessage()
1812 * to access the data of previously sent requests whithin this request
1813 * cycle.
1814 */
1815 PHP_METHOD(HttpRequest, getRequestMessage)
1816 {
1817 NO_ARGS;
1818
1819 IF_RETVAL_USED {
1820 http_message *msg;
1821 getObject(http_request_object, obj);
1822
1823 SET_EH_THROW_HTTP();
1824 if (msg = http_message_parse(PHPSTR_VAL(&obj->request), PHPSTR_LEN(&obj->request))) {
1825 RETVAL_OBJVAL(http_message_object_from_msg(msg));
1826 }
1827 SET_EH_NORMAL();
1828 }
1829 }
1830 /* }}} */
1831
1832 /* {{{ proto HttpMessage HttpRequest::getHistory()
1833 *
1834 * Get all sent requests and received responses as an HttpMessage object.
1835 *
1836 * If you don't want to record history at all, set the instance variable
1837 * HttpRequest::$recoedHistory to FALSE.
1838 *
1839 * Returns an HttpMessage object representing the complete request/response
1840 * history.
1841 *
1842 * The object references the last received response, use HttpMessage::getParentMessage()
1843 * to access the data of previously sent requests and received responses.
1844 *
1845 * Throws HttpMalformedHeaderException.
1846 */
1847 PHP_METHOD(HttpRequest, getHistory)
1848 {
1849 NO_ARGS;
1850
1851 IF_RETVAL_USED {
1852 http_message *msg;
1853 getObject(http_request_object, obj);
1854
1855 SET_EH_THROW_HTTP();
1856 if (msg = http_message_parse(PHPSTR_VAL(&obj->history), PHPSTR_LEN(&obj->history))) {
1857 RETVAL_OBJVAL(http_message_object_from_msg(msg));
1858 }
1859 SET_EH_NORMAL();
1860 }
1861 }
1862 /* }}} */
1863
1864 /* {{{ proto void HttpRequest::clearHistory()
1865 *
1866 * Clear the history.
1867 */
1868 PHP_METHOD(HttpRequest, clearHistory)
1869 {
1870 NO_ARGS {
1871 getObject(http_request_object, obj);
1872 phpstr_dtor(&obj->history);
1873 }
1874 }
1875 /* }}} */
1876
1877 /* {{{ proto HttpMessage HttpRequest::send()
1878 *
1879 * Send the HTTP request.
1880 *
1881 * Returns the received response as HttpMessage object.
1882 *
1883 * Throws HttpRuntimeException, HttpRequestException,
1884 * HttpMalformedHeaderException, HttpEncodingException.
1885 *
1886 * GET example:
1887 * <pre>
1888 * <?php
1889 * $r = new HttpRequest('http://example.com/feed.rss', HTTP_GET);
1890 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
1891 * $r->addQueryData(array('category' => 3));
1892 * try {
1893 * $r->send();
1894 * if ($r->getResponseCode() == 200) {
1895 * file_put_contents('local.rss', $r->getResponseBody());
1896 * }
1897 * } catch (HttpException $ex) {
1898 * echo $ex;
1899 * }
1900 * ?>
1901 * </pre>
1902 *
1903 * POST example:
1904 * <pre>
1905 * <?php
1906 * $r = new HttpRequest('http://example.com/form.php', HTTP_POST);
1907 * $r->setOptions(array('cookies' => array('lang' => 'de')));
1908 * $r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));
1909 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
1910 * try {
1911 * echo $r->send()->getBody();
1912 * } catch (HttpException $ex) {
1913 * echo $ex;
1914 * }
1915 * ?>
1916 * </pre>
1917 */
1918 PHP_METHOD(HttpRequest, send)
1919 {
1920 http_request_body body = {0, NULL, 0};
1921 getObject(http_request_object, obj);
1922
1923 NO_ARGS;
1924
1925 SET_EH_THROW_HTTP();
1926
1927 if (obj->pool) {
1928 http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot perform HttpRequest::send() while attached to an HttpRequestPool");
1929 SET_EH_NORMAL();
1930 RETURN_FALSE;
1931 }
1932
1933 RETVAL_NULL();
1934
1935 if ( (SUCCESS == http_request_object_requesthandler(obj, getThis(), &body)) &&
1936 (SUCCESS == http_request_exec(obj->ch, NULL, &obj->response, &obj->request)) &&
1937 (SUCCESS == http_request_object_responsehandler(obj, getThis()))) {
1938 RETVAL_OBJECT(GET_PROP(obj, responseMessage));
1939 }
1940 http_request_body_dtor(&body);
1941
1942 SET_EH_NORMAL();
1943 }
1944 /* }}} */
1945
1946 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
1947
1948 /*
1949 * Local variables:
1950 * tab-width: 4
1951 * c-basic-offset: 4
1952 * End:
1953 * vim600: noet sw=4 ts=4 fdm=marker
1954 * vim<600: noet sw=4 ts=4
1955 */
1956