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