- add clean_ob parameter to HttpResponse::send()
[m6w6/ext-http] / http_methods.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 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21
22 #include "php.h"
23 #include "php_streams.h"
24
25 #include "php_http.h"
26 #include "php_http_std_defs.h"
27 #include "php_http_api.h"
28 #include "php_http_cache_api.h"
29 #include "php_http_request_api.h"
30 #include "php_http_date_api.h"
31 #include "php_http_headers_api.h"
32 #include "php_http_message_api.h"
33 #include "php_http_send_api.h"
34 #include "php_http_url_api.h"
35
36 #include "php_http_message_object.h"
37 #include "php_http_response_object.h"
38 #include "php_http_request_object.h"
39 #include "php_http_exception_object.h"
40
41 #ifdef ZEND_ENGINE_2
42
43 #include "missing.h"
44
45 ZEND_EXTERN_MODULE_GLOBALS(http)
46
47 /* {{{ HttpResponse */
48
49 /* {{{ proto void HttpResponse::__construct(bool cache, bool gzip)
50 *
51 * Instantiates a new HttpResponse object, which can be used to send
52 * any data/resource/file to an HTTP client with caching and multiple
53 * ranges/resuming support.
54 *
55 * NOTE: GZIPping is not implemented yet.
56 */
57 PHP_METHOD(HttpResponse, __construct)
58 {
59 zend_bool do_cache = 0, do_gzip = 0;
60 getObject(http_response_object, obj);
61
62 SET_EH_THROW_HTTP();
63 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &do_cache, &do_gzip)) {
64 UPD_PROP(obj, long, cache, do_cache);
65 UPD_PROP(obj, long, gzip, do_gzip);
66 }
67 SET_EH_NORMAL();
68 }
69 /* }}} */
70
71 /* {{{ proto bool HttpResponse::setCache(bool cache)
72 *
73 * Whether it sould be attempted to cache the entitity.
74 * This will result in necessary caching headers and checks of clients
75 * "If-Modified-Since" and "If-None-Match" headers. If one of those headers
76 * matches a "304 Not Modified" status code will be issued.
77 *
78 * NOTE: If you're using sessions, be shure that you set session.cache_limiter
79 * to something more appropriate than "no-cache"!
80 */
81 PHP_METHOD(HttpResponse, setCache)
82 {
83 zend_bool do_cache = 0;
84 getObject(http_response_object, obj);
85
86 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_cache)) {
87 RETURN_FALSE;
88 }
89
90 UPD_PROP(obj, long, cache, do_cache);
91 RETURN_TRUE;
92 }
93 /* }}} */
94
95 /* {{{ proto bool HttpResponse::getCache()
96 *
97 * Get current caching setting.
98 */
99 PHP_METHOD(HttpResponse, getCache)
100 {
101 NO_ARGS;
102
103 IF_RETVAL_USED {
104 zval *do_cache = NULL;
105 getObject(http_response_object, obj);
106
107 do_cache = GET_PROP(obj, cache);
108 RETURN_BOOL(Z_LVAL_P(do_cache));
109 }
110 }
111 /* }}}*/
112
113 /* {{{ proto bool HttpResponse::setGzip(bool gzip)
114 *
115 * Enable on-thy-fly gzipping of the sent entity. NOT IMPLEMENTED YET.
116 */
117 PHP_METHOD(HttpResponse, setGzip)
118 {
119 zend_bool do_gzip = 0;
120 getObject(http_response_object, obj);
121
122 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_gzip)) {
123 RETURN_FALSE;
124 }
125
126 UPD_PROP(obj, long, gzip, do_gzip);
127 RETURN_TRUE;
128 }
129 /* }}} */
130
131 /* {{{ proto bool HttpResponse::getGzip()
132 *
133 * Get current gzipping setting.
134 */
135 PHP_METHOD(HttpResponse, getGzip)
136 {
137 NO_ARGS;
138
139 IF_RETVAL_USED {
140 zval *do_gzip;
141 getObject(http_response_object, obj);
142
143 do_gzip = GET_PROP(obj, gzip);
144 RETURN_BOOL(Z_LVAL_P(do_gzip));
145 }
146 }
147 /* }}} */
148
149 /* {{{ proto bool HttpResponse::setCacheControl(string control[, bool raw = false])
150 *
151 * Set a custom cache-control header, usually being "private" or "public"; if
152 * $raw is set to true the header will be sent as-is.
153 */
154 PHP_METHOD(HttpResponse, setCacheControl)
155 {
156 char *ccontrol;
157 int cc_len;
158 zend_bool raw = 0;
159 getObject(http_response_object, obj);
160
161 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &ccontrol, &cc_len, &raw)) {
162 RETURN_FALSE;
163 }
164
165 if ((!raw) && (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache"))) {
166 http_error_ex(E_WARNING, HTTP_E_PARAM, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol);
167 RETURN_FALSE;
168 }
169
170 UPD_PROP(obj, long, raw_cache_header, raw);
171 UPD_PROP(obj, string, cacheControl, ccontrol);
172 RETURN_TRUE;
173 }
174 /* }}} */
175
176 /* {{{ proto string HttpResponse::getCacheControl()
177 *
178 * Get current Cache-Control header setting.
179 */
180 PHP_METHOD(HttpResponse, getCacheControl)
181 {
182 NO_ARGS;
183
184 IF_RETVAL_USED {
185 zval *ccontrol;
186 getObject(http_response_object, obj);
187
188 ccontrol = GET_PROP(obj, cacheControl);
189 RETURN_STRINGL(Z_STRVAL_P(ccontrol), Z_STRLEN_P(ccontrol), 1);
190 }
191 }
192 /* }}} */
193
194 /* {{{ proto bool HttpResponse::setContentType(string content_type)
195 *
196 * Set the content-type of the sent entity.
197 */
198 PHP_METHOD(HttpResponse, setContentType)
199 {
200 char *ctype;
201 int ctype_len;
202 getObject(http_response_object, obj);
203
204 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ctype_len)) {
205 RETURN_FALSE;
206 }
207
208 if (!strchr(ctype, '/')) {
209 http_error_ex(E_WARNING, HTTP_E_PARAM, "Content type '%s' doesn't seem to contain a primary and a secondary part", ctype);
210 RETURN_FALSE;
211 }
212
213 UPD_PROP(obj, string, contentType, ctype);
214
215 RETURN_TRUE;
216 }
217 /* }}} */
218
219 /* {{{ proto string HttpResponse::getContentType()
220 *
221 * Get current Content-Type header setting.
222 */
223 PHP_METHOD(HttpResponse, getContentType)
224 {
225 NO_ARGS;
226
227 IF_RETVAL_USED {
228 zval *ctype;
229 getObject(http_response_object, obj);
230
231 ctype = GET_PROP(obj, contentType);
232 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
233 }
234 }
235 /* }}} */
236
237 /* {{{ proto bool HttpResponse::setContentDisposition(string filename[, bool inline = false])
238 *
239 * Set the Content-Disposition of the sent entity. This setting aims to suggest
240 * the receiveing user agent how to handle the sent entity; usually the client
241 * will show the user a "Save As..." popup.
242 */
243 PHP_METHOD(HttpResponse, setContentDisposition)
244 {
245 char *file;
246 int file_len;
247 zend_bool is_inline = 0;
248 getObject(http_response_object, obj);
249
250 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &file, &file_len, &is_inline)) {
251 RETURN_FALSE;
252 }
253
254 UPD_PROP(obj, string, dispoFile, file);
255 UPD_PROP(obj, long, dispoInline, is_inline);
256 RETURN_TRUE;
257 }
258 /* }}} */
259
260 /* {{{ proto array HttpResponse::getContentDisposition()
261 *
262 * Get current Content-Disposition setting.
263 * Will return an associative array like:
264 * <pre>
265 * array(
266 * 'filename' => 'foo.bar',
267 * 'inline' => false
268 * )
269 * </pre>
270 */
271 PHP_METHOD(HttpResponse, getContentDisposition)
272 {
273 NO_ARGS;
274
275 IF_RETVAL_USED {
276 zval *file, *is_inline;
277 getObject(http_response_object, obj);
278
279 file = GET_PROP(obj, dispoFile);
280 is_inline = GET_PROP(obj, dispoInline);
281
282 array_init(return_value);
283 add_assoc_stringl(return_value, "filename", Z_STRVAL_P(file), Z_STRLEN_P(file), 1);
284 add_assoc_bool(return_value, "inline", Z_LVAL_P(is_inline));
285 }
286 }
287 /* }}} */
288
289 /* {{{ proto bool HttpResponse::setETag(string etag)
290 *
291 * Set a custom ETag. Use this only if you know what you're doing.
292 */
293 PHP_METHOD(HttpResponse, setETag)
294 {
295 char *etag;
296 int etag_len;
297 getObject(http_response_object, obj);
298
299 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len)) {
300 RETURN_FALSE;
301 }
302
303 UPD_PROP(obj, string, eTag, etag);
304 RETURN_TRUE;
305 }
306 /* }}} */
307
308 /* {{{ proto string HttpResponse::getETag()
309 *
310 * Get the previously set custom ETag.
311 */
312 PHP_METHOD(HttpResponse, getETag)
313 {
314 NO_ARGS;
315
316 IF_RETVAL_USED {
317 zval *etag;
318 getObject(http_response_object, obj);
319
320 etag = GET_PROP(obj, eTag);
321 RETURN_STRINGL(Z_STRVAL_P(etag), Z_STRLEN_P(etag), 1);
322 }
323 }
324 /* }}} */
325
326 /* {{{ proto void HttpResponse::setThrottleDelay(double seconds)
327 *
328 */
329 PHP_METHOD(HttpResponse, setThrottleDelay)
330 {
331 double seconds;
332
333 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &seconds)) {
334 getObject(http_response_object, obj);
335
336 UPD_PROP(obj, double, throttleDelay, seconds);
337 }
338 }
339 /* }}} */
340
341 /* {{{ proto double HttpResponse::getThrottleDelay()
342 *
343 */
344 PHP_METHOD(HttpResponse, getThrottleDelay)
345 {
346 NO_ARGS;
347
348 IF_RETVAL_USED {
349 zval *seconds;
350 getObject(http_response_object, obj);
351
352 seconds = GET_PROP(obj, throttleDelay);
353 RETURN_DOUBLE(Z_DVAL_P(seconds));
354 }
355 }
356 /* }}} */
357
358 /* {{{ proto void HttpResponse::setSendBuffersize(long bytes)
359 *
360 */
361 PHP_METHOD(HttpResponse, setSendBuffersize)
362 {
363 long bytes;
364
365 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bytes)) {
366 getObject(http_response_object, obj);
367
368 UPD_PROP(obj, long, sendBuffersize, bytes);
369 }
370 }
371 /* }}} */
372
373 /* {{{ proto long HttpResponse::getSendBuffersize()
374 *
375 */
376 PHP_METHOD(HttpResponse, getSendBuffersize)
377 {
378 NO_ARGS;
379
380 IF_RETVAL_USED {
381 zval *bytes;
382 getObject(http_response_object, obj);
383
384 bytes = GET_PROP(obj, sendBuffersize);
385 RETURN_LONG(Z_LVAL_P(bytes));
386 }
387 }
388 /* }}} */
389
390 /* {{{ proto bool HttpResponse::setData(string data)
391 *
392 * Set the data to be sent.
393 */
394 PHP_METHOD(HttpResponse, setData)
395 {
396 zval *the_data;
397 getObject(http_response_object, obj);
398
399 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &the_data)) {
400 RETURN_FALSE;
401 }
402
403 convert_to_string_ex(&the_data);
404 SET_PROP(obj, data, the_data);
405 UPD_PROP(obj, long, lastModified, http_last_modified(the_data, SEND_DATA));
406 UPD_PROP(obj, long, send_mode, SEND_DATA);
407 RETURN_TRUE;
408 }
409 /* }}} */
410
411 /* {{{ proto string HttpResponse::getData()
412 *
413 * Get the previously set data to be sent.
414 */
415 PHP_METHOD(HttpResponse, getData)
416 {
417 NO_ARGS;
418
419 IF_RETVAL_USED {
420 zval *the_data;
421 getObject(http_response_object, obj);
422
423 the_data = GET_PROP(obj, data);
424 RETURN_STRINGL(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), 1);
425 }
426 }
427 /* }}} */
428
429 /* {{{ proto bool HttpResponse::setStream(resource stream)
430 *
431 * Set the resource to be sent.
432 */
433 PHP_METHOD(HttpResponse, setStream)
434 {
435 zval *the_stream;
436 php_stream *the_real_stream;
437 getObject(http_response_object, obj);
438
439 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &the_stream)) {
440 RETURN_FALSE;
441 }
442
443 php_stream_from_zval(the_real_stream, &the_stream);
444
445 SET_PROP(obj, stream, the_stream);
446 UPD_PROP(obj, long, lastModified, http_last_modified(the_real_stream, SEND_RSRC));
447 UPD_PROP(obj, long, send_mode, SEND_RSRC);
448 RETURN_TRUE;
449 }
450 /* }}} */
451
452 /* {{{ proto resource HttpResponse::getStream()
453 *
454 * Get the previously set resource to be sent.
455 */
456 PHP_METHOD(HttpResponse, getStream)
457 {
458 NO_ARGS;
459
460 IF_RETVAL_USED {
461 zval *the_stream;
462 getObject(http_response_object, obj);
463
464 the_stream = GET_PROP(obj, stream);
465 RETURN_RESOURCE(Z_LVAL_P(the_stream));
466 }
467 }
468 /* }}} */
469
470 /* {{{ proto bool HttpResponse::setFile(string file)
471 *
472 * Set the file to be sent.
473 */
474 PHP_METHOD(HttpResponse, setFile)
475 {
476 zval *the_file;
477 getObject(http_response_object, obj);
478
479 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_file)) {
480 RETURN_FALSE;
481 }
482
483 convert_to_string_ex(&the_file);
484
485 UPD_PROP(obj, string, file, Z_STRVAL_P(the_file));
486 UPD_PROP(obj, long, lastModified, http_last_modified(the_file, -1));
487 UPD_PROP(obj, long, send_mode, -1);
488 RETURN_TRUE;
489 }
490 /* }}} */
491
492 /* {{{ proto string HttpResponse::getFile()
493 *
494 * Get the previously set file to be sent.
495 */
496 PHP_METHOD(HttpResponse, getFile)
497 {
498 NO_ARGS;
499
500 IF_RETVAL_USED {
501 zval *the_file;
502 getObject(http_response_object, obj);
503
504 the_file = GET_PROP(obj, file);
505 RETURN_STRINGL(Z_STRVAL_P(the_file), Z_STRLEN_P(the_file), 1);
506 }
507 }
508 /* }}} */
509
510 /* {{{ proto bool HttpResponse::send([bool clean_ob = true])
511 *
512 * Finally send the entity.
513 *
514 * Example:
515 * <pre>
516 * <?php
517 * $r = new HttpResponse(true);
518 * $r->setFile('../hidden/contract.pdf');
519 * $r->setContentType('application/pdf');
520 * $r->send();
521 * ?>
522 * </pre>
523 *
524 */
525 PHP_METHOD(HttpResponse, send)
526 {
527 zend_bool clean_ob = 1;
528 zval *do_cache, *do_gzip;
529 getObject(http_response_object, obj);
530
531 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean_ob)) {
532 RETURN_FALSE;
533 }
534
535 do_cache = GET_PROP(obj, cache);
536 do_gzip = GET_PROP(obj, gzip);
537
538 if (clean_ob) {
539 /* interrupt on-the-fly etag generation */
540 HTTP_G(etag).started = 0;
541 /* discard previous output buffers */
542 php_end_ob_buffers(0 TSRMLS_CC);
543 }
544
545 /* gzip */
546 if (Z_LVAL_P(do_gzip)) {
547 php_start_ob_buffer_named("ob_gzhandler", 0, 1 TSRMLS_CC);
548 }
549
550 /* caching */
551 if (Z_LVAL_P(do_cache)) {
552 char *cc_hdr;
553 int cc_len;
554 zval *cctrl, *etag, *lmod, *ccraw;
555
556 etag = GET_PROP(obj, eTag);
557 lmod = GET_PROP(obj, lastModified);
558 cctrl = GET_PROP(obj, cacheControl);
559 ccraw = GET_PROP(obj, raw_cache_header);
560
561 if (Z_LVAL_P(ccraw)) {
562 cc_hdr = Z_STRVAL_P(cctrl);
563 cc_len = Z_STRLEN_P(cctrl);
564 } else {
565 char cc_header[42] = {0};
566 sprintf(cc_header, "%s, must-revalidate, max-age=0", Z_STRVAL_P(cctrl));
567 cc_hdr = cc_header;
568 cc_len = Z_STRLEN_P(cctrl) + lenof(", must-revalidate, max-age=0");
569 }
570
571 http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), cc_hdr, cc_len);
572 http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), cc_hdr, cc_len);
573 }
574
575 /* content type */
576 {
577 zval *ctype = GET_PROP(obj, contentType);
578 if (Z_STRLEN_P(ctype)) {
579 http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype));
580 } else {
581 http_send_content_type("application/x-octetstream", lenof("application/x-octetstream"));
582 }
583 }
584
585 /* content disposition */
586 {
587 zval *dispo_file = GET_PROP(obj, dispoFile);
588 if (Z_STRLEN_P(dispo_file)) {
589 zval *dispo_inline = GET_PROP(obj, dispoInline);
590 http_send_content_disposition(Z_STRVAL_P(dispo_file), Z_STRLEN_P(dispo_file), (zend_bool) Z_LVAL_P(dispo_inline));
591 }
592 }
593
594 /* throttling */
595 {
596 zval *send_buffersize, *throttle_delay;
597 send_buffersize = GET_PROP(obj, sendBuffersize);
598 throttle_delay = GET_PROP(obj, throttleDelay);
599 HTTP_G(send).buffer_size = Z_LVAL_P(send_buffersize);
600 HTTP_G(send).throttle_delay = Z_DVAL_P(throttle_delay);
601 }
602
603 /* send */
604 {
605 zval *send_mode = GET_PROP(obj, send_mode);
606 switch (Z_LVAL_P(send_mode))
607 {
608 case SEND_DATA:
609 {
610 zval *zdata = GET_PROP(obj, data);
611 RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
612 }
613
614 case SEND_RSRC:
615 {
616 php_stream *the_real_stream;
617 zval *the_stream = GET_PROP(obj, stream);
618 php_stream_from_zval(the_real_stream, &the_stream);
619 RETURN_SUCCESS(http_send_stream(the_real_stream));
620 }
621
622 default:
623 {
624 zval *zfile = GET_PROP(obj, file);
625 RETURN_SUCCESS(http_send_file(Z_STRVAL_P(zfile)));
626 }
627 }
628 }
629 }
630 /* }}} */
631 /* }}} */
632
633 /* {{{ HttpMessage */
634
635 /* {{{ proto void HttpMessage::__construct([string message])
636 *
637 * Instantiate a new HttpMessage object.
638 */
639 PHP_METHOD(HttpMessage, __construct)
640 {
641 char *message = NULL;
642 int length = 0;
643 getObject(http_message_object, obj);
644
645 SET_EH_THROW_HTTP();
646 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &message, &length) && message && length) {
647 if (obj->message = http_message_parse(message, length)) {
648 if (obj->message->parent) {
649 obj->parent = http_message_object_from_msg(obj->message->parent);
650 }
651 }
652 } else if (!obj->message) {
653 obj->message = http_message_new();
654 }
655 SET_EH_NORMAL();
656 }
657 /* }}} */
658
659 /* {{{ proto static HttpMessage HttpMessage::fromString(string raw_message)
660 *
661 * Create an HttpMessage object from a string.
662 */
663 PHP_METHOD(HttpMessage, fromString)
664 {
665 char *string = NULL;
666 int length = 0;
667 http_message *msg = NULL;
668
669 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &length)) {
670 RETURN_NULL();
671 }
672
673 if (!(msg = http_message_parse(string, length))) {
674 RETURN_NULL();
675 }
676
677 Z_TYPE_P(return_value) = IS_OBJECT;
678 return_value->value.obj = http_message_object_from_msg(msg);
679 }
680 /* }}} */
681
682 /* {{{ proto string HttpMessage::getBody()
683 *
684 * Get the body of the parsed Message.
685 */
686 PHP_METHOD(HttpMessage, getBody)
687 {
688 NO_ARGS;
689
690 IF_RETVAL_USED {
691 getObject(http_message_object, obj);
692 RETURN_PHPSTR(&obj->message->body, PHPSTR_FREE_NOT, 1);
693 }
694 }
695 /* }}} */
696
697 /* {{{ proto array HttpMessage::getHeaders()
698 *
699 * Get Message Headers.
700 */
701 PHP_METHOD(HttpMessage, getHeaders)
702 {
703 NO_ARGS;
704
705 IF_RETVAL_USED {
706 zval headers;
707 getObject(http_message_object, obj);
708
709 Z_ARRVAL(headers) = &obj->message->hdrs;
710 array_init(return_value);
711 array_copy(&headers, return_value);
712 }
713 }
714 /* }}} */
715
716 /* {{{ proto void HttpMessage::setHeaders(array headers)
717 *
718 * Sets new headers.
719 */
720 PHP_METHOD(HttpMessage, setHeaders)
721 {
722 zval *new_headers, old_headers;
723 getObject(http_message_object, obj);
724
725 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
726 return;
727 }
728
729 zend_hash_clean(&obj->message->hdrs);
730 Z_ARRVAL(old_headers) = &obj->message->hdrs;
731 array_copy(new_headers, &old_headers);
732 }
733 /* }}} */
734
735 /* {{{ proto void HttpMessage::addHeaders(array headers[, bool append = false])
736 *
737 * Add headers. If append is true, headers with the same name will be separated, else overwritten.
738 */
739 PHP_METHOD(HttpMessage, addHeaders)
740 {
741 zval old_headers, *new_headers;
742 zend_bool append = 0;
743 getObject(http_message_object, obj);
744
745 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &new_headers, &append)) {
746 return;
747 }
748
749 Z_ARRVAL(old_headers) = &obj->message->hdrs;
750 if (append) {
751 array_append(new_headers, &old_headers);
752 } else {
753 array_merge(new_headers, &old_headers);
754 }
755 }
756 /* }}} */
757
758 /* {{{ proto long HttpMessage::getType()
759 *
760 * Get Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
761 */
762 PHP_METHOD(HttpMessage, getType)
763 {
764 NO_ARGS;
765
766 IF_RETVAL_USED {
767 getObject(http_message_object, obj);
768 RETURN_LONG(obj->message->type);
769 }
770 }
771 /* }}} */
772
773 /* {{{ proto void HttpMessage::setType(long type)
774 *
775 * Set Message Type. (HTTP_MSG_NONE|HTTP_MSG_REQUEST|HTTP_MSG_RESPONSE)
776 */
777 PHP_METHOD(HttpMessage, setType)
778 {
779 long type;
780 getObject(http_message_object, obj);
781
782 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &type)) {
783 return;
784 }
785 http_message_set_type(obj->message, type);
786 }
787 /* }}} */
788
789 /* {{{ proto long HttpMessage::getResponseCode()
790 *
791 * Get the Response Code of the Message.
792 */
793 PHP_METHOD(HttpMessage, getResponseCode)
794 {
795 NO_ARGS;
796
797 IF_RETVAL_USED {
798 getObject(http_message_object, obj);
799
800 if (!HTTP_MSG_TYPE(RESPONSE, obj->message)) {
801 http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_RESPONSE");
802 RETURN_NULL();
803 }
804
805 RETURN_LONG(obj->message->info.response.code);
806 }
807 }
808 /* }}} */
809
810 /* {{{ proto bool HttpMessage::setResponseCode(long code)
811 *
812 * Set the response code of an HTTP Response Message.
813 * Returns false if the Message is not of type HTTP_MSG_RESPONSE,
814 * or if the response code is out of range (100-510).
815 */
816 PHP_METHOD(HttpMessage, setResponseCode)
817 {
818 long code;
819 getObject(http_message_object, obj);
820
821 if (!HTTP_MSG_TYPE(RESPONSE, obj->message)) {
822 http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_RESPONSE");
823 RETURN_FALSE;
824 }
825
826 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
827 RETURN_FALSE;
828 }
829 if (code < 100 || code > 510) {
830 http_error_ex(E_WARNING, HTTP_E_PARAM, "Invalid response code (100-510): %ld", code);
831 RETURN_FALSE;
832 }
833
834 obj->message->info.response.code = code;
835 RETURN_TRUE;
836 }
837 /* }}} */
838
839 /* {{{ proto string HttpMessage::getRequestMethod()
840 *
841 * Get the Request Method of the Message.
842 * Returns false if the Message is not of type HTTP_MSG_REQUEST.
843 */
844 PHP_METHOD(HttpMessage, getRequestMethod)
845 {
846 NO_ARGS;
847
848 IF_RETVAL_USED {
849 getObject(http_message_object, obj);
850
851 if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
852 http_error(E_NOTICE, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST");
853 RETURN_NULL();
854 }
855
856 RETURN_STRING(obj->message->info.request.method, 1);
857 }
858 }
859 /* }}} */
860
861 /* {{{ proto bool HttpMessage::setRequestMethod(string method)
862 *
863 * Set the Request Method of the HTTP Message.
864 * Returns false if the Message is not of type HTTP_MSG_REQUEST.
865 */
866 PHP_METHOD(HttpMessage, setRequestMethod)
867 {
868 char *method;
869 int method_len;
870 getObject(http_message_object, obj);
871
872 if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
873 http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST");
874 RETURN_FALSE;
875 }
876
877 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &method, &method_len)) {
878 RETURN_FALSE;
879 }
880 if (method_len < 1) {
881 http_error(E_WARNING, HTTP_E_PARAM, "Cannot set HttpMessage::requestMethod to an empty string");
882 RETURN_FALSE;
883 }
884 if (SUCCESS != http_check_method(method)) {
885 http_error_ex(E_WARNING, HTTP_E_PARAM, "Unkown request method: %s", method);
886 RETURN_FALSE;
887 }
888
889 STR_SET(obj->message->info.request.method, estrndup(method, method_len));
890 RETURN_TRUE;
891 }
892 /* }}} */
893
894 /* {{{ proto string HttpMessage::getRequestUri()
895 *
896 * Get the Request URI of the Message.
897 */
898 PHP_METHOD(HttpMessage, getRequestUri)
899 {
900 NO_ARGS;
901
902 IF_RETVAL_USED {
903 getObject(http_message_object, obj);
904
905 if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
906 http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST");
907 RETURN_NULL();
908 }
909
910 RETURN_STRING(obj->message->info.request.URI, 1);
911 }
912 }
913 /* }}} */
914
915 /* {{{ proto bool HttpMessage::setRequestUri(string URI)
916 *
917 * Set the Request URI of the HTTP Message.
918 * Returns false if the Message is not of type HTTP_MSG_REQUEST,
919 * or if paramtere URI was empty.
920 */
921 PHP_METHOD(HttpMessage, setRequestUri)
922 {
923 char *URI;
924 int URIlen;
925 getObject(http_message_object, obj);
926
927 if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
928 http_error(E_WARNING, HTTP_E_MSG, "HttpMessage is not of type HTTP_MSG_REQUEST");
929 RETURN_FALSE;
930 }
931 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URI, &URIlen)) {
932 RETURN_FALSE;
933 }
934 if (URIlen < 1) {
935 http_error(E_WARNING, HTTP_E_PARAM, "Cannot set HttpMessage::requestUri to an empty string");
936 RETURN_FALSE;
937 }
938
939 STR_SET(obj->message->info.request.URI, estrndup(URI, URIlen));
940 RETURN_TRUE;
941 }
942 /* }}} */
943
944 /* {{{ proto string HttpMessage::getHttpVersion()
945 *
946 * Get the HTTP Protocol Version of the Message.
947 */
948 PHP_METHOD(HttpMessage, getHttpVersion)
949 {
950 NO_ARGS;
951
952 IF_RETVAL_USED {
953 char ver[4] = {0};
954 float version;
955 getObject(http_message_object, obj);
956
957 switch (obj->message->type)
958 {
959 case HTTP_MSG_RESPONSE:
960 version = obj->message->info.response.http_version;
961 break;
962
963 case HTTP_MSG_REQUEST:
964 version = obj->message->info.request.http_version;
965 break;
966
967 case HTTP_MSG_NONE:
968 default:
969 RETURN_NULL();
970 }
971 sprintf(ver, "%1.1f", version);
972 RETURN_STRINGL(ver, 3, 1);
973 }
974 }
975 /* }}} */
976
977 /* {{{ proto bool HttpMessage::setHttpVersion(string version)
978 *
979 * Set the HTTP Protocol version of the Message.
980 * Returns false if version is invalid (1.0 and 1.1).
981 */
982 PHP_METHOD(HttpMessage, setHttpVersion)
983 {
984 char v[4];
985 zval *zv;
986 getObject(http_message_object, obj);
987
988 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &zv)) {
989 return;
990 }
991
992 if (HTTP_MSG_TYPE(NONE, obj->message)) {
993 http_error(E_WARNING, HTTP_E_MSG, "Message is neither of type HTTP_MSG_RESPONSE nor HTTP_MSG_REQUEST");
994 RETURN_FALSE;
995 }
996
997 convert_to_double(zv);
998 sprintf(v, "%1.1f", Z_DVAL_P(zv));
999 if (strcmp(v, "1.0") && strcmp(v, "1.1")) {
1000 http_error_ex(E_WARNING, HTTP_E_PARAM, "Invalid HTTP protocol version (1.0 or 1.1): %s", v);
1001 RETURN_FALSE;
1002 }
1003
1004 if (HTTP_MSG_TYPE(RESPONSE, obj->message)) {
1005 obj->message->info.response.http_version = (float) Z_DVAL_P(zv);
1006 } else {
1007 obj->message->info.request.http_version = (float) Z_DVAL_P(zv);
1008 }
1009 RETURN_TRUE;
1010 }
1011 /* }}} */
1012
1013 /* {{{ proto HttpMessage HttpMessage::getParentMessage()
1014 *
1015 * Get parent Message.
1016 */
1017 PHP_METHOD(HttpMessage, getParentMessage)
1018 {
1019 NO_ARGS;
1020
1021 IF_RETVAL_USED {
1022 getObject(http_message_object, obj);
1023
1024 if (obj->message->parent) {
1025 RETVAL_OBJVAL(obj->parent);
1026 } else {
1027 RETVAL_NULL();
1028 }
1029 }
1030 }
1031 /* }}} */
1032
1033 /* {{{ proto bool HttpMessage::send()
1034 *
1035 * Send the Message according to its type as Response or Request.
1036 */
1037 PHP_METHOD(HttpMessage, send)
1038 {
1039 getObject(http_message_object, obj);
1040
1041 NO_ARGS;
1042
1043 RETURN_SUCCESS(http_message_send(obj->message));
1044 }
1045 /* }}} */
1046
1047 /* {{{ proto string HttpMessage::toString([bool include_parent = true])
1048 *
1049 * Get the string representation of the Message.
1050 */
1051 PHP_METHOD(HttpMessage, toString)
1052 {
1053 IF_RETVAL_USED {
1054 char *string;
1055 size_t length;
1056 zend_bool include_parent = 1;
1057 getObject(http_message_object, obj);
1058
1059 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &include_parent)) {
1060 RETURN_FALSE;
1061 }
1062
1063 if (include_parent) {
1064 http_message_serialize(obj->message, &string, &length);
1065 } else {
1066 http_message_tostring(obj->message, &string, &length);
1067 }
1068 RETURN_STRINGL(string, length, 0);
1069 }
1070 }
1071 /* }}} */
1072
1073 /* }}} */
1074
1075 #ifdef HTTP_HAVE_CURL
1076 /* {{{ HttpRequest */
1077
1078 /* {{{ proto void HttpRequest::__construct([string url[, long request_method = HTTP_GET]])
1079 *
1080 * Instantiate a new HttpRequest object which can be used to issue HEAD, GET
1081 * and POST (including posting files) HTTP requests.
1082 */
1083 PHP_METHOD(HttpRequest, __construct)
1084 {
1085 char *URL = NULL;
1086 int URL_len;
1087 long meth = -1;
1088 getObject(http_request_object, obj);
1089
1090 SET_EH_THROW_HTTP();
1091 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &URL, &URL_len, &meth)) {
1092 INIT_PARR(obj, options);
1093 INIT_PARR(obj, responseInfo);
1094 INIT_PARR(obj, responseData);
1095 INIT_PARR(obj, postFields);
1096 INIT_PARR(obj, postFiles);
1097
1098 if (URL) {
1099 UPD_PROP(obj, string, url, URL);
1100 }
1101 if (meth > -1) {
1102 UPD_PROP(obj, long, method, meth);
1103 }
1104 }
1105 SET_EH_NORMAL();
1106 }
1107 /* }}} */
1108
1109 /* {{{ proto void HttpRequest::__destruct()
1110 *
1111 * Destroys the HttpRequest object.
1112 */
1113 PHP_METHOD(HttpRequest, __destruct)
1114 {
1115 getObject(http_request_object, obj);
1116
1117 NO_ARGS;
1118
1119 FREE_PARR(obj, options);
1120 FREE_PARR(obj, responseInfo);
1121 FREE_PARR(obj, responseData);
1122 FREE_PARR(obj, postFields);
1123 FREE_PARR(obj, postFiles);
1124 }
1125 /* }}} */
1126
1127 /* {{{ proto bool HttpRequest::setOptions(array options)
1128 *
1129 * Set the request options to use. See http_get() for a full list of available options.
1130 */
1131 PHP_METHOD(HttpRequest, setOptions)
1132 {
1133 char *key = NULL;
1134 long idx = 0;
1135 zval *opts, *old_opts, **opt;
1136 getObject(http_request_object, obj);
1137
1138 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
1139 RETURN_FALSE;
1140 }
1141
1142 old_opts = GET_PROP(obj, options);
1143
1144 /* headers and cookies need extra attention -- thus cannot use array_merge() directly */
1145 FOREACH_KEYVAL(opts, key, idx, opt) {
1146 if (key) {
1147 if (!strcmp(key, "headers")) {
1148 zval **headers;
1149 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
1150 array_merge(*opt, *headers);
1151 continue;
1152 }
1153 } else if (!strcmp(key, "cookies")) {
1154 zval **cookies;
1155 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
1156 array_merge(*opt, *cookies);
1157 continue;
1158 }
1159 }
1160 zval_add_ref(opt);
1161 add_assoc_zval(old_opts, key, *opt);
1162
1163 /* reset */
1164 key = NULL;
1165 }
1166 }
1167
1168 RETURN_TRUE;
1169 }
1170 /* }}} */
1171
1172 /* {{{ proto array HttpRequest::getOptions()
1173 *
1174 * Get current set options.
1175 */
1176 PHP_METHOD(HttpRequest, getOptions)
1177 {
1178 NO_ARGS;
1179
1180 IF_RETVAL_USED {
1181 zval *opts;
1182 getObject(http_request_object, obj);
1183
1184 opts = GET_PROP(obj, options);
1185 array_init(return_value);
1186 array_copy(opts, return_value);
1187 }
1188 }
1189 /* }}} */
1190
1191 /* {{{ proto void HttpRequest::unsetOptions()
1192 *
1193 * Unset all options/headers/cookies.
1194 */
1195 PHP_METHOD(HttpRequest, unsetOptions)
1196 {
1197 getObject(http_request_object, obj);
1198
1199 NO_ARGS;
1200
1201 FREE_PARR(obj, options);
1202 INIT_PARR(obj, options);
1203 }
1204 /* }}} */
1205
1206 /* {{{ proto bool HttpRequest::setSslOptions(array options)
1207 *
1208 * Set additional SSL options.
1209 */
1210 PHP_METHOD(HttpRequest, setSslOptions)
1211 {
1212 zval *opts, *old_opts, **ssl_options;
1213 getObject(http_request_object, obj);
1214
1215 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
1216 RETURN_FALSE;
1217 }
1218
1219 old_opts = GET_PROP(obj, options);
1220
1221 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
1222 array_merge(opts, *ssl_options);
1223 } else {
1224 zval_add_ref(&opts);
1225 add_assoc_zval(old_opts, "ssl", opts);
1226 }
1227
1228 RETURN_TRUE;
1229 }
1230 /* }}} */
1231
1232 /* {{{ proto array HttpRequest::getSslOtpions()
1233 *
1234 * Get previously set SSL options.
1235 */
1236 PHP_METHOD(HttpRequest, getSslOptions)
1237 {
1238 NO_ARGS;
1239
1240 IF_RETVAL_USED {
1241 zval *opts, **ssl_options;
1242 getObject(http_request_object, obj);
1243
1244 opts = GET_PROP(obj, options);
1245
1246 array_init(return_value);
1247
1248 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"), (void **) &ssl_options)) {
1249 array_copy(*ssl_options, return_value);
1250 }
1251 }
1252 }
1253 /* }}} */
1254
1255 /* {{{ proto void HttpRequest::unsetSslOptions()
1256 *
1257 * Unset previously set SSL options.
1258 */
1259 PHP_METHOD(HttpRequest, unsetSslOptions)
1260 {
1261 zval *opts;
1262 getObject(http_request_object, obj);
1263
1264 NO_ARGS;
1265
1266 opts = GET_PROP(obj, options);
1267 zend_hash_del(Z_ARRVAL_P(opts), "ssl", sizeof("ssl"));
1268 }
1269 /* }}} */
1270
1271 /* {{{ proto bool HttpRequest::addHeaders(array headers)
1272 *
1273 * Add request header name/value pairs.
1274 */
1275 PHP_METHOD(HttpRequest, addHeaders)
1276 {
1277 zval *opts, **headers, *new_headers;
1278 getObject(http_request_object, obj);
1279
1280 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_headers)) {
1281 RETURN_FALSE;
1282 }
1283
1284 opts = GET_PROP(obj, options);
1285
1286 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
1287 array_merge(new_headers, *headers);
1288 } else {
1289 zval_add_ref(&new_headers);
1290 add_assoc_zval(opts, "headers", new_headers);
1291 }
1292
1293 RETURN_TRUE;
1294 }
1295 /* }}} */
1296
1297 /* {{{ proto array HttpRequest::getHeaders()
1298 *
1299 * Get previously set request headers.
1300 */
1301 PHP_METHOD(HttpRequest, getHeaders)
1302 {
1303 NO_ARGS;
1304
1305 IF_RETVAL_USED {
1306 zval *opts, **headers;
1307 getObject(http_request_object, obj);
1308
1309 opts = GET_PROP(obj, options);
1310
1311 array_init(return_value);
1312
1313 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "headers", sizeof("headers"), (void **) &headers)) {
1314 array_copy(*headers, return_value);
1315 }
1316 }
1317 }
1318 /* }}} */
1319
1320 /* {{{ proto void HttpRequest::unsetHeaders()
1321 *
1322 * Unset previously set request headers.
1323 */
1324 PHP_METHOD(HttpRequest, unsetHeaders)
1325 {
1326 zval *opts;
1327 getObject(http_request_object, obj);
1328
1329 NO_ARGS;
1330
1331 opts = GET_PROP(obj, options);
1332 zend_hash_del(Z_ARRVAL_P(opts), "headers", sizeof("headers"));
1333 }
1334 /* }}} */
1335
1336 /* {{{ proto bool HttpRequest::addCookies(array cookies)
1337 *
1338 * Add cookies.
1339 */
1340 PHP_METHOD(HttpRequest, addCookies)
1341 {
1342 zval *opts, **cookies, *new_cookies;
1343 getObject(http_request_object, obj);
1344
1345 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &new_cookies)) {
1346 RETURN_FALSE;
1347 }
1348
1349 opts = GET_PROP(obj, options);
1350
1351 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
1352 array_merge(new_cookies, *cookies);
1353 } else {
1354 zval_add_ref(&new_cookies);
1355 add_assoc_zval(opts, "cookies", new_cookies);
1356 }
1357
1358 RETURN_TRUE;
1359 }
1360 /* }}} */
1361
1362 /* {{{ proto array HttpRequest::getCookies()
1363 *
1364 * Get previously set cookies.
1365 */
1366 PHP_METHOD(HttpRequest, getCookies)
1367 {
1368 NO_ARGS;
1369
1370 IF_RETVAL_USED {
1371 zval *opts, **cookies;
1372 getObject(http_request_object, obj);
1373
1374 opts = GET_PROP(obj, options);
1375
1376 array_init(return_value);
1377
1378 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
1379 array_copy(*cookies, return_value);
1380 }
1381 }
1382 }
1383 /* }}} */
1384
1385 /* {{{ proto void HttpRequest::unsetCookies()
1386 *
1387 */
1388 PHP_METHOD(HttpRequest, unsetCookies)
1389 {
1390 zval *opts;
1391 getObject(http_request_object, obj);
1392
1393 NO_ARGS;
1394
1395 opts = GET_PROP(obj, options);
1396 zend_hash_del(Z_ARRVAL_P(opts), "cookies", sizeof("cookies"));
1397 }
1398 /* }}} */
1399
1400 /* {{{ proto bool HttpRequest::setURL(string url)
1401 *
1402 * Set the request URL.
1403 */
1404 PHP_METHOD(HttpRequest, setURL)
1405 {
1406 char *URL = NULL;
1407 int URL_len;
1408 getObject(http_request_object, obj);
1409
1410 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
1411 RETURN_FALSE;
1412 }
1413
1414 UPD_PROP(obj, string, url, URL);
1415 RETURN_TRUE;
1416 }
1417 /* }}} */
1418
1419 /* {{{ proto string HttpRequest::getUrl()
1420 *
1421 * Get the previously set request URL.
1422 */
1423 PHP_METHOD(HttpRequest, getURL)
1424 {
1425 NO_ARGS;
1426
1427 IF_RETVAL_USED {
1428 zval *URL;
1429 getObject(http_request_object, obj);
1430
1431 URL = GET_PROP(obj, url);
1432 RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1);
1433 }
1434 }
1435 /* }}} */
1436
1437 /* {{{ proto bool HttpRequest::setMethod(long request_method)
1438 *
1439 * Set the request methods; one of the <tt>HTTP_HEAD</tt>, <tt>HTTP_GET</tt> or
1440 * <tt>HTTP_POST</tt> constants.
1441 */
1442 PHP_METHOD(HttpRequest, setMethod)
1443 {
1444 long meth;
1445 getObject(http_request_object, obj);
1446
1447 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
1448 RETURN_FALSE;
1449 }
1450
1451 UPD_PROP(obj, long, method, meth);
1452 RETURN_TRUE;
1453 }
1454 /* }}} */
1455
1456 /* {{{ proto long HttpRequest::getMethod()
1457 *
1458 * Get the previously set request method.
1459 */
1460 PHP_METHOD(HttpRequest, getMethod)
1461 {
1462 NO_ARGS;
1463
1464 IF_RETVAL_USED {
1465 zval *meth;
1466 getObject(http_request_object, obj);
1467
1468 meth = GET_PROP(obj, method);
1469 RETURN_LONG(Z_LVAL_P(meth));
1470 }
1471 }
1472 /* }}} */
1473
1474 /* {{{ proto bool HttpRequest::setContentType(string content_type)
1475 *
1476 * Set the content type the post request should have.
1477 * Use this only if you know what you're doing.
1478 */
1479 PHP_METHOD(HttpRequest, setContentType)
1480 {
1481 char *ctype;
1482 int ct_len;
1483 getObject(http_request_object, obj);
1484
1485 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
1486 RETURN_FALSE;
1487 }
1488
1489 if (!strchr(ctype, '/')) {
1490 http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", ctype);
1491 RETURN_FALSE;
1492 }
1493
1494 UPD_PROP(obj, string, contentType, ctype);
1495 RETURN_TRUE;
1496 }
1497 /* }}} */
1498
1499 /* {{{ proto string HttpRequest::getContentType()
1500 *
1501 * Get the previously content type.
1502 */
1503 PHP_METHOD(HttpRequest, getContentType)
1504 {
1505 NO_ARGS;
1506
1507 IF_RETVAL_USED {
1508 zval *ctype;
1509 getObject(http_request_object, obj);
1510
1511 ctype = GET_PROP(obj, contentType);
1512 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
1513 }
1514 }
1515 /* }}} */
1516
1517 /* {{{ proto bool HttpRequest::setQueryData(mixed query_data)
1518 *
1519 * Set the URL query parameters to use.
1520 * Overwrites previously set query parameters.
1521 * Affects any request types.
1522 */
1523 PHP_METHOD(HttpRequest, setQueryData)
1524 {
1525 zval *qdata;
1526 char *query_data = NULL;
1527 getObject(http_request_object, obj);
1528
1529 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata)) {
1530 RETURN_FALSE;
1531 }
1532
1533 if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1534 if (SUCCESS != http_urlencode_hash(HASH_OF(qdata), &query_data)) {
1535 RETURN_FALSE;
1536 }
1537 UPD_PROP(obj, string, queryData, query_data);
1538 efree(query_data);
1539 RETURN_TRUE;
1540 }
1541
1542 convert_to_string(qdata);
1543 UPD_PROP(obj, string, queryData, Z_STRVAL_P(qdata));
1544 RETURN_TRUE;
1545 }
1546 /* }}} */
1547
1548 /* {{{ proto string HttpRequest::getQueryData()
1549 *
1550 * Get the current query data in form of an urlencoded query string.
1551 */
1552 PHP_METHOD(HttpRequest, getQueryData)
1553 {
1554 NO_ARGS;
1555
1556 IF_RETVAL_USED {
1557 zval *qdata;
1558 getObject(http_request_object, obj);
1559
1560 qdata = GET_PROP(obj, queryData);
1561 RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1);
1562 }
1563 }
1564 /* }}} */
1565
1566 /* {{{ proto bool HttpRequest::addQueryData(array query_params)
1567 *
1568 * Add parameters to the query parameter list.
1569 * Affects any request type.
1570 */
1571 PHP_METHOD(HttpRequest, addQueryData)
1572 {
1573 zval *qdata, *old_qdata;
1574 char *query_data = NULL;
1575 getObject(http_request_object, obj);
1576
1577 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1578 RETURN_FALSE;
1579 }
1580
1581 old_qdata = GET_PROP(obj, queryData);
1582
1583 if (SUCCESS != http_urlencode_hash_ex(HASH_OF(qdata), 1, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata), &query_data, NULL)) {
1584 RETURN_FALSE;
1585 }
1586
1587 UPD_PROP(obj, string, queryData, query_data);
1588 efree(query_data);
1589
1590 RETURN_TRUE;
1591 }
1592 /* }}} */
1593
1594 /* {{{ proto void HttpRequest::unsetQueryData()
1595 *
1596 * Clean the query parameters.
1597 * Affects any request type.
1598 */
1599 PHP_METHOD(HttpRequest, unsetQueryData)
1600 {
1601 getObject(http_request_object, obj);
1602
1603 NO_ARGS;
1604
1605 UPD_PROP(obj, string, queryData, "");
1606 }
1607 /* }}} */
1608
1609 /* {{{ proto bool HttpRequest::addPostFields(array post_data)
1610 *
1611 * Adds POST data entries.
1612 * Affects only POST requests.
1613 */
1614 PHP_METHOD(HttpRequest, addPostFields)
1615 {
1616 zval *post, *post_data;
1617 getObject(http_request_object, obj);
1618
1619 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1620 RETURN_FALSE;
1621 }
1622
1623 post = GET_PROP(obj, postFields);
1624 array_merge(post_data, post);
1625
1626 RETURN_TRUE;
1627 }
1628 /* }}} */
1629
1630 /* {{{ proto bool HttpRequest::setPostFields(array post_data)
1631 *
1632 * Set the POST data entries.
1633 * Overwrites previously set POST data.
1634 * Affects only POST requests.
1635 */
1636 PHP_METHOD(HttpRequest, setPostFields)
1637 {
1638 zval *post, *post_data;
1639 getObject(http_request_object, obj);
1640
1641 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1642 RETURN_FALSE;
1643 }
1644
1645 post = GET_PROP(obj, postFields);
1646 zend_hash_clean(Z_ARRVAL_P(post));
1647 array_copy(post_data, post);
1648
1649 RETURN_TRUE;
1650 }
1651 /* }}}*/
1652
1653 /* {{{ proto array HttpRequest::getPostFields()
1654 *
1655 * Get previously set POST data.
1656 */
1657 PHP_METHOD(HttpRequest, getPostFields)
1658 {
1659 NO_ARGS;
1660
1661 IF_RETVAL_USED {
1662 zval *post_data;
1663 getObject(http_request_object, obj);
1664
1665 post_data = GET_PROP(obj, postFields);
1666 array_init(return_value);
1667 array_copy(post_data, return_value);
1668 }
1669 }
1670 /* }}} */
1671
1672 /* {{{ proto void HttpRequest::unsetPostFields()
1673 *
1674 * Clean POST data entires.
1675 * Affects only POST requests.
1676 */
1677 PHP_METHOD(HttpRequest, unsetPostFields)
1678 {
1679 zval *post_data;
1680 getObject(http_request_object, obj);
1681
1682 NO_ARGS;
1683
1684 post_data = GET_PROP(obj, postFields);
1685 zend_hash_clean(Z_ARRVAL_P(post_data));
1686 }
1687 /* }}} */
1688
1689 /* {{{ proto bool HttpRequest::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1690 *
1691 * Add a file to the POST request.
1692 * Affects only POST requests.
1693 */
1694 PHP_METHOD(HttpRequest, addPostFile)
1695 {
1696 zval *files, *entry;
1697 char *name, *file, *type = NULL;
1698 int name_len, file_len, type_len = 0;
1699 getObject(http_request_object, obj);
1700
1701 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1702 RETURN_FALSE;
1703 }
1704
1705 if (type_len) {
1706 if (!strchr(type, '/')) {
1707 http_error_ex(E_WARNING, HTTP_E_PARAM, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type);
1708 RETURN_FALSE;
1709 }
1710 } else {
1711 type = "application/x-octetstream";
1712 type_len = sizeof("application/x-octetstream") - 1;
1713 }
1714
1715 MAKE_STD_ZVAL(entry);
1716 array_init(entry);
1717
1718 add_assoc_stringl(entry, "name", name, name_len, 1);
1719 add_assoc_stringl(entry, "type", type, type_len, 1);
1720 add_assoc_stringl(entry, "file", file, file_len, 1);
1721
1722 files = GET_PROP(obj, postFiles);
1723 add_next_index_zval(files, entry);
1724
1725 RETURN_TRUE;
1726 }
1727 /* }}} */
1728
1729 /* {{{ proto array HttpRequest::getPostFiles()
1730 *
1731 * Get all previously added POST files.
1732 */
1733 PHP_METHOD(HttpRequest, getPostFiles)
1734 {
1735 NO_ARGS;
1736
1737 IF_RETVAL_USED {
1738 zval *files;
1739 getObject(http_request_object, obj);
1740
1741 files = GET_PROP(obj, postFiles);
1742
1743 array_init(return_value);
1744 array_copy(files, return_value);
1745 }
1746 }
1747 /* }}} */
1748
1749 /* {{{ proto void HttpRequest::unsetPostFiles()
1750 *
1751 * Unset the POST files list.
1752 * Affects only POST requests.
1753 */
1754 PHP_METHOD(HttpRequest, unsetPostFiles)
1755 {
1756 zval *files;
1757 getObject(http_request_object, obj);
1758
1759 NO_ARGS;
1760
1761 files = GET_PROP(obj, postFiles);
1762 zend_hash_clean(Z_ARRVAL_P(files));
1763 }
1764 /* }}} */
1765
1766 /* {{{ proto array HttpRequest::getResponseData()
1767 *
1768 * Get all response data after the request has been sent.
1769 */
1770 PHP_METHOD(HttpRequest, getResponseData)
1771 {
1772 NO_ARGS;
1773
1774 IF_RETVAL_USED {
1775 zval *data;
1776 getObject(http_request_object, obj);
1777
1778 data = GET_PROP(obj, responseData);
1779 array_init(return_value);
1780 array_copy(data, return_value);
1781 }
1782 }
1783 /* }}} */
1784
1785 /* {{{ proto mixed HttpRequest::getResponseHeader([string name])
1786 *
1787 * Get response header(s) after the request has been sent.
1788 */
1789 PHP_METHOD(HttpRequest, getResponseHeader)
1790 {
1791 IF_RETVAL_USED {
1792 zval *data, **headers, **header;
1793 char *header_name = NULL;
1794 int header_len = 0;
1795 getObject(http_response_object, obj);
1796
1797 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &header_name, &header_len)) {
1798 RETURN_FALSE;
1799 }
1800
1801 data = GET_PROP(obj, responseData);
1802 if (SUCCESS != zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1803 RETURN_FALSE;
1804 }
1805
1806 if (!header_len || !header_name) {
1807 array_init(return_value);
1808 array_copy(*headers, return_value);
1809 } else if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(headers), pretty_key(header_name, header_len, 1, 1), header_len + 1, (void **) &header)) {
1810 RETURN_STRINGL(Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1);
1811 } else {
1812 RETURN_FALSE;
1813 }
1814 }
1815 }
1816 /* }}} */
1817
1818 /* {{{ proto array HttpRequest::getResponseCookie([string name])
1819 *
1820 * Get response cookie(s) after the request has been sent.
1821 */
1822 PHP_METHOD(HttpRequest, getResponseCookie)
1823 {
1824 IF_RETVAL_USED {
1825 zval *data, **headers;
1826 char *cookie_name = NULL;
1827 int cookie_len = 0;
1828 getObject(http_request_object, obj);
1829
1830 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cookie_name, &cookie_len)) {
1831 RETURN_FALSE;
1832 }
1833
1834 array_init(return_value);
1835
1836 data = GET_PROP(obj, responseData);
1837 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1838 ulong idx = 0;
1839 char *key = NULL;
1840 zval **header = NULL;
1841
1842 FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) {
1843 if (key && !strcasecmp(key, "Set-Cookie")) {
1844 /* several cookies? */
1845 if (Z_TYPE_PP(header) == IS_ARRAY) {
1846 zval **cookie;
1847
1848 FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) {
1849 zval *cookie_hash;
1850 MAKE_STD_ZVAL(cookie_hash);
1851 array_init(cookie_hash);
1852
1853 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(cookie), Z_ARRVAL_P(cookie_hash))) {
1854 if (!cookie_len) {
1855 add_next_index_zval(return_value, cookie_hash);
1856 } else {
1857 zval **name;
1858
1859 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1860 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1861 add_next_index_zval(return_value, cookie_hash);
1862 return; /* <<< FOUND >>> */
1863 } else {
1864 zval_dtor(cookie_hash);
1865 efree(cookie_hash);
1866 }
1867 }
1868 } else {
1869 zval_dtor(cookie_hash);
1870 efree(cookie_hash);
1871 }
1872 }
1873 } else {
1874 zval *cookie_hash;
1875 MAKE_STD_ZVAL(cookie_hash);
1876 array_init(cookie_hash);
1877
1878 if (SUCCESS == http_parse_cookie(Z_STRVAL_PP(header), Z_ARRVAL_P(cookie_hash))) {
1879 if (!cookie_len) {
1880 add_next_index_zval(return_value, cookie_hash);
1881 } else {
1882 zval **name;
1883
1884 if ( (SUCCESS == zend_hash_find(Z_ARRVAL_P(cookie_hash), "name", sizeof("name"), (void **) &name)) &&
1885 (!strcmp(Z_STRVAL_PP(name), cookie_name))) {
1886 add_next_index_zval(return_value, cookie_hash);
1887 } else {
1888 zval_dtor(cookie_hash);
1889 efree(cookie_hash);
1890 }
1891 }
1892 } else {
1893 zval_dtor(cookie_hash);
1894 efree(cookie_hash);
1895 }
1896 }
1897 break;
1898 }
1899 /* reset key */
1900 key = NULL;
1901 }
1902 }
1903 }
1904 }
1905 /* }}} */
1906
1907 /* {{{ proto string HttpRequest::getResponseBody()
1908 *
1909 * Get the response body after the request has been sent.
1910 */
1911 PHP_METHOD(HttpRequest, getResponseBody)
1912 {
1913 NO_ARGS;
1914
1915 IF_RETVAL_USED {
1916 zval *data, **body;
1917 getObject(http_request_object, obj);
1918
1919 data = GET_PROP(obj, responseData);
1920 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1921 RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1);
1922 } else {
1923 RETURN_FALSE;
1924 }
1925 }
1926 }
1927 /* }}} */
1928
1929 /* {{{ proto int HttpRequest::getResponseCode()
1930 *
1931 * Get the response code after the request has been sent.
1932 */
1933 PHP_METHOD(HttpRequest, getResponseCode)
1934 {
1935 NO_ARGS;
1936
1937 IF_RETVAL_USED {
1938 zval *code;
1939 getObject(http_request_object, obj);
1940
1941 code = GET_PROP(obj, responseCode);
1942 RETURN_LONG(Z_LVAL_P(code));
1943 }
1944 }
1945 /* }}} */
1946
1947 /* {{{ proto array HttpRequest::getResponseInfo([string name])
1948 *
1949 * Get response info after the request has been sent.
1950 * See http_get() for a full list of returned info.
1951 */
1952 PHP_METHOD(HttpRequest, getResponseInfo)
1953 {
1954 IF_RETVAL_USED {
1955 zval *info, **infop;
1956 char *info_name = NULL;
1957 int info_len = 0;
1958 getObject(http_request_object, obj);
1959
1960 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
1961 RETURN_FALSE;
1962 }
1963
1964 info = GET_PROP(obj, responseInfo);
1965
1966 if (info_len && info_name) {
1967 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(info), pretty_key(info_name, info_len, 0, 0), info_len + 1, (void **) &infop)) {
1968 RETURN_ZVAL(*infop, 1, ZVAL_PTR_DTOR);
1969 } else {
1970 http_error_ex(E_NOTICE, HTTP_E_PARAM, "Could not find response info named %s", info_name);
1971 RETURN_FALSE;
1972 }
1973 } else {
1974 array_init(return_value);
1975 array_copy(info, return_value);
1976 }
1977 }
1978 }
1979 /* }}}*/
1980
1981 /* {{{ proto HttpMessage HttpRequest::getResponseMessage()
1982 *
1983 * Get the full response as HttpMessage object.
1984 */
1985 PHP_METHOD(HttpRequest, getResponseMessage)
1986 {
1987 NO_ARGS;
1988
1989 IF_RETVAL_USED {
1990 zval *message;
1991 getObject(http_request_object, obj);
1992
1993 message = GET_PROP(obj, responseMessage);
1994 Z_TYPE_P(return_value) = IS_OBJECT;
1995 return_value->is_ref = 1;
1996 return_value->value.obj = message->value.obj;
1997 zval_add_ref(&return_value);
1998 }
1999 }
2000
2001 /* {{{ proto bool HttpRequest::send()
2002 *
2003 * Send the HTTP request.
2004 *
2005 * GET example:
2006 * <pre>
2007 * <?php
2008 * $r = new HttpRequest('http://example.com/feed.rss', HTTP_GET);
2009 * $r->setOptions(array('lastmodified' => filemtime('local.rss')));
2010 * $r->addQueryData(array('category' => 3));
2011 * try {
2012 * $r->send();
2013 * if ($r->getResponseCode() == 200) {
2014 * file_put_contents('local.rss', $r->getResponseBody());
2015 * }
2016 * } catch (HttpException $ex) {
2017 * echo $ex;
2018 * }
2019 * ?>
2020 * </pre>
2021 *
2022 * POST example:
2023 * <pre>
2024 * <?php
2025 * $r = new HttpRequest('http://example.com/form.php', HTTP_POST);
2026 * $r->setOptions(array('cookies' => array('lang' => 'de')));
2027 * $r->addpostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));
2028 * $r->addPostFile('image', 'profile.jpg', 'image/jpeg');
2029 * if ($r->send()) {
2030 * echo $r->getResponseBody();
2031 * }
2032 * ?>
2033 * </pre>
2034 */
2035 PHP_METHOD(HttpRequest, send)
2036 {
2037 STATUS status = FAILURE;
2038 zval *meth, *URL, *qdata, *opts, *info, *resp;
2039 char *request_uri;
2040 getObject(http_request_object, obj);
2041
2042 NO_ARGS;
2043
2044 SET_EH_THROW_HTTP();
2045
2046 if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
2047 http_error(E_WARNING, HTTP_E_CURL, "Could not initilaize curl");
2048 RETURN_FALSE;
2049 }
2050
2051 meth = GET_PROP(obj, method);
2052 URL = GET_PROP(obj, url);
2053 qdata = GET_PROP(obj, queryData);
2054 opts = GET_PROP(obj, options);
2055 info = GET_PROP(obj, responseInfo);
2056 resp = GET_PROP(obj, responseData);
2057
2058 // HTTP_URI_MAXLEN+1 long char *
2059 if (!(request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0))) {
2060 RETURN_FALSE;
2061 }
2062
2063 if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
2064 if (!strchr(request_uri, '?')) {
2065 strcat(request_uri, "?");
2066 } else {
2067 strcat(request_uri, "&");
2068 }
2069 strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
2070 }
2071
2072 switch (Z_LVAL_P(meth))
2073 {
2074 case HTTP_GET:
2075 case HTTP_HEAD:
2076 status = http_request_ex(obj->ch, Z_LVAL_P(meth), request_uri, NULL, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
2077 break;
2078
2079 case HTTP_PUT:
2080 {
2081 http_request_body body;
2082 php_stream *stream;
2083 php_stream_statbuf ssb;
2084 zval *file = GET_PROP(obj, putFile);
2085
2086 if ( (stream = php_stream_open_wrapper(Z_STRVAL_P(file), "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL)) &&
2087 !php_stream_stat(stream, &ssb)) {
2088 body.type = HTTP_REQUEST_BODY_UPLOADFILE;
2089 body.data = stream;
2090 body.size = ssb.sb.st_size;
2091
2092 status = http_put_ex(obj->ch, request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
2093 http_request_body_dtor(&body);
2094 } else {
2095 status = FAILURE;
2096 }
2097 }
2098 break;
2099
2100 case HTTP_POST:
2101 {
2102 http_request_body body;
2103 zval *fields = GET_PROP(obj, postFields), *files = GET_PROP(obj, postFiles);
2104
2105 if (SUCCESS == (status = http_request_body_fill(&body, Z_ARRVAL_P(fields), Z_ARRVAL_P(files)))) {
2106 status = http_post_ex(obj->ch, request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
2107 http_request_body_dtor(&body);
2108 }
2109 }
2110 break;
2111
2112 default:
2113 {
2114 http_request_body body;
2115 zval *post = GET_PROP(obj, postData);
2116
2117 body.type = HTTP_REQUEST_BODY_CSTRING;
2118 body.data = Z_STRVAL_P(post);
2119 body.size = Z_STRLEN_P(post);
2120
2121 status = http_request_ex(obj->ch, Z_LVAL_P(meth), request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
2122 }
2123 break;
2124 }
2125
2126 efree(request_uri);
2127
2128 /* final data handling */
2129 if (status == SUCCESS) {
2130 http_message *msg;
2131
2132 if (msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response))) {
2133 zval *headers, *message;
2134 char *body;
2135 size_t body_len;
2136
2137 UPD_PROP(obj, long, responseCode, msg->info.response.code);
2138
2139 MAKE_STD_ZVAL(headers)
2140 array_init(headers);
2141
2142 zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
2143 phpstr_data(PHPSTR(msg), &body, &body_len);
2144
2145 add_assoc_zval(resp, "headers", headers);
2146 add_assoc_stringl(resp, "body", body, body_len, 0);
2147
2148 message = GET_PROP(obj, responseMessage);
2149 zval_dtor(message);
2150 Z_TYPE_P(message) = IS_OBJECT;
2151 message->value.obj = http_message_object_from_msg(msg);
2152 SET_PROP(obj, responseMessage, message);
2153 } else {
2154 status = FAILURE;
2155 }
2156 }
2157
2158 SET_EH_NORMAL();
2159 RETURN_SUCCESS(status);
2160 }
2161 /* }}} */
2162 /* }}} */
2163 #endif /* HTTP_HAVE_CURL */
2164
2165 #endif /* ZEND_ENGINE_2 */
2166
2167 /*
2168 * Local variables:
2169 * tab-width: 4
2170 * c-basic-offset: 4
2171 * End:
2172 * vim600: noet sw=4 ts=4 fdm=marker
2173 * vim<600: noet sw=4 ts=4
2174 */