#include 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 ngx_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 = (ndk_set_var_pt) 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 = (ndk_set_var_data_pt) 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 = (ndk_set_var_value_pt) 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 = (ndk_set_var_value_data_pt) 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 = (ndk_set_var_value_pt) 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 = (ndk_set_var_value_data_pt) 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 = (ndk_set_var_hash_pt) 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); }