From: Michael Wallner Date: Tue, 8 Nov 2005 14:07:23 +0000 (+0000) Subject: - added INI setting http.force_exit which can be used to disable script termination X-Git-Tag: RELEASE_0_18_0~24 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=8d25696948ed61d50c417275222117f43069ddd1 - added INI setting http.force_exit which can be used to disable script termination in case of redirects and positive cache hits (instead, standard output will be discarded) --- diff --git a/docs/http.ini b/docs/http.ini index bd575f2..372c1f3 100644 --- a/docs/http.ini +++ b/docs/http.ini @@ -3,7 +3,10 @@ [http] ; enable if you want to transform all errors to exceptions (PHP >= 5 only) -http.only_exceptions = 0 +;http.only_exceptions = 1 + +; disable if you want php not to exit in case of redirects and cache hits +;http.force_exit = 0 ; the hashing algorithm with wich ETags are generated ; you can use mhash constants if ext/mhash is enabled, or their diff --git a/http.c b/http.c index 888a1cf..a4b430a 100644 --- a/http.c +++ b/http.c @@ -258,10 +258,11 @@ PHP_INI_BEGIN() HTTP_PHP_INI_ENTRY("http.redirect_log", "", PHP_INI_ALL, OnUpdateString, log.redirect) HTTP_PHP_INI_ENTRY("http.allowed_methods_log", "", PHP_INI_ALL, OnUpdateString, log.allowed_methods) HTTP_PHP_INI_ENTRY("http.composite_log", "", PHP_INI_ALL, OnUpdateString, log.composite) + HTTP_PHP_INI_ENTRY_EX("http.etag_mode", "-2", PHP_INI_ALL, OnUpdateLong, http_etag_mode_displayer, etag.mode) #ifdef ZEND_ENGINE_2 HTTP_PHP_INI_ENTRY("http.only_exceptions", "0", PHP_INI_ALL, OnUpdateBool, only_exceptions) #endif - HTTP_PHP_INI_ENTRY_EX("http.etag_mode", "-2", PHP_INI_ALL, OnUpdateLong, http_etag_mode_displayer, etag.mode) + HTTP_PHP_INI_ENTRY("http.force_exit", "1", PHP_INI_ALL, OnUpdateBool, force_exit) PHP_INI_END() /* }}} */ diff --git a/http_api.c b/http_api.c index 8030c0f..a78416a 100644 --- a/http_api.c +++ b/http_api.c @@ -246,6 +246,12 @@ void _http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC) } /* }}} */ +static void http_ob_blackhole(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC) +{ + *handled_output = ecalloc(1,1); + *handled_output_len = 0; +} + /* {{{ STATUS http_exit(int, char*, char*) */ STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header TSRMLS_DC) { @@ -257,6 +263,7 @@ STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header return FAILURE; } + php_end_ob_buffers(0 TSRMLS_CC); if (php_header(TSRMLS_C) && body) { PHPWRITE(body, strlen(body)); } @@ -275,8 +282,12 @@ STATUS _http_exit_ex(int status, char *header, char *body, zend_bool send_header STR_FREE(header); STR_FREE(body); - zend_bailout(); - /* fake */ + if (HTTP_G(force_exit)) { + zend_bailout(); + } else { + php_ob_set_internal_handler(http_ob_blackhole, 4096, "blackhole", 0 TSRMLS_CC); + } + return SUCCESS; } /* }}} */ diff --git a/http_cache_api.c b/http_cache_api.c index 11609f9..322c509 100644 --- a/http_cache_api.c +++ b/http_cache_api.c @@ -160,6 +160,10 @@ PHP_HTTP_API STATUS _http_cache_last_modified(time_t last_modified, { char *sent_header = NULL; + if (SG(headers_sent)) { + return FAILURE; + } + if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) { return FAILURE; } @@ -184,6 +188,10 @@ PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len, { char *sent_header = NULL; + if (SG(headers_sent)) { + return FAILURE; + } + if (cc_len && (SUCCESS != http_send_cache_control(cache_control, cc_len))) { return FAILURE; } diff --git a/http_functions.c b/http_functions.c index de673a7..3ec0577 100644 --- a/http_functions.c +++ b/http_functions.c @@ -439,6 +439,8 @@ PHP_FUNCTION(http_cache_last_modified) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &last_modified) != SUCCESS) { RETURN_FALSE; } + + HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); t = (long) time(NULL); @@ -486,6 +488,8 @@ PHP_FUNCTION(http_cache_etag) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &etag, &etag_len) != SUCCESS) { RETURN_FALSE; } + + HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); RETURN_SUCCESS(http_cache_etag(etag, etag_len, HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL))); } diff --git a/http_response_object.c b/http_response_object.c index 2a0cbbd..a0b8817 100644 --- a/http_response_object.c +++ b/http_response_object.c @@ -1081,13 +1081,11 @@ PHP_METHOD(HttpResponse, send) if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean_ob)) { RETURN_FALSE; } - if (SG(headers_sent)) { - http_error(HE_WARNING, HTTP_E_RESPONSE, "Cannot send HttpResponse, headers have already been sent"); - RETURN_FALSE; - } + + HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); sent = GET_STATIC_PROP(sent); - if (zval_is_true(sent)) { + if (Z_LVAL_P(sent)) { http_error(HE_WARNING, HTTP_E_RESPONSE, "Cannot send HttpResponse, response has already been sent"); RETURN_FALSE; } else { @@ -1140,6 +1138,10 @@ PHP_METHOD(HttpResponse, send) if (etag_p) zval_ptr_dtor(&etag_p); if (lmod_p) zval_ptr_dtor(&lmod_p); if (cctl_p) zval_ptr_dtor(&cctl_p); + + if (php_ob_handler_used("blackhole" TSRMLS_CC)) { + RETURN_TRUE; + } } /* content type */ @@ -1238,6 +1240,8 @@ PHP_METHOD(HttpResponse, send) PHP_METHOD(HttpResponse, capture) { NO_ARGS; + + HTTP_CHECK_HEADERS_SENT(RETURN_FALSE); UPD_STATIC_PROP(long, catch, 1); diff --git a/package2.xml b/package2.xml index c502b43..5b2e950 100644 --- a/package2.xml +++ b/package2.xml @@ -39,6 +39,8 @@ BSD, revised = 5.1 with SPL is available + Class HttpMessage implements Serializable if PHP >= 5.1 is available diff --git a/php_http.h b/php_http.h index 33198fa..b62777e 100644 --- a/php_http.h +++ b/php_http.h @@ -79,6 +79,8 @@ ZEND_BEGIN_MODULE_GLOBALS(http) zend_bool only_exceptions; #endif + zend_bool force_exit; + ZEND_END_MODULE_GLOBALS(http) #ifdef ZTS diff --git a/php_http_api.h b/php_http_api.h index f6cd59f..e0e0150 100644 --- a/php_http_api.h +++ b/php_http_api.h @@ -72,6 +72,21 @@ extern void _http_error_ex(long type TSRMLS_DC, long code, const char *format, . action; \ } +#define HTTP_CHECK_HEADERS_SENT(action) \ + if (SG(headers_sent) && !SG(request_info).no_headers) { \ + char *output_start_filename = php_get_output_start_filename(TSRMLS_C); \ + int output_start_lineno = php_get_output_start_lineno(TSRMLS_C); \ + \ + if (output_start_filename) { \ + http_error_ex(HE_WARNING, HTTP_E_HEADER, "Cannot modify header information - headers already sent by (output started at %s:%d)", \ + output_start_filename, output_start_lineno); \ + } else { \ + http_error(HE_WARNING, HTTP_E_HEADER, "Cannot modify header information - headers already sent"); \ + } \ + action; \ + } + + #define http_log(f, i, m) _http_log_ex((f), (i), (m) TSRMLS_CC) extern void http_log_ex(char *file, const char *ident, const char *message TSRMLS_DC);