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