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