2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "base.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
|
|
|
|
#include "plugin.h"
|
|
|
|
#include "stream.h"
|
|
|
|
|
|
|
|
#include "response.h"
|
|
|
|
|
|
|
|
#include "mod_ssi.h"
|
|
|
|
|
|
|
|
#include "inet_ntop_cache.h"
|
|
|
|
|
|
|
|
#include "sys-socket.h"
|
|
|
|
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.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
|
|
|
|
|
|
|
|
#ifdef HAVE_FORK
|
2009-10-11 14:31:42 +00:00
|
|
|
# include <sys/wait.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"
|
2009-04-10 17:35:19 +00:00
|
|
|
#include "version.h"
|
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);
|
|
|
|
#ifdef HAVE_PCRE_H
|
|
|
|
pcre_free(p->ssi_regex);
|
|
|
|
#endif
|
|
|
|
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;
|
|
|
|
#ifdef HAVE_PCRE_H
|
|
|
|
const char *errptr;
|
|
|
|
int erroff;
|
|
|
|
#endif
|
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 */
|
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;
|
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);
|
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;
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef HAVE_PCRE_H
|
|
|
|
/* allow 2 params */
|
2016-04-18 03:37:40 +00:00
|
|
|
if (NULL == (p->ssi_regex = pcre_compile("^<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->$", 0, &errptr, &erroff, NULL))) {
|
2005-02-20 14:27:00 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sds",
|
2006-10-04 13:26:23 +00:00
|
|
|
"ssi: pcre ",
|
2005-02-20 14:27:00 +00:00
|
|
|
erroff, errptr);
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
#endif
|
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
|
|
|
|
|
|
|
#ifdef HAVE_PCRE_H
|
|
|
|
|
2009-03-07 21:05:37 +00:00
|
|
|
static int ssi_env_add(array *env, const char *key, const char *val) {
|
2005-02-20 14:27:00 +00:00
|
|
|
data_string *ds;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
|
|
|
|
ds = data_string_init();
|
|
|
|
}
|
|
|
|
buffer_copy_string(ds->key, key);
|
|
|
|
buffer_copy_string(ds->value, val);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* the next two functions are take from fcgi.c
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-02-20 14:27:00 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
|
|
|
|
size_t i;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 0; i < con->request.headers->used; i++) {
|
|
|
|
data_string *ds;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ds = (data_string *)con->request.headers->data[i];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
|
2005-02-20 14:27:00 +00:00
|
|
|
/* don't forward the Authorization: Header */
|
|
|
|
if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
|
|
|
|
continue;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 19:10:39 +00:00
|
|
|
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2009-04-27 09:28:45 +00:00
|
|
|
for (i = 0; i < con->environment->used; i++) {
|
|
|
|
data_string *ds;
|
|
|
|
|
|
|
|
ds = (data_string *)con->environment->data[i];
|
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
|
2015-02-08 19:10:39 +00:00
|
|
|
buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0);
|
2009-04-27 09:28:45 +00:00
|
|
|
|
|
|
|
ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
|
2015-02-08 12:37:10 +00:00
|
|
|
char buf[LI_ITOSTRING_LENGTH];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
server_socket *srv_sock = con->srv_socket;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
char b2[INET6_ADDRSTRLEN + 1];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define CONST_STRING(x) \
|
|
|
|
x
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
array_reset(p->ssi_cgi_env);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2009-04-10 17:35:19 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_DESC);
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
|
|
|
|
#ifdef HAVE_IPV6
|
2006-10-04 13:26:23 +00:00
|
|
|
inet_ntop(srv_sock->addr.plain.sa_family,
|
|
|
|
srv_sock->addr.plain.sa_family == AF_INET6 ?
|
2005-02-20 14:27:00 +00:00
|
|
|
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
|
|
|
|
(const void *) &(srv_sock->addr.ipv4.sin_addr),
|
|
|
|
b2, sizeof(b2)-1)
|
|
|
|
#else
|
|
|
|
inet_ntoa(srv_sock->addr.ipv4.sin_addr)
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-04-01 17:38:26 +00:00
|
|
|
li_utostrn(buf, sizeof(buf),
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
|
|
|
|
#else
|
|
|
|
ntohs(srv_sock->addr.ipv4.sin_port)
|
|
|
|
#endif
|
|
|
|
);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
|
|
|
|
inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (con->request.content_length > 0) {
|
|
|
|
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-04-01 17:38:26 +00:00
|
|
|
li_itostrn(buf, sizeof(buf), con->request.content_length);
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
|
|
|
|
* http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
|
|
|
|
* (6.1.14, 6.1.6, 6.1.7)
|
|
|
|
*/
|
|
|
|
|
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_NAME"), con->uri.path->ptr);
|
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), "");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
|
|
|
|
* http://www.php.net/manual/en/reserved.variables.php
|
|
|
|
* treatment of PATH_TRANSLATED is different from the one of CGI specs.
|
|
|
|
* TODO: this code should be checked against cgi.fix_pathinfo php
|
|
|
|
* parameter.
|
|
|
|
*/
|
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
if (!buffer_string_is_empty(con->request.pathinfo)) {
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
|
2016-05-02 18:31:36 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.basedir->ptr);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
|
2016-03-26 11:14:21 +00:00
|
|
|
|
|
|
|
if (!buffer_string_is_empty(con->uri.scheme)) {
|
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_SCHEME"), con->uri.scheme->ptr);
|
|
|
|
}
|
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), buffer_is_empty(con->uri.query) ? "" : con->uri.query->ptr);
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
|
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
|
2016-02-28 17:05:22 +00:00
|
|
|
/* set REDIRECT_STATUS for php compiled with --force-redirect
|
|
|
|
* (if REDIRECT_STATUS has not already been set by error handler) */
|
|
|
|
if (0 == con->error_handler_saved_status) {
|
|
|
|
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ssi_env_add_request_headers(srv, con, p);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-18 03:37:40 +00:00
|
|
|
static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const char **l, size_t n, struct stat *st) {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* <!--#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
|
|
|
|
|
|
|
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,
|
|
|
|
SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
|
|
|
|
} 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 },
|
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
|
|
|
|
|
|
|
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
|
|
|
/*
|
2006-10-04 13:26:23 +00:00
|
|
|
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",
|
2006-10-04 13:26:23 +00:00
|
|
|
"ssi: unknow 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
|
|
|
|
2016-01-03 14:48:07 +00:00
|
|
|
if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val)) ||
|
|
|
|
NULL != (ds = (data_string *)array_get_element(p->ssi_vars, 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",
|
2006-10-04 13:26:23 +00:00
|
|
|
"ssi: unknow 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 */
|
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
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_buffer(p->stat_fn, con->physical.doc_root);
|
2005-02-20 14:27:00 +00:00
|
|
|