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