Skip to content

Instantly share code, notes, and snippets.

@rlerdorf
Created May 22, 2023 17:07
Show Gist options
  • Save rlerdorf/3676d380acbafe79b76f1dc732c607c5 to your computer and use it in GitHub Desktop.
Save rlerdorf/3676d380acbafe79b76f1dc732c607c5 to your computer and use it in GitHub Desktop.
diff --git a/sapi/apache2handler/php_functions.c b/sapi/apache2handler/php_functions.c
index e7d29450ee..1c3900b952 100644
--- a/sapi/apache2handler/php_functions.c
+++ b/sapi/apache2handler/php_functions.c
@@ -26,6 +26,7 @@
#include "zend_smart_str.h"
#include "ext/standard/info.h"
#include "ext/standard/head.h"
+#include "php_main.h"
#include "php_ini.h"
#include "SAPI.h"
@@ -358,6 +359,37 @@ PHP_FUNCTION(apache_get_modules)
}
/* }}} */
+/* {{{ Force Apache request to finish */
+PHP_FUNCTION(apache_finish_request)
+{
+ php_struct *ctx;
+ apr_bucket *bucket;
+ apr_status_t rv;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ php_output_end_all();
+ php_header();
+ ctx = SG(server_context);
+ apr_brigade_cleanup(ctx->brigade);
+ bucket = apr_bucket_eos_create(ctx->r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(ctx->brigade, bucket);
+ rv = ap_pass_brigade(ctx->r->output_filters, ctx->brigade);
+ if (rv != APR_SUCCESS || ctx->r->connection->aborted) {
+ zend_first_try {
+ php_handle_aborted_connection();
+ } zend_end_try();
+ RETVAL_FALSE;
+ } else {
+ RETVAL_TRUE;
+ }
+ apr_brigade_cleanup(ctx->brigade);
+ ctx->request_processed = 1;
+}
+/* }}} */
+
PHP_MINFO_FUNCTION(apache)
{
char *apv = php_apache_get_version();
diff --git a/sapi/apache2handler/php_functions_arginfo.h b/sapi/apache2handler/php_functions_arginfo.h
index a712ce590c..984c316685 100644
--- a/sapi/apache2handler/php_functions_arginfo.h
+++ b/sapi/apache2handler/php_functions_arginfo.h
@@ -35,6 +35,9 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_apache_get_version, 0, 0, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_apache_finish_request, 0, 0, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
#define arginfo_apache_get_modules arginfo_apache_request_headers
@@ -47,6 +50,7 @@ ZEND_FUNCTION(apache_setenv);
ZEND_FUNCTION(apache_getenv);
ZEND_FUNCTION(apache_get_version);
ZEND_FUNCTION(apache_get_modules);
+ZEND_FUNCTION(apache_finish_request);
static const zend_function_entry ext_functions[] = {
@@ -60,5 +64,6 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(apache_getenv, arginfo_apache_getenv)
ZEND_FE(apache_get_version, arginfo_apache_get_version)
ZEND_FE(apache_get_modules, arginfo_apache_get_modules)
+ ZEND_FE(apache_finish_request, arginfo_apache_finish_request)
ZEND_FE_END
};
diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c
index 2266b46e58..62a3849800 100644
--- a/sapi/apache2handler/sapi_apache2.c
+++ b/sapi/apache2handler/sapi_apache2.c
@@ -714,18 +714,20 @@ zend_first_try {
if (!parent_req) {
php_apache_request_dtor(r);
- ctx->request_processed = 1;
- apr_brigade_cleanup(brigade);
- bucket = apr_bucket_eos_create(r->connection->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(brigade, bucket);
-
- rv = ap_pass_brigade(r->output_filters, brigade);
- if (rv != APR_SUCCESS || r->connection->aborted) {
+ if (!ctx->request_processed == 1) {
+ ctx->request_processed = 1;
+ apr_brigade_cleanup(brigade);
+ bucket = apr_bucket_eos_create(r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(brigade, bucket);
+
+ rv = ap_pass_brigade(r->output_filters, brigade);
+ if (rv != APR_SUCCESS || r->connection->aborted) {
zend_first_try {
- php_handle_aborted_connection();
+ php_handle_aborted_connection();
} zend_end_try();
+ }
+ apr_brigade_cleanup(brigade);
}
- apr_brigade_cleanup(brigade);
apr_pool_cleanup_run(r->pool, (void *)&SG(server_context), php_server_context_cleanup);
} else {
ctx->r = parent_req;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment