diff --git a/main/SAPI.c b/main/SAPI.c index 62e1c89e4bb9..fade21a79571 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -111,51 +111,25 @@ PHP_FUNCTION(header_register_callback) zend_fcall_info fci; zend_fcall_info_cache fcc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fci, &fcc) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "F", &fci, &fcc) == FAILURE) { RETURN_THROWS(); } - if (Z_TYPE(SG(callback_func)) != IS_UNDEF) { - zval_ptr_dtor(&SG(callback_func)); - SG(fci_cache) = empty_fcall_info_cache; + if (ZEND_FCC_INITIALIZED(SG(send_header_fcc))) { + zend_fcc_dtor(&SG(send_header_fcc)); } /* Don't store callback if headers have already been sent: * It won't get used and we won't have a chance to release it. */ - if (!SG(headers_sent)) { - ZVAL_COPY(&SG(callback_func), &fci.function_name); + if (UNEXPECTED(SG(headers_sent))) { + zend_release_fcall_info_cache(&fcc); + } else { + zend_fcc_dup(&SG(send_header_fcc), &fcc); } - RETURN_TRUE; } /* }}} */ -static void sapi_run_header_callback(zval *callback) -{ - int error; - zend_fcall_info fci; - char *callback_error = NULL; - zval retval; - - if (zend_fcall_info_init(callback, 0, &fci, &SG(fci_cache), NULL, &callback_error) == SUCCESS) { - fci.retval = &retval; - - error = zend_call_function(&fci, &SG(fci_cache)); - if (error == FAILURE) { - goto callback_failed; - } else { - zval_ptr_dtor(&retval); - } - } else { -callback_failed: - php_error_docref(NULL, E_WARNING, "Could not call the sapi_header_callback"); - } - - if (callback_error) { - efree(callback_error); - } -} - SAPI_API void sapi_handle_post(void *arg) { if (SG(request_info).post_entry && SG(request_info).content_type_dup) { @@ -436,7 +410,6 @@ SAPI_API void sapi_activate(void) SG(sapi_headers).http_status_line = NULL; SG(sapi_headers).mimetype = NULL; SG(headers_sent) = 0; - ZVAL_UNDEF(&SG(callback_func)); SG(read_post_bytes) = 0; SG(request_info).request_body = NULL; SG(request_info).current_user = NULL; @@ -446,6 +419,7 @@ SAPI_API void sapi_activate(void) SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */ SG(global_request_time) = 0; SG(post_read) = 0; + SG(send_header_fcc) = empty_fcall_info_cache; /* It's possible to override this general case in the activate() callback, if necessary. */ if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) { SG(request_info).headers_only = 1; @@ -890,12 +864,12 @@ SAPI_API int sapi_send_headers(void) SG(sapi_headers).send_default_content_type = 0; } - if (Z_TYPE(SG(callback_func)) != IS_UNDEF) { - zval cb; - ZVAL_COPY_VALUE(&cb, &SG(callback_func)); - ZVAL_UNDEF(&SG(callback_func)); - sapi_run_header_callback(&cb); - zval_ptr_dtor(&cb); + if (ZEND_FCC_INITIALIZED(SG(send_header_fcc))) { + zend_fcall_info_cache fcc = SG(send_header_fcc); + /* Prevent triggering the callback multiple times */ + SG(send_header_fcc) = empty_fcall_info_cache; + zend_call_known_fcc(&fcc, NULL, 0, NULL, NULL); + zend_fcc_dtor(&fcc); } SG(headers_sent) = 1; diff --git a/main/SAPI.h b/main/SAPI.h index e62f686603c4..d34c12f1bbc8 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -143,8 +143,7 @@ typedef struct _sapi_globals_struct { bool sapi_started; double global_request_time; HashTable known_post_content_types; - zval callback_func; - zend_fcall_info_cache fci_cache; + zend_fcall_info_cache send_header_fcc; sapi_request_parse_body_context request_parse_body_context; } sapi_globals_struct; diff --git a/tests/basic/header_register_callback_trampoline.phpt b/tests/basic/header_register_callback_trampoline.phpt new file mode 100644 index 000000000000..cc4a1e4014e4 --- /dev/null +++ b/tests/basic/header_register_callback_trampoline.phpt @@ -0,0 +1,16 @@ +--TEST-- +Test header_register_callback +--FILE-- + +--EXPECT-- +Trampoline for trampoline diff --git a/tests/basic/header_register_callback_trampoline_after_headers_sent.phpt b/tests/basic/header_register_callback_trampoline_after_headers_sent.phpt new file mode 100644 index 000000000000..7f343c6d813c --- /dev/null +++ b/tests/basic/header_register_callback_trampoline_after_headers_sent.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test header_register_callback +--FILE-- + +--EXPECT-- +Send headers.