summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2016-05-13 22:35:19 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2016-05-14 05:50:37 -0400
commita5fcfee6fca39ddc951dda92e6c0665981acd890 (patch)
treeb762820f39197b895dcc6523cdf4c7da7f9904a4
parentabfb9d9e2d0e9e98cafcfc7172264ac9e8708d14 (diff)
downloadlighttpd-git-a5fcfee6fca39ddc951dda92e6c0665981acd890.tar.gz
[mod_ssi] more flexible quoting (fixes #1768)
allow double-quotes, single-quotes or no quote on SSI param values remove use of PCRE from mod_ssi fix misspelling of 'unknow' to be 'unknown' x-ref: "mod_ssi doesn't accept single quotes" https://redmine.lighttpd.net/issues/1768
-rw-r--r--configure.ac4
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Makefile.am2
-rw-r--r--src/SConscript2
-rw-r--r--src/mod_ssi.c179
-rw-r--r--src/mod_ssi.h7
-rw-r--r--tests/docroot/www/ssi-include.shtml3
-rwxr-xr-xtests/mod-ssi.t2
8 files changed, 133 insertions, 68 deletions
diff --git a/configure.ac b/configure.ac
index 26c607dd..993eee0d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -841,9 +841,9 @@ AC_OUTPUT
do_build="mod_cgi mod_fastcgi mod_extforward mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog"
-do_build="$do_build mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfile mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming"
+do_build="$do_build mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfile mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming mod_ssi"
-plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
+plugins="mod_rewrite mod_redirect mod_trigger_b4_dl"
features="regex-conditionals"
if test ! "x$PCRE_LIB" = x; then
do_build="$do_build $plugins"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 502815e3..b4d0c2cb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -597,8 +597,6 @@ if(HAVE_PCRE_H)
add_target_properties(mod_dirlisting COMPILE_FLAGS ${PCRE_CFLAGS})
target_link_libraries(mod_redirect ${PCRE_LDFLAGS})
add_target_properties(mod_redirect COMPILE_FLAGS ${PCRE_CFLAGS})
- target_link_libraries(mod_ssi ${PCRE_LDFLAGS})
- add_target_properties(mod_ssi COMPILE_FLAGS ${PCRE_CFLAGS})
target_link_libraries(mod_trigger_b4_dl ${PCRE_LDFLAGS})
add_target_properties(mod_trigger_b4_dl COMPILE_FLAGS ${PCRE_CFLAGS})
endif()
diff --git a/src/Makefile.am b/src/Makefile.am
index 5bfed861..6ac25fda 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -204,7 +204,7 @@ mod_proxy_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_ssi.la
mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
mod_ssi_la_LDFLAGS = $(common_module_ldflags)
-mod_ssi_la_LIBADD = $(common_libadd) $(PCRE_LIB)
+mod_ssi_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_secdownload.la
mod_secdownload_la_SOURCES = mod_secdownload.c
diff --git a/src/SConscript b/src/SConscript
index 1decfda1..bf907934 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -106,7 +106,7 @@ modules = {
'mod_mysql_vhost' : { 'src' : [ 'mod_mysql_vhost.c' ], 'lib' : [ env['LIBMYSQL'] ] },
# 'mod_uploadprogress' : { 'src' : [ 'mod_uploadprogress.c' ] },
'mod_evasive' : { 'src' : [ 'mod_evasive.c' ] },
- 'mod_ssi' : { 'src' : [ 'mod_ssi_exprparser.c', 'mod_ssi_expr.c', 'mod_ssi.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_ssi' : { 'src' : [ 'mod_ssi_exprparser.c', 'mod_ssi_expr.c', 'mod_ssi.c' ] },
'mod_flv_streaming' : { 'src' : [ 'mod_flv_streaming.c' ] },
'mod_cml': {
'src' : [ 'mod_cml_lua.c', 'mod_cml.c', 'mod_cml_funcs.c' ],
diff --git a/src/mod_ssi.c b/src/mod_ssi.c
index 6dd4f9f6..ffba44ab 100644
--- a/src/mod_ssi.c
+++ b/src/mod_ssi.c
@@ -84,9 +84,6 @@ FREE_FUNC(mod_ssi_free) {
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);
@@ -100,10 +97,6 @@ FREE_FUNC(mod_ssi_free) {
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
config_values_t cv[] = {
{ "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
@@ -139,26 +132,10 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
}
}
-#ifdef HAVE_PCRE_H
- /* allow 2 params */
- if (NULL == (p->ssi_regex = pcre_compile("^<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->$", PCRE_ANCHORED|PCRE_DOLLAR_ENDONLY|PCRE_DOTALL|PCRE_UTF8, &errptr, &erroff, NULL))) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "ssi: pcre ",
- 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
-
return HANDLER_GO_ON;
}
-#ifdef HAVE_PCRE_H
-
static int ssi_env_add(array *env, const char *key, const char *val) {
data_string *ds;
@@ -471,7 +448,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
*/
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknown attribute for ",
l[1], l[i]);
}
}
@@ -598,7 +575,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
virt_path = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknown attribute for ",
l[1], l[i]);
}
}
@@ -747,7 +724,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
val = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknown attribute for ",
l[1], l[i]);
}
}
@@ -764,10 +741,12 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
buffer_copy_string(ds->value, val);
array_insert_unique(p->ssi_vars, (data_unset *)ds);
+ } else if (key || val) {
+ log_error_write(srv, __FILE__, __LINE__, "sSSss",
+ "ssi: var and value have to be set in <!--#set", l[1], "=", l[2], "-->");
} else {
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: var and value have to be set in",
- l[0], l[1]);
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ssi: var and value have to be set in <!--#set var=... value=... -->");
}
break;
}
@@ -784,14 +763,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
p->sizefmt = 0;
} else {
log_error_write(srv, __FILE__, __LINE__, "sssss",
- "ssi: unknow value for attribute '",
+ "ssi: unknown value for attribute '",
l[i],
"' for ",
l[1], l[i+1]);
}
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknown attribute for ",
l[1], l[i]);
}
}
@@ -834,7 +813,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
cmd = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknown attribute for ",
l[1], l[i]);
}
}
@@ -951,7 +930,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
expr = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknown attribute for ",
l[1], l[i]);
}
}
@@ -1005,7 +984,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
expr = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknown attribute for ",
l[1], l[i]);
}
}
@@ -1054,7 +1033,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
break;
default:
log_error_write(srv, __FILE__, __LINE__, "ss",
- "ssi: unknow ssi-command:",
+ "ssi: unknown ssi-command:",
l[1]);
break;
}
@@ -1063,27 +1042,125 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const
}
+static int mod_ssi_parse_ssi_stmt_value(const char * const s, const int len) {
+ int n;
+ const int c = (s[0] == '"' ? '"' : s[0] == '\'' ? '\'' : 0);
+ if (0 != c) {
+ for (n = 1; n < len; ++n) {
+ if (s[n] == c) return n+1;
+ if (s[n] == '\\') {
+ if (n+1 == len) return 0; /* invalid */
+ ++n;
+ }
+ }
+ return 0; /* invalid */
+ } else {
+ for (n = 0; n < len; ++n) {
+ if (isspace(s[n])) return n;
+ if (s[n] == '\\') {
+ if (n+1 == len) return 0; /* invalid */
+ ++n;
+ }
+ }
+ return n;
+ }
+}
+
+static int mod_ssi_parse_ssi_stmt_offlen(int o[10], const char * const s, const int len) {
+
+ /**
+ * <!--#element attribute=value attribute=value ... -->
+ */
+
+ /* s must begin "<!--#" and must end with "-->" */
+ int n = 5;
+ o[0] = n;
+ for (; light_isalpha(s[n]); ++n) ; /*(n = 5 to begin after "<!--#")*/
+ o[1] = n - o[0];
+ if (0 == o[1]) return -1; /* empty token */
+
+ if (n+3 == len) return 2; /* token only; no params */
+ if (!isspace(s[n])) return -1;
+ do { ++n; } while (isspace(s[n])); /* string ends "-->", so n < len */
+ if (n+3 == len) return 2; /* token only; no params */
+
+ o[2] = n;
+ for (; light_isalpha(s[n]); ++n) ;
+ o[3] = n - o[2];
+ if (0 == o[3] || s[n++] != '=') return -1;
+
+ o[4] = n;
+ o[5] = mod_ssi_parse_ssi_stmt_value(s+n, len-n-3);
+ if (0 == o[5]) return -1; /* empty or invalid token */
+ n += o[5];
+
+ if (n+3 == len) return 6; /* token and one param */
+ if (!isspace(s[n])) return -1;
+ do { ++n; } while (isspace(s[n])); /* string ends "-->", so n < len */
+ if (n+3 == len) return 6; /* token and one param */
+
+ o[6] = n;
+ for (; light_isalpha(s[n]); ++n) ;
+ o[7] = n - o[6];
+ if (0 == o[7] || s[n++] != '=') return -1;
+
+ o[8] = n;
+ o[9] = mod_ssi_parse_ssi_stmt_value(s+n, len-n-3);
+ if (0 == o[9]) return -1; /* empty or invalid token */
+ n += o[9];
+
+ if (n+3 == len) return 10; /* token and two params */
+ if (!isspace(s[n])) return -1;
+ do { ++n; } while (isspace(s[n])); /* string ends "-->", so n < len */
+ if (n+3 == len) return 10; /* token and two params */
+ return -1;
+}
+
static void mod_ssi_parse_ssi_stmt(server *srv, connection *con, plugin_data *p, char *s, int len, struct stat *st) {
/**
* <!--#element attribute=value attribute=value ... -->
*/
-#define N 10
- int ovec[N * 3];
- int n = pcre_exec(p->ssi_regex, NULL, s, len, 0, PCRE_ANCHORED, ovec, sizeof(ovec)/sizeof(*ovec));
- if (n > 0) {
- const char **l;
- pcre_get_substring_list(s, ovec, n, &l);
- process_ssi_stmt(srv, con, p, l, n, st);
- pcre_free_substring_list(l);
- } else {
- if (n != PCRE_ERROR_NOMATCH) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "execution error while matching: ", n);
- }
+ int o[10];
+ int m;
+ const int n = mod_ssi_parse_ssi_stmt_offlen(o, s, len);
+ char *l[6] = { s, NULL, NULL, NULL, NULL, NULL };
+ if (-1 == n) {
+ /* XXX: perhaps emit error comment instead of invalid <!--#...--> code to client */
chunkqueue_append_mem(con->write_queue, s, len); /* append stmt as-is */
+ return;
+ }
+
+ #if 0
+ /* dup s and then modify s */
+ /*(l[0] is no longer used; was previously used in only one place for error reporting)*/
+ l[0] = malloc((size_t)(len+1));
+ memcpy(l[0], s, (size_t)len);
+ (l[0])[len] = '\0';
+ #endif
+
+ /* modify s in-place to split string into arg tokens */
+ for (m = 0; m < n; m += 2) {
+ char *ptr = s+o[m];
+ switch (*ptr) {
+ case '"':
+ case '\'': (++ptr)[o[m+1]-2] = '\0'; break;
+ default: ptr[o[m+1]] = '\0'; break;
+ }
+ l[1+(m>>1)] = ptr;
+ if (m == 4 || m == 8) {
+ /* XXX: removing '\\' escapes from param value would be
+ * the right thing to do, but would potentially change
+ * current behavior, e.g. <!--#exec cmd=... --> */
+ }
}
+
+ process_ssi_stmt(srv, con, p, (const char **)l, 1+(n>>1), st);
+
+ #if 0
+ free(l[0]);
+ #endif
}
static int mod_ssi_stmt_len(const char *s, const int len) {
@@ -1184,8 +1261,6 @@ static void mod_ssi_read_fd(server *srv, connection *con, plugin_data *p, int fd
}
}
-#endif /* HAVE_PCRE_H */
-
/* don't want to block when open()ing a fifo */
#if defined(O_NONBLOCK)
@@ -1222,11 +1297,7 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p)
return -1;
}
- #ifdef HAVE_PCRE_H
mod_ssi_read_fd(srv, con, p, fd, &st);
- #else
- chunkqueue_append_file(con->write_queue, con->physical.path, 0, st.st_size);
- #endif
close(fd);
con->file_started = 1;
diff --git a/src/mod_ssi.h b/src/mod_ssi.h
index 474757eb..9ce88c16 100644
--- a/src/mod_ssi.h
+++ b/src/mod_ssi.h
@@ -8,10 +8,6 @@
#include "plugin.h"
-#ifdef HAVE_PCRE_H
-#include <pcre.h>
-#endif
-
/* plugin config for all request/connections */
typedef struct {
@@ -24,9 +20,6 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-#ifdef HAVE_PCRE_H
- pcre *ssi_regex;
-#endif
buffer *timefmt;
int sizefmt;
diff --git a/tests/docroot/www/ssi-include.shtml b/tests/docroot/www/ssi-include.shtml
index fb65ef20..317c6e3a 100644
--- a/tests/docroot/www/ssi-include.shtml
+++ b/tests/docroot/www/ssi-include.shtml
@@ -1,2 +1,5 @@
+<!--#echo var=SCRIPT_NAME-->
+<!--#echo var='SCRIPT_NAME'-->
+<!--#echo var="SCRIPT_NAME"-->
<!--#include virtual="ssi-include.txt" -->
<!--#include file="ssi-include.txt" -->
diff --git a/tests/mod-ssi.t b/tests/mod-ssi.t
index a6f1e7b2..f2f3bf4c 100755
--- a/tests/mod-ssi.t
+++ b/tests/mod-ssi.t
@@ -37,7 +37,7 @@ $t->{REQUEST} = ( <<EOF
GET /ssi-include.shtml HTTP/1.0
EOF
);
-$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "ssi-include\n\nssi-include\n\n" } ];
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "/ssi-include.shtml\n/ssi-include.shtml\n/ssi-include.shtml\nssi-include\n\nssi-include\n\n" } ];
ok($tf->handle_http($t) == 0, 'ssi - include');