[core] tighten struct data_config and related code

tighten struct data_config and config_cond_info
create config key at startup and reuse for debug/trace
separate routine for configparser_parse_condition()
separate routine for configparser_parse_else_condition()
master
Glenn Strauss 2 years ago
parent 0045b9aa1a
commit cf3e301272

@ -36,9 +36,7 @@ void config_get_config_cond_info(config_cond_info * const cfginfo, uint32_t idx)
cfginfo->comp = dc->comp;
cfginfo->cond = dc->cond;
cfginfo->string = &dc->string;
cfginfo->comp_tag = dc->comp_tag;
cfginfo->comp_key = dc->comp_key;
cfginfo->op = dc->op;
}
int config_plugin_value_tobool (const data_unset *du, int default_value)
@ -591,7 +589,8 @@ static cond_result_t config_check_cond_nocache(request_st * const r, const data_
break;
case COMP_HTTP_REQUEST_HEADER:
*((const buffer **)&l) = http_header_request_get(r, dc->ext, CONST_BUF_LEN(dc->comp_tag));
*((const buffer **)&l) =
http_header_request_get(r, dc->ext, CONST_BUF_LEN(&dc->comp_tag));
if (NULL == l) l = (buffer *)&empty_string;
break;
case COMP_HTTP_REQUEST_METHOD:
@ -605,12 +604,12 @@ static cond_result_t config_check_cond_nocache(request_st * const r, const data_
if (NULL == l) { /*(should not happen)*/
log_error(r->conf.errh, __FILE__, __LINE__,
"%s () compare to NULL", dc->comp_key->ptr);
"%s compare to NULL", dc->comp_key);
return COND_RESULT_FALSE;
}
else if (debug_cond) {
log_error(r->conf.errh, __FILE__, __LINE__,
"%s (%s) compare to %s", dc->comp_key->ptr, l->ptr, dc->string.ptr);
"%s compare to %s", dc->comp_key, l->ptr);
}
switch(dc->cond) {

@ -38,9 +38,8 @@ struct data_config {
struct pcre_extra *regex_study;
#endif
int ext;
buffer *comp_tag;
buffer *comp_key;
const char *op;
buffer comp_tag;
const char *comp_key;
vector_config_weak children;
array *value;

@ -17,6 +17,7 @@
#include <stdio.h>
#include <string.h>
__attribute_pure__
static data_config * configparser_get_data_config(const array *a, const char *k, const size_t klen) {
return (data_config *)array_get_data_unset(a, k, klen);
}
@ -150,6 +151,200 @@ static int configparser_remoteip_normalize_compat(buffer *rvalue) {
return rc;
}
__attribute_pure__
static comp_key_t
configparser_comp_key_id(const buffer * const obj_tag, const buffer * const comp_tag)
{
/* $REQUEST_HEADER["..."] */
/* $SERVER["socket"] */
/* $HTTP["..."] */
if (buffer_eq_slen(obj_tag, CONST_STR_LEN("REQUEST_HEADER")))
return COMP_HTTP_REQUEST_HEADER;
else if (buffer_eq_slen(obj_tag, CONST_STR_LEN("SERVER")))
return (buffer_eq_slen(comp_tag, CONST_STR_LEN("socket")))
? COMP_SERVER_SOCKET
: COMP_UNSET;
else if (buffer_eq_slen(obj_tag, CONST_STR_LEN("HTTP"))) {
static const struct {
comp_key_t comp;
uint32_t len;
const char *comp_tag;
} comps[] = {
{ COMP_HTTP_URL, CONST_LEN_STR("url" ) },
{ COMP_HTTP_HOST, CONST_LEN_STR("host" ) },
{ COMP_HTTP_REQUEST_HEADER, CONST_LEN_STR("referer" ) },
{ COMP_HTTP_USER_AGENT, CONST_LEN_STR("useragent" ) },
{ COMP_HTTP_REQUEST_HEADER, CONST_LEN_STR("user-agent" ) },
{ COMP_HTTP_LANGUAGE, CONST_LEN_STR("language" ) },
{ COMP_HTTP_REQUEST_HEADER, CONST_LEN_STR("cookie" ) },
{ COMP_HTTP_REMOTE_IP, CONST_LEN_STR("remoteip" ) },
{ COMP_HTTP_REMOTE_IP, CONST_LEN_STR("remote-ip" ) },
{ COMP_HTTP_QUERY_STRING, CONST_LEN_STR("querystring" ) },
{ COMP_HTTP_QUERY_STRING, CONST_LEN_STR("query-string" ) },
{ COMP_HTTP_REQUEST_METHOD, CONST_LEN_STR("request-method") },
{ COMP_HTTP_SCHEME, CONST_LEN_STR("scheme" ) }
};
for (uint32_t i = 0; i < sizeof(comps)/sizeof(comps[0]); ++i) {
if (buffer_eq_slen(comp_tag, comps[i].comp_tag, comps[i].len))
return comps[i].comp;
}
}
return COMP_UNSET;
}
static void
configparser_parse_condition(config_t * const ctx, const buffer * const obj_tag, const buffer * const comp_tag, const config_cond_t cond, buffer * const rvalue)
{
const char *op = NULL;
switch(cond) {
case CONFIG_COND_NE: op = "!="; break;
case CONFIG_COND_EQ: op = "=="; break;
case CONFIG_COND_NOMATCH: op = "!~"; break;
case CONFIG_COND_MATCH: op = "=~"; break;
default:
force_assert(0);
return; /* unreachable */
}
buffer * const tb = ctx->srv->tmp_buf;
buffer_copy_buffer(tb, &ctx->current->key);
buffer_append_string_len(tb, CONST_STR_LEN(" / "));
const uint32_t comp_offset = buffer_string_length(tb);
buffer_append_string_len(tb, CONST_STR_LEN("$"));
buffer_append_string_buffer(tb, obj_tag); /*(HTTP, REQUEST_HEADER, SERVER)*/
buffer_append_string_len(tb, CONST_STR_LEN("[\""));
buffer_append_string_buffer(tb, comp_tag);
buffer_append_string_len(tb, CONST_STR_LEN("\"] "));
buffer_append_string_len(tb, op, 2);
buffer_append_string_len(tb, CONST_STR_LEN(" \""));
buffer_append_string_buffer(tb, rvalue);
buffer_append_string_len(tb, CONST_STR_LEN("\""));
data_config *dc;
if (NULL != (dc = configparser_get_data_config(ctx->all_configs,
CONST_BUF_LEN(tb)))) {
configparser_push(ctx, dc, 0);
}
else {
dc = data_config_init();
dc->cond = cond;
dc->comp = configparser_comp_key_id(obj_tag, comp_tag);
buffer_copy_buffer(&dc->key, tb);
buffer_copy_buffer(&dc->comp_tag, comp_tag);
dc->comp_key = dc->key.ptr + comp_offset;
if (COMP_UNSET == dc->comp) {
fprintf(stderr, "error comp_key %s", dc->comp_key);
ctx->ok = 0;
}
else if (COMP_HTTP_LANGUAGE == dc->comp) {
dc->comp = COMP_HTTP_REQUEST_HEADER;
buffer_copy_string_len(&dc->comp_tag, CONST_STR_LEN("Accept-Language"));
}
else if (COMP_HTTP_USER_AGENT == dc->comp) {
dc->comp = COMP_HTTP_REQUEST_HEADER;
buffer_copy_string_len(&dc->comp_tag, CONST_STR_LEN("User-Agent"));
}
else if (COMP_HTTP_REMOTE_IP == dc->comp
&& (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE)) {
char * const slash = strchr(rvalue->ptr, '/'); /* CIDR mask */
char * const colon = strchr(rvalue->ptr, ':'); /* IPv6 */
if (NULL != slash && slash == rvalue->ptr){/*(skip AF_UNIX /path/file)*/
}
else if (NULL != slash) {
char *nptr;
const unsigned long nm_bits = strtoul(slash + 1, &nptr, 10);
if (*nptr || 0 == nm_bits || nm_bits > (NULL != colon ? 128 : 32)) {
/*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/
fprintf(stderr, "invalid or missing netmask: %s\n", rvalue->ptr);
ctx->ok = 0;
}
else {
int rc;
buffer_string_set_length(rvalue, (size_t)(slash - rvalue->ptr)); /*(truncate)*/
rc = (NULL == colon)
? http_request_host_normalize(rvalue, 0)
: configparser_remoteip_normalize_compat(rvalue);
buffer_append_string_len(rvalue, CONST_STR_LEN("/"));
buffer_append_int(rvalue, (int)nm_bits);
if (0 != rc) {
fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
ctx->ok = 0;
}
}
}
else {
int rc = (NULL == colon)
? http_request_host_normalize(rvalue, 0)
: configparser_remoteip_normalize_compat(rvalue);
if (0 != rc) {
fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
ctx->ok = 0;
}
}
}
else if (COMP_SERVER_SOCKET == dc->comp) {
/*(redundant with parsing in network.c; not actually required here)*/
if (rvalue->ptr[0] != ':' /*(network.c special-cases ":" and "[]")*/
&& !(rvalue->ptr[0] == '[' && rvalue->ptr[1] == ']')) {
if (http_request_host_normalize(rvalue, 0)) {
fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
ctx->ok = 0;
}
}
}
else if (COMP_HTTP_HOST == dc->comp) {
if (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) {
if (http_request_host_normalize(rvalue, 0)) {
fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
ctx->ok = 0;
}
}
}
if (COMP_HTTP_REQUEST_HEADER == dc->comp) {
dc->ext = http_header_hkey_get(CONST_BUF_LEN(&dc->comp_tag));
}
buffer_copy_buffer(&dc->string, rvalue);
if (ctx->ok) switch(dc->cond) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
break;
case CONFIG_COND_NOMATCH:
case CONFIG_COND_MATCH: {
if (!data_config_pcre_compile(dc)) {
ctx->ok = 0;
}
break;
}
default:
fprintf(stderr, "unknown condition for %s\n", dc->comp_key);
ctx->ok = 0;
break;
}
if (ctx->ok)
configparser_push(ctx, dc, 1);
else
dc->fn->free((data_unset*) dc);
}
}
static void
configparser_parse_else_condition(config_t * const ctx)
{
data_config * const dc = data_config_init();
dc->cond = CONFIG_COND_ELSE;
buffer_copy_buffer(&dc->key, &ctx->current->key);
buffer_append_string_len(&dc->key, CONST_STR_LEN(" / "));
buffer_append_string_len(&dc->key, CONST_STR_LEN("else_tmp_token"));
configparser_push(ctx, dc, 1);
}
}
%parse_failure {
@ -467,10 +662,11 @@ condlines(A) ::= condlines(B) eols ELSE cond_else(C). {
dc = (data_config *)array_extract_element_klen(ctx->all_configs, CONST_BUF_LEN(&C->key));
force_assert(C == dc);
buffer_copy_buffer(&C->key, &B->key);
C->comp_key = C->key.ptr + (B->comp_key - B->key.ptr);
C->comp = B->comp;
/*buffer_copy_buffer(C->comp_key, B->comp_key);*/
/*buffer_copy_buffer(&C->string, &B->string);*/
pos = buffer_string_length(&C->key)-buffer_string_length(&B->string)-2;
/* -2 for "==" and minus 3 for spaces and quotes around string (in key) */
pos = buffer_string_length(&C->key)-buffer_string_length(&B->string)-5;
switch(B->cond) {
case CONFIG_COND_NE:
C->key.ptr[pos] = '='; /* opposite cond */
@ -544,9 +740,6 @@ cond_else(A) ::= context_else LCURLY metalines RCURLY. {
}
context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
data_config *dc;
buffer *b = NULL, *rvalue;
const char *op = NULL;
if (ctx->ok && D->type != TYPE_STRING) {
fprintf(stderr, "rvalue must be string");
@ -554,201 +747,20 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
}
if (ctx->ok) {
switch(E) {
case CONFIG_COND_NE:
op = "!=";
break;
case CONFIG_COND_EQ:
op = "==";
break;
case CONFIG_COND_NOMATCH:
op = "!~";
break;
case CONFIG_COND_MATCH:
op = "=~";
break;
default:
force_assert(0);
return; /* unreachable */
}
b = buffer_init();
buffer_copy_buffer(b, &ctx->current->key);
buffer_append_string_len(b, CONST_STR_LEN("/"));
buffer_append_string_buffer(b, B);
buffer_append_string_buffer(b, C);
buffer_append_string_len(b, op, 2);
rvalue = &((data_string*)D)->value;
buffer_append_string_buffer(b, rvalue);
if (NULL != (dc = configparser_get_data_config(ctx->all_configs, CONST_BUF_LEN(b)))) {
configparser_push(ctx, dc, 0);
} else {
static const struct {
comp_key_t comp;
char *comp_key;
size_t len;
} comps[] = {
{ COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
{ COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
{ COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
{ COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"referer\"]" ) },
{ COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
{ COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
{ COMP_HTTP_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) },
{ COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"cookie\"]" ) },
{ COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
{ COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
{ COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
{ COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
{ COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
{ COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
{ COMP_UNSET, NULL, 0 },
};
size_t i;
dc = data_config_init();
buffer_copy_buffer(&dc->key, b);
dc->op = op;
buffer_copy_buffer(dc->comp_tag, C);
buffer_copy_buffer(dc->comp_key, B);
buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
buffer_append_string_buffer(dc->comp_key, C);
buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
dc->cond = E;
for (i = 0; comps[i].comp_key; i ++) {
if (buffer_is_equal_string(
dc->comp_key, comps[i].comp_key, comps[i].len)) {
dc->comp = comps[i].comp;
break;
}
}
if (COMP_UNSET == dc->comp) {
if (buffer_is_equal_string(B, CONST_STR_LEN("REQUEST_HEADER"))) {
dc->comp = COMP_HTTP_REQUEST_HEADER;
}
else {
fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
ctx->ok = 0;
}
}
else if (COMP_HTTP_LANGUAGE == dc->comp) {
dc->comp = COMP_HTTP_REQUEST_HEADER;
buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("Accept-Language"));
}
else if (COMP_HTTP_USER_AGENT == dc->comp) {
dc->comp = COMP_HTTP_REQUEST_HEADER;
buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("User-Agent"));
}
else if (COMP_HTTP_REMOTE_IP == dc->comp
&& (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE)) {
char * const slash = strchr(rvalue->ptr, '/'); /* CIDR mask */
char * const colon = strchr(rvalue->ptr, ':'); /* IPv6 */
if (NULL != slash && slash == rvalue->ptr){/*(skip AF_UNIX /path/file)*/
}
else if (NULL != slash) {
char *nptr;
const unsigned long nm_bits = strtoul(slash + 1, &nptr, 10);
if (*nptr || 0 == nm_bits || nm_bits > (NULL != colon ? 128 : 32)) {
/*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/
fprintf(stderr, "invalid or missing netmask: %s\n", rvalue->ptr);
ctx->ok = 0;
}
else {
int rc;
buffer_string_set_length(rvalue, (size_t)(slash - rvalue->ptr)); /*(truncate)*/
rc = (NULL == colon)
? http_request_host_normalize(rvalue, 0)
: configparser_remoteip_normalize_compat(rvalue);
buffer_append_string_len(rvalue, CONST_STR_LEN("/"));
buffer_append_int(rvalue, (int)nm_bits);
if (0 != rc) {
fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
ctx->ok = 0;
}
}
}
else {
int rc = (NULL == colon)
? http_request_host_normalize(rvalue, 0)
: configparser_remoteip_normalize_compat(rvalue);
if (0 != rc) {
fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
ctx->ok = 0;
}
}
}
else if (COMP_SERVER_SOCKET == dc->comp) {
/*(redundant with parsing in network.c; not actually required here)*/
if (rvalue->ptr[0] != ':' /*(network.c special-cases ":" and "[]")*/
&& !(rvalue->ptr[0] == '[' && rvalue->ptr[1] == ']')) {
if (http_request_host_normalize(rvalue, 0)) {
fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
ctx->ok = 0;
}
}
}
else if (COMP_HTTP_HOST == dc->comp) {
if (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) {
if (http_request_host_normalize(rvalue, 0)) {
fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
ctx->ok = 0;
}
}
}
if (COMP_HTTP_REQUEST_HEADER == dc->comp) {
dc->ext = http_header_hkey_get(CONST_BUF_LEN(dc->comp_tag));
}
buffer_copy_buffer(&dc->string, rvalue);
if (ctx->ok) switch(E) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
break;
case CONFIG_COND_NOMATCH:
case CONFIG_COND_MATCH: {
if (!data_config_pcre_compile(dc)) {
ctx->ok = 0;
}
break;
}
default:
fprintf(stderr, "unknown condition for $%s[%s]\n",
B->ptr, C->ptr);
ctx->ok = 0;
break;
}
if (ctx->ok) {
configparser_push(ctx, dc, 1);
} else {
dc->fn->free((data_unset*) dc);
}
}
configparser_parse_condition(ctx, B, C, E, &((data_string *)D)->value);
}
buffer_free(b);
buffer_free(B);
B = NULL;
buffer_free(C);
C = NULL;
if (D) D->fn->free(D);
D->fn->free(D);
D = NULL;
}
context_else ::= . {
if (ctx->ok) {
data_config *dc = data_config_init();
buffer_copy_buffer(&dc->key, &ctx->current->key);
buffer_append_string_len(&dc->key, CONST_STR_LEN("/"));
buffer_append_string_len(&dc->key, CONST_STR_LEN("else_tmp_token"));
dc->cond = CONFIG_COND_ELSE;
configparser_push(ctx, dc, 1);
configparser_parse_else_condition(ctx);
}
}

@ -17,9 +17,11 @@ static data_unset *data_config_copy(const data_unset *s) {
data_config *ds = data_config_init();
ds->comp = src->comp;
if (!buffer_is_empty(&src->key)) buffer_copy_buffer(&ds->key, &src->key);
buffer_copy_buffer(ds->comp_tag, src->comp_tag);
buffer_copy_buffer(ds->comp_key, src->comp_key);
if (!buffer_is_empty(&src->key)) {
buffer_copy_buffer(&ds->key, &src->key);
ds->comp_key = ds->key.ptr + (src->comp_key - src->key.ptr);
}
buffer_copy_buffer(&ds->comp_tag, &src->comp_tag);
array_copy_array(ds->value, src->value);
return (data_unset *)ds;
}
@ -29,8 +31,7 @@ static void data_config_free(data_unset *d) {
data_config *ds = (data_config *)d;
free(ds->key.ptr);
buffer_free(ds->comp_tag);
buffer_free(ds->comp_key);
free(ds->comp_tag.ptr);
array_free(ds->value);
vector_config_weak_clear(&ds->children);
@ -65,8 +66,7 @@ static void data_config_print(const data_unset *d, int depth) {
}
else {
if (ds->cond != CONFIG_COND_ELSE) {
fprintf(stdout, "$%s %s \"%s\" {\n",
ds->comp_key->ptr, ds->op, ds->string.ptr);
fprintf(stdout, "%s {\n", ds->comp_key);
} else {
fprintf(stdout, "{\n");
}
@ -109,8 +109,7 @@ static void data_config_print(const data_unset *d, int depth) {
fprintf(stdout, "}");
if (0 != ds->context_ndx) {
if (ds->cond != CONFIG_COND_ELSE) {
fprintf(stdout, " # end of $%s %s \"%s\"",
ds->comp_key->ptr, ds->op, ds->string.ptr);
fprintf(stdout, " # end of %s", ds->comp_key);
} else {
fprintf(stdout, " # end of else");
}
@ -136,8 +135,7 @@ data_config *data_config_init(void) {
ds = calloc(1, sizeof(*ds));
force_assert(ds);
ds->comp_tag = buffer_init();
ds->comp_key = buffer_init();
ds->comp_key = "";
ds->value = array_init(4);
vector_config_weak_init(&ds->children);
@ -183,9 +181,9 @@ int data_config_pcre_compile(data_config *dc) {
}
return 1;
#else
fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
fprintf(stderr, "can't handle '%s' as you compiled without pcre support. \n"
"(perhaps just a missing pcre-devel package ?) \n",
dc->comp_key->ptr, dc->comp_tag->ptr);
dc->comp_key);
return 0;
#endif
}

@ -261,8 +261,7 @@ static handler_t process_rewrite_rules(request_st * const r, plugin_data *p, con
log_error(r->conf.errh, __FILE__, __LINE__,
"ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, "
"perhaps you want to use url.rewrite-once instead of "
"url.rewrite-repeat ($%s %s \"%s\")", cfginfo.comp_key->ptr,
cfginfo.op, cfginfo.string->ptr);
"url.rewrite-repeat (%s)", cfginfo.comp_key);
return HANDLER_ERROR;
}

@ -43,9 +43,7 @@ typedef struct {
comp_key_t comp;
config_cond_t cond;
const buffer *string;
const buffer *comp_tag;
const buffer *comp_key;
const char *op;
const char *comp_key;
} config_cond_info;
__attribute_cold__

Loading…
Cancel
Save