- added INI setting http.force_exit which can be used to disable script termination
authorMichael Wallner <mike@php.net>
Tue, 8 Nov 2005 14:07:23 +0000 (14:07 +0000)
committerMichael Wallner <mike@php.net>
Tue, 8 Nov 2005 14:07:23 +0000 (14:07 +0000)
  in case of redirects and positive cache hits (instead, standard output will be discarded)

docs/http.ini
http.c
http_api.c
http_cache_api.c
http_functions.c
http_response_object.c
package2.xml
php_http.h
php_http_api.h

index bd575f2fb73ab1fb07f7bab8d1b964d00ba03f40..372c1f33268564f5169fff0dd8d1aa4c38816028 100644 (file)
@@ -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 888a1cf0c487533a6b25bafa43c0fdee6aa247c5..a4b430a6812a5e6cec58e9f63554de080bd8641a 100644 (file)
--- 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()
 /* }}} */
 
index 8030c0f5d358df3f1bb5360d3cb57d6e3b7969a4..a78416a0bcb5bc73ff0c384cfac3530ae3d1e19c 100644 (file)
@@ -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;
 }
 /* }}} */
index 11609f989fee4132832bc67c7144ff08ee569e13..322c509d2f5a8873a526a1be104f6b7fc8a9768f 100644 (file)
@@ -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;
        }
index de673a724061383a2ad7eb52812dcb38169185e7..3ec05777fc273bbdacb68533fa97545a2403547c 100644 (file)
@@ -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)));
 }
index 2a0cbbd0aaad9db54ec57e4591e469abaf681171..a0b8817cc218563e95fc758e23af0a826da952eb 100644 (file)
@@ -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);
 
index c502b4321c3198ba3c6899b19aaa7c32c6030656..5b2e9508060d27993f89ebdeae091ccbabb845e0 100644 (file)
@@ -39,6 +39,8 @@
  </stability>
  <license>BSD, revised</license>
  <notes><![CDATA[
++ 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)
 + Classes HttpMessage and HttpRequestPool implement Countable if PHP >= 5.1 with SPL is available
 + Class HttpMessage implements Serializable if PHP >= 5.1 is available
 
index 33198fad8e8a287e01ee1a254acf253111e63050..b62777ee4f93552c0d2d4c443f1e1270bbd85f54 100644 (file)
@@ -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
index f6cd59ffe624278ddc42ceae916ef54584286396..e0e01505b2bed953f637ccf0706bc80c32a60281 100644 (file)
@@ -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);