Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 14 additions & 40 deletions main/SAPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions main/SAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
16 changes: 16 additions & 0 deletions tests/basic/header_register_callback_trampoline.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Test header_register_callback
--FILE--
<?php
class TrampolineTest {
public function __call(string $name, array $arguments) {
echo 'Trampoline for ', $name, PHP_EOL;
}
}
$o = new TrampolineTest();
$callback = [$o, 'trampoline'];

header_register_callback($callback);
?>
--EXPECT--
Trampoline for trampoline
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Test header_register_callback
--FILE--
<?php
class TrampolineTest {
public function __call(string $name, array $arguments) {
echo 'Trampoline for ', $name, PHP_EOL;
}
}
$o = new TrampolineTest();
$callback = [$o, 'trampoline'];

echo "Send headers.\n";
header_register_callback($callback);
?>
--EXPECT--
Send headers.
Loading