Add new cookie into headers_in
michalkraus
nginx-forum at nginx.us
Mon Jan 24 18:07:04 MSK 2011
Hello,
I have a filter module in rewrite phase. The module tests if a cookie is
in the request. If not the module generates one (if cookie is found the
module modifies it) and then send it back to the client via
headers_out.
But I need one more functionality. I want the generated/modified cookie
to be sent to the proxy module. I have used the headers_more_module for
this purpose so far and it worked perfectly. I generate an
$ap_filter_cookie_sid variable in my module that contains the cookie. I
would like my module to be able to modify headers_in on its own.
I have managed to modify existing cookie in the headers_in.headers. But
when no cookie is in headers_in.headers my module is not able to store
newly generated cookie to headers_in.headers. It seems OK in my module
but before running proxy module the Nginx stops processing the request.
When the first request contains a cookie the Nginx server processes it
correctly and each next request (also withnou cookie) as well. This
behaviour is a bit confusing and I have no idea how to fix it.
Can anybody help me?
Thank you, Michal
Complete code:
typedef u_char *(*ngx_http_ap_filter_op_run_pt) (ngx_http_request_t *r,
u_char *buf,
ngx_http_ap_filter_op_t *op);
typedef size_t (*ngx_http_ap_filter_op_getlen_pt) (ngx_http_request_t
*r, uintptr_t data);
#define COOKIE_EXPIRES_TIME 2592000
typedef struct {
ngx_str_t cookie_sid;
ngx_str_t sessionid;
} ngx_http_ap_filter_ctx_t;
typedef struct {
ngx_flag_t enable;
ngx_str_t sessionid;
} ngx_http_ap_filter_loc_conf_t;
static ngx_int_t ngx_http_ap_filter_add_variables(ngx_conf_t *cf);
static ngx_int_t
ngx_http_ap_filter_cookie_sid_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static void* ngx_http_ap_filter_create_loc_conf(ngx_conf_t *cf);
static ngx_int_t ngx_http_ap_filter_init(ngx_conf_t *cf);
static char* ngx_http_ap_filter_merge_loc_conf(ngx_conf_t *cf, void
*parent, void *child);
static ngx_int_t ngx_http_ap_filter(ngx_http_request_t *r,
ngx_http_ap_filter_ctx_t *ctx);
static ngx_int_t ngx_http_ap_filter_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_ap_filter_get_cookie(ngx_http_request_t *r,
ngx_str_t *cookie_value);
static ngx_int_t ngx_http_ap_filter_set_cookie(ngx_http_request_t *r,
ngx_str_t* cookie_value, ngx_http_ap_filter_ctx_t *ctx);
static ngx_command_t ngx_http_ap_filter_commands[] = {
{ ngx_string("ap_filter"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_ap_filter_loc_conf_t, enable),
NULL },
{ ngx_string("ap_filter_sessionid"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_ap_filter_loc_conf_t, sessionid),
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_ap_filter_module_ctx = {
ngx_http_ap_filter_add_variables, /* preconfiguration */
ngx_http_ap_filter_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_ap_filter_create_loc_conf, /* create location
configuration */
ngx_http_ap_filter_merge_loc_conf /* merge location configuration
*/
};
ngx_module_t ngx_http_ap_filter_module = {
NGX_MODULE_V1,
&ngx_http_ap_filter_module_ctx,/* module context */
ngx_http_ap_filter_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_variable_t ngx_http_ap_filter_vars[] = {
// $ap_mod_cookie_sid - modified/generated cookie
{ ngx_string("ap_filter_cookie_sid"), NULL,
ngx_http_ap_filter_cookie_sid_variable, 0,
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0
},
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
static ngx_int_t ngx_http_ap_filter_add_variables(ngx_conf_t *cf) {
ngx_http_variable_t *var, *v;
for (v = ngx_http_ap_filter_vars; v->name.len; v++) {
var = ngx_http_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_ap_filter_cookie_sid_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data) {
ngx_http_ap_filter_ctx_t *ctx;
ctx = reinterpret_cast(ngx_http_get_module_ctx(r,
ngx_http_ap_filter_module));
if (ctx == NULL) {
v->not_found = 1;
return NGX_OK;
}
v->len = ctx->cookie_sid.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = ctx->cookie_sid.data;
return NGX_OK;
}
static void *ngx_http_ap_filter_create_loc_conf(ngx_conf_t *cf) {
ngx_http_ap_filter_loc_conf_t *conf;
conf = reinterpret_cast(ngx_pcalloc(cf->pool,
sizeof(ngx_http_ap_filter_loc_conf_t)));
if (conf == NULL) {
return NGX_CONF_ERROR;
}
conf->enable = NGX_CONF_UNSET_UINT;
return conf;
}
static char *ngx_http_ap_filter_merge_loc_conf(ngx_conf_t *cf, void
*parent, void *child) {
ngx_http_ap_filter_loc_conf_t *prev = reinterpret_cast(parent);
ngx_http_ap_filter_loc_conf_t *conf = reinterpret_cast(child);
ngx_conf_merge_value(conf->enable, prev->enable, 0);
ngx_conf_merge_str_value(conf->sessionid, prev->sessionid, "url");
return NGX_CONF_OK;
}
static ngx_int_t ngx_http_ap_filter_init(ngx_conf_t *cf) {
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = reinterpret_cast(ngx_http_conf_get_module_main_conf(cf,
ngx_http_core_module));
h =
reinterpret_cast(ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers));
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_ap_filter_handler;
return NGX_OK;
}
static ngx_int_t ngx_http_ap_filter_handler(ngx_http_request_t *r) {
ngx_int_t rc;
ngx_http_ap_filter_ctx_t *ctx;
ctx = reinterpret_cast(ngx_http_get_module_ctx(r,
ngx_http_ap_filter_module));
if (ctx == NULL) {
ctx = reinterpret_cast(ngx_pcalloc(r->pool,
sizeof(ngx_http_ap_filter_module)));
if (ctx == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_ap_filter_module);
}
rc = ngx_http_ap_filter(r, ctx);
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
}
if (rc == NGX_AGAIN) {
return NGX_DONE;
}
if (rc != NGX_OK) {
return rc;
}
return NGX_DECLINED;
}
static ngx_int_t ngx_http_ap_filter_get_cookie(ngx_http_request_t *r,
ngx_str_t *cookie_value) {
ngx_int_t n;
ngx_str_t cookie_key;
cookie_key.len = sizeof("sid")-1;
ngx_str_set(&cookie_key, "sid");
n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies,
&cookie_key, cookie_value);
if (n != NGX_DECLINED) {
// ziskal jsem cookie
return NGX_OK;
} else {
return NGX_DECLINED;
}
}
static ngx_int_t ngx_http_ap_filter_set_cookie(ngx_http_request_t *r,
ngx_str_t *cookie_value,
ngx_http_ap_filter_ctx_t *ctx) {
u_char *cookie, *p;
size_t len;
ngx_table_elt_t *set_cookie;
u_char expires[] = "; expires=Thu, 31-Dec-37 23:55:55
GMT";
len = 250;
cookie = reinterpret_cast(ngx_pnalloc(r->pool, len));
// vlozime nazev cookie - sid
p = ngx_copy(cookie, "sid", 3);
*p++ = '=';
p = ngx_cpymem(p, cookie_value->data, cookie_value->len);
p = ngx_cpymem(p, expires, sizeof("; expires=") - 1);
p = ngx_http_cookie_time(p, ngx_time() + COOKIE_EXPIRES_TIME);
set_cookie =
reinterpret_cast(ngx_list_push(&r->headers_out.headers));
if (set_cookie == NULL) {
return NGX_ERROR;
}
set_cookie->hash = 1;
ngx_str_set(&set_cookie->key, "Set-Cookie");
set_cookie->value.len = p - cookie;
set_cookie->value.data = cookie;
ctx->cookie_sid = set_cookie->value;
// HEADERS_IN SECTION:
const u_char cookie_key[] = "COOKIE";
ngx_table_elt_t *set_cookie_in;
u_char ch;
ngx_uint_t i,j;
ngx_list_part_t *part = &(r->headers_in.headers.part);
ngx_table_elt_t *header = reinterpret_cast(part->elts);
set_cookie_in = NULL;
// find cookies in headers_in.headers
for (i = 0; ; ++i) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = reinterpret_cast(part->elts);
i = 0;
}
if (header[i].key.len != (sizeof(cookie_key) - 1)) {
continue;
}
for (j = 0; j < (sizeof(cookie_key) - 1); ++j) {
ch = header[i].key.data[j];
if (ch >= 'a' && ch <= 'z') ch &= ~0x20;
if (ch != cookie_key[j]) break;
}
if (j == (sizeof(cookie_key) - 1)) {
set_cookie_in = &header[i];
}
}
// cookie not found !!!!!!!!!!
if (set_cookie_in == NULL) {
set_cookie_in =
reinterpret_cast(ngx_list_push(&(r->headers_in.headers)));
if (set_cookie_in == NULL) {
return 0;
}
set_cookie_in->hash = 1;
ngx_str_set(&set_cookie_in->key, "Cookie");
set_cookie_in->value.len = p - cookie;
set_cookie_in->value.data = cookie;
// cookie found - everything OK
} else {
set_cookie_in->value.len = p - cookie;
set_cookie_in->value.data = cookie;
}
ngx_pfree(r->pool, cookie);
return NGX_OK;
}
static ngx_int_t ngx_http_ap_filter(ngx_http_request_t *r,
ngx_http_ap_filter_ctx_t *ctx) {
ngx_http_ap_filter_loc_conf_t *cglcf;
ngx_str_t cookie_value;
cglcf = reinterpret_cast(ngx_http_get_module_loc_conf(r,
ngx_http_ap_filter_module));
if (cglcf->enable != 0) {
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"ap_filter enable");
} else {
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"ap_filter disable");
return NGX_OK;
}
// a C++ object for processinf the cookie
ApCookie_t cookieSid;
if (ngx_http_ap_filter_get_cookie(r, &cookie_value) == NGX_DECLINED)
{
cookieSid.createCookie(reinterpret_cast(cglcf->salt.data),
cglcf->salt.len,
reinterpret_cast(r->args.data), r->args.len);
} else {
cookieSid = ApCookie_t(reinterpret_cast(cookie_value.data),
cookie_value.len,
reinterpret_cast(cglcf->salt.data), cglcf->salt.len,
reinterpret_cast(r->args.data), r->args.len);
} // else
ngx_str_t cookieString;
ngx_str_set(&cookieString,
cookieSid.returnCookie(&(cookieString.len)));
ngx_int_t n = ngx_http_ap_filter_set_cookie(r, &cookieString, ctx);
if (n != NGX_OK) {
return NGX_ERROR;
}
return NGX_OK;
}
Posted at Nginx Forum: http://forum.nginx.org/read.php?2,169118,169118#msg-169118
More information about the nginx
mailing list