summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2021-11-09 15:00:36 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2021-11-12 17:56:38 -0500
commit741513ecd11d341d1e752175eee5d180334a4c35 (patch)
treea31a164c4948538c1182d1dce114f750867b1376 /src
parent457362cbe35533926694d97557a39e906cce4e55 (diff)
downloadlighttpd-git-741513ecd11d341d1e752175eee5d180334a4c35.tar.gz
[mod_ssi] merge mod_ssi_expr.c into mod_ssi.c
isolate this ancient relic
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Makefile.am5
-rw-r--r--src/SConscript2
-rw-r--r--src/meson.build2
-rw-r--r--src/mod_ssi.c374
-rw-r--r--src/mod_ssi.h47
-rw-r--r--src/mod_ssi_expr.c335
-rw-r--r--src/t/test_mod_ssi.c1
8 files changed, 377 insertions, 391 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f0e17673..1e36cc31 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -838,7 +838,7 @@ add_and_install_library(mod_secdownload "mod_secdownload.c;algo_hmac.c")
add_and_install_library(mod_setenv mod_setenv.c)
add_and_install_library(mod_simple_vhost mod_simple_vhost.c)
add_and_install_library(mod_sockproxy mod_sockproxy.c)
-add_and_install_library(mod_ssi "mod_ssi_expr.c;mod_ssi.c")
+add_and_install_library(mod_ssi mod_ssi.c)
add_and_install_library(mod_staticfile mod_staticfile.c)
add_and_install_library(mod_status mod_status.c)
add_and_install_library(mod_uploadprogress mod_uploadprogress.c)
diff --git a/src/Makefile.am b/src/Makefile.am
index 329c598c..ee2a403b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -282,7 +282,7 @@ mod_sockproxy_la_LDFLAGS = $(common_module_ldflags)
mod_sockproxy_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_ssi.la
-mod_ssi_la_SOURCES = mod_ssi_expr.c mod_ssi.c
+mod_ssi_la_SOURCES = mod_ssi.c
mod_ssi_la_LDFLAGS = $(common_module_ldflags)
mod_ssi_la_LIBADD = $(common_libadd)
@@ -478,7 +478,6 @@ hdr = base64.h buffer.h burl.h network.h log.h http_kv.h keyvalue.h \
plugin.h plugin_config.h \
http_etag.h array.h vector.h \
fdevent_impl.h network_write.h configfile.h \
- mod_ssi.h \
sock_addr_cache.h \
configparser.h \
rand.h \
@@ -528,7 +527,7 @@ lighttpd_SOURCES = \
mod_secdownload.c algo_hmac.c \
mod_setenv.c \
mod_simple_vhost.c \
- mod_ssi_expr.c mod_ssi.c \
+ mod_ssi.c \
mod_staticfile.c \
mod_status.c \
mod_uploadprogress.c \
diff --git a/src/SConscript b/src/SConscript
index 79a5df88..0b9bba20 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -119,7 +119,7 @@ modules = {
'mod_setenv' : { 'src' : [ 'mod_setenv.c' ] },
'mod_simple_vhost' : { 'src' : [ 'mod_simple_vhost.c' ] },
'mod_sockproxy' : { 'src' : [ 'mod_sockproxy.c' ] },
- 'mod_ssi' : { 'src' : [ 'mod_ssi_expr.c', 'mod_ssi.c' ] },
+ 'mod_ssi' : { 'src' : [ 'mod_ssi.c' ] },
'mod_staticfile' : { 'src' : [ 'mod_staticfile.c' ] },
'mod_status' : { 'src' : [ 'mod_status.c' ] },
'mod_uploadprogress' : { 'src' : [ 'mod_uploadprogress.c' ] },
diff --git a/src/meson.build b/src/meson.build
index 548bb5a0..a51bb5c9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1117,7 +1117,7 @@ modules = [
[ 'mod_setenv', [ 'mod_setenv.c' ] ],
[ 'mod_simple_vhost', [ 'mod_simple_vhost.c' ] ],
[ 'mod_sockproxy', [ 'mod_sockproxy.c' ] ],
- [ 'mod_ssi', [ 'mod_ssi_expr.c', 'mod_ssi.c' ], libws2_32 ],
+ [ 'mod_ssi', [ 'mod_ssi.c' ], libws2_32 ],
[ 'mod_staticfile', [ 'mod_staticfile.c' ] ],
[ 'mod_status', [ 'mod_status.c' ] ],
[ 'mod_uploadprogress', [ 'mod_uploadprogress.c' ] ],
diff --git a/src/mod_ssi.c b/src/mod_ssi.c
index 1b1cf467..5ccd92b8 100644
--- a/src/mod_ssi.c
+++ b/src/mod_ssi.c
@@ -3,7 +3,9 @@
#include "fdevent.h"
#include "fdlog.h"
#include "log.h"
+#include "array.h"
#include "buffer.h"
+#include "chunk.h"
#include "http_cgi.h"
#include "http_chunk.h"
#include "http_etag.h"
@@ -15,8 +17,6 @@
#include "response.h"
-#include "mod_ssi.h"
-
#include "sys-socket.h"
#include "sys-time.h"
@@ -41,6 +41,39 @@
# include <sys/filio.h>
#endif
+typedef struct {
+ const array *ssi_extension;
+ const buffer *content_type;
+ unsigned short conditional_requests;
+ unsigned short ssi_exec;
+ unsigned short ssi_recursion_max;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_config defaults;
+ plugin_config conf;
+ array *ssi_vars;
+ array *ssi_cgi_env;
+ buffer stat_fn;
+ buffer timefmt;
+} plugin_data;
+
+typedef struct {
+ array *ssi_vars;
+ array *ssi_cgi_env;
+ buffer *stat_fn;
+ buffer *timefmt;
+ int sizefmt;
+
+ int if_level, if_is_false_level, if_is_false, if_is_false_endif;
+ unsigned short ssi_recursion_depth;
+
+ chunkqueue wq;
+ log_error_st *errh;
+ plugin_config conf;
+} handler_ctx;
+
static handler_ctx * handler_ctx_init(plugin_data *p, log_error_st *errh) {
handler_ctx *hctx = calloc(1, sizeof(*hctx));
force_assert(hctx);
@@ -178,6 +211,343 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
}
+
+
+#define TK_AND 1
+#define TK_OR 2
+#define TK_EQ 3
+#define TK_NE 4
+#define TK_GT 5
+#define TK_GE 6
+#define TK_LT 7
+#define TK_LE 8
+#define TK_NOT 9
+#define TK_LPARAN 10
+#define TK_RPARAN 11
+#define TK_VALUE 12
+
+typedef struct {
+ const char *input;
+ size_t offset;
+ size_t size;
+ int in_brace;
+ int depth;
+ handler_ctx *p;
+} ssi_tokenizer_t;
+
+typedef struct {
+ buffer str;
+ enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
+ int bo;
+} ssi_val_t;
+
+__attribute_pure__
+static int ssi_val_tobool(const ssi_val_t *B) {
+ return B->type == SSI_TYPE_BOOL ? B->bo : !buffer_is_blank(&B->str);
+}
+
+__attribute_pure__
+static int ssi_eval_expr_cmp(const ssi_val_t * const v1, const ssi_val_t * const v2, const int cond) {
+ int cmp = (v1->type != SSI_TYPE_BOOL && v2->type != SSI_TYPE_BOOL)
+ ? strcmp(v1->str.ptr ? v1->str.ptr : "",
+ v2->str.ptr ? v2->str.ptr : "")
+ : ssi_val_tobool(v1) - ssi_val_tobool(v2);
+ switch (cond) {
+ case TK_EQ: return (cmp == 0);
+ case TK_NE: return (cmp != 0);
+ case TK_GE: return (cmp >= 0);
+ case TK_GT: return (cmp > 0);
+ case TK_LE: return (cmp <= 0);
+ case TK_LT: return (cmp < 0);
+ default: return 0;/*(should not happen)*/
+ }
+}
+
+__attribute_pure__
+static int ssi_eval_expr_cmp_bool(const ssi_val_t * const v1, const ssi_val_t * const v2, const int cond) {
+ return (cond == TK_OR)
+ ? ssi_val_tobool(v1) || ssi_val_tobool(v2) /* TK_OR */
+ : ssi_val_tobool(v1) && ssi_val_tobool(v2); /* TK_AND */
+}
+
+static void ssi_eval_expr_append_val(buffer * const b, const char *s, const size_t slen) {
+ if (buffer_is_blank(b))
+ buffer_append_string_len(b, s, slen);
+ else if (slen)
+ buffer_append_str2(b, CONST_STR_LEN(" "), s, slen);
+}
+
+static int ssi_expr_tokenizer(ssi_tokenizer_t * const t, buffer * const token) {
+ size_t i;
+
+ while (t->offset < t->size
+ && (t->input[t->offset] == ' ' || t->input[t->offset] == '\t')) {
+ ++t->offset;
+ }
+ if (t->offset >= t->size)
+ return 0;
+ if (t->input[t->offset] == '\0') {
+ log_error(t->p->errh, __FILE__, __LINE__,
+ "pos: %zu foobar", t->offset+1);
+ return -1;
+ }
+
+ switch (t->input[t->offset]) {
+ case '=':
+ #if 0 /*(maybe accept "==", too)*/
+ if (t->input[t->offset + 1] == '=')
+ ++t->offset;
+ #endif
+ t->offset++;
+ return TK_EQ;
+ case '>':
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+ return TK_GE;
+ }
+ else {
+ t->offset += 1;
+ return TK_GT;
+ }
+ case '<':
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+ return TK_LE;
+ }
+ else {
+ t->offset += 1;
+ return TK_LT;
+ }
+ case '!':
+ if (t->input[t->offset + 1] == '=') {
+ t->offset += 2;
+ return TK_NE;
+ }
+ else {
+ t->offset += 1;
+ return TK_NOT;
+ }
+ case '&':
+ if (t->input[t->offset + 1] == '&') {
+ t->offset += 2;
+ return TK_AND;
+ }
+ else {
+ log_error(t->p->errh, __FILE__, __LINE__,
+ "pos: %zu missing second &", t->offset+1);
+ return -1;
+ }
+ case '|':
+ if (t->input[t->offset + 1] == '|') {
+ t->offset += 2;
+ return TK_OR;
+ }
+ else {
+ log_error(t->p->errh, __FILE__, __LINE__,
+ "pos: %zu missing second |", t->offset+1);
+ return -1;
+ }
+ case '(':
+ t->offset++;
+ t->in_brace++;
+ return TK_LPARAN;
+ case ')':
+ t->offset++;
+ t->in_brace--;
+ return TK_RPARAN;
+ case '\'':
+ /* search for the terminating "'" */
+ i = 1;
+ while (t->input[t->offset + i] && t->input[t->offset + i] != '\'')
+ ++i;
+ if (t->input[t->offset + i]) {
+ ssi_eval_expr_append_val(token, t->input + t->offset + 1, i-1);
+ t->offset += i + 1;
+ return TK_VALUE;
+ }
+ else {
+ log_error(t->p->errh, __FILE__, __LINE__,
+ "pos: %zu missing closing quote", t->offset+1);
+ return -1;
+ }
+ case '$': {
+ const char *var;
+ size_t varlen;
+ if (t->input[t->offset + 1] == '{') {
+ i = 2;
+ while (t->input[t->offset + i] && t->input[t->offset + i] != '}')
+ ++i;
+ if (t->input[t->offset + i] != '}') {
+ log_error(t->p->errh, __FILE__, __LINE__,
+ "pos: %zu missing closing curly-brace", t->offset+1);
+ return -1;
+ }
+ ++i; /* step past '}' */
+ var = t->input + t->offset + 2;
+ varlen = i-3;
+ }
+ else {
+ for (i = 1; light_isalpha(t->input[t->offset + i]) ||
+ t->input[t->offset + i] == '_' ||
+ ((i > 1) && light_isdigit(t->input[t->offset + i])); ++i) ;
+ var = t->input + t->offset + 1;
+ varlen = i-1;
+ }
+
+ const data_string *ds;
+ if ((ds = (const data_string *)
+ array_get_element_klen(t->p->ssi_cgi_env, var, varlen))
+ || (ds = (const data_string *)
+ array_get_element_klen(t->p->ssi_vars, var, varlen)))
+ ssi_eval_expr_append_val(token, BUF_PTR_LEN(&ds->value));
+ t->offset += i;
+ return TK_VALUE;
+ }
+ default:
+ for (i = 0; isgraph(((unsigned char *)t->input)[t->offset + i]); ++i) {
+ char d = t->input[t->offset + i];
+ switch(d) {
+ default: continue;
+ case ' ':
+ case '\t':
+ case ')':
+ case '(':
+ case '\'':
+ case '=':
+ case '!':
+ case '<':
+ case '>':
+ case '&':
+ case '|':
+ break;
+ }
+ break;
+ }
+ ssi_eval_expr_append_val(token, t->input + t->offset, i);
+ t->offset += i;
+ return TK_VALUE;
+ }
+}
+
+static int ssi_eval_expr_loop(ssi_tokenizer_t * const t, ssi_val_t * const v);
+
+static int ssi_eval_expr_step(ssi_tokenizer_t * const t, ssi_val_t * const v) {
+ buffer_clear(&v->str);
+ v->type = SSI_TYPE_UNSET; /*(not SSI_TYPE_BOOL)*/
+ int next;
+ const int level = t->in_brace;
+ switch ((next = ssi_expr_tokenizer(t, &v->str))) {
+ case TK_VALUE:
+ do { next = ssi_expr_tokenizer(t, &v->str); } while (next == TK_VALUE);
+ return next;
+ case TK_LPARAN:
+ if (t->in_brace > 16) return -1; /*(arbitrary limit)*/
+ next = ssi_eval_expr_loop(t, v);
+ if (next == TK_RPARAN && level == t->in_brace) {
+ int result = ssi_val_tobool(v);
+ next = ssi_eval_expr_step(t, v); /*(resets v)*/
+ v->bo = result;
+ v->type = SSI_TYPE_BOOL;
+ return (next==TK_AND || next==TK_OR || next==TK_RPARAN || 0==next)
+ ? next
+ : -1;
+ }
+ else
+ return -1;
+ case TK_RPARAN:
+ return t->in_brace >= 0 ? TK_RPARAN : -1;
+ case TK_NOT:
+ if (++t->depth > 16) return -1; /*(arbitrary limit)*/
+ next = ssi_eval_expr_step(t, v);
+ --t->depth;
+ if (-1 == next) return next;
+ v->bo = !ssi_val_tobool(v);
+ v->type = SSI_TYPE_BOOL;
+ return next;
+ default:
+ return next;
+ }
+}
+
+static int ssi_eval_expr_loop_cmp(ssi_tokenizer_t * const t, ssi_val_t * const v1, int cond) {
+ ssi_val_t v2 = { { NULL, 0, 0 }, SSI_TYPE_UNSET, 0 };
+ int next = ssi_eval_expr_step(t, &v2);
+ if (-1 != next) {
+ v1->bo = ssi_eval_expr_cmp(v1, &v2, cond);
+ v1->type = SSI_TYPE_BOOL;
+ }
+ buffer_free_ptr(&v2.str);
+ return next;
+}
+
+static int ssi_eval_expr_loop(ssi_tokenizer_t * const t, ssi_val_t * const v1) {
+ int next = ssi_eval_expr_step(t, v1);
+ switch (next) {
+ case TK_AND: case TK_OR:
+ break;
+ case TK_EQ: case TK_NE:
+ case TK_GT: case TK_GE:
+ case TK_LT: case TK_LE:
+ next = ssi_eval_expr_loop_cmp(t, v1, next);
+ if (next == TK_RPARAN || 0 == next) return next;
+ if (next != TK_AND && next != TK_OR) {
+ log_error(t->p->errh, __FILE__, __LINE__,
+ "pos: %zu parser failed somehow near here", t->offset+1);
+ return -1;
+ }
+ break;
+ default:
+ return next;
+ }
+
+ /*(Note: '&&' and '||' evaluations are not short-circuited)*/
+ ssi_val_t v2 = { { NULL, 0, 0 }, SSI_TYPE_UNSET, 0 };
+ do {
+ int cond = next;
+ next = ssi_eval_expr_step(t, &v2);
+ switch (next) {
+ case TK_AND: case TK_OR: case 0:
+ break;
+ case TK_EQ: case TK_NE:
+ case TK_GT: case TK_GE:
+ case TK_LT: case TK_LE:
+ next = ssi_eval_expr_loop_cmp(t, &v2, next);
+ if (-1 == next) continue;
+ break;
+ case TK_RPARAN:
+ break;
+ default:
+ continue;
+ }
+ v1->bo = ssi_eval_expr_cmp_bool(v1, &v2, cond);
+ v1->type = SSI_TYPE_BOOL;
+ } while (next == TK_AND || next == TK_OR);
+ buffer_free_ptr(&v2.str);
+ return next;
+}
+
+static int ssi_eval_expr(handler_ctx *p, const char *expr) {
+ ssi_tokenizer_t t;
+ t.input = expr;
+ t.offset = 0;
+ t.size = strlen(expr);
+ t.in_brace = 0;
+ t.depth = 0;
+ t.p = p;
+
+ ssi_val_t v = { { NULL, 0, 0 }, SSI_TYPE_UNSET, 0 };
+ int rc = ssi_eval_expr_loop(&t, &v);
+ rc = (0 == rc && 0 == t.in_brace && 0 == t.depth)
+ ? ssi_val_tobool(&v)
+ : -1;
+ buffer_free_ptr(&v.str);
+
+ return rc;
+}
+
+
+
+
static int ssi_env_add(void *venv, const char *key, size_t klen, const char *val, size_t vlen) {
array_set_key_value((array *)venv, key, klen, val, vlen);
return 0;
diff --git a/src/mod_ssi.h b/src/mod_ssi.h
deleted file mode 100644
index 49581d39..00000000
--- a/src/mod_ssi.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef _MOD_SSI_H_
-#define _MOD_SSI_H_
-#include "first.h"
-
-#include "base_decls.h"
-#include "buffer.h"
-#include "array.h"
-#include "chunk.h"
-
-#include "plugin.h"
-
-typedef struct {
- const array *ssi_extension;
- const buffer *content_type;
- unsigned short conditional_requests;
- unsigned short ssi_exec;
- unsigned short ssi_recursion_max;
-} plugin_config;
-
-typedef struct {
- PLUGIN_DATA;
- plugin_config defaults;
- plugin_config conf;
- array *ssi_vars;
- array *ssi_cgi_env;
- buffer stat_fn;
- buffer timefmt;
-} plugin_data;
-
-typedef struct {
- array *ssi_vars;
- array *ssi_cgi_env;
- buffer *stat_fn;
- buffer *timefmt;
- int sizefmt;
-
- int if_level, if_is_false_level, if_is_false, if_is_false_endif;
- unsigned short ssi_recursion_depth;
-
- chunkqueue wq;
- log_error_st *errh;
- plugin_config conf;
-} handler_ctx;
-
-int ssi_eval_expr(handler_ctx *p, const char *expr);
-
-#endif
diff --git a/src/mod_ssi_expr.c b/src/mod_ssi_expr.c
deleted file mode 100644
index a72825cd..00000000
--- a/src/mod_ssi_expr.c
+++ /dev/null
@@ -1,335 +0,0 @@
-#include "first.h"
-
-#include "buffer.h"
-#include "log.h"
-#include "mod_ssi.h"
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define TK_AND 1
-#define TK_OR 2
-#define TK_EQ 3
-#define TK_NE 4
-#define TK_GT 5
-#define TK_GE 6
-#define TK_LT 7
-#define TK_LE 8
-#define TK_NOT 9
-#define TK_LPARAN 10
-#define TK_RPARAN 11
-#define TK_VALUE 12
-
-typedef struct {
- const char *input;
- size_t offset;
- size_t size;
-
- int in_brace;
- int depth;
- handler_ctx *p;
-} ssi_tokenizer_t;
-
-typedef struct {
- enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
-
- buffer *str;
- int bo;
-} ssi_val_t;
-
-__attribute_pure__
-static int ssi_val_tobool(const ssi_val_t *B) {
- return B->type == SSI_TYPE_BOOL ? B->bo : !buffer_is_blank(B->str);
-}
-
-__attribute_pure__
-static int ssi_eval_expr_cmp(const ssi_val_t * const v1, const ssi_val_t * const v2, const int cond) {
- int cmp = (v1->type != SSI_TYPE_BOOL && v2->type != SSI_TYPE_BOOL)
- ? strcmp(v1->str->ptr ? v1->str->ptr : "",
- v2->str->ptr ? v2->str->ptr : "")
- : ssi_val_tobool(v1) - ssi_val_tobool(v2);
- switch (cond) {
- case TK_EQ: return (cmp == 0);
- case TK_NE: return (cmp != 0);
- case TK_GE: return (cmp >= 0);
- case TK_GT: return (cmp > 0);
- case TK_LE: return (cmp <= 0);
- case TK_LT: return (cmp < 0);
- default: return 0;/*(should not happen)*/
- }
-}
-
-__attribute_pure__
-static int ssi_eval_expr_cmp_bool(const ssi_val_t * const v1, const ssi_val_t * const v2, const int cond) {
- return (cond == TK_OR)
- ? ssi_val_tobool(v1) || ssi_val_tobool(v2) /* TK_OR */
- : ssi_val_tobool(v1) && ssi_val_tobool(v2); /* TK_AND */
-}
-
-static void ssi_eval_expr_append_val(buffer * const b, const char *s, const size_t slen) {
- if (buffer_is_blank(b))
- buffer_append_string_len(b, s, slen);
- else
- buffer_append_str2(b, CONST_STR_LEN(""), s, slen);
-}
-
-static int ssi_expr_tokenizer(ssi_tokenizer_t * const t, buffer * const token) {
- size_t i;
-
- while (t->offset < t->size
- && (t->input[t->offset] == ' ' || t->input[t->offset] == '\t')) {
- ++t->offset;
- }
- if (t->offset >= t->size)
- return 0;
- if (t->input[t->offset] == '\0') {
- log_error(t->p->errh, __FILE__, __LINE__,
- "pos: %zu foobar", t->offset+1);
- return -1;
- }
-
- switch (t->input[t->offset]) {
- case '=':
- #if 0 /*(maybe accept "==", too)*/
- if (t->input[t->offset + 1] == '=')
- ++t->offset;
- #endif
- t->offset++;
- return TK_EQ;
- case '>':
- if (t->input[t->offset + 1] == '=') {
- t->offset += 2;
- return TK_GE;
- } else {
- t->offset += 1;
- return TK_GT;
- }
- case '<':
- if (t->input[t->offset + 1] == '=') {
- t->offset += 2;
- return TK_LE;
- } else {
- t->offset += 1;
- return TK_LT;
- }
- case '!':
- if (t->input[t->offset + 1] == '=') {
- t->offset += 2;
- return TK_NE;
- } else {
- t->offset += 1;
- return TK_NOT;
- }
- case '&':
- if (t->input[t->offset + 1] == '&') {
- t->offset += 2;
- return TK_AND;
- } else {
- log_error(t->p->errh, __FILE__, __LINE__,
- "pos: %zu missing second &", t->offset+1);
- return -1;
- }
- case '|':
- if (t->input[t->offset + 1] == '|') {
- t->offset += 2;
- return TK_OR;
- } else {
- log_error(t->p->errh, __FILE__, __LINE__,
- "pos: %zu missing second |", t->offset+1);
- return -1;
- }
- case '(':
- t->offset++;
- t->in_brace++;
- return TK_LPARAN;
- case ')':
- t->offset++;
- t->in_brace--;
- return TK_RPARAN;
- case '\'':
- /* search for the terminating "'" */
- for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++);
-
- if (t->input[t->offset + i]) {
- ssi_eval_expr_append_val(token, t->input + t->offset + 1, i-1);
- t->offset += i + 1;
- return TK_VALUE;
- } else {
- log_error(t->p->errh, __FILE__, __LINE__,
- "pos: %zu missing closing quote", t->offset+1);
- return -1;
- }
- case '$': {
- const char *var;
- size_t varlen;
- if (t->input[t->offset + 1] == '{') {
- for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++);
-
- if (t->input[t->offset + i] != '}') {
- log_error(t->p->errh, __FILE__, __LINE__,
- "pos: %zu missing closing curly-brace", t->offset+1);
- return -1;
- }
- ++i; /* step past '}' */
- var = t->input + t->offset + 2;
- varlen = i-3;
- } else {
- for (i = 1; isalpha(((unsigned char *)t->input)[t->offset + i]) ||
- t->input[t->offset + i] == '_' ||
- ((i > 1) && isdigit(((unsigned char *)t->input)[t->offset + i])); i++);
- var = t->input + t->offset + 1;
- varlen = i-1;
- }
-
- const data_string *ds;
- if (NULL != (ds = (const data_string *)array_get_element_klen(t->p->ssi_cgi_env, var, varlen))
- || NULL != (ds = (const data_string *)array_get_element_klen(t->p->ssi_vars, var, varlen)))
- ssi_eval_expr_append_val(token, BUF_PTR_LEN(&ds->value));
- t->offset += i;
- return TK_VALUE;
- }
- default:
- for (i = 0; isgraph(((unsigned char *)t->input)[t->offset + i]); i++) {
- char d = t->input[t->offset + i];
- switch(d) {
- default: continue;
- case ' ':
- case '\t':
- case ')':
- case '(':
- case '\'':
- case '=':
- case '!':
- case '<':
- case '>':
- case '&':
- case '|':
- break;
- }
- break;
- }
- ssi_eval_expr_append_val(token, t->input + t->offset, i);
- t->offset += i;
- return TK_VALUE;
- }
-}
-
-static int ssi_eval_expr_loop(ssi_tokenizer_t * const t, ssi_val_t * const v);
-
-static int ssi_eval_expr_step(ssi_tokenizer_t * const t, ssi_val_t * const v) {
- buffer_clear(v->str);
- v->type = SSI_TYPE_UNSET; /*(not SSI_TYPE_BOOL)*/
- int next;
- const int level = t->in_brace;
- switch ((next = ssi_expr_tokenizer(t, v->str))) {
- case TK_VALUE:
- do { next=ssi_expr_tokenizer(t, v->str); } while (next == TK_VALUE);
- return next;
- case TK_LPARAN:
- if (t->in_brace > 16) return -1; /*(arbitrary limit)*/
- next = ssi_eval_expr_loop(t, v);
- if (next == TK_RPARAN && level == t->in_brace) {
- int result = ssi_val_tobool(v);
- next = ssi_eval_expr_step(t, v); /*(resets v)*/
- v->bo = result;
- v->type = SSI_TYPE_BOOL;
- return (next==TK_AND || next==TK_OR || next==TK_RPARAN || 0==next)
- ? next
- : -1;
- }
- else
- return -1;
- case TK_RPARAN:
- return t->in_brace >= 0 ? TK_RPARAN : -1;
- case TK_NOT:
- if (++t->depth > 16) return -1; /*(arbitrary limit)*/
- next = ssi_eval_expr_step(t, v);
- --t->depth;
- if (-1 == next) return next;
- v->bo = !ssi_val_tobool(v);
- v->type = SSI_TYPE_BOOL;
- return next;
- default:
- return next;
- }
-}
-
-static int ssi_eval_expr_loop_cmp(ssi_tokenizer_t * const t, ssi_val_t * const v1, int cond) {
- ssi_val_t v2 = { SSI_TYPE_UNSET, NULL, 0 };
- v2.str = buffer_init();
- int next = ssi_eval_expr_step(t, &v2);
- if (-1 != next) {
- v1->bo = ssi_eval_expr_cmp(v1, &v2, cond);
- v1->type = SSI_TYPE_BOOL;
- }
- buffer_free(v2.str);
- return next;
-}
-
-static int ssi_eval_expr_loop(ssi_tokenizer_t * const t, ssi_val_t * const v1) {
- int next = ssi_eval_expr_step(t, v1);
- switch (next) {
- case TK_AND: case TK_OR:
- break;
- case TK_EQ: case TK_NE:
- case TK_GT: case TK_GE:
- case TK_LT: case TK_LE:
- next = ssi_eval_expr_loop_cmp(t, v1, next);
- if (next == TK_RPARAN || 0 == next) return next;
- if (next != TK_AND && next != TK_OR) {
- log_error(t->p->errh, __FILE__, __LINE__,
- "pos: %zu parser failed somehow near here", t->offset+1);
- return -1;
- }
- break;
- default:
- return next;
- }
-
- /*(Note: '&&' and '||' evaluations are not short-circuited)*/
- ssi_val_t v2 = { SSI_TYPE_UNSET, NULL, 0 };
- v2.str = buffer_init();
- do {
- int cond = next;
- next = ssi_eval_expr_step(t, &v2);
- switch (next) {
- case TK_AND: case TK_OR: case 0:
- break;
- case TK_EQ: case TK_NE:
- case TK_GT: case TK_GE:
- case TK_LT: case TK_LE:
- next = ssi_eval_expr_loop_cmp(t, &v2, next);
- if (-1 != next)
- break;
- __attribute_fallthrough__
- default:
- buffer_free(v2.str);
- return next;
- }
- v1->bo = ssi_eval_expr_cmp_bool(v1, &v2, cond);
- v1->type = SSI_TYPE_BOOL;
- } while (next == TK_AND || next == TK_OR);
- buffer_free(v2.str);
- return next;
-}
-
-int ssi_eval_expr(handler_ctx *p, const char *expr) {
- ssi_tokenizer_t t;
- t.input = expr;
- t.offset = 0;
- t.size = strlen(expr);
- t.in_brace = 0;
- t.depth = 0;
- t.p = p;
-
- ssi_val_t v = { SSI_TYPE_UNSET, NULL, 0 };
- v.str = buffer_init();
- int rc = ssi_eval_expr_loop(&t, &v);
- rc = (0 == rc && 0 == t.in_brace && 0 == t.depth)
- ? ssi_val_tobool(&v)
- : -1;
- buffer_free(v.str);
-
- return rc;
-}
diff --git a/src/t/test_mod_ssi.c b/src/t/test_mod_ssi.c
index 75904a72..7c64dd02 100644
--- a/src/t/test_mod_ssi.c
+++ b/src/t/test_mod_ssi.c
@@ -8,7 +8,6 @@
#include <unistd.h>
#include "mod_ssi.c"
-#include "mod_ssi_expr.c"
#include "fdlog.h"
static void test_mod_ssi_reset (request_st * const r, handler_ctx * const hctx)