* weird, weird
[m6w6/ext-http] / http.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 #define _WINSOCKAPI_
19 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include "php.h"
26 #include "php_ini.h"
27 #include "snprintf.h"
28 #include "ext/standard/info.h"
29 #include "ext/session/php_session.h"
30 #include "ext/standard/php_string.h"
31 #include "ext/standard/php_smart_str.h"
32
33 #include "SAPI.h"
34
35 #include "php_http.h"
36 #include "php_http_api.h"
37
38 #ifdef ZEND_ENGINE_2
39 # include "ext/standard/php_http.h"
40 #endif
41
42 #ifdef HTTP_HAVE_CURL
43
44 # ifdef PHP_WIN32
45 # include <winsock2.h>
46 # include <sys/types.h>
47 # endif
48
49 # include <curl/curl.h>
50
51 /* {{{ ARG_INFO */
52 # ifdef ZEND_BEGIN_ARG_INFO
53 ZEND_BEGIN_ARG_INFO(http_request_info_ref_3, 0)
54 ZEND_ARG_PASS_INFO(0)
55 ZEND_ARG_PASS_INFO(0)
56 ZEND_ARG_PASS_INFO(1)
57 ZEND_END_ARG_INFO();
58
59 ZEND_BEGIN_ARG_INFO(http_request_info_ref_4, 0)
60 ZEND_ARG_PASS_INFO(0)
61 ZEND_ARG_PASS_INFO(0)
62 ZEND_ARG_PASS_INFO(0)
63 ZEND_ARG_PASS_INFO(1)
64 ZEND_END_ARG_INFO();
65 # else
66 static unsigned char http_request_info_ref_3[] = {3, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
67 static unsigned char http_request_info_ref_4[] = {4, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE};
68 # endif
69 /* }}} ARG_INFO */
70
71 #endif /* HTTP_HAVE_CURL */
72
73 ZEND_DECLARE_MODULE_GLOBALS(http)
74
75 #ifdef COMPILE_DL_HTTP
76 ZEND_GET_MODULE(http)
77 #endif
78
79 /* {{{ http_functions[] */
80 function_entry http_functions[] = {
81 PHP_FE(http_date, NULL)
82 PHP_FE(http_absolute_uri, NULL)
83 PHP_FE(http_negotiate_language, NULL)
84 PHP_FE(http_negotiate_charset, NULL)
85 PHP_FE(http_redirect, NULL)
86 PHP_FE(http_send_status, NULL)
87 PHP_FE(http_send_last_modified, NULL)
88 PHP_FE(http_send_content_type, NULL)
89 PHP_FE(http_send_content_disposition, NULL)
90 PHP_FE(http_match_modified, NULL)
91 PHP_FE(http_match_etag, NULL)
92 PHP_FE(http_cache_last_modified, NULL)
93 PHP_FE(http_cache_etag, NULL)
94 PHP_FE(http_send_data, NULL)
95 PHP_FE(http_send_file, NULL)
96 PHP_FE(http_send_stream, NULL)
97 PHP_FE(http_chunked_decode, NULL)
98 PHP_FE(http_split_response, NULL)
99 PHP_FE(http_parse_headers, NULL)
100 PHP_FE(http_get_request_headers, NULL)
101 #ifdef HTTP_HAVE_CURL
102 PHP_FE(http_get, http_request_info_ref_3)
103 PHP_FE(http_head, http_request_info_ref_3)
104 PHP_FE(http_post_data, http_request_info_ref_4)
105 PHP_FE(http_post_array, http_request_info_ref_4)
106 #endif
107 PHP_FE(http_auth_basic, NULL)
108 PHP_FE(http_auth_basic_cb, NULL)
109 #ifndef ZEND_ENGINE_2
110 PHP_FE(http_build_query, NULL)
111 #endif
112 PHP_FE(ob_httpetaghandler, NULL)
113 {NULL, NULL, NULL}
114 };
115 /* }}} */
116
117 #define RETURN_SUCCESS(v) RETURN_BOOL(SUCCESS == (v))
118 #define HASH_ORNULL(z) ((z) ? Z_ARRVAL_P(z) : NULL)
119 #define NO_ARGS if (ZEND_NUM_ARGS()) WRONG_PARAM_COUNT
120
121 #define array_copy(src, dst) zend_hash_copy(Z_ARRVAL_P(dst), Z_ARRVAL_P(src), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *))
122 #define array_merge(src, dst) zend_hash_merge(Z_ARRVAL_P(dst), Z_ARRVAL_P(src), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *), 1)
123
124 #ifdef ZEND_ENGINE_2
125
126 # define HTTP_REGISTER_CLASS_EX(classname, name, parent, flags) \
127 { \
128 zend_class_entry ce; \
129 INIT_CLASS_ENTRY(ce, #classname, name## _class_methods); \
130 ce.create_object = name## _new_object; \
131 name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
132 name## _ce->ce_flags |= flags; \
133 memcpy(& name## _object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \
134 name## _object_handlers.clone_obj = NULL; \
135 name## _declare_default_properties(name## _ce); \
136 }
137
138 # define HTTP_REGISTER_CLASS(classname, name, parent, flags) \
139 { \
140 zend_class_entry ce; \
141 INIT_CLASS_ENTRY(ce, #classname, name## _class_methods); \
142 ce.create_object = NULL; \
143 name## _ce = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
144 name## _ce->ce_flags |= flags; \
145 }
146
147 # define getObject(t, o) t * o = ((t *) zend_object_store_get_object(getThis() TSRMLS_CC))
148 # define OBJ_PROP(o) o->zo.properties
149 # define DCL_PROP(a, t, n, v) zend_declare_property_ ##t(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)
150 # define DCL_PROP_Z(a, n, v) zend_declare_property(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)
151 # define DCL_PROP_N(a, n) zend_declare_property_null(ce, (#n), sizeof(#n), (ZEND_ACC_ ##a) TSRMLS_CC)
152 # define UPD_PROP(o, t, n, v) zend_update_property_ ##t(o->zo.ce, getThis(), (#n), sizeof(#n), (v) TSRMLS_CC)
153 # define SET_PROP(o, n, z) zend_update_property(o->zo.ce, getThis(), (#n), sizeof(#n), (z) TSRMLS_CC)
154 # define GET_PROP(o, n) zend_read_property(o->zo.ce, getThis(), (#n), sizeof(#n), 0 TSRMLS_CC)
155
156 # define INIT_PARR(o, n) \
157 { \
158 zval *__tmp; \
159 MAKE_STD_ZVAL(__tmp); \
160 array_init(__tmp); \
161 SET_PROP(o, n, __tmp); \
162 }
163
164 # define FREE_PARR(o, p) \
165 { \
166 zval *__tmp = NULL; \
167 if (__tmp = GET_PROP(o, p)) { \
168 zval_dtor(__tmp); \
169 FREE_ZVAL(__tmp); \
170 __tmp = NULL; \
171 } \
172 }
173
174 /* {{{ HTTPi */
175
176 zend_class_entry *httpi_ce;
177
178 #define HTTPi_ME(me, al, ai) ZEND_FENTRY(me, ZEND_FN(al), ai, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
179
180 zend_function_entry httpi_class_methods[] = {
181 HTTPi_ME(date, http_date, NULL)
182 HTTPi_ME(absoluteURI, http_absolute_uri, NULL)
183 HTTPi_ME(negotiateLanguage, http_negotiate_language, NULL)
184 HTTPi_ME(negotiateCharset, http_negotiate_charset, NULL)
185 HTTPi_ME(redirect, http_redirect, NULL)
186 HTTPi_ME(sendStatus, http_send_status, NULL)
187 HTTPi_ME(sendLastModified, http_send_last_modified, NULL)
188 HTTPi_ME(sendContentType, http_send_content_type, NULL)
189 HTTPi_ME(sendContentDisposition, http_send_content_disposition, NULL)
190 HTTPi_ME(matchModified, http_match_modified, NULL)
191 HTTPi_ME(matchEtag, http_match_etag, NULL)
192 HTTPi_ME(cacheLastModified, http_cache_last_modified, NULL)
193 HTTPi_ME(cacheEtag, http_cache_etag, NULL)
194 HTTPi_ME(chunkedDecode, http_chunked_decode, NULL)
195 HTTPi_ME(splitResponse, http_split_response, NULL)
196 HTTPi_ME(parseHeaders, http_parse_headers, NULL)
197 HTTPi_ME(getRequestHeaders, http_get_request_headers, NULL)
198 #ifdef HTTP_HAVE_CURL
199 HTTPi_ME(get, http_get, http_request_info_ref_3)
200 HTTPi_ME(head, http_head, http_request_info_ref_3)
201 HTTPi_ME(postData, http_post_data, http_request_info_ref_4)
202 HTTPi_ME(postArray, http_post_array, http_request_info_ref_4)
203 #endif
204 HTTPi_ME(authBasic, http_auth_basic, NULL)
205 HTTPi_ME(authBasicCallback, http_auth_basic_cb, NULL)
206 {NULL, NULL, NULL}
207 };
208 /* }}} HTTPi */
209
210 /* {{{ HTTPi_Response */
211
212 zend_class_entry *httpi_response_ce;
213 static zend_object_handlers httpi_response_object_handlers;
214
215 typedef struct {
216 zend_object zo;
217 } httpi_response_object;
218
219 #define httpi_response_declare_default_properties(ce) _httpi_response_declare_default_properties(ce TSRMLS_CC)
220 static inline void _httpi_response_declare_default_properties(zend_class_entry *ce TSRMLS_DC)
221 {
222 DCL_PROP(PROTECTED, string, contentType, "application/x-octetstream");
223 DCL_PROP(PROTECTED, string, eTag, "");
224 DCL_PROP(PROTECTED, string, dispoFile, "");
225 DCL_PROP(PROTECTED, string, cacheControl, "public");
226 DCL_PROP(PROTECTED, string, data, "");
227 DCL_PROP(PROTECTED, string, file, "");
228 DCL_PROP(PROTECTED, long, stream, 0);
229 DCL_PROP(PROTECTED, long, lastModified, 0);
230 DCL_PROP(PROTECTED, long, dispoInline, 0);
231 DCL_PROP(PROTECTED, long, cache, 0);
232 DCL_PROP(PROTECTED, long, gzip, 0);
233
234 DCL_PROP(PRIVATE, long, raw_cache_header, 0);
235 DCL_PROP(PRIVATE, long, send_mode, -1);
236 }
237
238 #define httpi_response_destroy_object _httpi_response_destroy_object
239 void _httpi_response_destroy_object(void *object, zend_object_handle handle TSRMLS_DC)
240 {
241 httpi_response_object *o = object;
242 if (OBJ_PROP(o)) {
243 zend_hash_destroy(OBJ_PROP(o));
244 FREE_HASHTABLE(OBJ_PROP(o));
245 }
246 efree(o);
247 }
248
249 #define httpi_response_new_object _httpi_response_new_object
250 zend_object_value _httpi_response_new_object(zend_class_entry *ce TSRMLS_DC)
251 {
252 zend_object_value ov;
253 httpi_response_object *o;
254
255 o = ecalloc(1, sizeof(httpi_response_object));
256 o->zo.ce = ce;
257
258 ALLOC_HASHTABLE(OBJ_PROP(o));
259 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
260 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
261
262 ov.handle = zend_objects_store_put(o, httpi_response_destroy_object, NULL, NULL TSRMLS_CC);
263 ov.handlers = &httpi_response_object_handlers;
264
265 return ov;
266 }
267
268 zend_function_entry httpi_response_class_methods[] = {
269 PHP_ME(HTTPi_Response, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
270 /* PHP_ME(HTTPi_Response, __destruct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
271 */
272 PHP_ME(HTTPi_Response, setETag, NULL, ZEND_ACC_PUBLIC)
273 PHP_ME(HTTPi_Response, getETag, NULL, ZEND_ACC_PUBLIC)
274
275 PHP_ME(HTTPi_Response, setContentDisposition, NULL, ZEND_ACC_PUBLIC)
276 PHP_ME(HTTPi_Response, getContentDisposition, NULL, ZEND_ACC_PUBLIC)
277
278 PHP_ME(HTTPi_Response, setContentType, NULL, ZEND_ACC_PUBLIC)
279 PHP_ME(HTTPi_Response, getContentType, NULL, ZEND_ACC_PUBLIC)
280
281 PHP_ME(HTTPi_Response, setCache, NULL, ZEND_ACC_PUBLIC)
282 PHP_ME(HTTPi_Response, getCache, NULL, ZEND_ACC_PUBLIC)
283
284 PHP_ME(HTTPi_Response, setCacheControl, NULL, ZEND_ACC_PUBLIC)
285 PHP_ME(HTTPi_Response, getCacheControl, NULL, ZEND_ACC_PUBLIC)
286
287 PHP_ME(HTTPi_Response, setGzip, NULL, ZEND_ACC_PUBLIC)
288 PHP_ME(HTTPi_Response, getGzip, NULL, ZEND_ACC_PUBLIC)
289
290 PHP_ME(HTTPi_Response, setData, NULL, ZEND_ACC_PUBLIC)
291 PHP_ME(HTTPi_Response, getData, NULL, ZEND_ACC_PUBLIC)
292
293 PHP_ME(HTTPi_Response, setFile, NULL, ZEND_ACC_PUBLIC)
294 PHP_ME(HTTPi_Response, getFile, NULL, ZEND_ACC_PUBLIC)
295
296 PHP_ME(HTTPi_Response, setStream, NULL, ZEND_ACC_PUBLIC)
297 PHP_ME(HTTPi_Response, getStream, NULL, ZEND_ACC_PUBLIC)
298
299 PHP_ME(HTTPi_Response, send, NULL, ZEND_ACC_PUBLIC)
300
301 {NULL, NULL, NULL}
302 };
303
304 /* {{{ proto void HTTPi_Response::__construct(bool cache, bool gzip)
305 *
306 */
307 PHP_METHOD(HTTPi_Response, __construct)
308 {
309 zend_bool do_cache = 0, do_gzip = 0;
310 getObject(httpi_response_object, obj);
311
312 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &do_cache, &do_gzip)) {
313 // throw exception
314 return;
315 }
316
317 UPD_PROP(obj, long, cache, do_cache);
318 UPD_PROP(obj, long, gzip, do_gzip);
319 }
320 /* }}} */
321
322 /* {{{ proto bool HTTPi_Response::setCache(bool cache)
323 *
324 */
325 PHP_METHOD(HTTPi_Response, setCache)
326 {
327 zend_bool do_cache = 0;
328 getObject(httpi_response_object, obj);
329
330 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_cache)) {
331 RETURN_FALSE;
332 }
333
334 UPD_PROP(obj, long, cache, do_cache);
335 RETURN_TRUE;
336 }
337 /* }}} */
338
339 /* {{{ proto bool HTTPi_Response::getCache()
340 *
341 */
342 PHP_METHOD(HTTPi_Response, getCache)
343 {
344 zval *do_cache = NULL;
345 getObject(httpi_response_object, obj);
346
347 NO_ARGS;
348
349 do_cache = GET_PROP(obj, cache);
350 RETURN_BOOL(Z_LVAL_P(do_cache));
351 }
352 /* }}}*/
353
354 /* {{{ proto bool HTTPi_Response::setGzip(bool gzip)
355 *
356 */
357 PHP_METHOD(HTTPi_Response, setGzip)
358 {
359 zend_bool do_gzip = 0;
360 getObject(httpi_response_object, obj);
361
362 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &do_gzip)) {
363 RETURN_FALSE;
364 }
365
366 UPD_PROP(obj, long, gzip, do_gzip);
367 RETURN_TRUE;
368 }
369 /* }}} */
370
371 /* {{{ proto bool HTTPi_Response::getGzip()
372 *
373 */
374 PHP_METHOD(HTTPi_Response, getGzip)
375 {
376 zval *do_gzip = NULL;
377 getObject(httpi_response_object, obj);
378
379 NO_ARGS;
380
381 do_gzip = GET_PROP(obj, gzip);
382 RETURN_BOOL(Z_LVAL_P(do_gzip));
383 }
384 /* }}} */
385
386 /* {{{ proto bool HTTPi_Response::setCacheControl(string control[, bool raw = false])
387 *
388 */
389 PHP_METHOD(HTTPi_Response, setCacheControl)
390 {
391 char *ccontrol;
392 int cc_len;
393 zend_bool raw = 0;
394 getObject(httpi_response_object, obj);
395
396 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &ccontrol, &cc_len, &raw)) {
397 RETURN_FALSE;
398 }
399
400 if ((!raw) && (strcmp(ccontrol, "public") && strcmp(ccontrol, "private") && strcmp(ccontrol, "no-cache"))) {
401 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cache-Control '%s' doesn't match public, private or no-cache", ccontrol);
402 RETURN_FALSE;
403 }
404
405 UPD_PROP(obj, long, raw_cache_header, raw);
406 UPD_PROP(obj, string, cacheControl, ccontrol);
407 RETURN_TRUE;
408 }
409 /* }}} */
410
411 /* {{{ proto string HTTPi_Response::getCacheControl()
412 *
413 */
414 PHP_METHOD(HTTPi_Response, getCacheControl)
415 {
416 zval *ccontrol;
417 getObject(httpi_response_object, obj);
418
419 NO_ARGS;
420
421 ccontrol = GET_PROP(obj, cacheControl);
422 RETURN_STRINGL(Z_STRVAL_P(ccontrol), Z_STRLEN_P(ccontrol), 1);
423 }
424 /* }}} */
425
426 /* {{{ proto bool HTTPi::setContentType(string content_type)
427 *
428 */
429 PHP_METHOD(HTTPi_Response, setContentType)
430 {
431 char *ctype;
432 int ctype_len;
433 getObject(httpi_response_object, obj);
434
435 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ctype_len)) {
436 RETURN_FALSE;
437 }
438
439 if (!strchr(ctype, '/')) {
440 php_error_docref(NULL TSRMLS_CC, E_WARNING,
441 "Content type '%s' doesn't seem to contain a primary and a secondary part", ctype);
442 RETURN_FALSE;
443 }
444
445 UPD_PROP(obj, string, contentType, ctype);
446
447 RETURN_TRUE;
448 }
449 /* }}} */
450
451 /* {{{ proto string HTTPi_Response::getContentType()
452 *
453 */
454 PHP_METHOD(HTTPi_Response, getContentType)
455 {
456 zval *ctype;
457 getObject(httpi_response_object, obj);
458
459 NO_ARGS;
460
461 ctype = GET_PROP(obj, contentType);
462 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
463 }
464 /* }}} */
465
466 /* {{{ proto bool HTTPi_Response::setContentDisposition(string filename[, bool inline = false])
467 *
468 */
469 PHP_METHOD(HTTPi_Response, setContentDisposition)
470 {
471 char *file;
472 int file_len;
473 zend_bool is_inline = 0;
474 getObject(httpi_response_object, obj);
475
476 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &file, &file_len, &is_inline)) {
477 RETURN_FALSE;
478 }
479
480 UPD_PROP(obj, string, dispoFile, file);
481 UPD_PROP(obj, long, dispoInline, is_inline);
482 RETURN_TRUE;
483 }
484 /* }}} */
485
486 /* {{{ proto array HTTPi_Response::getContentDisposition()
487 *
488 */
489 PHP_METHOD(HTTPi_Response, getContentDisposition)
490 {
491 zval *file;
492 zval *is_inline;
493 getObject(httpi_response_object, obj);
494
495 if (ZEND_NUM_ARGS()) {
496 WRONG_PARAM_COUNT;
497 }
498
499 file = GET_PROP(obj, dispoFile);
500 is_inline = GET_PROP(obj, dispoInline);
501
502 array_init(return_value);
503 add_assoc_stringl(return_value, "filename", Z_STRVAL_P(file), Z_STRLEN_P(file), 1);
504 add_assoc_bool(return_value, "inline", Z_LVAL_P(is_inline));
505 }
506 /* }}} */
507
508 /* {{{ proto bool HTTPi_Response::setETag(string etag)
509 *
510 */
511 PHP_METHOD(HTTPi_Response, setETag)
512 {
513 char *etag;
514 int etag_len;
515 getObject(httpi_response_object, obj);
516
517 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len)) {
518 RETURN_FALSE;
519 }
520
521 UPD_PROP(obj, string, eTag, etag);
522 RETURN_TRUE;
523 }
524 /* }}} */
525
526 /* {{{ proto string HTTPi_Response::getETag()
527 *
528 */
529 PHP_METHOD(HTTPi_Response, getETag)
530 {
531 zval *etag;
532 getObject(httpi_response_object, obj);
533
534 NO_ARGS;
535
536 etag = GET_PROP(obj, eTag);
537 RETURN_STRINGL(Z_STRVAL_P(etag), Z_STRLEN_P(etag), 1);
538 }
539 /* }}} */
540
541 /* {{{ proto bool HTTPi_Response::setData(string data)
542 *
543 */
544 PHP_METHOD(HTTPi_Response, setData)
545 {
546 zval *the_data;
547 char *etag;
548 getObject(httpi_response_object, obj);
549
550 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_data)) {
551 RETURN_FALSE;
552 }
553
554 convert_to_string_ex(&the_data);
555 SET_PROP(obj, data, the_data);
556 UPD_PROP(obj, long, lastModified, http_lmod(the_data, SEND_DATA));
557 UPD_PROP(obj, long, send_mode, SEND_DATA);
558 RETURN_TRUE;
559 }
560 /* }}} */
561
562 /* {{{ proto string HTTPi_Response::getData()
563 *
564 */
565 PHP_METHOD(HTTPi_Response, getData)
566 {
567 zval *the_data;
568 getObject(httpi_response_object, obj);
569
570 NO_ARGS;
571
572 the_data = GET_PROP(obj, data);
573 RETURN_STRINGL(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), 1);
574 }
575 /* }}} */
576
577 /* {{{ proto bool HTTPi_Response::setStream(resource stream)
578 *
579 */
580 PHP_METHOD(HTTPi_Response, setStream)
581 {
582 zval *the_stream;
583 php_stream *the_real_stream;
584 char *etag;
585 getObject(httpi_response_object, obj);
586
587 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &the_stream)) {
588 RETURN_FALSE;
589 }
590
591 php_stream_from_zval(the_real_stream, &the_stream);
592
593 SET_PROP(obj, stream, the_stream);
594 UPD_PROP(obj, long, lastModified, http_lmod(the_real_stream, SEND_RSRC));
595 UPD_PROP(obj, long, send_mode, SEND_RSRC);
596 RETURN_TRUE;
597 }
598 /* }}} */
599
600 /* {{{ proto resource HTTPi_Response::getStream()
601 *
602 */
603 PHP_METHOD(HTTPi_Response, getStream)
604 {
605 zval *the_stream;
606 getObject(httpi_response_object, obj);
607
608 NO_ARGS;
609
610 the_stream = GET_PROP(obj, stream);
611 RETURN_RESOURCE(Z_LVAL_P(the_stream));
612 }
613 /* }}} */
614
615 /* {{{ proto bool HTTPi_Response::setFile(string file)
616 *
617 */
618 PHP_METHOD(HTTPi_Response, setFile)
619 {
620 zval *the_file;
621 getObject(httpi_response_object, obj);
622
623 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_file)) {
624 RETURN_FALSE;
625 }
626
627 convert_to_string_ex(&the_file);
628
629 UPD_PROP(obj, string, file, Z_STRVAL_P(the_file));
630 UPD_PROP(obj, long, lastModified, http_lmod(the_file, -1));
631 UPD_PROP(obj, long, send_mode, -1);
632 RETURN_TRUE;
633 }
634 /* }}} */
635
636 /* {{{ proto string HTTPi_Response::getFile()
637 *
638 */
639 PHP_METHOD(HTTPi_Response, getFile)
640 {
641 zval *the_file;
642 getObject(httpi_response_object, obj);
643
644 NO_ARGS;
645
646 the_file = GET_PROP(obj, file);
647 RETURN_STRINGL(Z_STRVAL_P(the_file), Z_STRLEN_P(the_file), 1);
648 }
649 /* }}} */
650
651 PHP_METHOD(HTTPi_Response, send)
652 {
653 zval *do_cache, *do_gzip;
654 getObject(httpi_response_object, obj);
655
656 do_cache = GET_PROP(obj, cache);
657 do_gzip = GET_PROP(obj, gzip);
658
659 /* caching */
660 if (Z_LVAL_P(do_cache)) {
661 zval *cctrl, *etag, *lmod, *ccraw;
662
663 etag = GET_PROP(obj, eTag);
664 lmod = GET_PROP(obj, lastModified);
665 cctrl = GET_PROP(obj, cacheControl);
666 ccraw = GET_PROP(obj, raw_cache_header);
667
668 if (Z_LVAL_P(ccraw)) {
669 http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), Z_STRVAL_P(cctrl), Z_STRLEN_P(cctrl));
670 http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), Z_STRVAL_P(cctrl), Z_STRLEN_P(cctrl));
671 } else {
672 char cc_header[42] = {0};
673 sprintf(cc_header, "%s, must-revalidate, max-age=0", Z_STRVAL_P(cctrl));
674 http_cache_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag), cc_header, strlen(cc_header));
675 http_cache_last_modified(Z_LVAL_P(lmod), Z_LVAL_P(lmod) ? Z_LVAL_P(lmod) : time(NULL), cc_header, strlen(cc_header));
676 }
677 }
678
679 /* gzip */
680 if (Z_LVAL_P(do_gzip)) {
681 /* ... */
682 }
683
684 /* content type */
685 {
686 zval *ctype = GET_PROP(obj, contentType);
687 if (Z_STRLEN_P(ctype)) {
688 http_send_content_type(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype));
689 } else {
690 http_send_content_type("application/x-octetstream", sizeof("application/x-octetstream") - 1);
691 }
692 }
693
694 /* content disposition */
695 {
696 zval *dispo_file = GET_PROP(obj, dispoFile);
697 if (Z_STRLEN_P(dispo_file)) {
698 zval *dispo_inline = GET_PROP(obj, dispoInline);
699 http_send_content_disposition(Z_STRVAL_P(dispo_file), Z_STRLEN_P(dispo_file), Z_LVAL_P(dispo_inline));
700 }
701 }
702
703 /* send */
704 {
705 zval *send_mode = GET_PROP(obj, send_mode);
706 switch (Z_LVAL_P(send_mode))
707 {
708 case SEND_DATA:
709 {
710 RETURN_SUCCESS(http_send_data(GET_PROP(obj, data)));
711 }
712
713 case SEND_RSRC:
714 {
715 php_stream *the_real_stream;
716 zval *the_stream = GET_PROP(obj, stream);
717 php_stream_from_zval(the_real_stream, &the_stream);
718 RETURN_SUCCESS(http_send_stream(the_real_stream));
719 }
720
721 default:
722 {
723 RETURN_SUCCESS(http_send_file(GET_PROP(obj, file)));
724 }
725 }
726 }
727 }
728 /* }}} */
729
730 /* {{{ HTTPi_Request */
731 #ifdef HTTP_HAVE_CURL
732
733 zend_class_entry *httpi_request_ce;
734 static zend_object_handlers httpi_request_object_handlers;
735
736 typedef struct {
737 zend_object zo;
738 CURL *ch;
739
740 struct curl_httppost *post_data[2];
741
742 } httpi_request_object;
743
744 #define httpi_request_declare_default_properties(ce) _httpi_request_declare_default_properties(ce TSRMLS_CC)
745 static inline void _httpi_request_declare_default_properties(zend_class_entry *ce TSRMLS_DC)
746 {
747 DCL_PROP_N(PROTECTED, options);
748 DCL_PROP_N(PROTECTED, responseInfo);
749 DCL_PROP_N(PROTECTED, responseData);
750 DCL_PROP_N(PROTECTED, postData);
751 DCL_PROP_N(PROTECTED, postFiles);
752
753 DCL_PROP(PROTECTED, long, method, HTTP_GET);
754
755 DCL_PROP(PROTECTED, string, url, "");
756 DCL_PROP(PROTECTED, string, contentType, "");
757 DCL_PROP(PROTECTED, string, queryData, "");
758 DCL_PROP(PROTECTED, string, postData, "");
759 }
760
761 #define httpi_request_free_object _httpi_request_free_object
762 void _httpi_request_free_object(zend_object /* void */ *object TSRMLS_DC)
763 {
764 httpi_request_object *o = (httpi_request_object *) object;
765
766 if (OBJ_PROP(o)) {
767 zend_hash_destroy(OBJ_PROP(o));
768 FREE_HASHTABLE(OBJ_PROP(o));
769 }
770 if (o->ch) {
771 curl_easy_cleanup(o->ch);
772 o->ch = NULL;
773 }
774 efree(o);
775 }
776
777 #define httpi_request_new_object _httpi_request_new_object
778 zend_object_value _httpi_request_new_object(zend_class_entry *ce TSRMLS_DC)
779 {
780 zend_object_value ov;
781 httpi_request_object *o;
782
783 o = ecalloc(1, sizeof(httpi_request_object));
784 o->zo.ce = ce;
785 o->ch = curl_easy_init();
786 o->post_data[0] = NULL;
787 o->post_data[1] = NULL;
788
789 ALLOC_HASHTABLE(OBJ_PROP(o));
790 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
791 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
792
793 ov.handle = zend_objects_store_put(o, (zend_objects_store_dtor_t) zend_objects_destroy_object, httpi_request_free_object, NULL TSRMLS_CC);
794 ov.handlers = &httpi_request_object_handlers;
795
796 return ov;
797 }
798
799 zend_function_entry httpi_request_class_methods[] = {
800 PHP_ME(HTTPi_Request, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
801 PHP_ME(HTTPi_Request, __destruct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
802
803 PHP_ME(HTTPi_Request, setOptions, NULL, ZEND_ACC_PUBLIC)
804 PHP_ME(HTTPi_Request, getOptions, NULL, ZEND_ACC_PUBLIC)
805
806 PHP_ME(HTTPi_Request, setMethod, NULL, ZEND_ACC_PUBLIC)
807 PHP_ME(HTTPi_Request, getMethod, NULL, ZEND_ACC_PUBLIC)
808
809 PHP_ME(HTTPi_Request, setURL, NULL, ZEND_ACC_PUBLIC)
810 PHP_ME(HTTPi_Request, getURL, NULL, ZEND_ACC_PUBLIC)
811
812 PHP_ME(HTTPi_Request, setContentType, NULL, ZEND_ACC_PUBLIC)
813 PHP_ME(HTTPi_Request, getContentType, NULL, ZEND_ACC_PUBLIC)
814
815 PHP_ME(HTTPi_Request, setQueryData, NULL, ZEND_ACC_PUBLIC)
816 PHP_ME(HTTPi_Request, getQueryData, NULL, ZEND_ACC_PUBLIC)
817 PHP_ME(HTTPi_Request, addQueryData, NULL, ZEND_ACC_PUBLIC)
818 PHP_ME(HTTPi_Request, unsetQueryData, NULL, ZEND_ACC_PUBLIC)
819
820 PHP_ME(HTTPi_Request, setPostData, NULL, ZEND_ACC_PUBLIC)
821 PHP_ME(HTTPi_Request, getPostData, NULL, ZEND_ACC_PUBLIC)
822 PHP_ME(HTTPi_Request, addPostData, NULL, ZEND_ACC_PUBLIC)
823 PHP_ME(HTTPi_Request, unsetPostData, NULL, ZEND_ACC_PUBLIC)
824
825 PHP_ME(HTTPi_Request, addPostFile, NULL, ZEND_ACC_PUBLIC)
826 PHP_ME(HTTPi_Request, getPostFiles, NULL, ZEND_ACC_PUBLIC)
827 PHP_ME(HTTPi_Request, unsetPostFiles, NULL, ZEND_ACC_PUBLIC)
828
829 PHP_ME(HTTPi_Request, send, NULL, ZEND_ACC_PUBLIC)
830
831 PHP_ME(HTTPi_Request, getResponseData, NULL, ZEND_ACC_PUBLIC)
832 PHP_ME(HTTPi_Request, getResponseHeaders, NULL, ZEND_ACC_PUBLIC)
833 PHP_ME(HTTPi_Request, getResponseBody, NULL, ZEND_ACC_PUBLIC)
834 PHP_ME(HTTPi_Request, getResponseInfo, NULL, ZEND_ACC_PUBLIC)
835
836 {NULL, NULL, NULL}
837 };
838
839 /* {{{ proto void HTTPi_Request::__construct([string url[, long request_method = HTTP_GET]])
840 *
841 */
842 PHP_METHOD(HTTPi_Request, __construct)
843 {
844 char *URL = NULL;
845 int URL_len;
846 long meth = -1;
847 zval *info, *opts, *resp;
848 getObject(httpi_request_object, obj);
849
850 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &URL, &URL_len, &meth)) {
851 return;
852 }
853
854 INIT_PARR(obj, options);
855 INIT_PARR(obj, responseInfo);
856 INIT_PARR(obj, responseData);
857 INIT_PARR(obj, postData);
858 INIT_PARR(obj, postFiles);
859
860 if (URL) {
861 UPD_PROP(obj, string, url, URL);
862 }
863 if (meth > -1) {
864 UPD_PROP(obj, long, method, meth);
865 }
866 }
867 /* }}} */
868
869 /* {{{ proto void HTTPi_Request::__destruct()
870 *
871 */
872 PHP_METHOD(HTTPi_Request, __destruct)
873 {
874 getObject(httpi_request_object, obj);
875
876 NO_ARGS;
877
878 FREE_PARR(obj, options);
879 FREE_PARR(obj, responseInfo);
880 FREE_PARR(obj, responseData);
881 FREE_PARR(obj, postData);
882 FREE_PARR(obj, postFiles);
883 }
884 /* }}} */
885
886 /* {{{ proto bool HTTPi_Request::setOptions(array options)
887 *
888 */
889 PHP_METHOD(HTTPi_Request, setOptions)
890 {
891 zval *opts, *old_opts, **opt;
892 getObject(httpi_request_object, obj);
893
894 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &opts)) {
895 RETURN_FALSE;
896 }
897
898 old_opts = GET_PROP(obj, options);
899
900 /* headers and cookies need extra attention -- thus cannot use zend_hash_merge() or php_array_merge() directly */
901 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(opts));
902 zend_hash_get_current_data(Z_ARRVAL_P(opts), (void **) &opt) == SUCCESS;
903 zend_hash_move_forward(Z_ARRVAL_P(opts))) {
904 char *key;
905 long idx;
906 if (HASH_KEY_IS_STRING == zend_hash_get_current_key(Z_ARRVAL_P(opts), &key, &idx, 0)) {
907 if (!strcmp(key, "headers")) {
908 zval **headers;
909 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "headers", sizeof("headers"), (void **) &headers)) {
910 array_merge(*opt, *headers);
911 continue;
912 }
913 } else if (!strcmp(key, "cookies")) {
914 zval **cookies;
915 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(old_opts), "cookies", sizeof("cookies"), (void **) &cookies)) {
916 array_merge(*opt, *cookies);
917 continue;
918 }
919 }
920 zval_add_ref(opt);
921 add_assoc_zval(old_opts, key, *opt);
922 }
923 }
924 RETURN_TRUE;
925 }
926 /* }}} */
927
928 /* {{{ proto array HTTPi_Request::getOptions()
929 *
930 */
931 PHP_METHOD(HTTPi_Request, getOptions)
932 {
933 zval *opts;
934 getObject(httpi_request_object, obj);
935
936 NO_ARGS;
937
938 opts = GET_PROP(obj, options);
939 array_init(return_value);
940 array_copy(opts, return_value);
941 }
942 /* }}} */
943
944 /* {{{ proto bool HTTPi_Request::setURL(string url)
945 *
946 */
947 PHP_METHOD(HTTPi_Request, setURL)
948 {
949 char *URL = NULL;
950 int URL_len;
951 getObject(httpi_request_object, obj);
952
953 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &URL, &URL_len)) {
954 RETURN_FALSE;
955 }
956
957 UPD_PROP(obj, string, url, URL);
958 RETURN_TRUE;
959 }
960 /* }}} */
961
962 /* {{{ proto string HTTPi_Request::getUrl()
963 *
964 */
965 PHP_METHOD(HTTPi_Request, getURL)
966 {
967 zval *URL;
968 getObject(httpi_request_object, obj);
969
970 NO_ARGS;
971
972 URL = GET_PROP(obj, url);
973 RETURN_STRINGL(Z_STRVAL_P(URL), Z_STRLEN_P(URL), 1);
974 }
975 /* }}} */
976
977 /* {{{ proto bool HTTPi_Request::setMethod(long request_method)
978 *
979 */
980 PHP_METHOD(HTTPi_Request, setMethod)
981 {
982 long meth;
983 getObject(httpi_request_object, obj);
984
985 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &meth)) {
986 RETURN_FALSE;
987 }
988
989 UPD_PROP(obj, long, method, meth);
990 RETURN_TRUE;
991 }
992 /* }}} */
993
994 /* {{{ proto long HTTPi_Request::getMethod()
995 *
996 */
997 PHP_METHOD(HTTPi_Request, getMethod)
998 {
999 zval *meth;
1000 getObject(httpi_request_object, obj);
1001
1002 NO_ARGS;
1003
1004 meth = GET_PROP(obj, method);
1005 RETURN_LONG(Z_LVAL_P(meth));
1006 }
1007 /* }}} */
1008
1009 /* {{{ proto bool HTTPi_Request::setContentType(string content_type)
1010 *
1011 */
1012 PHP_METHOD(HTTPi_Request, setContentType)
1013 {
1014 char *ctype;
1015 int ct_len;
1016 getObject(httpi_request_object, obj);
1017
1018 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ctype, &ct_len)) {
1019 RETURN_FALSE;
1020 }
1021
1022 if (!strchr(ctype, '/')) {
1023 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1024 "Content-Type '%s' doesn't seem to contain a primary and a secondary part",
1025 ctype);
1026 RETURN_FALSE;
1027 }
1028
1029 UPD_PROP(obj, string, contentType, ctype);
1030 RETURN_TRUE;
1031 }
1032 /* }}} */
1033
1034 /* {{{ proto string HTTPi_Request::getContentType()
1035 *
1036 */
1037 PHP_METHOD(HTTPi_Request, getContentType)
1038 {
1039 zval *ctype;
1040 getObject(httpi_request_object, obj);
1041
1042 NO_ARGS;
1043
1044 ctype = GET_PROP(obj, contentType);
1045 RETURN_STRINGL(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype), 1);
1046 }
1047 /* }}} */
1048
1049 /* {{{ proto bool HTTPi_Request::setQueryData(mixed query_data)
1050 *
1051 */
1052 PHP_METHOD(HTTPi_Request, setQueryData)
1053 {
1054 zval *qdata;
1055 getObject(httpi_request_object, obj);
1056
1057 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata)) {
1058 RETURN_FALSE;
1059 }
1060
1061 if ((Z_TYPE_P(qdata) == IS_ARRAY) || (Z_TYPE_P(qdata) == IS_OBJECT)) {
1062 smart_str qstr = {0};
1063 HTTP_URL_ARGSEP_OVERRIDE;
1064 if (SUCCESS != php_url_encode_hash_ex(HASH_OF(qdata), &qstr, NULL, 0, NULL, 0, NULL, 0, NULL TSRMLS_CC)) {
1065 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't encode query data");
1066 if (qstr.c) {
1067 efree(qstr.c);
1068 }
1069 HTTP_URL_ARGSEP_RESTORE;
1070 RETURN_FALSE;
1071 }
1072 HTTP_URL_ARGSEP_RESTORE;
1073 smart_str_0(&qstr);
1074 UPD_PROP(obj, string, queryData, qstr.c);
1075 efree(qstr.c);
1076 RETURN_TRUE;
1077 }
1078
1079 convert_to_string(qdata);
1080 UPD_PROP(obj, string, queryData, Z_STRVAL_P(qdata));
1081 RETURN_TRUE;
1082 }
1083 /* }}} */
1084
1085 /* {{{ proto string HTTPi_Request::getQueryData()
1086 *
1087 */
1088 PHP_METHOD(HTTPi_Request, getQueryData)
1089 {
1090 zval *qdata;
1091 getObject(httpi_request_object, obj);
1092
1093 NO_ARGS;
1094
1095 qdata = GET_PROP(obj, queryData);
1096 RETURN_STRINGL(Z_STRVAL_P(qdata), Z_STRLEN_P(qdata), 1);
1097 }
1098 /* }}} */
1099
1100 /* {{{ proto bool HTTPi_Request::addQueryData(array query_params)
1101 *
1102 */
1103 PHP_METHOD(HTTPi_Request, addQueryData)
1104 {
1105 zval *qdata, *old_qdata;
1106 smart_str qstr = {0};
1107 char *separator;
1108 getObject(httpi_request_object, obj);
1109
1110 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &qdata)) {
1111 RETURN_FALSE;
1112 }
1113
1114 old_qdata = GET_PROP(obj, queryData);
1115 if (Z_STRLEN_P(old_qdata)) {
1116 smart_str_appendl(&qstr, Z_STRVAL_P(old_qdata), Z_STRLEN_P(old_qdata));
1117 }
1118
1119 HTTP_URL_ARGSEP_OVERRIDE;
1120 if (SUCCESS != php_url_encode_hash_ex(HASH_OF(qdata), &qstr, NULL, 0, NULL, 0, NULL, 0, NULL TSRMLS_CC)) {
1121 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't encode query data");
1122 if (qstr.c) {
1123 efree(qstr.c);
1124 }
1125 HTTP_URL_ARGSEP_RESTORE;
1126 RETURN_FALSE;
1127 }
1128 HTTP_URL_ARGSEP_RESTORE;
1129
1130 smart_str_0(&qstr);
1131
1132 UPD_PROP(obj, string, queryData, qstr.c);
1133 efree(qstr.c);
1134 RETURN_TRUE;
1135 }
1136 /* }}} */
1137
1138 /* {{{ proto void HTTPi_Request::unsetQueryData()
1139 *
1140 */
1141 PHP_METHOD(HTTPi_Request, unsetQueryData)
1142 {
1143 getObject(httpi_request_object, obj);
1144
1145 NO_ARGS;
1146
1147 UPD_PROP(obj, string, queryData, "");
1148 }
1149 /* }}} */
1150
1151 /* {{{ proto bool HTTPi_Request::addPostData(array post_data)
1152 *
1153 */
1154 PHP_METHOD(HTTPi_Request, addPostData)
1155 {
1156 zval *post, *post_data;
1157 getObject(httpi_request_object, obj);
1158
1159 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1160 RETURN_FALSE;
1161 }
1162
1163 post = GET_PROP(obj, postData);
1164 array_merge(post_data, post);
1165
1166 RETURN_TRUE;
1167 }
1168 /* }}} */
1169
1170 /* {{{ proto bool HTTPi_Request::setPostData(array post_data)
1171 *
1172 */
1173 PHP_METHOD(HTTPi_Request, setPostData)
1174 {
1175 zval *post, *post_data;
1176 getObject(httpi_request_object, obj);
1177
1178 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &post_data)) {
1179 RETURN_FALSE;
1180 }
1181
1182 post = GET_PROP(obj, postData);
1183 zend_hash_clean(Z_ARRVAL_P(post));
1184 array_copy(post_data, post);
1185
1186 RETURN_TRUE;
1187 }
1188 /* }}}*/
1189
1190 /* {{{ proto array HTTPi_Request::getPostData()
1191 *
1192 */
1193 PHP_METHOD(HTTPi_Request, getPostData)
1194 {
1195 zval *post_data;
1196 getObject(httpi_request_object, obj);
1197
1198 NO_ARGS;
1199
1200 post_data = GET_PROP(obj, postData);
1201 array_init(return_value);
1202 array_copy(post_data, return_value);
1203 }
1204 /* }}} */
1205
1206 /* {{{ proto void HTTPi_Request::unsetPostData()
1207 *
1208 */
1209 PHP_METHOD(HTTPi_Request, unsetPostData)
1210 {
1211 zval *post_data;
1212 getObject(httpi_request_object, obj);
1213
1214 NO_ARGS;
1215
1216 post_data = GET_PROP(obj, postData);
1217 zend_hash_clean(Z_ARRVAL_P(post_data));
1218 }
1219 /* }}} */
1220
1221 /* {{{ proto bool HTTPi_Request::addPostFile(string name, string file[, string content_type = "application/x-octetstream"])
1222 *
1223 */
1224 PHP_METHOD(HTTPi_Request, addPostFile)
1225 {
1226 zval *files, *entry;
1227 char *name, *file, *type = NULL;
1228 int name_len, file_len, type_len = 0;
1229 getObject(httpi_request_object, obj);
1230
1231 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &name, &name_len, &file, &file_len, &type, &type_len)) {
1232 RETURN_FALSE;
1233 }
1234
1235 if (type_len) {
1236 if (!strchr(type, '/')) {
1237 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Content-Type '%s' doesn't seem to contain a primary and a secondary part", type);
1238 RETURN_FALSE;
1239 }
1240 } else {
1241 type = "application/x-octetstream";
1242 type_len = sizeof("application/x-octetstream") - 1;
1243 }
1244
1245 MAKE_STD_ZVAL(entry);
1246 array_init(entry);
1247
1248 add_assoc_stringl(entry, "name", name, name_len, 1);
1249 add_assoc_stringl(entry, "type", type, type_len, 1);
1250 add_assoc_stringl(entry, "file", file, file_len, 1);
1251
1252 files = GET_PROP(obj, postFiles);
1253 add_next_index_zval(files, entry);
1254
1255 RETURN_TRUE;
1256 }
1257 /* }}} */
1258
1259 /* {{{ proto array HTTPi_Request::getPostFiles()
1260 *
1261 */
1262 PHP_METHOD(HTTPi_Request, getPostFiles)
1263 {
1264 zval *files;
1265 getObject(httpi_request_object, obj);
1266
1267 NO_ARGS;
1268
1269 files = GET_PROP(obj, postFiles);
1270
1271 array_init(return_value);
1272 array_copy(files, return_value);
1273 }
1274 /* }}} */
1275
1276 /* {{{ proto void HTTPi_Request::unsetPostFiles()
1277 *
1278 */
1279 PHP_METHOD(HTTPi_Request, unsetPostFiles)
1280 {
1281 zval *files;
1282 getObject(httpi_request_object, obj);
1283
1284 NO_ARGS;
1285
1286 files = GET_PROP(obj, postFiles);
1287 zend_hash_clean(Z_ARRVAL_P(files));
1288 }
1289 /* }}} */
1290
1291 /* {{{ proto array HTTPi_Request::getResponseData()
1292 *
1293 */
1294 PHP_METHOD(HTTPi_Request, getResponseData)
1295 {
1296 zval *data;
1297 getObject(httpi_request_object, obj);
1298
1299 NO_ARGS;
1300
1301 data = GET_PROP(obj, responseData);
1302 array_init(return_value);
1303 array_copy(data, return_value);
1304 }
1305 /* }}} */
1306
1307 /* {{{ proto array HTTPi_Request::getResponseHeaders()
1308 *
1309 */
1310 PHP_METHOD(HTTPi_Request, getResponseHeaders)
1311 {
1312 zval *data, **headers;
1313 getObject(httpi_request_object, obj);
1314
1315 NO_ARGS;
1316
1317 array_init(return_value);
1318 data = GET_PROP(obj, responseData);
1319 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "headers", sizeof("headers"), (void **) &headers)) {
1320 array_copy(*headers, return_value);
1321 }
1322 }
1323 /* }}} */
1324
1325 /* {{{ proto string HTTPi_Request::getResponseBody()
1326 *
1327 */
1328 PHP_METHOD(HTTPi_Request, getResponseBody)
1329 {
1330 zval *data, **body;
1331 getObject(httpi_request_object, obj);
1332
1333 NO_ARGS;
1334
1335 data = GET_PROP(obj, responseData);
1336 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), "body", sizeof("body"), (void **) &body)) {
1337 RETURN_STRINGL(Z_STRVAL_PP(body), Z_STRLEN_PP(body), 1);
1338 } else {
1339 Z_TYPE_P(return_value) = IS_NULL;
1340 }
1341 }
1342 /* }}} */
1343
1344 /* {{{ proto array HTTPi_Request::getResponseInfo()
1345 *
1346 */
1347 PHP_METHOD(HTTPi_Request, getResponseInfo)
1348 {
1349 zval *info;
1350 getObject(httpi_request_object, obj);
1351
1352 NO_ARGS;
1353
1354 info = GET_PROP(obj, responseInfo);
1355 array_init(return_value);
1356 array_copy(info, return_value);
1357 }
1358 /* }}}*/
1359
1360 /* {{{ proto bool HTTPi_Request::send()
1361 *
1362 */
1363 PHP_METHOD(HTTPi_Request, send)
1364 {
1365 STATUS status = FAILURE;
1366 zval *meth, *URL, *qdata, *opts, *info, *resp;
1367 char *response_data, *request_uri;
1368 size_t response_len;
1369 getObject(httpi_request_object, obj);
1370
1371 NO_ARGS;
1372
1373 if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
1374 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initilaize cURL");
1375 RETURN_FALSE;
1376 }
1377
1378 meth = GET_PROP(obj, method);
1379 URL = GET_PROP(obj, url);
1380 qdata = GET_PROP(obj, queryData);
1381 opts = GET_PROP(obj, options);
1382 info = GET_PROP(obj, responseInfo);
1383 resp = GET_PROP(obj, responseData);
1384
1385 // HTTP_URI_MAXLEN+1 big char *
1386 request_uri = http_absolute_uri(Z_STRVAL_P(URL), NULL);
1387
1388 if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
1389 if (!strchr(request_uri, '?')) {
1390 strcat(request_uri, "?");
1391 } else {
1392 strcat(request_uri, "&");
1393 }
1394 strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
1395 }
1396
1397 switch (Z_LVAL_P(meth))
1398 {
1399 case HTTP_GET:
1400 status = http_get_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1401 break;
1402
1403 case HTTP_HEAD:
1404 status = http_head_ex(obj->ch, request_uri, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1405 break;
1406
1407 case HTTP_POST:
1408 {
1409 zval *post_files, *post_data, **data;
1410
1411 post_files = GET_PROP(obj, postFiles);
1412 post_data = GET_PROP(obj, postData);
1413
1414 if (!zend_hash_num_elements(Z_ARRVAL_P(post_files))) {
1415
1416 /* urlencoded post */
1417 status = http_post_array_ex(obj->ch, request_uri, Z_ARRVAL_P(post_data), Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1418
1419 } else {
1420
1421 /*
1422 * multipart post
1423 */
1424
1425 /* normal data */
1426 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(post_data));
1427 zend_hash_get_current_data(Z_ARRVAL_P(post_data), (void **) &data) == SUCCESS;
1428 zend_hash_move_forward(Z_ARRVAL_P(post_data))) {
1429
1430 char *key;
1431 long idx;
1432
1433 if (HASH_KEY_IS_STRING == zend_hash_get_current_key(Z_ARRVAL_P(post_data), &key, &idx, 0)) {
1434 convert_to_string_ex(data);
1435 curl_formadd(&obj->post_data[0], &obj->post_data[1],
1436 CURLFORM_COPYNAME, key,
1437 CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
1438 CURLFORM_CONTENTSLENGTH, Z_STRLEN_PP(data),
1439 CURLFORM_END
1440 );
1441 }
1442 }
1443
1444 /* file data */
1445 for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(post_files));
1446 zend_hash_get_current_data(Z_ARRVAL_P(post_files), (void **) &data) == SUCCESS;
1447 zend_hash_move_forward(Z_ARRVAL_P(post_files))) {
1448
1449 zval **file, **type, **name;
1450
1451 if (
1452 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void **) &name) &&
1453 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void **) &type) &&
1454 SUCCESS == zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void **) &file)
1455 ) {
1456
1457 curl_formadd(&obj->post_data[0], &obj->post_data[1],
1458 CURLFORM_COPYNAME, Z_STRVAL_PP(name),
1459 CURLFORM_FILENAME, Z_STRVAL_PP(name),
1460 CURLFORM_FILE, Z_STRVAL_PP(file),
1461 CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
1462 CURLFORM_END
1463 );
1464 }
1465 }
1466
1467 status = http_post_curldata_ex(obj->ch, request_uri, obj->post_data[0], Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &response_data, &response_len);
1468 curl_formfree(obj->post_data[0]);
1469 }
1470 }
1471 break;
1472
1473 default:
1474 break;
1475 }
1476
1477 efree(request_uri);
1478
1479 /* final data handling */
1480 if (status != SUCCESS) {
1481 RETURN_FALSE;
1482 } else {
1483 zval *zheaders, *zbody;
1484
1485 MAKE_STD_ZVAL(zbody);
1486 MAKE_STD_ZVAL(zheaders)
1487 array_init(zheaders);
1488
1489 if (SUCCESS != http_split_response_ex(response_data, response_len, zheaders, zbody)) {
1490 zval_dtor(zheaders);
1491 efree(zheaders),
1492 efree(zbody);
1493 efree(response_data);
1494 RETURN_FALSE;
1495 }
1496
1497 add_assoc_zval(resp, "headers", zheaders);
1498 add_assoc_zval(resp, "body", zbody);
1499
1500 efree(response_data);
1501
1502 RETURN_TRUE;
1503 }
1504 /* */
1505 }
1506 /* }}} */
1507
1508 #endif /* HTTP_HAVE_CURL */
1509 /* }}} */
1510
1511 #endif /* ZEND_ENGINE_2 */
1512
1513 /* {{{ http_module_entry */
1514 zend_module_entry http_module_entry = {
1515 #if ZEND_MODULE_API_NO >= 20010901
1516 STANDARD_MODULE_HEADER,
1517 #endif
1518 "http",
1519 http_functions,
1520 PHP_MINIT(http),
1521 PHP_MSHUTDOWN(http),
1522 PHP_RINIT(http),
1523 PHP_RSHUTDOWN(http),
1524 PHP_MINFO(http),
1525 #if ZEND_MODULE_API_NO >= 20010901
1526 PHP_EXT_HTTP_VERSION,
1527 #endif
1528 STANDARD_MODULE_PROPERTIES
1529 };
1530 /* }}} */
1531
1532 /* {{{ proto string http_date([int timestamp])
1533 *
1534 * This function returns a valid HTTP date regarding RFC 822/1123
1535 * looking like: "Wed, 22 Dec 2004 11:34:47 GMT"
1536 *
1537 */
1538 PHP_FUNCTION(http_date)
1539 {
1540 long t = -1;
1541
1542 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
1543 RETURN_FALSE;
1544 }
1545
1546 if (t == -1) {
1547 t = (long) time(NULL);
1548 }
1549
1550 RETURN_STRING(http_date(t), 0);
1551 }
1552 /* }}} */
1553
1554 /* {{{ proto string http_absolute_uri(string url[, string proto])
1555 *
1556 * This function returns an absolute URI constructed from url.
1557 * If the url is already abolute but a different proto was supplied,
1558 * only the proto part of the URI will be updated. If url has no
1559 * path specified, the path of the current REQUEST_URI will be taken.
1560 * The host will be taken either from the Host HTTP header of the client
1561 * the SERVER_NAME or just localhost if prior are not available.
1562 *
1563 * Some examples:
1564 * <pre>
1565 * url = "page.php" => http://www.example.com/current/path/page.php
1566 * url = "/page.php" => http://www.example.com/page.php
1567 * url = "/page.php", proto = "https" => https://www.example.com/page.php
1568 * </pre>
1569 *
1570 */
1571 PHP_FUNCTION(http_absolute_uri)
1572 {
1573 char *url = NULL, *proto = NULL;
1574 int url_len = 0, proto_len = 0;
1575
1576 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &url, &url_len, &proto, &proto_len) != SUCCESS) {
1577 RETURN_FALSE;
1578 }
1579
1580 RETURN_STRING(http_absolute_uri(url, proto), 0);
1581 }
1582 /* }}} */
1583
1584 /* {{{ proto string http_negotiate_language(array supported[, string default = 'en-US'])
1585 *
1586 * This function negotiates the clients preferred language based on its
1587 * Accept-Language HTTP header. It returns the negotiated language or
1588 * the default language if none match.
1589 *
1590 * The qualifier is recognized and languages without qualifier are rated highest.
1591 *
1592 * The supported parameter is expected to be an array having
1593 * the supported languages as array values.
1594 *
1595 * Example:
1596 * <pre>
1597 * <?php
1598 * $langs = array(
1599 * 'en-US',// default
1600 * 'fr',
1601 * 'fr-FR',
1602 * 'de',
1603 * 'de-DE',
1604 * 'de-AT',
1605 * 'de-CH',
1606 * );
1607 * include './langs/'. http_negotiate_language($langs) .'.php';
1608 * ?>
1609 * </pre>
1610 *
1611 */
1612 PHP_FUNCTION(http_negotiate_language)
1613 {
1614 zval *supported;
1615 char *def = NULL;
1616 int def_len = 0;
1617
1618 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
1619 RETURN_FALSE;
1620 }
1621
1622 if (!def) {
1623 def = "en-US";
1624 }
1625
1626 RETURN_STRING(http_negotiate_language(supported, def), 0);
1627 }
1628 /* }}} */
1629
1630 /* {{{ proto string http_negotiate_charset(array supported[, string default = 'iso-8859-1'])
1631 *
1632 * This function negotiates the clients preferred charset based on its
1633 * Accept-Charset HTTP header. It returns the negotiated charset or
1634 * the default charset if none match.
1635 *
1636 * The qualifier is recognized and charset without qualifier are rated highest.
1637 *
1638 * The supported parameter is expected to be an array having
1639 * the supported charsets as array values.
1640 *
1641 * Example:
1642 * <pre>
1643 * <?php
1644 * $charsets = array(
1645 * 'iso-8859-1', // default
1646 * 'iso-8859-2',
1647 * 'iso-8859-15',
1648 * 'utf-8'
1649 * );
1650 * $pref = http_negotiate_charset($charsets);
1651 * if (!strcmp($pref, 'iso-8859-1')) {
1652 * iconv_set_encoding('internal_encoding', 'iso-8859-1');
1653 * iconv_set_encoding('output_encoding', $pref);
1654 * ob_start('ob_iconv_handler');
1655 * }
1656 * ?>
1657 * </pre>
1658 */
1659 PHP_FUNCTION(http_negotiate_charset)
1660 {
1661 zval *supported;
1662 char *def = NULL;
1663 int def_len = 0;
1664
1665 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|s", &supported, &def, &def_len) != SUCCESS) {
1666 RETURN_FALSE;
1667 }
1668
1669 if (!def) {
1670 def = "iso-8859-1";
1671 }
1672
1673 RETURN_STRING(http_negotiate_charset(supported, def), 0);
1674 }
1675 /* }}} */
1676
1677 /* {{{ proto bool http_send_status(int status)
1678 *
1679 * Send HTTP status code.
1680 *
1681 */
1682 PHP_FUNCTION(http_send_status)
1683 {
1684 int status = 0;
1685
1686 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status) != SUCCESS) {
1687 RETURN_FALSE;
1688 }
1689 if (status < 100 || status > 510) {
1690 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid HTTP status code (100-510): %d", status);
1691 RETURN_FALSE;
1692 }
1693
1694 RETURN_SUCCESS(http_send_status(status));
1695 }
1696 /* }}} */
1697
1698 /* {{{ proto bool http_send_last_modified([int timestamp])
1699 *
1700 * This converts the given timestamp to a valid HTTP date and
1701 * sends it as "Last-Modified" HTTP header. If timestamp is
1702 * omitted, current time is sent.
1703 *
1704 */
1705 PHP_FUNCTION(http_send_last_modified)
1706 {
1707 long t = -1;
1708
1709 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
1710 RETURN_FALSE;
1711 }
1712
1713 if (t == -1) {
1714 t = (long) time(NULL);
1715 }
1716
1717 RETURN_SUCCESS(http_send_last_modified(t));
1718 }
1719 /* }}} */
1720
1721 /* {{{ proto bool http_send_content_type([string content_type = 'application/x-octetstream'])
1722 *
1723 * Sets the content type.
1724 *
1725 */
1726 PHP_FUNCTION(http_send_content_type)
1727 {
1728 char *ct;
1729 int ct_len = 0;
1730
1731 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &ct, &ct_len) != SUCCESS) {
1732 RETURN_FALSE;
1733 }
1734
1735 if (!ct_len) {
1736 RETURN_SUCCESS(http_send_content_type("application/x-octetstream", sizeof("application/x-octetstream") - 1));
1737 }
1738 RETURN_SUCCESS(http_send_content_type(ct, ct_len));
1739 }
1740 /* }}} */
1741
1742 /* {{{ proto bool http_send_content_disposition(string filename[, bool inline = false])
1743 *
1744 * Set the Content Disposition. The Content-Disposition header is very useful
1745 * if the data actually sent came from a file or something similar, that should
1746 * be "saved" by the client/user (i.e. by browsers "Save as..." popup window).
1747 *
1748 */
1749 PHP_FUNCTION(http_send_content_disposition)
1750 {
1751 char *filename;
1752 int f_len;
1753 zend_bool send_inline = 0;
1754
1755 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &filename, &f_len, &send_inline) != SUCCESS) {
1756 RETURN_FALSE;
1757 }
1758 RETURN_SUCCESS(http_send_content_disposition(filename, f_len, send_inline));
1759 }
1760 /* }}} */
1761
1762 /* {{{ proto bool http_match_modified([int timestamp])
1763 *
1764 * Matches the given timestamp against the clients "If-Modified-Since" resp.
1765 * "If-Unmodified-Since" HTTP headers.
1766 *
1767 */
1768 PHP_FUNCTION(http_match_modified)
1769 {
1770 long t = -1;
1771
1772 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
1773 RETURN_FALSE;
1774 }
1775
1776 // current time if not supplied (senseless though)
1777 if (t == -1) {
1778 t = (long) time(NULL);
1779 }
1780
1781 RETURN_BOOL(http_modified_match("HTTP_IF_MODIFIED_SINCE", t) || http_modified_match("HTTP_IF_UNMODIFIED_SINCE", t));
1782 }
1783 /* }}} */
1784
1785 /* {{{ proto bool http_match_etag(string etag)
1786 *
1787 * This matches the given ETag against the clients
1788 * "If-Match" resp. "If-None-Match" HTTP headers.
1789 *
1790 */
1791 PHP_FUNCTION(http_match_etag)
1792 {
1793 int etag_len;
1794 char *etag;
1795
1796 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len) != SUCCESS) {
1797 RETURN_FALSE;
1798 }
1799
1800 RETURN_BOOL(http_etag_match("HTTP_IF_NONE_MATCH", etag) || http_etag_match("HTTP_IF_MATCH", etag));
1801 }
1802 /* }}} */
1803
1804 /* {{{ proto bool http_cache_last_modified([int timestamp_or_expires]])
1805 *
1806 * If timestamp_or_exires is greater than 0, it is handled as timestamp
1807 * and will be sent as date of last modification. If it is 0 or omitted,
1808 * the current time will be sent as Last-Modified date. If it's negative,
1809 * it is handled as expiration time in seconds, which means that if the
1810 * requested last modification date is not between the calculated timespan,
1811 * the Last-Modified header is updated and the actual body will be sent.
1812 *
1813 */
1814 PHP_FUNCTION(http_cache_last_modified)
1815 {
1816 long last_modified = 0, send_modified = 0, t;
1817 zval *zlm;
1818
1819 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) {
1820 RETURN_FALSE;
1821 }
1822
1823 t = (long) time(NULL);
1824
1825 /* 0 or omitted */
1826 if (!last_modified) {
1827 /* does the client have? (att: caching "forever") */
1828 if (zlm = http_get_server_var("HTTP_IF_MODIFIED_SINCE")) {
1829 last_modified = send_modified = http_parse_date(Z_STRVAL_P(zlm));
1830 /* send current time */
1831 } else {
1832 send_modified = t;
1833 }
1834 /* negative value is supposed to be expiration time */
1835 } else if (last_modified < 0) {
1836 last_modified += t;
1837 send_modified = t;
1838 /* send supplied time explicitly */
1839 } else {
1840 send_modified = last_modified;
1841 }
1842
1843 RETURN_SUCCESS(http_cache_last_modified(last_modified, send_modified, HTTP_DEFAULT_CACHECONTROL, sizeof(HTTP_DEFAULT_CACHECONTROL) - 1));
1844 }
1845 /* }}} */
1846
1847 /* {{{ proto bool http_cache_etag([string etag])
1848 *
1849 * This function attempts to cache the HTTP body based on an ETag,
1850 * either supplied or generated through calculation of the MD5
1851 * checksum of the output (uses output buffering).
1852 *
1853 * If clients "If-None-Match" header matches the supplied/calculated
1854 * ETag, the body is considered cached on the clients side and
1855 * a "304 Not Modified" status code is issued.
1856 *
1857 */
1858 PHP_FUNCTION(http_cache_etag)
1859 {
1860 char *etag;
1861 int etag_len = 0;
1862
1863 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) {
1864 RETURN_FALSE;
1865 }
1866
1867 RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, sizeof(HTTP_DEFAULT_CACHECONTROL) - 1));
1868 }
1869 /* }}} */
1870
1871 /* {{{ proto string ob_httpetaghandler(string data, int mode)
1872 *
1873 * For use with ob_start().
1874 * Note that this has to be started as first output buffer.
1875 * WARNING: Don't use with http_send_*().
1876 */
1877 PHP_FUNCTION(ob_httpetaghandler)
1878 {
1879 char *data;
1880 int data_len;
1881 long mode;
1882
1883 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &data, &data_len, &mode)) {
1884 RETURN_FALSE;
1885 }
1886
1887 if (mode & PHP_OUTPUT_HANDLER_START) {
1888 if (HTTP_G(etag_started)) {
1889 php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_httpetaghandler can only be used once");
1890 RETURN_STRINGL(data, data_len, 1);
1891 }
1892 http_send_header("Cache-Control: " HTTP_DEFAULT_CACHECONTROL);
1893 HTTP_G(etag_started) = 1;
1894 }
1895
1896 if (OG(ob_nesting_level) > 1) {
1897 php_error_docref(NULL TSRMLS_CC, E_WARNING, "ob_httpetaghandler must be started prior to other output buffers");
1898 RETURN_STRINGL(data, data_len, 1);
1899 }
1900
1901 Z_TYPE_P(return_value) = IS_STRING;
1902 http_ob_etaghandler(data, data_len, &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), mode);
1903 }
1904 /* }}} */
1905
1906 /* {{{ proto void http_redirect([string url[, array params[, bool session,[ bool permanent]]]])
1907 *
1908 * Redirect to a given url.
1909 * The supplied url will be expanded with http_absolute_uri(), the params array will
1910 * be treated with http_build_query() and the session identification will be appended
1911 * if session is true.
1912 *
1913 * Depending on permanent the redirection will be issued with a permanent
1914 * ("301 Moved Permanently") or a temporary ("302 Found") redirection
1915 * status code.
1916 *
1917 * To be RFC compliant, "Redirecting to <a>URI</a>." will be displayed,
1918 * if the client doesn't redirect immediatly.
1919 */
1920 PHP_FUNCTION(http_redirect)
1921 {
1922 int url_len;
1923 zend_bool session = 0, permanent = 0;
1924 zval *params = NULL;
1925 smart_str qstr = {0};
1926 char *url, *URI, LOC[HTTP_URI_MAXLEN + 9], RED[HTTP_URI_MAXLEN * 2 + 34];
1927
1928 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sa!/bb", &url, &url_len, &params, &session, &permanent) != SUCCESS) {
1929 RETURN_FALSE;
1930 }
1931
1932 /* append session info */
1933 if (session && (PS(session_status) == php_session_active)) {
1934 if (!params) {
1935 MAKE_STD_ZVAL(params);
1936 array_init(params);
1937 }
1938 if (add_assoc_string(params, PS(session_name), PS(id), 1) != SUCCESS) {
1939 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not append session information");
1940 }
1941 }
1942
1943 /* treat params array with http_build_query() */
1944 if (params) {
1945 if (php_url_encode_hash_ex(Z_ARRVAL_P(params), &qstr, NULL,0,NULL,0,NULL,0,NULL TSRMLS_CC) != SUCCESS) {
1946 if (qstr.c) {
1947 efree(qstr.c);
1948 }
1949 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not encode query parameters");
1950 RETURN_FALSE;
1951 }
1952 smart_str_0(&qstr);
1953 }
1954
1955 URI = http_absolute_uri(url, NULL);
1956 if (qstr.c) {
1957 snprintf(LOC, HTTP_URI_MAXLEN + strlen("Location: "), "Location: %s?%s", URI, qstr.c);
1958 sprintf(RED, "Redirecting to <a href=\"%s?%s\">%s?%s</a>.\n", URI, qstr.c, URI, qstr.c);
1959 efree(qstr.c);
1960 } else {
1961 snprintf(LOC, HTTP_URI_MAXLEN + strlen("Location: "), "Location: %s", URI);
1962 sprintf(RED, "Redirecting to <a href=\"%s\">%s</a>.\n", URI, URI);
1963 }
1964 efree(URI);
1965
1966 if ((SUCCESS == http_send_header(LOC)) && (SUCCESS == http_send_status((permanent ? 301 : 302)))) {
1967 php_body_write(RED, strlen(RED) TSRMLS_CC);
1968 RETURN_TRUE;
1969 }
1970 RETURN_FALSE;
1971 }
1972 /* }}} */
1973
1974 /* {{{ proto bool http_send_data(string data)
1975 *
1976 * Sends raw data with support for (multiple) range requests.
1977 *
1978 */
1979 PHP_FUNCTION(http_send_data)
1980 {
1981 zval *zdata;
1982
1983 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zdata) != SUCCESS) {
1984 RETURN_FALSE;
1985 }
1986
1987 convert_to_string_ex(&zdata);
1988 http_send_header("Accept-Ranges: bytes");
1989 RETURN_SUCCESS(http_send_data(zdata));
1990 }
1991 /* }}} */
1992
1993 /* {{{ proto bool http_send_file(string file)
1994 *
1995 * Sends a file with support for (multiple) range requests.
1996 *
1997 */
1998 PHP_FUNCTION(http_send_file)
1999 {
2000 zval *zfile;
2001
2002 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zfile) != SUCCESS) {
2003 RETURN_FALSE;
2004 }
2005
2006 convert_to_string_ex(&zfile);
2007 http_send_header("Accept-Ranges: bytes");
2008 RETURN_SUCCESS(http_send_file(zfile));
2009 }
2010 /* }}} */
2011
2012 /* {{{ proto bool http_send_stream(resource stream)
2013 *
2014 * Sends an already opened stream with support for (multiple) range requests.
2015 *
2016 */
2017 PHP_FUNCTION(http_send_stream)
2018 {
2019 zval *zstream;
2020 php_stream *file;
2021
2022 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) != SUCCESS) {
2023 RETURN_FALSE;
2024 }
2025
2026 php_stream_from_zval(file, &zstream);
2027 http_send_header("Accept-Ranges: bytes");
2028 RETURN_SUCCESS(http_send_stream(file));
2029 }
2030 /* }}} */
2031
2032 /* {{{ proto string http_chunked_decode(string encoded)
2033 *
2034 * This function decodes a string that was HTTP-chunked encoded.
2035 * Returns false on failure.
2036 */
2037 PHP_FUNCTION(http_chunked_decode)
2038 {
2039 char *encoded = NULL, *decoded = NULL;
2040 int encoded_len = 0, decoded_len = 0;
2041
2042 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoded, &encoded_len) != SUCCESS) {
2043 RETURN_FALSE;
2044 }
2045
2046 if (SUCCESS == http_chunked_decode(encoded, encoded_len, &decoded, &decoded_len)) {
2047 RETURN_STRINGL(decoded, decoded_len, 0);
2048 } else {
2049 RETURN_FALSE;
2050 }
2051 }
2052 /* }}} */
2053
2054 /* {{{ proto array http_split_response(string http_response)
2055 *
2056 * This function splits an HTTP response into an array with headers and the
2057 * content body. The returned array may look simliar to the following example:
2058 *
2059 * <pre>
2060 * <?php
2061 * array(
2062 * 0 => array(
2063 * 'Status' => '200 Ok',
2064 * 'Content-Type' => 'text/plain',
2065 * 'Content-Language' => 'en-US'
2066 * ),
2067 * 1 => "Hello World!"
2068 * );
2069 * ?>
2070 * </pre>
2071 */
2072 PHP_FUNCTION(http_split_response)
2073 {
2074 zval *zresponse, *zbody, *zheaders;
2075
2076 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zresponse) != SUCCESS) {
2077 RETURN_FALSE;
2078 }
2079
2080 convert_to_string_ex(&zresponse);
2081
2082 MAKE_STD_ZVAL(zbody);
2083 MAKE_STD_ZVAL(zheaders);
2084 array_init(zheaders);
2085
2086 if (SUCCESS != http_split_response(zresponse, zheaders, zbody)) {
2087 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP response");
2088 RETURN_FALSE;
2089 }
2090
2091 array_init(return_value);
2092 add_index_zval(return_value, 0, zheaders);
2093 add_index_zval(return_value, 1, zbody);
2094 }
2095 /* }}} */
2096
2097 /* {{{ proto array http_parse_headers(string header)
2098 *
2099 */
2100 PHP_FUNCTION(http_parse_headers)
2101 {
2102 char *header, *rnrn;
2103 int header_len;
2104
2105 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &header, &header_len)) {
2106 RETURN_FALSE;
2107 }
2108
2109 array_init(return_value);
2110
2111 if (rnrn = strstr(header, HTTP_CRLF HTTP_CRLF)) {
2112 header_len = rnrn - header + 2;
2113 }
2114 if (SUCCESS != http_parse_headers(header, header_len, return_value)) {
2115 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP header");
2116 zval_dtor(return_value);
2117 RETURN_FALSE;
2118 }
2119 }
2120 /* }}}*/
2121
2122 /* {{{ proto array http_get_request_headers(void)
2123 *
2124 */
2125 PHP_FUNCTION(http_get_request_headers)
2126 {
2127 if (ZEND_NUM_ARGS()) {
2128 WRONG_PARAM_COUNT;
2129 }
2130
2131 array_init(return_value);
2132 http_get_request_headers(return_value);
2133 }
2134 /* }}} */
2135
2136 /* {{{ HAVE_CURL */
2137 #ifdef HTTP_HAVE_CURL
2138
2139 /* {{{ proto string http_get(string url[, array options[, array &info]])
2140 *
2141 * Performs an HTTP GET request on the supplied url.
2142 *
2143 * The second parameter is expected to be an associative
2144 * array where the following keys will be recognized:
2145 * <pre>
2146 * - redirect: int, whether and how many redirects to follow
2147 * - unrestrictedauth: bool, whether to continue sending credentials on
2148 * redirects to a different host
2149 * - proxyhost: string, proxy host in "host[:port]" format
2150 * - proxyport: int, use another proxy port as specified in proxyhost
2151 * - proxyauth: string, proxy credentials in "user:pass" format
2152 * - proxyauthtype: int, HTTP_AUTH_BASIC and/or HTTP_AUTH_NTLM
2153 * - httpauth: string, http credentials in "user:pass" format
2154 * - httpauthtype: int, HTTP_AUTH_BASIC, DIGEST and/or NTLM
2155 * - compress: bool, whether to allow gzip/deflate content encoding
2156 * (defaults to true)
2157 * - port: int, use another port as specified in the url
2158 * - referer: string, the referer to sends
2159 * - useragent: string, the user agent to send
2160 * (defaults to PECL::HTTP/version (PHP/version)))
2161 * - headers: array, list of custom headers as associative array
2162 * like array("header" => "value")
2163 * - cookies: array, list of cookies as associative array
2164 * like array("cookie" => "value")
2165 * - cookiestore: string, path to a file where cookies are/will be stored
2166 * </pre>
2167 *
2168 * The optional third parameter will be filled with some additional information
2169 * in form af an associative array, if supplied, like the following example:
2170 * <pre>
2171 * <?php
2172 * array (
2173 * 'effective_url' => 'http://localhost',
2174 * 'response_code' => 403,
2175 * 'total_time' => 0.017,
2176 * 'namelookup_time' => 0.013,
2177 * 'connect_time' => 0.014,
2178 * 'pretransfer_time' => 0.014,
2179 * 'size_upload' => 0,
2180 * 'size_download' => 202,
2181 * 'speed_download' => 11882,
2182 * 'speed_upload' => 0,
2183 * 'header_size' => 145,
2184 * 'request_size' => 62,
2185 * 'ssl_verifyresult' => 0,
2186 * 'filetime' => -1,
2187 * 'content_length_download' => 202,
2188 * 'content_length_upload' => 0,
2189 * 'starttransfer_time' => 0.017,
2190 * 'content_type' => 'text/html; charset=iso-8859-1',
2191 * 'redirect_time' => 0,
2192 * 'redirect_count' => 0,
2193 * 'private' => '',
2194 * 'http_connectcode' => 0,
2195 * 'httpauth_avail' => 0,
2196 * 'proxyauth_avail' => 0,
2197 * )
2198 * ?>
2199 * </pre>
2200 */
2201 PHP_FUNCTION(http_get)
2202 {
2203 char *URL, *data = NULL;
2204 size_t data_len = 0;
2205 int URL_len;
2206 zval *options = NULL, *info = NULL;
2207
2208 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
2209 RETURN_FALSE;
2210 }
2211
2212 if (info) {
2213 zval_dtor(info);
2214 array_init(info);
2215 }
2216
2217 if (SUCCESS == http_get(URL, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
2218 RETURN_STRINGL(data, data_len, 0);
2219 } else {
2220 RETURN_FALSE;
2221 }
2222 }
2223 /* }}} */
2224
2225 /* {{{ proto string http_head(string url[, array options[, array &info]])
2226 *
2227 * Performs an HTTP HEAD request on the suppied url.
2228 * Returns the HTTP response as string.
2229 * See http_get() for a full list of available options.
2230 */
2231 PHP_FUNCTION(http_head)
2232 {
2233 char *URL, *data = NULL;
2234 size_t data_len = 0;
2235 int URL_len;
2236 zval *options = NULL, *info = NULL;
2237
2238 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a/!z", &URL, &URL_len, &options, &info) != SUCCESS) {
2239 RETURN_FALSE;
2240 }
2241
2242 if (info) {
2243 zval_dtor(info);
2244 array_init(info);
2245 }
2246
2247 if (SUCCESS == http_head(URL, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
2248 RETURN_STRINGL(data, data_len, 0);
2249 } else {
2250 RETURN_FALSE;
2251 }
2252 }
2253 /* }}} */
2254
2255 /* {{{ proto string http_post_data(string url, string data[, array options[, &info]])
2256 *
2257 * Performs an HTTP POST request, posting data.
2258 * Returns the HTTP response as string.
2259 * See http_get() for a full list of available options.
2260 */
2261 PHP_FUNCTION(http_post_data)
2262 {
2263 char *URL, *postdata, *data = NULL;
2264 size_t data_len = 0;
2265 int postdata_len, URL_len;
2266 zval *options = NULL, *info = NULL;
2267
2268 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a/!z", &URL, &URL_len, &postdata, &postdata_len, &options, &info) != SUCCESS) {
2269 RETURN_FALSE;
2270 }
2271
2272 if (info) {
2273 zval_dtor(info);
2274 array_init(info);
2275 }
2276
2277 if (SUCCESS == http_post_data(URL, postdata, (size_t) postdata_len, HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
2278 RETURN_STRINGL(data, data_len, 0);
2279 } else {
2280 RETURN_FALSE;
2281 }
2282 }
2283 /* }}} */
2284
2285 /* {{{ proto string http_post_array(string url, array data[, array options[, array &info]])
2286 *
2287 * Performs an HTTP POST request, posting www-form-urlencoded array data.
2288 * Returns the HTTP response as string.
2289 * See http_get() for a full list of available options.
2290 */
2291 PHP_FUNCTION(http_post_array)
2292 {
2293 char *URL, *data = NULL;
2294 size_t data_len = 0;
2295 int URL_len;
2296 zval *options = NULL, *info = NULL, *postdata;
2297
2298 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|a/!z", &URL, &URL_len, &postdata, &options, &info) != SUCCESS) {
2299 RETURN_FALSE;
2300 }
2301
2302 if (info) {
2303 zval_dtor(info);
2304 array_init(info);
2305 }
2306
2307 if (SUCCESS == http_post_array(URL, Z_ARRVAL_P(postdata), HASH_ORNULL(options), HASH_ORNULL(info), &data, &data_len)) {
2308 RETURN_STRINGL(data, data_len, 0);
2309 } else {
2310 RETURN_FALSE;
2311 }
2312 }
2313 /* }}} */
2314
2315 #endif
2316 /* }}} HAVE_CURL */
2317
2318
2319 /* {{{ proto bool http_auth_basic(string user, string pass[, string realm = "Restricted"])
2320 *
2321 * Example:
2322 * <pre>
2323 * <?php
2324 * if (!http_auth_basic('mike', 's3c|r3t')) {
2325 * die('<h1>Authorization failed!</h1>');
2326 * }
2327 * ?>
2328 * </pre>
2329 */
2330 PHP_FUNCTION(http_auth_basic)
2331 {
2332 char *realm = NULL, *user, *pass, *suser, *spass;
2333 int r_len, u_len, p_len;
2334
2335 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", &user, &u_len, &pass, &p_len, &realm, &r_len) != SUCCESS) {
2336 RETURN_FALSE;
2337 }
2338
2339 if (!realm) {
2340 realm = "Restricted";
2341 }
2342
2343 if (SUCCESS != http_auth_credentials(&suser, &spass)) {
2344 http_auth_header("Basic", realm);
2345 RETURN_FALSE;
2346 }
2347
2348 if (strcasecmp(suser, user)) {
2349 http_auth_header("Basic", realm);
2350 RETURN_FALSE;
2351 }
2352
2353 if (strcmp(spass, pass)) {
2354 http_auth_header("Basic", realm);
2355 RETURN_FALSE;
2356 }
2357
2358 RETURN_TRUE;
2359 }
2360 /* }}} */
2361
2362 /* {{{ proto bool http_auth_basic_cb(mixed callback[, string realm = "Restricted"])
2363 *
2364 * Example:
2365 * <pre>
2366 * <?php
2367 * function auth_cb($user, $pass)
2368 * {
2369 * global $db;
2370 * $query = 'SELECT pass FROM users WHERE user='. $db->quoteSmart($user);
2371 * if (strlen($realpass = $db->getOne($query)) {
2372 * return $pass === $realpass;
2373 * }
2374 * return false;
2375 * }
2376 *
2377 * if (!http_auth_basic_cb('auth_cb')) {
2378 * die('<h1>Authorization failed</h1>');
2379 * }
2380 * ?>
2381 * </pre>
2382 */
2383 PHP_FUNCTION(http_auth_basic_cb)
2384 {
2385 zval *cb;
2386 char *realm = NULL, *user, *pass;
2387 int r_len;
2388
2389 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &cb, &realm, &r_len) != SUCCESS) {
2390 RETURN_FALSE;
2391 }
2392
2393 if (!realm) {
2394 realm = "Restricted";
2395 }
2396
2397 if (SUCCESS != http_auth_credentials(&user, &pass)) {
2398 http_auth_header("Basic", realm);
2399 RETURN_FALSE;
2400 }
2401 {
2402 zval *zparams[2] = {NULL, NULL}, retval;
2403 int result = 0;
2404
2405 MAKE_STD_ZVAL(zparams[0]);
2406 MAKE_STD_ZVAL(zparams[1]);
2407 ZVAL_STRING(zparams[0], user, 0);
2408 ZVAL_STRING(zparams[1], pass, 0);
2409
2410 if (SUCCESS == call_user_function(EG(function_table), NULL, cb,
2411 &retval, 2, zparams TSRMLS_CC)) {
2412 result = Z_LVAL(retval);
2413 }
2414
2415 efree(user);
2416 efree(pass);
2417 efree(zparams[0]);
2418 efree(zparams[1]);
2419
2420 if (!result) {
2421 http_auth_header("Basic", realm);
2422 }
2423
2424 RETURN_BOOL(result);
2425 }
2426 }
2427 /* }}}*/
2428
2429
2430 /* {{{ php_http_init_globals(zend_http_globals *) */
2431 static void php_http_init_globals(zend_http_globals *http_globals)
2432 {
2433 http_globals->etag_started = 0;
2434 http_globals->ctype = NULL;
2435 http_globals->etag = NULL;
2436 http_globals->lmod = 0;
2437 #ifdef HTTP_HAVE_CURL
2438 http_globals->curlbuf.body.data = NULL;
2439 http_globals->curlbuf.body.used = 0;
2440 http_globals->curlbuf.body.free = 0;
2441 http_globals->curlbuf.hdrs.data = NULL;
2442 http_globals->curlbuf.hdrs.used = 0;
2443 http_globals->curlbuf.hdrs.free = 0;
2444 #endif
2445 http_globals->allowed_methods = NULL;
2446 }
2447 /* }}} */
2448
2449 /* {{{ static inline STATUS http_check_allowed_methods(char *, int) */
2450 #define http_check_allowed_methods(m, l) _http_check_allowed_methods((m), (l) TSRMLS_CC)
2451 static inline void _http_check_allowed_methods(char *methods, int length TSRMLS_DC)
2452 {
2453 if (length && SG(request_info).request_method && (!strstr(methods, SG(request_info).request_method))) {
2454 char *allow_header = emalloc(length + sizeof("Allow: "));
2455 sprintf(allow_header, "Allow: %s", methods);
2456 http_send_header(allow_header);
2457 efree(allow_header);
2458 http_send_status(405);
2459 zend_bailout();
2460 }
2461 }
2462 /* }}} */
2463
2464 /* {{{ PHP_INI */
2465 PHP_INI_MH(update_allowed_methods)
2466 {
2467 http_check_allowed_methods(new_value, new_value_length);
2468 return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
2469 }
2470
2471 PHP_INI_BEGIN()
2472 STD_PHP_INI_ENTRY("http.allowed_methods", "OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,CONNECT", PHP_INI_ALL, update_allowed_methods, allowed_methods, zend_http_globals, http_globals)
2473 PHP_INI_END()
2474 /* }}} */
2475
2476 /* {{{ PHP_MINIT_FUNCTION */
2477 PHP_MINIT_FUNCTION(http)
2478 {
2479 ZEND_INIT_MODULE_GLOBALS(http, php_http_init_globals, NULL);
2480 REGISTER_INI_ENTRIES();
2481
2482 #if defined(HTTP_HAVE_CURL) && (LIBCURL_VERSION_NUM >= 0x070a05)
2483 REGISTER_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC, CONST_CS | CONST_PERSISTENT);
2484 REGISTER_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS | CONST_PERSISTENT);
2485 REGISTER_LONG_CONSTANT("HTTP_AUTH_NTLM", CURLAUTH_NTLM, CONST_CS | CONST_PERSISTENT);
2486 #endif
2487
2488 #ifdef ZEND_ENGINE_2
2489 HTTP_REGISTER_CLASS(HTTPi, httpi, NULL, ZEND_ACC_FINAL_CLASS);
2490 HTTP_REGISTER_CLASS_EX(HTTPi_Response, httpi_response, NULL, 0);
2491 # ifdef HTTP_HAVE_CURL
2492 HTTP_REGISTER_CLASS_EX(HTTPi_Request, httpi_request, NULL, 0);
2493 REGISTER_LONG_CONSTANT("HTTP_GET", HTTP_GET, CONST_CS | CONST_PERSISTENT);
2494 REGISTER_LONG_CONSTANT("HTTP_HEAD", HTTP_HEAD, CONST_CS | CONST_PERSISTENT);
2495 REGISTER_LONG_CONSTANT("HTTP_POST", HTTP_POST, CONST_CS | CONST_PERSISTENT);
2496 # endif /* HTTP_HAVE_CURL */
2497 #endif /* ZEND_ENGINE_2 */
2498 return SUCCESS;
2499 }
2500 /* }}} */
2501
2502 /* {{{ PHP_MSHUTDOWN_FUNCTION */
2503 PHP_MSHUTDOWN_FUNCTION(http)
2504 {
2505 UNREGISTER_INI_ENTRIES();
2506 return SUCCESS;
2507 }
2508 /* }}} */
2509
2510 /* {{{ PHP_RINIT_FUNCTION */
2511 PHP_RINIT_FUNCTION(http)
2512 {
2513 char *allowed_methods = INI_STR("http.allowed_methods");
2514 http_check_allowed_methods(allowed_methods, strlen(allowed_methods));
2515 return SUCCESS;
2516 }
2517 /* }}} */
2518
2519 /* {{{ PHP_RSHUTDOWN_FUNCTION */
2520 PHP_RSHUTDOWN_FUNCTION(http)
2521 {
2522 HTTP_G(etag_started) = 0;
2523 HTTP_G(lmod) = 0;
2524
2525 if (HTTP_G(etag)) {
2526 efree(HTTP_G(etag));
2527 HTTP_G(etag) = NULL;
2528 }
2529
2530 if (HTTP_G(ctype)) {
2531 efree(HTTP_G(ctype));
2532 HTTP_G(ctype) = NULL;
2533 }
2534 #ifdef HTTP_HAVE_CURL
2535 if (HTTP_G(curlbuf).body.data) {
2536 efree(HTTP_G(curlbuf).body.data);
2537 HTTP_G(curlbuf).body.data = NULL;
2538 }
2539 if (HTTP_G(curlbuf).hdrs.data) {
2540 efree(HTTP_G(curlbuf).hdrs.data);
2541 HTTP_G(curlbuf).hdrs.data = NULL;
2542 }
2543 #endif
2544 return SUCCESS;
2545 }
2546 /* }}} */
2547
2548 /* {{{ PHP_MINFO_FUNCTION */
2549 PHP_MINFO_FUNCTION(http)
2550 {
2551 php_info_print_table_start();
2552 php_info_print_table_header(2, "Extended HTTP support", "enabled");
2553 php_info_print_table_row(2, "Version:", PHP_EXT_HTTP_VERSION);
2554 php_info_print_table_row(2, "cURL convenience functions:",
2555 #ifdef HTTP_HAVE_CURL
2556 "enabled"
2557 #else
2558 "disabled"
2559 #endif
2560 );
2561 php_info_print_table_end();
2562
2563 DISPLAY_INI_ENTRIES();
2564 }
2565 /* }}} */
2566
2567 /*
2568 * Local variables:
2569 * tab-width: 4
2570 * c-basic-offset: 4
2571 * End:
2572 * vim600: noet sw=4 ts=4 fdm=marker
2573 * vim<600: noet sw=4 ts=4
2574 */
2575