Welcome! Log In Create A New Profile

Advanced

Add new cookie into headers_in

January 24, 2011 10:07AM
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_ap_filter_ctx_t*>(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_http_ap_filter_loc_conf_t*>(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<ngx_http_ap_filter_loc_conf_t*>(parent);
ngx_http_ap_filter_loc_conf_t *conf = reinterpret_cast<ngx_http_ap_filter_loc_conf_t*>(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_core_main_conf_t*>(ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module));
h = reinterpret_cast<ngx_http_handler_pt*>(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_ap_filter_ctx_t*>(ngx_http_get_module_ctx(r, ngx_http_ap_filter_module));
if (ctx == NULL) {
ctx = reinterpret_cast<ngx_http_ap_filter_ctx_t*>(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<u_char*>(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_table_elt_t*>(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<ngx_table_elt_t*>(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<ngx_table_elt_t*>(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_table_elt_t*>(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_ap_filter_loc_conf_t*>(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<char*>(cglcf->salt.data), cglcf->salt.len,
reinterpret_cast<char*>(r->args.data), r->args.len);
} else {
cookieSid = ApCookie_t(reinterpret_cast<char*>(cookie_value.data), cookie_value.len,
reinterpret_cast<char*>(cglcf->salt.data), cglcf->salt.len,
reinterpret_cast<char*>(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;

}
Subject Author Posted

Add new cookie into headers_in

michalkraus January 24, 2011 10:07AM

Re: Add new cookie into headers_in

Maxim Dounin January 24, 2011 10:40AM

Re: Add new cookie into headers_in

michalkraus January 25, 2011 03:34AM

Re: Add new cookie into headers_in

Maxim Dounin January 25, 2011 07:58AM

Re: Add new cookie into headers_in

agentzh January 25, 2011 11:38PM

Re: Add new cookie into headers_in

agentzh January 25, 2011 11:50PM

Re: Add new cookie into headers_in

agentzh January 25, 2011 11:56PM

Re: Add new cookie into headers_in

michalkraus January 26, 2011 02:08AM



Sorry, only registered users may post in this forum.

Click here to login

Online Users

Guests: 248
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready