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