blob: a5dd3c03ce0cf04a5dcf62615bea8c4311f09e98 [file] [log] [blame] [raw]
#include <ndk.h>
typedef struct {
ngx_http_script_code_pt code;
void *func;
} ndk_set_var_code_t;
typedef struct {
ngx_http_script_code_pt code;
void *func;
size_t size;
} ndk_set_var_size_code_t;
typedef struct {
ngx_http_script_code_pt code;
void *func;
void *data;
} ndk_set_var_data_code_t;
typedef struct {
ngx_http_script_code_pt code;
void *func;
size_t size;
void *data;
} ndk_set_var_size_data_code_t;
typedef struct {
ngx_int_t index;
ngx_str_t *value;
ngx_http_variable_t *v;
ngx_conf_t *cf;
ndk_http_rewrite_loc_conf_t *rlcf;
} ndk_set_var_info_t;
static void ndk_set_var_code (ngx_http_script_engine_t *e);
static void ndk_set_var_hash_code (ngx_http_script_engine_t *e);
static void ndk_set_var_value_code (ngx_http_script_engine_t *e);
static inline void
ndk_set_var_code_finalize (ngx_http_script_engine_t *e, ngx_int_t rc,
ngx_http_variable_value_t *v, ngx_str_t *str)
{
switch (rc) {
case NGX_OK :
v->data = str->data;
v->len = str->len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script value (post filter): \"%v\"", v);
break;
case NGX_DECLINED :
v->valid = 0;
v->not_found = 1;
v->no_cacheable = 1;
break;
case NGX_ERROR :
e->ip = ndk_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
break;
}
}
static void
ndk_set_var_code (ngx_http_script_engine_t *e)
{
ngx_int_t rc;
ngx_str_t str;
ngx_http_variable_value_t *v;
ndk_set_var_code_t *sv;
ndk_set_var_pt func;
sv = (ndk_set_var_code_t *) e->ip;
e->ip += sizeof (ndk_set_var_code_t);
v = e->sp++;
func = sv->func;
rc = func (e->request, &str);
ndk_set_var_code_finalize (e, rc, v, &str);
}
static void
ndk_set_var_data_code (ngx_http_script_engine_t *e)
{
ngx_int_t rc;
ngx_str_t str;
ngx_http_variable_value_t *v;
ndk_set_var_data_code_t *svd;
ndk_set_var_data_pt func;
svd = (ndk_set_var_data_code_t *) e->ip;
e->ip += sizeof (ndk_set_var_data_code_t);
v = e->sp++;
func = svd->func;
rc = func (e->request, &str, svd->data);
ndk_set_var_code_finalize (e, rc, v, &str);
}
static void
ndk_set_var_value_code (ngx_http_script_engine_t *e)
{
ngx_int_t rc;
ngx_str_t str;
ngx_http_variable_value_t *v;
ndk_set_var_code_t *sv;
ndk_set_var_value_pt func;
sv = (ndk_set_var_code_t *) e->ip;
e->ip += sizeof (ndk_set_var_code_t);
v = e->sp - 1;
func = sv->func;
rc = func (e->request, &str, v);
ndk_set_var_code_finalize (e, rc, v, &str);
}
static void
ndk_set_var_value_data_code (ngx_http_script_engine_t *e)
{
ngx_int_t rc;
ngx_str_t str;
ngx_http_variable_value_t *v;
ndk_set_var_data_code_t *svd;
ndk_set_var_value_data_pt func;
svd = (ndk_set_var_data_code_t *) e->ip;
e->ip += sizeof (ndk_set_var_data_code_t);
v = e->sp - 1;
func = svd->func;
rc = func (e->request, &str, v, svd->data);
ndk_set_var_code_finalize (e, rc, v, &str);
}
static void
ndk_set_var_multi_value_code (ngx_http_script_engine_t *e)
{
ngx_int_t rc;
ngx_str_t str;
ngx_http_variable_value_t *v;
ndk_set_var_size_code_t *svs;
ndk_set_var_value_pt func;
svs = (ndk_set_var_size_code_t *) e->ip;
e->ip += sizeof (ndk_set_var_size_code_t);
v = e->sp - svs->size;
e->sp = v + 1;
func = svs->func;
rc = func (e->request, &str, v);
ndk_set_var_code_finalize (e, rc, v, &str);
}
static void
ndk_set_var_multi_value_data_code (ngx_http_script_engine_t *e)
{
ngx_int_t rc;
ngx_str_t str;
ngx_http_variable_value_t *v;
ndk_set_var_size_data_code_t *svsd;
ndk_set_var_value_data_pt func;
svsd = (ndk_set_var_size_data_code_t *) e->ip;
e->ip += sizeof (ndk_set_var_size_data_code_t);
v = e->sp - svsd->size;
e->sp = v + 1;
func = svsd->func;
rc = func (e->request, &str, v, svsd->data);
ndk_set_var_code_finalize (e, rc, v, &str);
}
static void
ndk_set_var_hash_code (ngx_http_script_engine_t *e)
{
u_char *p;
ngx_http_variable_value_t *v;
ndk_set_var_size_code_t *svs;
ndk_set_var_hash_pt func;
svs = (ndk_set_var_size_code_t *) e->ip;
e->ip += sizeof (ndk_set_var_size_code_t);
p = ngx_palloc (e->request->pool, svs->size);
if (p == NULL) {
e->ip = ndk_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
}
v = e->sp - 1;
func = svs->func;
func (p, (char *) v->data, v->len);
v->data = (u_char *) p;
v->len = svs->size;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
"http script hashed value: \"%v\"", v);
}
static char *
ndk_set_var_name (ndk_set_var_info_t *info, ngx_str_t *varname)
{
ngx_int_t index;
ngx_http_variable_t *v;
ngx_conf_t *cf;
ndk_http_rewrite_loc_conf_t *rlcf;
ngx_str_t name;
name = *varname;
cf = info->cf;
rlcf = ngx_http_conf_get_module_loc_conf (cf, ngx_http_rewrite_module);
if (name.data[0] != '$') {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid variable name \"%V\"", &name);
return NGX_CONF_ERROR;
}
name.len--;
name.data++;
v = ngx_http_add_variable (cf, &name, NGX_HTTP_VAR_CHANGEABLE);
if (v == NULL) {
return NGX_CONF_ERROR;
}
index = ngx_http_get_variable_index (cf, &name);
if (index == NGX_ERROR) {
return NGX_CONF_ERROR;
}
if (v->get_handler == NULL
&& ngx_strncasecmp(name.data, (u_char *) "arg_", 4) != 0
&& ngx_strncasecmp(name.data, (u_char *) "cookie_", 7) != 0
&& ngx_strncasecmp(name.data, (u_char *) "http_", 5) != 0
&& ngx_strncasecmp(name.data, (u_char *) "sent_http_", 10) != 0
&& ngx_strncasecmp(name.data, (u_char *) "upstream_http_", 14) != 0)
{
v->get_handler = ndk_http_rewrite_var;
v->data = index;
}
info->v = v;
info->index = index;
info->rlcf = rlcf;
return NGX_CONF_OK;
}
static void
ndk_set_variable_value_space (ndk_http_rewrite_loc_conf_t *rlcf, ngx_uint_t count)
{
// if the number of variable values that will be used is greater than 10,
// make sure there is enough space allocated on the rewrite value stack
if (count <= 10)
return;
if (rlcf->stack_size == NGX_CONF_UNSET_UINT) {
rlcf->stack_size = count;
return;
}
if (rlcf->stack_size < count)
rlcf->stack_size = count;
}
static char *
ndk_set_var_filter (ngx_conf_t *cf, ndk_http_rewrite_loc_conf_t *rlcf,
ndk_set_var_t *filter)
{
ndk_set_var_code_t *sv;
ndk_set_var_size_code_t *svs;
ndk_set_var_data_code_t *svd;
ndk_set_var_size_data_code_t *svsd;
if (filter == NULL) {
return "no filter set";
}
switch (filter->type) {
case NDK_SET_VAR_BASIC :
sv = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ndk_set_var_code_t));
if (sv == NULL) {
return NGX_CONF_ERROR;
}
sv->code = ndk_set_var_code;
sv->func = filter->func;
break;
case NDK_SET_VAR_DATA :
svd = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ndk_set_var_data_code_t));
if (svd == NULL) {
return NGX_CONF_ERROR;
}
svd->code = ndk_set_var_data_code;
svd->func = filter->func;
svd->data = filter->data;
break;
case NDK_SET_VAR_VALUE :
sv = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ndk_set_var_code_t));
if (sv == NULL) {
return NGX_CONF_ERROR;
}
sv->code = ndk_set_var_value_code;
sv->func = filter->func;
break;
case NDK_SET_VAR_VALUE_DATA :
svd = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ndk_set_var_data_code_t));
if (svd == NULL) {
return NGX_CONF_ERROR;
}
svd->code = ndk_set_var_value_data_code;
svd->func = filter->func;
svd->data = filter->data;
break;
case NDK_SET_VAR_MULTI_VALUE :
svs = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ndk_set_var_size_code_t));
if (svs == NULL) {
return NGX_CONF_ERROR;
}
svs->code = ndk_set_var_multi_value_code;
svs->func = filter->func;
svs->size = filter->size;
ndk_set_variable_value_space (rlcf, svs->size);
break;
case NDK_SET_VAR_MULTI_VALUE_DATA :
svsd = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ndk_set_var_size_data_code_t));
if (svsd == NULL) {
return NGX_CONF_ERROR;
}
svsd->code = ndk_set_var_multi_value_data_code;
svsd->func = filter->func;
svsd->size = filter->size;
svsd->data = filter->data;
ndk_set_variable_value_space (rlcf, svsd->size);
break;
case NDK_SET_VAR_HASH :
svs = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ndk_set_var_size_code_t));
if (svs == NULL) {
return NGX_CONF_ERROR;
}
svs->code = ndk_set_var_hash_code;
svs->func = filter->func;
svs->size = filter->size;
break;
default :
ngx_conf_log_error (NGX_LOG_EMERG, cf, 0,
"invalid filter type \"%ul\"", filter->type);
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
static char *
ndk_set_var_filter_value (ndk_set_var_info_t *info, ndk_set_var_t *filter)
{
ngx_conf_t *cf;
ngx_http_variable_t *v;
ndk_http_rewrite_loc_conf_t *rlcf;
ngx_http_script_var_code_t *vcode;
ngx_http_script_var_handler_code_t *vhcode;
v = info->v;
cf = info->cf;
rlcf = info->rlcf;
if (ndk_set_var_filter (cf, rlcf, filter) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
if (v->set_handler) {
vhcode = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ngx_http_script_var_handler_code_t));
if (vhcode == NULL) {
return NGX_CONF_ERROR;
}
vhcode->code = ngx_http_script_var_set_handler_code;
vhcode->handler = v->set_handler;
vhcode->data = v->data;
return NGX_CONF_OK;
}
vcode = ngx_http_script_start_code (cf->pool, &rlcf->codes,
sizeof(ngx_http_script_var_code_t));
if (vcode == NULL) {
return NGX_CONF_ERROR;
}
vcode->code = ngx_http_script_set_var_code;
vcode->index = (uintptr_t) info->index;
return NGX_CONF_OK;
}
char *
ndk_set_var_core (ngx_conf_t *cf, ngx_str_t *name, ndk_set_var_t *filter)
{
char *p;
ndk_set_var_info_t info;
info.cf = cf;
p = ndk_set_var_name (&info, name);
if (p != NGX_CONF_OK)
return p;
return ndk_set_var_filter_value (&info, filter);
}
char *
ndk_set_var_value_core (ngx_conf_t *cf, ngx_str_t *name, ngx_str_t *value, ndk_set_var_t *filter)
{
char *p;
ndk_set_var_info_t info;
info.cf = cf;
p = ndk_set_var_name (&info, name);
if (p != NGX_CONF_OK)
return p;
p = ndk_http_rewrite_value (cf, info.rlcf, value);
if (p != NGX_CONF_OK) {
return p;
}
return ndk_set_var_filter_value (&info, filter);
}
char *
ndk_set_var_multi_value_core (ngx_conf_t *cf, ngx_str_t *name, ngx_str_t *value, ndk_set_var_t *filter)
{
char *p;
ndk_set_var_info_t info;
ngx_int_t i;
info.cf = cf;
p = ndk_set_var_name (&info, name);
if (p != NGX_CONF_OK)
return p;
for (i=filter->size; i; i--, value++) {
p = ndk_http_rewrite_value (cf, info.rlcf, value);
if (p != NGX_CONF_OK) {
return p;
}
}
return ndk_set_var_filter_value (&info, filter);
}
char *
ndk_set_var (ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value;
ndk_set_var_t *filter;
value = cf->args->elts;
value++;
filter = (ndk_set_var_t *) cmd->post;
return ndk_set_var_core (cf, value, filter);
}
char *
ndk_set_var_value (ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value;
ndk_set_var_t *filter;
value = cf->args->elts;
value++;
filter = (ndk_set_var_t *) cmd->post;
return ndk_set_var_value_core (cf, value,
cf->args->nelts == 1 + 1 ? value : value + 1, filter);
}
char *
ndk_set_var_multi_value (ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value;
ndk_set_var_t *filter;
value = cf->args->elts;
value++;
filter = (ndk_set_var_t *) cmd->post;
return ndk_set_var_multi_value_core (cf, value, value + 1, filter);
}