Skip to content

Instantly share code, notes, and snippets.

@adsr
Created October 13, 2022 22:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adsr/d6360b5cd59c084d67adc5e8e6127695 to your computer and use it in GitHub Desktop.
Save adsr/d6360b5cd59c084d67adc5e8e6127695 to your computer and use it in GitHub Desktop.
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