Skip to content

Instantly share code, notes, and snippets.

@adsr
Created October 21, 2017 20:10
Show Gist options
  • Save adsr/d5015ae37f8a080dcf5bac428f7fdee0 to your computer and use it in GitHub Desktop.
Save adsr/d5015ae37f8a080dcf5bac428f7fdee0 to your computer and use it in GitHub Desktop.
diff --git a/server/config.c b/server/config.c
index 7c7a1e0033..754152b86b 100644
--- a/server/config.c
+++ b/server/config.c
@@ -45,37 +45,42 @@
#include "http_protocol.h"
#include "http_core.h"
#include "http_log.h" /* for errors in parse_htaccess */
#include "http_request.h" /* for default_handler (see invoke_handler) */
#include "http_main.h"
#include "http_vhost.h"
#include "util_cfgtree.h"
#include "util_varbuf.h"
#include "mpm_common.h"
+#include "setjmp.h"
+#include "apr_signal.h"
+
#define APLOG_UNSET (APLOG_NO_MODULE - 1)
/* we know core's module_index is 0 */
#undef APLOG_MODULE_INDEX
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
AP_DECLARE_DATA const char *ap_server_argv0 = NULL;
AP_DECLARE_DATA const char *ap_server_root = NULL;
AP_DECLARE_DATA const char *ap_runtime_dir = NULL;
AP_DECLARE_DATA server_rec *ap_server_conf = NULL;
AP_DECLARE_DATA apr_pool_t *ap_pglobal = NULL;
AP_DECLARE_DATA apr_array_header_t *ap_server_pre_read_config = NULL;
AP_DECLARE_DATA apr_array_header_t *ap_server_post_read_config = NULL;
AP_DECLARE_DATA apr_array_header_t *ap_server_config_defines = NULL;
AP_DECLARE_DATA ap_directive_t *ap_conftree = NULL;
+AP_DECLARE_DATA sigjmp_buf ap_invoke_handler_jmpenv;
+
APR_HOOK_STRUCT(
APR_HOOK_LINK(header_parser)
APR_HOOK_LINK(pre_config)
APR_HOOK_LINK(check_config)
APR_HOOK_LINK(post_config)
APR_HOOK_LINK(open_logs)
APR_HOOK_LINK(child_init)
APR_HOOK_LINK(handler)
APR_HOOK_LINK(quick_handler)
APR_HOOK_LINK(optional_fn_retrieve)
@@ -370,20 +375,25 @@ static int invoke_filter_init(request_rec *r, ap_filter_t *filters)
int result = filters->frec->filter_init_func(filters);
if (result != OK) {
return result;
}
}
filters = filters->next;
}
return OK;
}
+static void ap_invoke_handler_timeout(int sig)
+{
+ siglongjmp(ap_invoke_handler_jmpenv, 1);
+}
+
AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
{
const char *handler;
const char *p;
int result;
const char *old_handler = r->handler;
const char *ignore;
/*
* The new insert_filter stage makes the most sense here. We only use
@@ -424,22 +434,44 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
*p2='\0';
}
}
else {
handler = AP_DEFAULT_HANDLER_NAME;
}
r->handler = handler;
}
- result = ap_run_handler(r);
+ struct itimerval ntimer;
+ struct sigaction sigact;
+ int jmpv;
+ jmpv = sigsetjmp(ap_invoke_handler_jmpenv, 1);
+ if (jmpv == 0) {
+ // Timeout after 50ms
+ ntimer.it_interval.tv_sec = 0;
+ ntimer.it_interval.tv_usec = 0;
+ ntimer.it_value.tv_sec = 0;
+ ntimer.it_value.tv_usec = 50 * 1000;
+ setitimer(ITIMER_REAL, &ntimer, NULL);
+
+ // Install signal handler
+ apr_signal(SIGALRM, ap_invoke_handler_timeout);
+
+ // Run handler
+ result = ap_run_handler(r);
+ apr_signal(SIGALRM, SIG_IGN);
+ } else {
+ // Timed out; clear signal handler
+ apr_signal(SIGALRM, SIG_IGN);
+ result = HTTP_GATEWAY_TIME_OUT;
+ }
r->handler = old_handler;
if (result == DECLINED && r->handler && r->filename) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00523)
"handler \"%s\" not found for: %s", r->handler, r->filename);
}
if ((result != OK) && (result != DONE) && (result != DECLINED) && (result != SUSPENDED)
&& (result != AP_FILTER_ERROR) /* ap_die() knows about this specifically */
&& !ap_is_HTTP_VALID_RESPONSE(result)) {
/* If a module is deliberately returning something else
@adsr
Copy link
Author

adsr commented Oct 21, 2017

Shitty proof of concept. Works with mpm=prefork only. Might be able to generalize for mpm=event etc using timerfd* or signalfd*.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment