--- src/mod_ssi.c.orig 2008-09-02 01:10:38.000000000 +0200 +++ src/mod_ssi.c 2008-09-02 01:41:35.000000000 +0200 @@ -37,6 +37,10 @@ #include #endif +#define DEFAULT_MAX_SSI_RECURSION 25 + +URIHANDLER_FUNC(mod_ssi_physical_path); + /* init the plugin data */ INIT_FUNC(mod_ssi_init) { plugin_data *p; @@ -98,6 +102,7 @@ config_values_t cv[] = { { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ + { "ssi.max_recursion", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -110,8 +115,10 @@ s = calloc(1, sizeof(plugin_config)); s->ssi_extension = array_init(); + s->ssi_max_recursion = DEFAULT_MAX_SSI_RECURSION; cv[0].destination = s->ssi_extension; + cv[1].destination = &(s->ssi_max_recursion); p->config_storage[i] = s; @@ -577,7 +584,40 @@ } break; case SSI_INCLUDE: - chunkqueue_append_file(con->send, p->stat_fn, 0, st.st_size); + if (file_path) { + /* don't process if #include file="..." is used */ + chunkqueue_append_file(con->send, p->stat_fn, 0, st.st_size); + } else { + buffer *tmp = NULL; + /* do recursive SSI expansion */ + + b = chunkqueue_get_append_buffer(con->send); + + /* prevents simple infinite loop */ + if (buffer_is_equal(con->physical.path, p->stat_fn)) { + buffer_copy_string(b, "(error: include directives create an infinite loop)"); + break; + } + + /* only allow predefined recursion depth */ + if (con->loops_per_request > p->conf.ssi_max_recursion) { + buffer_copy_string(b, "(error: include directives recurse deeper than pre-defined max_recursion)"); + break; + } + + tmp = buffer_init(); + /* save path of current document */ + buffer_copy_string_buffer(tmp, con->physical.path); + /* next sub-document to parse */ + buffer_copy_string_buffer(con->physical.path, p->stat_fn); + if (mod_ssi_physical_path(srv,con,p) != HANDLER_FINISHED) { + /* the document was not processed, so write it as is */ + chunkqueue_append_file(con->send, con->physical.path, 0, st.st_size); + } + /* restore saved path */ + buffer_copy_string_buffer(con->physical.path, tmp); + buffer_free(tmp); + } break; } } else { @@ -897,15 +937,20 @@ int ovec[N * 3]; #endif - /* get a stream to the file */ + /* for nested requests increase recursion depth */ + con->loops_per_request++; - array_reset(p->ssi_vars); - array_reset(p->ssi_cgi_env); - buffer_copy_string_len(p->timefmt, CONST_STR_LEN("%a, %d %b %Y %H:%M:%S %Z")); - p->sizefmt = 0; - build_ssi_cgi_vars(srv, con, p); + /* initialize values only if in the first level of recursion */ + if(con->loops_per_request <= 1) { + array_reset(p->ssi_vars); + array_reset(p->ssi_cgi_env); + buffer_copy_string_len(p->timefmt, CONST_STR_LEN("%a, %d %b %Y %H:%M:%S %Z")); + p->sizefmt = 0; + build_ssi_cgi_vars(srv, con, p); + } p->if_is_false = 0; + /* get a stream to the file */ if (-1 == stream_open(&s, con->physical.path)) { log_error_write(srv, __FILE__, __LINE__, "sb", "stream-open: ", con->physical.path); @@ -1007,6 +1052,9 @@ /* reset physical.path */ buffer_reset(con->physical.path); + /* for nested requests decrease recursion depth afterwards */ + con->loops_per_request--; + return 0; } @@ -1015,6 +1063,7 @@ plugin_config *s = p->config_storage[0]; PATCH_OPTION(ssi_extension); + PATCH_OPTION(ssi_max_recursion); /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { @@ -1030,6 +1079,8 @@ if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) { PATCH_OPTION(ssi_extension); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.max_recursion"))) { + PATCH_OPTION(ssi_max_recursion); } } } --- src/mod_ssi.h.orig 2008-09-02 01:10:38.000000000 +0200 +++ src/mod_ssi.h 2008-09-02 01:35:06.000000000 +0200 @@ -15,6 +15,7 @@ typedef struct { array *ssi_extension; + unsigned short ssi_max_recursion; } plugin_config; typedef struct {