Created
October 13, 2022 22:30
-
-
Save adsr/d6360b5cd59c084d67adc5e8e6127695 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/include/http_config.h b/include/http_config.h | |
index c93c3b2..ade284b 100644 | |
--- a/include/http_config.h | |
+++ b/include/http_config.h | |
@@ -269,20 +269,22 @@ struct ap_configfile_t { | |
/**< an apr_file_gets()-like function */ | |
apr_status_t (*getstr) (void *buf, apr_size_t bufsiz, void *param); | |
/**< a close handler function */ | |
apr_status_t (*close) (void *param); | |
/**< the argument passed to getch/getstr/close */ | |
void *param; | |
/**< the filename / description */ | |
const char *name; | |
/**< current line number, starting at 1 */ | |
unsigned line_number; | |
+ /** mtime of conf file */ | |
+ apr_time_t mtime; | |
}; | |
/** | |
* This structure is passed to a command which is being invoked, | |
* to carry a large variety of miscellaneous data which is all of | |
* use to *somebody*... | |
*/ | |
struct cmd_parms_struct { | |
/** Argument to command from cmd_table */ | |
void *info; | |
diff --git a/include/httpd.h b/include/httpd.h | |
index a552358..1c83df4 100644 | |
--- a/include/httpd.h | |
+++ b/include/httpd.h | |
@@ -726,20 +726,24 @@ struct htaccess_result { | |
/** the directory to which this applies */ | |
const char *dir; | |
/** the overrides allowed for the .htaccess file */ | |
int override; | |
/** the override options allowed for the .htaccess file */ | |
int override_opts; | |
/** Table of allowed directives for override */ | |
apr_table_t *override_list; | |
/** the configuration directives */ | |
struct ap_conf_vector_t *htaccess; | |
+ /** mtime of htaccess when cached */ | |
+ apr_time_t cache_mtime; | |
+ /** full path of htaccess */ | |
+ const char *cache_fpath; | |
/** the next one, or NULL if no more; N.B. never change this */ | |
const struct htaccess_result *next; | |
}; | |
/* The following four types define a hierarchy of activities, so that | |
* given a request_rec r you can write r->connection->server->process | |
* to get to the process_rec. While this reduces substantially the | |
* number of arguments that various hooks require beware that in | |
* threaded versions of the server you must consider multiplexing | |
* issues. */ | |
@@ -767,20 +771,26 @@ struct process_rec { | |
/** Global pool. Cleared upon normal exit */ | |
apr_pool_t *pool; | |
/** Configuration pool. Cleared upon restart */ | |
apr_pool_t *pconf; | |
/** The program name used to execute the program */ | |
const char *short_name; | |
/** The command line arguments */ | |
const char * const *argv; | |
/** Number of command line arguments passed to the program */ | |
int argc; | |
+ /** htaccess cache memory pool */ | |
+ apr_pool_t *htaccess_pool; | |
+ /** htaccess cache entries */ | |
+ const struct htaccess_result *htaccess; | |
+ /** flag to clear cache */ | |
+ int htaccess_cache_invalid; | |
}; | |
/** | |
* @brief A structure that represents the current request | |
*/ | |
struct request_rec { | |
/** The pool associated with the request */ | |
apr_pool_t *pool; | |
/** The connection to the client */ | |
conn_rec *connection; | |
diff --git a/modules/http/http_request.c b/modules/http/http_request.c | |
index 9885de4..6b31b31 100644 | |
--- a/modules/http/http_request.c | |
+++ b/modules/http/http_request.c | |
@@ -362,20 +362,21 @@ void ap_process_async_request(request_rec *r) | |
ap_die_r(access_status, r, HTTP_OK); | |
ap_process_request_after_handler(r); | |
} | |
void ap_process_request(request_rec *r) | |
{ | |
apr_bucket_brigade *bb; | |
apr_bucket *b; | |
conn_rec *c = r->connection; | |
+ process_rec *process = r->server->process; | |
apr_status_t rv; | |
ap_process_async_request(r); | |
if (!c->data_in_input_filters) { | |
RETRIEVE_BRIGADE_FROM_POOL(bb, "ap_process_request_after_handler_brigade", | |
c->pool, c->bucket_alloc); | |
b = apr_bucket_flush_create(c->bucket_alloc); | |
APR_BRIGADE_INSERT_HEAD(bb, b); | |
rv = ap_pass_brigade(c->output_filters, bb); | |
@@ -385,20 +386,33 @@ void ap_process_request(request_rec *r) | |
* valuable for detecting clients with broken network | |
* connections or possible DoS attacks. | |
* | |
* It is still safe to use r / r->pool here as the eor bucket | |
* could not have been destroyed in the event of a timeout. | |
*/ | |
ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r, APLOGNO(01581) | |
"Timeout while writing data for URI %s to the" | |
" client", r->unparsed_uri); | |
} | |
+ | |
+ /* Clear htaccess cache if invalid. | |
+ * | |
+ * We do it here at the very end of a request to avoid freeing | |
+ * elements from htaccess_pool that make it into request | |
+ * processing. | |
+ */ | |
+ if (process->htaccess_cache_invalid) { | |
+ apr_pool_clear(process->htaccess_pool); | |
+ process->htaccess = NULL; | |
+ process->htaccess_cache_invalid = 0; | |
+ } | |
+ | |
apr_brigade_cleanup(bb); | |
} | |
if (ap_extended_status) { | |
ap_time_process_request(c->sbh, STOP_PREQUEST); | |
} | |
} | |
static apr_table_t *rename_original_env(apr_pool_t *p, apr_table_t *t) | |
{ | |
const apr_array_header_t *env_arr = apr_table_elts(t); | |
diff --git a/server/config.c b/server/config.c | |
index 265744e..fd5ee1a 100644 | |
--- a/server/config.c | |
+++ b/server/config.c | |
@@ -2082,64 +2082,99 @@ AP_DECLARE(int) ap_process_config_tree(server_rec *s, | |
apr_status_t ap_open_htaccess(request_rec *r, const char *dir_name, | |
const char *access_name, | |
ap_configfile_t **conffile, | |
const char **full_name) | |
{ | |
*full_name = ap_make_full_path(r->pool, dir_name, access_name); | |
return ap_pcfg_openfile(conffile, r->pool, *full_name); | |
} | |
+static int ap_htaccess_cache_mtime_changed(const struct htaccess_result *entry, apr_pool_t *pool) { | |
+ apr_status_t status; | |
+ apr_file_t *file = NULL; | |
+ apr_finfo_t finfo; | |
+ | |
+ status = apr_file_open(&file, entry->cache_fpath, | |
+ APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool); | |
+ if (status != APR_SUCCESS) { | |
+ /** act as if mtime changed on error */ | |
+ return 1; | |
+ } | |
+ | |
+ status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file); | |
+ apr_file_close(file); | |
+ if (status != APR_SUCCESS) { | |
+ /** act as if mtime changed on error */ | |
+ return 1; | |
+ } | |
+ | |
+ if (entry->cache_mtime != finfo.mtime) { | |
+ return 1; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, | |
request_rec *r, int override, | |
int override_opts, apr_table_t *override_list, | |
const char *d, const char *access_names) | |
{ | |
ap_configfile_t *f = NULL; | |
cmd_parms parms; | |
const char *filename; | |
const struct htaccess_result *cache; | |
struct htaccess_result *new; | |
ap_conf_vector_t *dc = NULL; | |
apr_status_t status; | |
+ process_rec *process = r->server->process; | |
+ apr_pool_t *htaccess_pool = process->htaccess_pool; | |
/* firstly, search cache */ | |
- for (cache = r->htaccess; cache != NULL; cache = cache->next) { | |
- if (cache->override == override && strcmp(cache->dir, d) == 0) { | |
- *result = cache->htaccess; | |
- return OK; | |
+ if (!process->htaccess_cache_invalid) { | |
+ for (cache = process->htaccess; cache != NULL; cache = cache->next) { | |
+ if (cache->override == override && strcmp(cache->dir, d) == 0) { | |
+ if (ap_htaccess_cache_mtime_changed(cache, r->pool)) { | |
+ /* set flag to blow up entire cache if mtime changed */ | |
+ process->htaccess_cache_invalid = 1; | |
+ break; | |
+ } | |
+ *result = cache->htaccess; | |
+ return OK; | |
+ } | |
} | |
} | |
parms = default_parms; | |
parms.override = override; | |
parms.override_opts = override_opts; | |
parms.override_list = override_list; | |
- parms.pool = r->pool; | |
- parms.temp_pool = r->pool; | |
+ parms.pool = htaccess_pool; | |
+ parms.temp_pool = htaccess_pool; | |
parms.server = r->server; | |
- parms.path = apr_pstrdup(r->pool, d); | |
/* loop through the access names and find the first one */ | |
while (access_names[0]) { | |
const char *access_name = ap_getword_conf(r->pool, &access_names); | |
filename = NULL; | |
status = ap_run_open_htaccess(r, d, access_name, &f, &filename); | |
if (status == APR_SUCCESS) { | |
const char *errmsg; | |
ap_directive_t *temptree = NULL; | |
- dc = ap_create_per_dir_config(r->pool); | |
+ dc = ap_create_per_dir_config(htaccess_pool); | |
+ parms.path = apr_pstrdup(htaccess_pool, d); | |
parms.config_file = f; | |
- errmsg = ap_build_config(&parms, r->pool, r->pool, &temptree); | |
+ errmsg = ap_build_config(&parms, htaccess_pool, htaccess_pool, &temptree); | |
if (errmsg == NULL) | |
errmsg = ap_walk_config(temptree, &parms, dc); | |
ap_cfg_closefile(f); | |
if (errmsg) { | |
ap_log_rerror(APLOG_MARK, APLOG_ALERT, 0, r, | |
"%s: %s", filename, errmsg); | |
return HTTP_INTERNAL_SERVER_ERROR; | |
} | |
@@ -2156,30 +2191,34 @@ AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, | |
"is executable", | |
filename, d); | |
apr_table_setn(r->notes, "error-notes", | |
"Server unable to read htaccess file, denying " | |
"access to be safe"); | |
return HTTP_FORBIDDEN; | |
} | |
} | |
} | |
- /* cache it */ | |
- new = apr_palloc(r->pool, sizeof(struct htaccess_result)); | |
- new->dir = parms.path; | |
- new->override = override; | |
- new->override_opts = override_opts; | |
- new->htaccess = dc; | |
+ if (!process->htaccess_cache_invalid && parms.config_file) { | |
+ /* cache it */ | |
+ new = apr_palloc(htaccess_pool, sizeof(struct htaccess_result)); | |
+ new->dir = parms.path; | |
+ new->override = override; | |
+ new->override_opts = override_opts; | |
+ new->htaccess = dc; | |
+ new->cache_fpath = apr_pstrdup(htaccess_pool, (parms.config_file)->name); | |
+ new->cache_mtime = (parms.config_file)->mtime; | |
- /* add to head of list */ | |
- new->next = r->htaccess; | |
- r->htaccess = new; | |
+ /* add to head of list */ | |
+ new->next = process->htaccess; | |
+ process->htaccess = new; | |
+ } | |
return OK; | |
} | |
AP_CORE_DECLARE(const char *) ap_init_virtual_host(apr_pool_t *p, | |
const char *hostname, | |
server_rec *main_server, | |
server_rec **ps) | |
{ | |
server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec)); | |
diff --git a/server/main.c b/server/main.c | |
index 3bacccd..3cc826b 100644 | |
--- a/server/main.c | |
+++ b/server/main.c | |
@@ -315,20 +315,25 @@ static process_rec *init_process(int *argc, const char * const * *argv) | |
*/ | |
process = apr_palloc(cntx, sizeof(process_rec)); | |
process->pool = cntx; | |
apr_pool_create(&process->pconf, process->pool); | |
apr_pool_tag(process->pconf, "pconf"); | |
process->argc = *argc; | |
process->argv = *argv; | |
process->short_name = apr_filepath_name_get((*argv)[0]); | |
+ | |
+ process->htaccess = NULL; | |
+ apr_pool_create(&process->htaccess_pool, cntx); | |
+ process->htaccess_cache_invalid = 0; | |
+ | |
return process; | |
} | |
static void usage(process_rec *process) | |
{ | |
const char *bin = process->argv[0]; | |
int pad_len = strlen(bin); | |
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, | |
"Usage: %s [-D name] [-d directory] [-f file]", bin); | |
diff --git a/server/util.c b/server/util.c | |
index 7373fec..a655cf5 100644 | |
--- a/server/util.c | |
+++ b/server/util.c | |
@@ -922,39 +922,41 @@ AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg, | |
} | |
#endif | |
new_cfg = apr_palloc(p, sizeof(*new_cfg)); | |
new_cfg->param = file; | |
new_cfg->name = apr_pstrdup(p, name); | |
new_cfg->getch = cfg_getch; | |
new_cfg->getstr = cfg_getstr; | |
new_cfg->close = cfg_close; | |
new_cfg->line_number = 0; | |
+ new_cfg->mtime = finfo.mtime; | |
*ret_cfg = new_cfg; | |
return APR_SUCCESS; | |
} | |
/* Allocate a ap_configfile_t handle with user defined functions and params */ | |
AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom( | |
apr_pool_t *p, const char *descr, void *param, | |
apr_status_t (*getc_func) (char *ch, void *param), | |
apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param), | |
apr_status_t (*close_func) (void *param)) | |
{ | |
ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg)); | |
new_cfg->param = param; | |
new_cfg->name = descr; | |
new_cfg->getch = getc_func; | |
new_cfg->getstr = gets_func; | |
new_cfg->close = close_func; | |
new_cfg->line_number = 0; | |
+ new_cfg->mtime = 0; | |
return new_cfg; | |
} | |
/* Read one character from a configfile_t */ | |
AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp) | |
{ | |
apr_status_t rc = cfp->getch(ch, cfp->param); | |
if (rc == APR_SUCCESS && *ch == LF) | |
++cfp->line_number; | |
return rc; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment