diff --git a/NEWS b/NEWS index 6a934ded..38b2e200 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,7 @@ NEWS * [mod_dirlisting] class for dir (fixes #2304) * [core] define __STDC_WANT_LIB_EXT1__ (fixes #2722) * [core] setrlimit max-fds <= rlim_max for non-root (fixes #2723) + * [mod_ssi] config ssi.conditional-requests - 1.4.39 - 2016-01-02 * [core] fix memset_s call (fixes #2698) diff --git a/doc/config/conf.d/ssi.conf b/doc/config/conf.d/ssi.conf index 48af91c3..cd1f552c 100644 --- a/doc/config/conf.d/ssi.conf +++ b/doc/config/conf.d/ssi.conf @@ -1,6 +1,6 @@ ####################################################################### ## -## Server Side Includes +## Server Side Includes ## ----------------------- ## ## See http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModSSI @@ -12,5 +12,34 @@ server.modules += ( "mod_ssi" ) ## ssi.extension = ( ".shtml" ) +## +## The ssi.conditional-requests directive only affects requests +## handled by the SSI module and allows to declare which SSI pages +## are cacheable and which are not. This directive can be enabled +## or disabled globally and/or in any context. +## +## As the name of this directive suggests, conditional requests will +## be handled appropriately for any SSI page for which the directive +## is enabled. In particular, the "ETag" and "Last-Modified" headers +## will both be sent. Conversely, these headers will NOT be sent for +## pages for which the directive is disabled. +## +## The directive should be set to "enable" ONLY for requests that are +## known to generate cacheable documents. An SSI page which only +## includes contents from other static files and/or which uses SSI +## commands that produce predictable output (e.g. the echo command +## for the LAST_MODIFIED variable) is likely to be cacheable. +## +## The directive should be set to "disable" for ALL other documents, +## that is, for SSI pages which depend on non-predictable input such +## as (but not limited to) output from ssi exec commands, data from +## the client's request headers (other than the request URI), or any +## other non constant input such as the current date or time, the +## client's user-agent, etc... +## +## Disabled by default. +## +#ssi.conditional-requests = "enable" + ## ####################################################################### diff --git a/src/mod_ssi.c b/src/mod_ssi.c index 16f1e1b7..f214ace7 100644 --- a/src/mod_ssi.c +++ b/src/mod_ssi.c @@ -107,6 +107,7 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) { config_values_t cv[] = { { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "ssi.content-type", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ + { "ssi.conditional-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -121,9 +122,11 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) { s = calloc(1, sizeof(plugin_config)); s->ssi_extension = array_init(); s->content_type = buffer_init(); + s->conditional_requests = 0; cv[0].destination = s->ssi_extension; cv[1].destination = s->content_type; + cv[2].destination = &(s->conditional_requests); p->config_storage[i] = s; @@ -1078,7 +1081,7 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->conf.content_type)); } - { + if (p->conf.conditional_requests) { /* Generate "ETag" & "Last-Modified" headers */ time_t lm_time = 0; buffer *mtime = NULL; @@ -1093,6 +1096,13 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) mtime = strftime_cache_get(srv, lm_time); response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); + + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) { + /* ok, the client already has our content, + * no need to send it again */ + + chunkqueue_reset(con->write_queue); + } } /* Reset the modified time of included files */ @@ -1112,6 +1122,7 @@ static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p PATCH(ssi_extension); PATCH(content_type); + PATCH(conditional_requests); /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { @@ -1129,6 +1140,8 @@ static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p PATCH(ssi_extension); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.content-type"))) { PATCH(content_type); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.conditional-requests"))) { + PATCH(conditional_requests); } } } diff --git a/src/mod_ssi.h b/src/mod_ssi.h index aeff85e4..91d2f667 100644 --- a/src/mod_ssi.h +++ b/src/mod_ssi.h @@ -17,6 +17,7 @@ typedef struct { array *ssi_extension; buffer *content_type; + unsigned short conditional_requests; } plugin_config; typedef struct {