2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "base.h"
|
2017-06-20 03:00:45 +00:00
|
|
|
#include "fdevent.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "log.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
|
|
|
|
#include "plugin.h"
|
|
|
|
|
|
|
|
#include "response.h"
|
|
|
|
|
|
|
|
#include "mod_ssi.h"
|
|
|
|
|
|
|
|
#include "sys-socket.h"
|
|
|
|
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <sys/types.h>
|
2017-04-24 14:13:41 +00:00
|
|
|
#include "sys-strings.h"
|
2017-06-20 03:00:45 +00:00
|
|
|
#include <sys/wait.h>
|
2009-10-11 14:31:42 +00:00
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
2016-04-18 03:37:40 +00:00
|
|
|
#include <fcntl.h>
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef HAVE_PWD_H
|
2009-10-11 14:31:42 +00:00
|
|
|
# include <pwd.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
#endif
|
|
|
|
|
2005-10-18 10:38:11 +00:00
|
|
|
#ifdef HAVE_SYS_FILIO_H
|
2009-10-11 14:31:42 +00:00
|
|
|
# include <sys/filio.h>
|
2005-10-18 10:38:11 +00:00
|
|
|
#endif
|
|
|
|
|
2008-01-18 09:21:07 +00:00
|
|
|
#include "etag.h"
|
|
|
|
|
2016-12-06 05:25:56 +00:00
|
|
|
static handler_ctx * handler_ctx_init(plugin_data *p) {
|
|
|
|
handler_ctx *hctx = calloc(1, sizeof(*hctx));
|
|
|
|
force_assert(hctx);
|
|
|
|
hctx->timefmt = p->timefmt;
|
|
|
|
hctx->stat_fn = p->stat_fn;
|
|
|
|
hctx->ssi_vars = p->ssi_vars;
|
|
|
|
hctx->ssi_cgi_env = p->ssi_cgi_env;
|
|
|
|
memcpy(&hctx->conf, &p->conf, sizeof(plugin_config));
|
|
|
|
return hctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handler_ctx_free(handler_ctx *hctx) {
|
|
|
|
free(hctx);
|
|
|
|
}
|
|
|
|
|
2008-01-18 09:21:07 +00:00
|
|
|
/* The newest modified time of included files for include statement */
|
|
|
|
static volatile time_t include_file_last_mtime = 0;
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
/* init the plugin data */
|
|
|
|
INIT_FUNC(mod_ssi_init) {
|
|
|
|
plugin_data *p;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
p = calloc(1, sizeof(*p));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
p->timefmt = buffer_init();
|
|
|
|
p->stat_fn = buffer_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
p->ssi_vars = array_init();
|
|
|
|
p->ssi_cgi_env = array_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* detroy the plugin data */
|
|
|
|
FREE_FUNC(mod_ssi_free) {
|
|
|
|
plugin_data *p = p_d;
|
|
|
|
UNUSED(srv);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (!p) return HANDLER_GO_ON;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (p->config_storage) {
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
|
|
|
plugin_config *s = p->config_storage[i];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-05-14 09:38:33 +00:00
|
|
|
if (NULL == s) continue;
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
array_free(s->ssi_extension);
|
2009-06-10 14:50:42 +00:00
|
|
|
buffer_free(s->content_type);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
free(p->config_storage);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
array_free(p->ssi_vars);
|
|
|
|
array_free(p->ssi_cgi_env);
|
|
|
|
buffer_free(p->timefmt);
|
|
|
|
buffer_free(p->stat_fn);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
free(p);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle plugin config and check values */
|
|
|
|
|
|
|
|
SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
|
|
|
|
plugin_data *p = p_d;
|
|
|
|
size_t i = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
config_values_t cv[] = {
|
2005-02-20 14:27:00 +00:00
|
|
|
{ "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
|
2009-06-10 14:50:42 +00:00
|
|
|
{ "ssi.content-type", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
|
[mod_ssi] config ssi.conditional-requests
Summary:
A new SSI directive, "ssi.conditional-requests", allows to inform
lighttpd which SSI pages should be considered as cacheable and which
should not. In particular, the "ETag" & "Last-Modified" headers will
only be sent for those SSI pages for which the directive is enabled.
Long description:
"ETag" and "Last-Modified" headers were being sent for all SSI pages,
regardless of whether they were cacheable or not. And yet, there was
no cache validation at all for any SSI page.
This commit fixes these two minor issues by adding a new directive,
"ssi.conditional-requests", which allows to specify which SSI pages
are cacheable and which are not, and by adding cache validation to
those SSI pages which are cacheable. And since sending ETags for
non-cacheable documents is not appropriate, they are no longuer
computed nor sent for those SSI pages which are not cacheable.
Regarding the "Last-Modified" header for non-cacheable documents,
the standards allow to either send the current date and time for
that header or to simply skip it. The approach chosen is to not send
it for non-cacheable SSI pages. "ETag" and "Last-Modified" headers
are therefore only sent for an SSI page if ssi.conditional-requests
is enabled for that page.
The ssi.conditional-requests directive can be enabled or disabled
globally and/or in any context. It is disabled by default.
An index.shtml which only includes deterministic SSI commands such as:
<!--#echo var="LAST_MODIFIED"-->
is a trivial example of a dynamic SSI page that is cacheable.
2016-04-13 12:27:47 +00:00
|
|
|
{ "ssi.conditional-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
|
2016-04-13 23:50:31 +00:00
|
|
|
{ "ssi.exec", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
|
2016-12-11 06:49:11 +00:00
|
|
|
{ "ssi.recursion-max", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
|
2005-02-20 14:27:00 +00:00
|
|
|
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
|
|
|
};
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (!p) return HANDLER_ERROR;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2013-11-13 11:43:26 +00:00
|
|
|
p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
2015-11-07 12:51:11 +00:00
|
|
|
data_config const* config = (data_config const*)srv->config_context->data[i];
|
2005-02-20 14:27:00 +00:00
|
|
|
plugin_config *s;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-16 13:07:46 +00:00
|
|
|
s = calloc(1, sizeof(plugin_config));
|
2005-02-20 14:27:00 +00:00
|
|
|
s->ssi_extension = array_init();
|
2009-06-10 14:50:42 +00:00
|
|
|
s->content_type = buffer_init();
|
[mod_ssi] config ssi.conditional-requests
Summary:
A new SSI directive, "ssi.conditional-requests", allows to inform
lighttpd which SSI pages should be considered as cacheable and which
should not. In particular, the "ETag" & "Last-Modified" headers will
only be sent for those SSI pages for which the directive is enabled.
Long description:
"ETag" and "Last-Modified" headers were being sent for all SSI pages,
regardless of whether they were cacheable or not. And yet, there was
no cache validation at all for any SSI page.
This commit fixes these two minor issues by adding a new directive,
"ssi.conditional-requests", which allows to specify which SSI pages
are cacheable and which are not, and by adding cache validation to
those SSI pages which are cacheable. And since sending ETags for
non-cacheable documents is not appropriate, they are no longuer
computed nor sent for those SSI pages which are not cacheable.
Regarding the "Last-Modified" header for non-cacheable documents,
the standards allow to either send the current date and time for
that header or to simply skip it. The approach chosen is to not send
it for non-cacheable SSI pages. "ETag" and "Last-Modified" headers
are therefore only sent for an SSI page if ssi.conditional-requests
is enabled for that page.
The ssi.conditional-requests directive can be enabled or disabled
globally and/or in any context. It is disabled by default.
An index.shtml which only includes deterministic SSI commands such as:
<!--#echo var="LAST_MODIFIED"-->
is a trivial example of a dynamic SSI page that is cacheable.
2016-04-13 12:27:47 +00:00
|
|
|
s->conditional_requests = 0;
|
2016-04-13 23:50:31 +00:00
|
|
|
s->ssi_exec = 1;
|
2016-12-11 06:49:11 +00:00
|
|
|
s->ssi_recursion_max = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
cv[0].destination = s->ssi_extension;
|
2009-06-10 14:50:42 +00:00
|
|
|
cv[1].destination = s->content_type;
|
[mod_ssi] config ssi.conditional-requests
Summary:
A new SSI directive, "ssi.conditional-requests", allows to inform
lighttpd which SSI pages should be considered as cacheable and which
should not. In particular, the "ETag" & "Last-Modified" headers will
only be sent for those SSI pages for which the directive is enabled.
Long description:
"ETag" and "Last-Modified" headers were being sent for all SSI pages,
regardless of whether they were cacheable or not. And yet, there was
no cache validation at all for any SSI page.
This commit fixes these two minor issues by adding a new directive,
"ssi.conditional-requests", which allows to specify which SSI pages
are cacheable and which are not, and by adding cache validation to
those SSI pages which are cacheable. And since sending ETags for
non-cacheable documents is not appropriate, they are no longuer
computed nor sent for those SSI pages which are not cacheable.
Regarding the "Last-Modified" header for non-cacheable documents,
the standards allow to either send the current date and time for
that header or to simply skip it. The approach chosen is to not send
it for non-cacheable SSI pages. "ETag" and "Last-Modified" headers
are therefore only sent for an SSI page if ssi.conditional-requests
is enabled for that page.
The ssi.conditional-requests directive can be enabled or disabled
globally and/or in any context. It is disabled by default.
An index.shtml which only includes deterministic SSI commands such as:
<!--#echo var="LAST_MODIFIED"-->
is a trivial example of a dynamic SSI page that is cacheable.
2016-04-13 12:27:47 +00:00
|
|
|
cv[2].destination = &(s->conditional_requests);
|
2016-04-13 23:50:31 +00:00
|
|
|
cv[3].destination = &(s->ssi_exec);
|
2016-12-11 06:49:11 +00:00
|
|
|
cv[4].destination = &(s->ssi_recursion_max);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
p->config_storage[i] = s;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-11-07 12:51:11 +00:00
|
|
|
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2017-03-05 20:39:45 +00:00
|
|
|
|
|
|
|
if (!array_is_vlist(s->ssi_extension)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"unexpected value for ssi.extension; expected list of \"ext\"");
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
2016-04-18 03:37:40 +00:00
|
|
|
|
consistent, shared code to create CGI env
consolidated from CGI, FastCGI, SCGI, SSI
Note: due to prior inconsistencies between the code in mod_cgi,
mod_fastcgi, mod_scgi, and mod_ssi, there are some minor behavior
changes.
CONTENT_LENGTH is now always set, even if 0
(though CONTENT_LENGTH is never set for FASTCGI_AUTHORIZER)
PATH_INFO is created only if present, not if empty.
(mod_fastcgi and mod_ssi previously set PATH_INFO="" (blank value))
PATH_TRANSLATED is now set if PATH_INFO is present
(previously missing from mod_cgi and mod_ssi)
mod_ssi now sets DOCUMENT_ROOT to con->physical.basedir, like others
(previously, mod_ssi set DOCUMENT_ROOT to con->physical.doc_root,
which matched con->physical.basedir unless mod_alias changed basedir)
mod_ssi now sets REQUEST_URI to con->request.orig_uri, like others
(previously, mod_ssi set REQUEST_URI to con->request.uri, which
matched con->request.orig_uri except after redirects, error docs)
2016-10-10 17:37:36 +00:00
|
|
|
static int ssi_env_add(void *venv, const char *key, size_t klen, const char *val, size_t vlen) {
|
|
|
|
array *env = venv;
|
2005-02-20 14:27:00 +00:00
|
|
|
data_string *ds;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
consistent, shared code to create CGI env
consolidated from CGI, FastCGI, SCGI, SSI
Note: due to prior inconsistencies between the code in mod_cgi,
mod_fastcgi, mod_scgi, and mod_ssi, there are some minor behavior
changes.
CONTENT_LENGTH is now always set, even if 0
(though CONTENT_LENGTH is never set for FASTCGI_AUTHORIZER)
PATH_INFO is created only if present, not if empty.
(mod_fastcgi and mod_ssi previously set PATH_INFO="" (blank value))
PATH_TRANSLATED is now set if PATH_INFO is present
(previously missing from mod_cgi and mod_ssi)
mod_ssi now sets DOCUMENT_ROOT to con->physical.basedir, like others
(previously, mod_ssi set DOCUMENT_ROOT to con->physical.doc_root,
which matched con->physical.basedir unless mod_alias changed basedir)
mod_ssi now sets REQUEST_URI to con->request.orig_uri, like others
(previously, mod_ssi set REQUEST_URI to con->request.uri, which
matched con->request.orig_uri except after redirects, error docs)
2016-10-10 17:37:36 +00:00
|
|
|
/* array_set_key_value() w/o extra lookup to see if key already exists */
|
2005-02-20 14:27:00 +00:00
|
|
|
if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
|
|
|
|
ds = data_string_init();
|
|
|
|
}
|
consistent, shared code to create CGI env
consolidated from CGI, FastCGI, SCGI, SSI
Note: due to prior inconsistencies between the code in mod_cgi,
mod_fastcgi, mod_scgi, and mod_ssi, there are some minor behavior
changes.
CONTENT_LENGTH is now always set, even if 0
(though CONTENT_LENGTH is never set for FASTCGI_AUTHORIZER)
PATH_INFO is created only if present, not if empty.
(mod_fastcgi and mod_ssi previously set PATH_INFO="" (blank value))
PATH_TRANSLATED is now set if PATH_INFO is present
(previously missing from mod_cgi and mod_ssi)
mod_ssi now sets DOCUMENT_ROOT to con->physical.basedir, like others
(previously, mod_ssi set DOCUMENT_ROOT to con->physical.doc_root,
which matched con->physical.basedir unless mod_alias changed basedir)
mod_ssi now sets REQUEST_URI to con->request.orig_uri, like others
(previously, mod_ssi set REQUEST_URI to con->request.uri, which
matched con->request.orig_uri except after redirects, error docs)
2016-10-10 17:37:36 +00:00
|
|
|
buffer_copy_string_len(ds->key, key, klen);
|
|
|
|
buffer_copy_string_len(ds->value, val, vlen);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
array_insert_unique(env, (data_unset *)ds);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-06 05:25:56 +00:00
|
|
|
static int build_ssi_cgi_vars(server *srv, connection *con, handler_ctx *p) {
|
consistent, shared code to create CGI env
consolidated from CGI, FastCGI, SCGI, SSI
Note: due to prior inconsistencies between the code in mod_cgi,
mod_fastcgi, mod_scgi, and mod_ssi, there are some minor behavior
changes.
CONTENT_LENGTH is now always set, even if 0
(though CONTENT_LENGTH is never set for FASTCGI_AUTHORIZER)
PATH_INFO is created only if present, not if empty.
(mod_fastcgi and mod_ssi previously set PATH_INFO="" (blank value))
PATH_TRANSLATED is now set if PATH_INFO is present
(previously missing from mod_cgi and mod_ssi)
mod_ssi now sets DOCUMENT_ROOT to con->physical.basedir, like others
(previously, mod_ssi set DOCUMENT_ROOT to con->physical.doc_root,
which matched con->physical.basedir unless mod_alias changed basedir)
mod_ssi now sets REQUEST_URI to con->request.orig_uri, like others
(previously, mod_ssi set REQUEST_URI to con->request.uri, which
matched con->request.orig_uri except after redirects, error docs)
2016-10-10 17:37:36 +00:00
|
|
|
http_cgi_opts opts = { 0, 0, NULL, NULL };
|
|
|
|
/* temporarily remove Authorization from request headers
|
|
|
|
* so that Authorization does not end up in SSI environment */
|
|
|
|
data_string *ds_auth = (data_string *)array_get_element(con->request.headers, "Authorization");
|
|
|
|
buffer *b_auth = NULL;
|
|
|
|
if (ds_auth) {
|
|
|
|
b_auth = ds_auth->value;
|
|
|
|
ds_auth->value = NULL;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
consistent, shared code to create CGI env
consolidated from CGI, FastCGI, SCGI, SSI
Note: due to prior inconsistencies between the code in mod_cgi,
mod_fastcgi, mod_scgi, and mod_ssi, there are some minor behavior
changes.
CONTENT_LENGTH is now always set, even if 0
(though CONTENT_LENGTH is never set for FASTCGI_AUTHORIZER)
PATH_INFO is created only if present, not if empty.
(mod_fastcgi and mod_ssi previously set PATH_INFO="" (blank value))
PATH_TRANSLATED is now set if PATH_INFO is present
(previously missing from mod_cgi and mod_ssi)
mod_ssi now sets DOCUMENT_ROOT to con->physical.basedir, like others
(previously, mod_ssi set DOCUMENT_ROOT to con->physical.doc_root,
which matched con->physical.basedir unless mod_alias changed basedir)
mod_ssi now sets REQUEST_URI to con->request.orig_uri, like others
(previously, mod_ssi set REQUEST_URI to con->request.uri, which
matched con->request.orig_uri except after redirects, error docs)
2016-10-10 17:37:36 +00:00
|
|
|
array_reset(p->ssi_cgi_env);
|
2016-03-26 11:14:21 +00:00
|
|
|
|
consistent, shared code to create CGI env
consolidated from CGI, FastCGI, SCGI, SSI
Note: due to prior inconsistencies between the code in mod_cgi,
mod_fastcgi, mod_scgi, and mod_ssi, there are some minor behavior
changes.
CONTENT_LENGTH is now always set, even if 0
(though CONTENT_LENGTH is never set for FASTCGI_AUTHORIZER)
PATH_INFO is created only if present, not if empty.
(mod_fastcgi and mod_ssi previously set PATH_INFO="" (blank value))
PATH_TRANSLATED is now set if PATH_INFO is present
(previously missing from mod_cgi and mod_ssi)
mod_ssi now sets DOCUMENT_ROOT to con->physical.basedir, like others
(previously, mod_ssi set DOCUMENT_ROOT to con->physical.doc_root,
which matched con->physical.basedir unless mod_alias changed basedir)
mod_ssi now sets REQUEST_URI to con->request.orig_uri, like others
(previously, mod_ssi set REQUEST_URI to con->request.uri, which
matched con->request.orig_uri except after redirects, error docs)
2016-10-10 17:37:36 +00:00
|
|
|
if (0 != http_cgi_headers(srv, con, &opts, ssi_env_add, p->ssi_cgi_env)) {
|
|
|
|
con->http_status = 400;
|
|
|
|
return -1;
|
2016-03-26 11:14:21 +00:00
|
|
|
}
|
|
|
|
|
consistent, shared code to create CGI env
consolidated from CGI, FastCGI, SCGI, SSI
Note: due to prior inconsistencies between the code in mod_cgi,
mod_fastcgi, mod_scgi, and mod_ssi, there are some minor behavior
changes.
CONTENT_LENGTH is now always set, even if 0
(though CONTENT_LENGTH is never set for FASTCGI_AUTHORIZER)
PATH_INFO is created only if present, not if empty.
(mod_fastcgi and mod_ssi previously set PATH_INFO="" (blank value))
PATH_TRANSLATED is now set if PATH_INFO is present
(previously missing from mod_cgi and mod_ssi)
mod_ssi now sets DOCUMENT_ROOT to con->physical.basedir, like others
(previously, mod_ssi set DOCUMENT_ROOT to con->physical.doc_root,
which matched con->physical.basedir unless mod_alias changed basedir)
mod_ssi now sets REQUEST_URI to con->request.orig_uri, like others
(previously, mod_ssi set REQUEST_URI to con->request.uri, which
matched con->request.orig_uri except after redirects, error docs)
2016-10-10 17:37:36 +00:00
|
|
|
if (ds_auth) {
|
|
|
|
ds_auth->value = b_auth;
|
2016-02-28 17:05:22 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-11 06:49:11 +00:00
|
|
|
static int mod_ssi_process_file(server *srv, connection *con, handler_ctx *p, struct stat *st);
|
|
|
|
|
2016-12-06 05:25:56 +00:00
|
|
|
static int process_ssi_stmt(server *srv, connection *con, handler_ctx *p, const char **l, size_t n, struct stat *st) {
|
2016-04-18 03:37:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* <!--#element attribute=value attribute=value ... -->
|
|
|
|
*
|
|
|
|
* config DONE
|
|
|
|
* errmsg -- missing
|
|
|
|
* sizefmt DONE
|
|
|
|
* timefmt DONE
|
|
|
|
* echo DONE
|
|
|
|
* var DONE
|
|
|
|
* encoding -- missing
|
|
|
|
* exec DONE
|
|
|
|
* cgi -- never
|
|
|
|
* cmd DONE
|
|
|
|
* fsize DONE
|
|
|
|
* file DONE
|
|
|
|
* virtual DONE
|
|
|
|
* flastmod DONE
|
|
|
|
* file DONE
|
|
|
|
* virtual DONE
|
|
|
|
* include DONE
|
|
|
|
* file DONE
|
|
|
|
* virtual DONE
|
|
|
|
* printenv DONE
|
|
|
|
* set DONE
|
|
|
|
* var DONE
|
|
|
|
* value DONE
|
|
|
|
*
|
|
|
|
* if DONE
|
|
|
|
* elif DONE
|
|
|
|
* else DONE
|
|
|
|
* endif DONE
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* expressions
|
|
|
|
* AND, OR DONE
|
|
|
|
* comp DONE
|
|
|
|
* ${...} -- missing
|
|
|
|
* $... DONE
|
|
|
|
* '...' DONE
|
|
|
|
* ( ... ) DONE
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* ** all DONE **
|
|
|
|
* DATE_GMT
|
|
|
|
* The current date in Greenwich Mean Time.
|
|
|
|
* DATE_LOCAL
|
|
|
|
* The current date in the local time zone.
|
|
|
|
* DOCUMENT_NAME
|
|
|
|
* The filename (excluding directories) of the document requested by the user.
|
|
|
|
* DOCUMENT_URI
|
|
|
|
* The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document.
|
|
|
|
* LAST_MODIFIED
|
|
|
|
* The last modification date of the document requested by the user.
|
|
|
|
* USER_NAME
|
|
|
|
* Contains the owner of the file which included it.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
size_t i, ssicmd = 0;
|
|
|
|
char buf[255];
|
|
|
|
buffer *b = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-12-11 06:49:11 +00:00
|
|
|
static const struct {
|
2005-02-20 14:27:00 +00:00
|
|
|
const char *var;
|
2006-10-04 13:26:23 +00:00
|
|
|
enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
|
2005-02-20 14:27:00 +00:00
|
|
|
SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
|
2016-12-11 07:39:59 +00:00
|
|
|
SSI_ELSE, SSI_ENDIF, SSI_EXEC, SSI_COMMENT } type;
|
2005-02-20 14:27:00 +00:00
|
|
|
} ssicmds[] = {
|
|
|
|
{ "echo", SSI_ECHO },
|
|
|
|
{ "include", SSI_INCLUDE },
|
|
|
|
{ "flastmod", SSI_FLASTMOD },
|
|
|
|
{ "fsize", SSI_FSIZE },
|
|
|
|
{ "config", SSI_CONFIG },
|
|
|
|
{ "printenv", SSI_PRINTENV },
|
|
|
|
{ "set", SSI_SET },
|
|
|
|
{ "if", SSI_IF },
|
|
|
|
{ "elif", SSI_ELIF },
|
|
|
|
{ "endif", SSI_ENDIF },
|
|
|
|
{ "else", SSI_ELSE },
|
|
|
|
{ "exec", SSI_EXEC },
|
2016-12-11 07:39:59 +00:00
|
|
|
{ "comment", SSI_COMMENT },
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
{ NULL, SSI_UNSET }
|
|
|
|
};
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 0; ssicmds[i].var; i++) {
|
|
|
|
if (0 == strcmp(l[1], ssicmds[i].var)) {
|
|
|
|
ssicmd = ssicmds[i].type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
switch(ssicmd) {
|
|
|
|
case SSI_ECHO: {
|
|
|
|
/* echo */
|
2009-07-21 20:35:27 +00:00
|
|
|
int var = 0;
|
|
|
|
/* int enc = 0; */
|
2005-02-20 14:27:00 +00:00
|
|
|
const char *var_val = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-12-11 06:49:11 +00:00
|
|
|
static const struct {
|
2005-02-20 14:27:00 +00:00
|
|
|
const char *var;
|
2016-03-26 11:14:21 +00:00
|
|
|
enum {
|
|
|
|
SSI_ECHO_UNSET,
|
|
|
|
SSI_ECHO_DATE_GMT,
|
|
|
|
SSI_ECHO_DATE_LOCAL,
|
|
|
|
SSI_ECHO_DOCUMENT_NAME,
|
|
|
|
SSI_ECHO_DOCUMENT_URI,
|
|
|
|
SSI_ECHO_LAST_MODIFIED,
|
|
|
|
SSI_ECHO_USER_NAME,
|
|
|
|
SSI_ECHO_SCRIPT_URI,
|
|
|
|
SSI_ECHO_SCRIPT_URL,
|
|
|
|
} type;
|
2005-02-20 14:27:00 +00:00
|
|
|
} echovars[] = {
|
|
|
|
{ "DATE_GMT", SSI_ECHO_DATE_GMT },
|
|
|
|
{ "DATE_LOCAL", SSI_ECHO_DATE_LOCAL },
|
|
|
|
{ "DOCUMENT_NAME", SSI_ECHO_DOCUMENT_NAME },
|
|
|
|
{ "DOCUMENT_URI", SSI_ECHO_DOCUMENT_URI },
|
|
|
|
{ "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
|
|
|
|
{ "USER_NAME", SSI_ECHO_USER_NAME },
|
2016-03-26 11:14:21 +00:00
|
|
|
{ "SCRIPT_URI", SSI_ECHO_SCRIPT_URI },
|
|
|
|
{ "SCRIPT_URL", SSI_ECHO_SCRIPT_URL },
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
{ NULL, SSI_ECHO_UNSET }
|
|
|
|
};
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2009-07-21 20:35:27 +00:00
|
|
|
/*
|
2016-12-11 06:49:11 +00:00
|
|
|
static const struct {
|
2005-02-20 14:27:00 +00:00
|
|
|
const char *var;
|
|
|
|
enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
|
|
|
|
} encvars[] = {
|
|
|
|
{ "url", SSI_ENC_URL },
|
|
|
|
{ "none", SSI_ENC_NONE },
|
|
|
|
{ "entity", SSI_ENC_ENTITY },
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
{ NULL, SSI_ENC_UNSET }
|
|
|
|
};
|
2009-07-21 20:35:27 +00:00
|
|
|
*/
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 2; i < n; i += 2) {
|
|
|
|
if (0 == strcmp(l[i], "var")) {
|
|
|
|
int j;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
var_val = l[i+1];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (j = 0; echovars[j].var; j++) {
|
|
|
|
if (0 == strcmp(l[i+1], echovars[j].var)) {
|
|
|
|
var = echovars[j].type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (0 == strcmp(l[i], "encoding")) {
|
2009-07-21 20:35:27 +00:00
|
|
|
/*
|
2005-02-20 14:27:00 +00:00
|
|
|
int j;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (j = 0; encvars[j].var; j++) {
|
|
|
|
if (0 == strcmp(l[i+1], encvars[j].var)) {
|
|
|
|
enc = encvars[j].type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-07-21 20:35:27 +00:00
|
|
|
*/
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sss",
|
2016-05-14 02:35:19 +00:00
|
|
|
"ssi: unknown attribute for ",
|
2005-02-20 14:27:00 +00:00
|
|
|
l[1], l[i]);
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (p->if_is_false) break;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (!var_val) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sss",
|
2006-10-04 13:26:23 +00:00
|
|
|
"ssi: ",
|
2005-02-20 14:27:00 +00:00
|
|
|
l[1], "var is missing");
|
|
|
|
break;
|
|
|
|
}
|
2005-08-08 08:22:06 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
switch(var) {
|
|
|
|
case SSI_ECHO_USER_NAME: {
|
|
|
|
struct passwd *pw;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 19:10:36 +00:00
|
|
|
b = buffer_init();
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef HAVE_PWD_H
|
2016-04-18 03:37:40 +00:00
|
|
|
if (NULL == (pw = getpwuid(st->st_uid))) {
|
|
|
|
buffer_copy_int(b, st->st_uid);
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
|
|
|
buffer_copy_string(b, pw->pw_name);
|
|
|
|
}
|
|
|
|
#else
|
2016-04-18 03:37:40 +00:00
|
|
|
buffer_copy_int(b, st->st_uid);
|
2005-02-20 14:27:00 +00:00
|
|
|
#endif
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_buffer(con->write_queue, b);
|
|
|
|
buffer_free(b);
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-03-26 11:14:21 +00:00
|
|
|
case SSI_ECHO_LAST_MODIFIED: {
|
2016-04-18 03:37:40 +00:00
|
|
|
time_t t = st->st_mtime;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SSI_ECHO_DATE_LOCAL: {
|
|
|
|
time_t t = time(NULL);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SSI_ECHO_DATE_GMT: {
|
|
|
|
time_t t = time(NULL);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SSI_ECHO_DOCUMENT_NAME: {
|
|
|
|
char *sl;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->physical.path));
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, sl + 1, strlen(sl + 1));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SSI_ECHO_DOCUMENT_URI: {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.path));
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-03-26 11:14:21 +00:00
|
|
|
case SSI_ECHO_SCRIPT_URI: {
|
|
|
|
if (!buffer_string_is_empty(con->uri.scheme) && !buffer_string_is_empty(con->uri.authority)) {
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.scheme));
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("://"));
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.authority));
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->request.uri));
|
|
|
|
if (!buffer_string_is_empty(con->uri.query)) {
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("?"));
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.query));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SSI_ECHO_SCRIPT_URL: {
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->request.uri));
|
|
|
|
if (!buffer_string_is_empty(con->uri.query)) {
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("?"));
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(con->uri.query));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
default: {
|
|
|
|
data_string *ds;
|
2016-01-03 14:48:07 +00:00
|
|
|
/* check if it is a cgi-var or a ssi-var */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2017-05-12 03:15:29 +00:00
|
|
|
if (NULL != (ds = (data_string *)array_get_element_klen(p->ssi_cgi_env, var_val, strlen(var_val))) ||
|
|
|
|
NULL != (ds = (data_string *)array_get_element_klen(p->ssi_vars, var_val, strlen(var_val)))) {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_BUF_LEN(ds->value));
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SSI_INCLUDE:
|
|
|
|
case SSI_FLASTMOD:
|
|
|
|
case SSI_FSIZE: {
|
|
|
|
const char * file_path = NULL, *virt_path = NULL;
|
2016-04-18 03:37:40 +00:00
|
|
|
struct stat stb;
|
2005-02-20 14:27:00 +00:00
|
|
|
char *sl;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 2; i < n; i += 2) {
|
|
|
|
if (0 == strcmp(l[i], "file")) {
|
|
|
|
file_path = l[i+1];
|
|
|
|
} else if (0 == strcmp(l[i], "virtual")) {
|
|
|
|
virt_path = l[i+1];
|
|
|
|
} else {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sss",
|
2016-05-14 02:35:19 +00:00
|
|
|
"ssi: unknown attribute for ",
|
2005-02-20 14:27:00 +00:00
|
|
|
l[1], l[i]);
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (!file_path && !virt_path) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sss",
|
2006-10-04 13:26:23 +00:00
|
|
|
"ssi: ",
|
2005-02-20 14:27:00 +00:00
|
|
|
l[1], "file or virtual are missing");
|
|
|
|
break;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (file_path && virt_path) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sss",
|
2006-10-04 13:26:23 +00:00
|
|
|
"ssi: ",
|
2005-02-20 14:27:00 +00:00
|
|
|
l[1], "only one of file and virtual is allowed here");
|
|
|
|
break;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (p->if_is_false) break;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (file_path) {
|
|
|
|
/* current doc-root */
|
|
|
|
if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
|
2008-07-30 19:38:32 +00:00
|
|
|
buffer_copy_string_len(p->stat_fn, CONST_STR_LEN("/"));
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
|
|
|
buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
|
|
|
|
}
|
2006-03-04 15:12:17 +00:00
|
|
|
|
2006-10-04 13:26:23 +00:00
|
|
|
buffer_copy_string(srv->tmp_buf, file_path);
|
2006-03-04 15:12:17 +00:00
|
|
|
buffer_urldecode_path(srv->tmp_buf);
|
2006-10-04 13:26:23 +00:00
|
|
|
buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
|
|
|
|
buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
|
|
|
/* virtual */
|
2016-05-12 16:12:53 +00:00
|
|
|
size_t remain;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (virt_path[0] == '/') {
|
|
|
|
buffer_copy_string(p->stat_fn, virt_path);
|
|
|
|
} else {
|
|
|
|
/* there is always a / */
|
|
|
|
sl = strrchr(con->uri.path->ptr, '/');
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
|
|
|
|
buffer_append_string(p->stat_fn, virt_path);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-06-04 15:42:31 +00:00
|
|
|
buffer_urldecode_path(p->stat_fn);
|
2005-02-28 10:38:16 +00:00
|
|
|
buffer_path_simplify(srv->tmp_buf, p->stat_fn);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
/* we have an uri */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-05-12 16:12:53 +00:00
|
|
|
/* Destination physical path (similar to code in mod_webdav.c)
|
|
|
|
* src con->physical.path might have been remapped with mod_alias, mod_userdir.
|
|
|
|
* (but neither modifies con->physical.rel_path)
|
|
|
|
* Find matching prefix to support relative paths to current physical path.
|
|
|
|
* Aliasing of paths underneath current con->physical.basedir might not work.
|
|
|
|
* Likewise, mod_rewrite URL rewriting might thwart this comparison.
|
|
|
|
* Use mod_redirect instead of mod_alias to remap paths *under* this basedir.
|
|
|
|
* Use mod_redirect instead of mod_rewrite on *any* parts of path to basedir.
|
|
|
|
* (Related, use mod_auth to protect this basedir, but avoid attempting to
|
|
|
|
* use mod_auth on paths underneath this basedir, as target path is not
|
|
|
|
* validated with mod_auth)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* find matching URI prefix
|
|
|
|
* check if remaining con->physical.rel_path matches suffix
|
|
|
|
* of con->physical.basedir so that we can use it to
|
|
|
|
* remap Destination physical path */
|
|
|
|
{
|
|
|
|
const char *sep, *sep2;
|
|
|
|
sep = con->uri.path->ptr;
|
|
|
|
sep2 = srv->tmp_buf->ptr;
|
|
|
|
for (i = 0; sep[i] && sep[i] == sep2[i]; ++i) ;
|
|
|
|
while (i != 0 && sep[--i] != '/') ; /* find matching directory path */
|
|
|
|
}
|
|
|
|
if (con->conf.force_lowercase_filenames) {
|
|
|
|
buffer_to_lower(srv->tmp_buf);
|
|
|
|
}
|
|
|
|
remain = buffer_string_length(con->uri.path) - i;
|
|
|
|
if (!con->conf.force_lowercase_filenames
|
|
|
|
? buffer_is_equal_right_len(con->physical.path, con->physical.rel_path, remain)
|
|
|
|
:(buffer_string_length(con->physical.path) >= remain
|
|
|
|
&& 0 == strncasecmp(con->physical.path->ptr+buffer_string_length(con->physical.path)-remain, con->physical.rel_path->ptr+i, remain))) {
|
|
|
|
buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, buffer_string_length(con->physical.path)-remain);
|
|
|
|
buffer_append_string_len(p->stat_fn, srv->tmp_buf->ptr+i, buffer_string_length(srv->tmp_buf)-i);
|
|
|
|
} else {
|
|
|
|
/* unable to perform physical path remap here;
|
|
|
|
* assume doc_root/rel_path and no remapping */
|
|
|
|
buffer_copy_buffer(p->stat_fn, con->physical.doc_root);
|
|
|
|
buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-04-18 03:37:40 +00:00
|
|
|
if (0 == stat(p->stat_fn->ptr, &stb)) {
|
|
|
|
time_t t = stb.st_mtime;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
switch (ssicmd) {
|
|
|
|
case SSI_FSIZE:
|
2015-02-08 19:10:36 +00:00
|
|
|
b = buffer_init();
|
2005-02-20 14:27:00 +00:00
|
|
|
if (p->sizefmt) {
|
|
|
|
int j = 0;
|
|
|
|
const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-04-18 03:37:40 +00:00
|
|
|
off_t s = stb.st_size;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_int(b, s);
|
2005-02-20 14:27:00 +00:00
|
|
|
buffer_append_string(b, abr[j]);
|
|
|
|
} else {
|
2016-04-18 03:37:40 +00:00
|
|
|
buffer_copy_int(b, stb.st_size);
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_buffer(con->write_queue, b);
|
|
|
|
buffer_free(b);
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
case SSI_FLASTMOD:
|
|
|
|
if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(none)"));
|
2005-02-20 14:27:00 +00:00
|
|
|
} else {
|
2015-02-08 19:10:36 +00:00
|
|
|
chunkqueue_append_mem(con->write_queue, buf, strlen(buf));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SSI_INCLUDE:
|
2008-01-18 09:21:07 +00:00
|
|
|
/* Keep the newest mtime of included files */
|
2016-04-18 03:37:40 +00:00
|
|
|
if (stb.st_mtime > include_file_last_mtime)
|
|
|
|
include_file_last_mtime = stb.st_mtime;
|
2008-01-18 09:21:07 +00:00
|
|
|
|
2016-12-11 06:49:11 +00:00
|
|
|
if (file_path || 0 == p->conf.ssi_recursion_max) {
|
|
|
|
/* don't process if #include file="..." is used */
|
|
|
|
chunkqueue_append_file(con->write_queue, p->stat_fn, 0, stb.st_size);
|
|
|
|
} else {
|
|
|
|
buffer *upsave, *ppsave, *prpsave;
|
|
|
|
|
|
|
|
/* only allow predefined recursion depth */
|
|
|
|
if (p->ssi_recursion_depth >= p->conf.ssi_recursion_max) {
|
|
|
|
chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("(error: include directives recurse deeper than pre-defined ssi.recursion-max)"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|