Browse Source

[mod_ssi] merge mod_ssi_expr.c into mod_ssi.c

isolate this ancient relic
master
Glenn Strauss 2 months ago
parent
commit
741513ecd1
  1. 2
      src/CMakeLists.txt
  2. 5
      src/Makefile.am
  3. 2
      src/SConscript
  4. 2
      src/meson.build
  5. 374
      src/mod_ssi.c
  6. 47
      src/mod_ssi.h
  7. 335
      src/mod_ssi_expr.c
  8. 1
      src/t/test_mod_ssi.c

2
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)

5
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 \

2
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' ] },

2
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' ] ],

374
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;

47
src/mod_ssi.h

@ -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

335
src/mod_ssi_expr.c

@ -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;
}

1
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)

Loading…
Cancel
Save