- Fixed build with 5.4+
[m6w6/ext-http] / http.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_SAPI
16 #define HTTP_WANT_CURL
17 #define HTTP_WANT_EVENT
18 #define HTTP_WANT_ZLIB
19 #define HTTP_WANT_MAGIC
20 #include "php_http.h"
21
22 #include "php_ini.h"
23 #include "ext/standard/info.h"
24 #include "zend_extensions.h"
25
26 #include "php_http_api.h"
27 #include "php_http_cache_api.h"
28 #include "php_http_cookie_api.h"
29 #include "php_http_encoding_api.h"
30 #include "php_http_filter_api.h"
31 #include "php_http_message_api.h"
32 #include "php_http_persistent_handle_api.h"
33 #include "php_http_request_api.h"
34 #include "php_http_request_datashare_api.h"
35 #include "php_http_request_method_api.h"
36 #include "php_http_request_pool_api.h"
37 #include "php_http_send_api.h"
38 #include "php_http_url_api.h"
39
40 #include "php_http_deflatestream_object.h"
41 #include "php_http_exception_object.h"
42 #include "php_http_inflatestream_object.h"
43 #include "php_http_message_object.h"
44 #include "php_http_querystring_object.h"
45 #include "php_http_request_object.h"
46 #include "php_http_requestdatashare_object.h"
47 #include "php_http_requestpool_object.h"
48 #include "php_http_response_object.h"
49 #include "php_http_util_object.h"
50
51 ZEND_DECLARE_MODULE_GLOBALS(http);
52 HTTP_DECLARE_ARG_PASS_INFO();
53
54 #ifdef COMPILE_DL_HTTP
55 ZEND_GET_MODULE(http)
56 #endif
57
58 /* {{{ http_functions[] */
59 zend_function_entry http_functions[] = {
60 PHP_FE(http_date, NULL)
61 PHP_FE(http_build_url, http_arg_pass_ref_4)
62 PHP_FE(http_build_str, NULL)
63 #ifndef ZEND_ENGINE_2
64 PHP_FALIAS(http_build_query, http_build_str, NULL)
65 #endif
66 PHP_FE(http_negotiate_language, http_arg_pass_ref_2)
67 PHP_FE(http_negotiate_charset, http_arg_pass_ref_2)
68 PHP_FE(http_negotiate_content_type, http_arg_pass_ref_2)
69 PHP_FE(http_negotiate, http_arg_pass_ref_3)
70 PHP_FE(http_redirect, NULL)
71 PHP_FE(http_throttle, NULL)
72 PHP_FE(http_send_status, NULL)
73 PHP_FE(http_send_last_modified, NULL)
74 PHP_FE(http_send_content_type, NULL)
75 PHP_FE(http_send_content_disposition, NULL)
76 PHP_FE(http_match_modified, NULL)
77 PHP_FE(http_match_etag, NULL)
78 PHP_FE(http_cache_last_modified, NULL)
79 PHP_FE(http_cache_etag, NULL)
80 PHP_FE(http_send_data, NULL)
81 PHP_FE(http_send_file, NULL)
82 PHP_FE(http_send_stream, NULL)
83 PHP_FE(http_chunked_decode, NULL)
84 PHP_FE(http_parse_message, NULL)
85 PHP_FE(http_parse_headers, NULL)
86 PHP_FE(http_parse_cookie, NULL)
87 PHP_FE(http_build_cookie, NULL)
88 PHP_FE(http_parse_params, NULL)
89 PHP_FE(http_get_request_headers, NULL)
90 PHP_FE(http_get_request_body, NULL)
91 PHP_FE(http_get_request_body_stream, NULL)
92 PHP_FE(http_match_request_header, NULL)
93 PHP_FE(http_persistent_handles_count, NULL)
94 PHP_FE(http_persistent_handles_clean, NULL)
95 PHP_FE(http_persistent_handles_ident, NULL)
96 #ifdef HTTP_HAVE_CURL
97 PHP_FE(http_get, http_arg_pass_ref_3)
98 PHP_FE(http_head, http_arg_pass_ref_3)
99 PHP_FE(http_post_data, http_arg_pass_ref_4)
100 PHP_FE(http_post_fields, http_arg_pass_ref_5)
101 PHP_FE(http_put_data, http_arg_pass_ref_4)
102 PHP_FE(http_put_file, http_arg_pass_ref_4)
103 PHP_FE(http_put_stream, http_arg_pass_ref_4)
104 PHP_FE(http_request, http_arg_pass_ref_5)
105 PHP_FE(http_request_body_encode, NULL)
106 #endif
107 PHP_FE(http_request_method_register, NULL)
108 PHP_FE(http_request_method_unregister, NULL)
109 PHP_FE(http_request_method_exists, NULL)
110 PHP_FE(http_request_method_name, NULL)
111 PHP_FE(ob_etaghandler, NULL)
112 #ifdef HTTP_HAVE_ZLIB
113 PHP_FE(http_deflate, NULL)
114 PHP_FE(http_inflate, NULL)
115 PHP_FE(ob_deflatehandler, NULL)
116 PHP_FE(ob_inflatehandler, NULL)
117 #endif
118 PHP_FE(http_support, NULL)
119
120 EMPTY_FUNCTION_ENTRY
121 };
122 /* }}} */
123
124 PHP_MINIT_FUNCTION(http);
125 PHP_MSHUTDOWN_FUNCTION(http);
126 PHP_RINIT_FUNCTION(http);
127 PHP_RSHUTDOWN_FUNCTION(http);
128 PHP_MINFO_FUNCTION(http);
129
130 /* {{{ http_module_dep */
131 #if ZEND_EXTENSION_API_NO >= 220050617
132 static zend_module_dep http_module_deps[] = {
133 # ifdef HTTP_HAVE_SPL
134 ZEND_MOD_REQUIRED("spl")
135 # endif
136 # ifdef HTTP_HAVE_HASH
137 ZEND_MOD_REQUIRED("hash")
138 # endif
139 # ifdef HTTP_HAVE_SESSION
140 ZEND_MOD_REQUIRED("session")
141 # endif
142 # ifdef HTTP_HAVE_ICONV
143 ZEND_MOD_REQUIRED("iconv")
144 # endif
145 # ifdef HTTP_HAVE_EVENT
146 ZEND_MOD_CONFLICTS("event")
147 #endif
148 {NULL, NULL, NULL, 0}
149 };
150 #endif
151 /* }}} */
152
153 /* {{{ http_module_entry */
154 zend_module_entry http_module_entry = {
155 #if ZEND_EXTENSION_API_NO >= 220050617
156 STANDARD_MODULE_HEADER_EX, NULL,
157 http_module_deps,
158 #else
159 STANDARD_MODULE_HEADER,
160 #endif
161 "http",
162 http_functions,
163 PHP_MINIT(http),
164 PHP_MSHUTDOWN(http),
165 PHP_RINIT(http),
166 PHP_RSHUTDOWN(http),
167 PHP_MINFO(http),
168 PHP_HTTP_VERSION,
169 STANDARD_MODULE_PROPERTIES
170 };
171 /* }}} */
172
173 int http_module_number;
174
175 /* {{{ http_globals */
176 static void http_globals_init_once(zend_http_globals *G)
177 {
178 memset(G, 0, sizeof(zend_http_globals));
179 }
180
181 #define http_globals_init(g) _http_globals_init((g) TSRMLS_CC)
182 static inline void _http_globals_init(zend_http_globals *G TSRMLS_DC)
183 {
184 #ifdef HTTP_HAVE_SAPI_RTIME
185 G->request.time = sapi_get_request_time(TSRMLS_C);
186 #else
187 G->request.time = time(NULL);
188 #endif
189 G->send.buffer_size = 0;
190 G->read_post_data = 0;
191 }
192
193 #define http_globals_free(g) _http_globals_free((g) TSRMLS_CC)
194 static inline void _http_globals_free(zend_http_globals *G TSRMLS_DC)
195 {
196 if (G->request.headers) {
197 zend_hash_destroy(G->request.headers);
198 FREE_HASHTABLE(G->request.headers);
199 G->request.headers = NULL;
200 }
201 STR_SET(G->send.content_type, NULL);
202 STR_SET(G->send.unquoted_etag, NULL);
203 if (G->server_var) {
204 zval_ptr_dtor(&G->server_var);
205 G->server_var = NULL;
206 }
207 }
208
209 #if defined(ZTS) && defined(PHP_DEBUG)
210 #if ZTS && PHP_DEBUG
211 zend_http_globals *http_globals(void)
212 {
213 TSRMLS_FETCH();
214 return HTTP_G;
215 }
216 #endif
217 #endif
218 /* }}} */
219
220 /* {{{ static inline void http_check_allowed_methods(char *) */
221 #define http_check_allowed_methods(m) _http_check_allowed_methods((m) TSRMLS_CC)
222 static inline void _http_check_allowed_methods(const char *methods TSRMLS_DC)
223 {
224 if (*methods && SG(request_info).request_method) {
225 if (SUCCESS != http_check_method_ex(SG(request_info).request_method, methods)) {
226 char *header;
227 spprintf(&header, 0, "Allow: %s", methods);
228 http_exit(405, header);
229 }
230 }
231 }
232 /* }}} */
233
234 /* {{{ PHP_INI */
235 PHP_INI_MH(http_update_allowed_methods)
236 {
237 if (*new_value) {
238 http_check_allowed_methods(new_value);
239 }
240 return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
241 }
242 PHP_INI_MH(http_update_persistent_handle_ident)
243 {
244 HTTP_G->persistent.handles.ident.h = zend_hash_func(new_value, HTTP_G->persistent.handles.ident.l = new_value_length+1);
245 return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
246 }
247
248 #ifndef ZEND_ENGINE_2
249 # define OnUpdateLong OnUpdateInt
250 #endif
251
252 PHP_INI_BEGIN()
253 HTTP_PHP_INI_ENTRY("http.etag.mode", "MD5", PHP_INI_ALL, OnUpdateString, etag.mode)
254 HTTP_PHP_INI_ENTRY("http.log.cache", "", PHP_INI_ALL, OnUpdateString, log.cache)
255 HTTP_PHP_INI_ENTRY("http.log.redirect", "", PHP_INI_ALL, OnUpdateString, log.redirect)
256 HTTP_PHP_INI_ENTRY("http.log.not_found", "", PHP_INI_ALL, OnUpdateString, log.not_found)
257 HTTP_PHP_INI_ENTRY("http.log.allowed_methods", "", PHP_INI_ALL, OnUpdateString, log.allowed_methods)
258 HTTP_PHP_INI_ENTRY("http.log.composite", "", PHP_INI_ALL, OnUpdateString, log.composite)
259 HTTP_PHP_INI_ENTRY("http.request.methods.allowed", "", PHP_INI_ALL, http_update_allowed_methods, request.methods.allowed)
260 HTTP_PHP_INI_ENTRY("http.request.methods.custom", "", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateString, request.methods.custom)
261 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
262 HTTP_PHP_INI_ENTRY("http.request.datashare.cookie", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.cookie)
263 HTTP_PHP_INI_ENTRY("http.request.datashare.dns", "1", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.dns)
264 HTTP_PHP_INI_ENTRY("http.request.datashare.ssl", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.ssl)
265 HTTP_PHP_INI_ENTRY("http.request.datashare.connect", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.connect)
266 #endif
267 #ifdef HTTP_HAVE_ZLIB
268 HTTP_PHP_INI_ENTRY("http.send.inflate.start_auto", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, send.inflate.start_auto)
269 HTTP_PHP_INI_ENTRY("http.send.inflate.start_flags", "0", PHP_INI_ALL, OnUpdateLong, send.inflate.start_flags)
270 HTTP_PHP_INI_ENTRY("http.send.deflate.start_auto", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, send.deflate.start_auto)
271 HTTP_PHP_INI_ENTRY("http.send.deflate.start_flags", "0", PHP_INI_ALL, OnUpdateLong, send.deflate.start_flags)
272 #endif
273 HTTP_PHP_INI_ENTRY("http.persistent.handles.limit", "-1", PHP_INI_SYSTEM, OnUpdateLong, persistent.handles.limit)
274 HTTP_PHP_INI_ENTRY("http.persistent.handles.ident", "GLOBAL", PHP_INI_ALL, http_update_persistent_handle_ident, persistent.handles.ident.s)
275 HTTP_PHP_INI_ENTRY("http.send.not_found_404", "1", PHP_INI_ALL, OnUpdateBool, send.not_found_404)
276 #ifdef ZEND_ENGINE_2
277 HTTP_PHP_INI_ENTRY("http.only_exceptions", "0", PHP_INI_ALL, OnUpdateBool, only_exceptions)
278 #endif
279 HTTP_PHP_INI_ENTRY("http.force_exit", "1", PHP_INI_ALL, OnUpdateBool, force_exit)
280 PHP_INI_END()
281 /* }}} */
282
283 /* {{{ PHP_MINIT_FUNCTION */
284 PHP_MINIT_FUNCTION(http)
285 {
286 http_module_number = module_number;
287 ZEND_INIT_MODULE_GLOBALS(http, http_globals_init_once, NULL);
288 REGISTER_INI_ENTRIES();
289
290 if (0
291 || SUCCESS != PHP_MINIT_CALL(http_persistent_handle) /* first */
292 || SUCCESS != PHP_MINIT_CALL(http_cookie)
293 #ifdef HTTP_HAVE_ZLIB
294 || SUCCESS != PHP_MINIT_CALL(http_encoding)
295 #endif
296 #ifdef HTTP_HAVE_CURL
297 || SUCCESS != PHP_MINIT_CALL(http_request)
298 # ifdef ZEND_ENGINE_2
299 # endif
300 #endif
301 || SUCCESS != PHP_MINIT_CALL(http_request_method)
302 || SUCCESS != PHP_MINIT_CALL(http_send)
303 || SUCCESS != PHP_MINIT_CALL(http_support)
304 || SUCCESS != PHP_MINIT_CALL(http_url)
305
306 #ifdef ZEND_ENGINE_2
307 || SUCCESS != PHP_MINIT_CALL(http_filter)
308 || SUCCESS != PHP_MINIT_CALL(http_exception_object)
309 # ifdef HTTP_HAVE_ZLIB
310 || SUCCESS != PHP_MINIT_CALL(http_deflatestream_object)
311 || SUCCESS != PHP_MINIT_CALL(http_inflatestream_object)
312 # endif
313 || SUCCESS != PHP_MINIT_CALL(http_message_object)
314 || SUCCESS != PHP_MINIT_CALL(http_querystring_object)
315 # ifdef HTTP_HAVE_CURL
316 || SUCCESS != PHP_MINIT_CALL(http_request_datashare)
317 || SUCCESS != PHP_MINIT_CALL(http_request_pool)
318 || SUCCESS != PHP_MINIT_CALL(http_request_object)
319 || SUCCESS != PHP_MINIT_CALL(http_requestdatashare_object)
320 || SUCCESS != PHP_MINIT_CALL(http_requestpool_object)
321 # endif
322 # ifndef WONKY
323 || SUCCESS != PHP_MINIT_CALL(http_response_object)
324 # endif
325 || SUCCESS != PHP_MINIT_CALL(http_util_object)
326 #endif
327 ) {
328 return FAILURE;
329 }
330
331 return SUCCESS;
332 }
333 /* }}} */
334
335 /* {{{ PHP_MSHUTDOWN_FUNCTION */
336 PHP_MSHUTDOWN_FUNCTION(http)
337 {
338 UNREGISTER_INI_ENTRIES();
339
340 if (0
341 #ifdef HTTP_HAVE_CURL
342 || SUCCESS != PHP_MSHUTDOWN_CALL(http_request)
343 # ifdef ZEND_ENGINE_2
344 || SUCCESS != PHP_MSHUTDOWN_CALL(http_request_datashare)
345 # endif
346 #endif
347 || SUCCESS != PHP_MSHUTDOWN_CALL(http_message_object)
348 || SUCCESS != PHP_MSHUTDOWN_CALL(http_persistent_handle) /* last */
349 ) {
350 return FAILURE;
351 }
352
353 return SUCCESS;
354 }
355 /* }}} */
356
357 /* {{{ PHP_RINIT_FUNCTION */
358 PHP_RINIT_FUNCTION(http)
359 {
360 http_globals_init(HTTP_G);
361
362 if (HTTP_G->request.methods.allowed && *HTTP_G->request.methods.allowed) {
363 http_check_allowed_methods(HTTP_G->request.methods.allowed);
364 }
365
366 if (0
367 #ifdef HTTP_HAVE_ZLIB
368 || SUCCESS != PHP_RINIT_CALL(http_encoding)
369 #endif
370 #ifdef HTTP_HAVE_CURL
371 # ifdef ZEND_ENGINE_2
372 # ifdef HTTP_HAVE_EVENT
373 || SUCCESS != PHP_RINIT_CALL(http_request_pool)
374 # endif
375 || SUCCESS != PHP_RINIT_CALL(http_request_datashare)
376 # endif
377 #endif
378 || SUCCESS != PHP_RINIT_CALL(http_request_method)
379 ) {
380 return FAILURE;
381 }
382
383 return SUCCESS;
384 }
385 /* }}} */
386
387 /* {{{ PHP_RSHUTDOWN_FUNCTION */
388 PHP_RSHUTDOWN_FUNCTION(http)
389 {
390 STATUS status = SUCCESS;
391
392 if (0
393 #ifdef HTTP_HAVE_ZLIB
394 || SUCCESS != PHP_RSHUTDOWN_CALL(http_encoding)
395 #endif
396 #ifdef HTTP_HAVE_CURL
397 # ifdef ZEND_ENGINE_2
398 || SUCCESS != PHP_RSHUTDOWN_CALL(http_request_datashare)
399 # endif
400 #endif
401 || SUCCESS != PHP_RSHUTDOWN_CALL(http_request_method)
402 ) {
403 status = FAILURE;
404 }
405
406 http_globals_free(HTTP_G);
407 return status;
408 }
409 /* }}} */
410
411 /* {{{ PHP_MINFO_FUNCTION */
412 PHP_MINFO_FUNCTION(http)
413 {
414 php_info_print_table_start();
415 {
416 php_info_print_table_header(2, "HTTP Support", "enabled");
417 php_info_print_table_row(2, "Extension Version", PHP_HTTP_VERSION);
418 php_info_print_table_row(2, "Registered Classes",
419 #ifndef ZEND_ENGINE_2
420 "none"
421 #else
422 "HttpUtil, "
423 "HttpMessage, "
424 # ifdef HTTP_HAVE_CURL
425 "HttpRequest, "
426 "HttpRequestPool, "
427 "HttpRequestDataShare, "
428 # endif
429 # ifdef HTTP_HAVE_ZLIB
430 "HttpDeflateStream, "
431 "HttpInflateStream, "
432 # endif
433 # ifndef WONKY
434 "HttpResponse, "
435 # endif
436 "HttpQueryString"
437 #endif
438 );
439 php_info_print_table_row(2, "Output Handlers", "ob_deflatehandler, ob_inflatehandler, ob_etaghandler");
440 php_info_print_table_row(2, "Stream Filters",
441 #ifndef ZEND_ENGINE_2
442 "none"
443 #else
444 "http.chunked_decode, http.chunked_encode, http.deflate, http.inflate"
445 #endif
446 );
447 }
448 php_info_print_table_end();
449
450 php_info_print_table_start();
451 php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
452 {
453 #ifdef HTTP_HAVE_CURL
454 curl_version_info_data *cv = curl_version_info(CURLVERSION_NOW);
455 php_info_print_table_row(3, "libcurl", LIBCURL_VERSION, cv->version);
456 #else
457 php_info_print_table_row(2, "libcurl", "disabled", "disabled");
458 #endif
459 #ifdef HTTP_HAVE_EVENT
460 php_info_print_table_row(3, "libevent", HTTP_EVENT_VERSION, event_get_version());
461 #else
462 php_info_print_table_row(3, "libevent", "disabled", "disabled");
463 #endif
464 #ifdef HTTP_HAVE_ZLIB
465 php_info_print_table_row(3, "libz", ZLIB_VERSION, zlibVersion());
466 #else
467 php_info_print_table_row(3, "libz", "disabled", "disabled");
468 #endif
469 #if defined(HTTP_HAVE_MAGIC)
470 php_info_print_table_row(3, "libmagic", "unknown", "unknown");
471 #else
472 php_info_print_table_row(3, "libmagic", "disabled", "disabled");
473 #endif
474 }
475 php_info_print_table_end();
476
477 php_info_print_table_start();
478 php_info_print_table_colspan_header(4, "Persistent Handles");
479 php_info_print_table_header(4, "Provider", "Ident", "Used", "Free");
480 {
481 HashTable *ht;
482 HashPosition pos1, pos2;
483 HashKey provider = initHashKey(0), ident = initHashKey(0);
484 zval **val, **sub, **zused, **zfree;
485
486 if ((ht = http_persistent_handle_statall()) && zend_hash_num_elements(ht)) {
487 FOREACH_HASH_KEYVAL(pos1, ht, provider, val) {
488 if (zend_hash_num_elements(Z_ARRVAL_PP(val))) {
489 FOREACH_KEYVAL(pos2, *val, ident, sub) {
490 if ( SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("used"), (void *) &zused) &&
491 SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("free"), (void *) &zfree)) {
492 zval *used = http_zsep(IS_STRING, *zused);
493 zval *free = http_zsep(IS_STRING, *zfree);
494 php_info_print_table_row(4, provider.str, ident.str, Z_STRVAL_P(used), Z_STRVAL_P(free));
495 zval_ptr_dtor(&used);
496 zval_ptr_dtor(&free);
497 } else {
498 php_info_print_table_row(4, provider.str, ident.str, "0", "0");
499 }
500 }
501 } else {
502 php_info_print_table_row(4, provider.str, "N/A", "0", "0");
503 }
504 }
505 } else {
506 php_info_print_table_row(4, "N/A", "N/A", "0", "0");
507 }
508 if (ht) {
509 zend_hash_destroy(ht);
510 FREE_HASHTABLE(ht);
511 }
512 }
513 php_info_print_table_end();
514
515 php_info_print_table_start();
516 php_info_print_table_colspan_header(2, "Request Methods");
517 {
518 HashPosition pos;
519 phpstr *methods = phpstr_new();
520 char **name;
521
522 FOREACH_HASH_VAL(pos, &HTTP_G->request.methods.registered, name) {
523 if (pos->h) {
524 phpstr_appendf(methods, "%s, ", *name);
525 }
526 }
527 phpstr_fix(methods);
528 php_info_print_table_row(2, "Registered", PHPSTR_VAL(methods));
529 php_info_print_table_row(2, "Allowed", *HTTP_G->request.methods.allowed ? HTTP_G->request.methods.allowed : "(ANY)");
530 phpstr_free(&methods);
531 }
532 php_info_print_table_end();
533
534 DISPLAY_INI_ENTRIES();
535 }
536 /* }}} */
537
538 /*
539 * Local variables:
540 * tab-width: 4
541 * c-basic-offset: 4
542 * End:
543 * vim600: noet sw=4 ts=4 fdm=marker
544 * vim<600: noet sw=4 ts=4
545 */
546