How to modfiy headers in and headers out

Igor Sysoev is at rambler-co.ru
Thu Nov 1 08:37:42 MSK 2007


On Thu, Nov 01, 2007 at 11:22:22AM +0800, Yingyuan Cheng wrote:

> 
> Hello Igor.
> 
> I tracked executing path using gdb, found the content of param "r" 
> (ngx_http_request_t) past by hook routine was a awful mess, and 
> r.headers_out.headers.last pointed to 0x22, which was in a protected 
> memory region. When executing path left my module and went to other 
> modules, the same param "r" was in its normal status. After I changed 
> the module code layout, such as moving "#include <openssl/md5>" after 
> nginx including headers, the problem diminished. Is it a compiling 
> problem? The configuring line is:

I suspect that you did it on Linux or Solaris, where default off_t
is 32-bit size. nginx headers set "#define _FILE_OFFSET_BITS  64" and
nginx is built with 64-bit off_t.

If you include openssl/md5.h before nginx headers then your module
is built with 32-bit off_t, whereas all another obj files are built
with 64-bit off_t.

The general rule: include custom headers after nginx headers.

> CFLAGS="-g" ./configure --with-debug 
> --add-module=/home/yingyuan/workspace/ngx_http_sessid_filter/
> 
> ngx_http_sessid_filter_module "borrows" code snippets from 
> ngx_http_userid_filter_module and ngx_http_upstream_ip_hash_module. 
> First it acts as a load balancer, dispatching requests to backends based 
> on cookie. If the cookie not found in request, it'll generate a new one. 
> Then in the filter phase, it sends the cookie to client if it was 
> generated newly in balancing phase. So we can make the client always 
> dispatched to the same backend.
> 
> Another question I want to ask: May I change request headers_out in 
> upstream_init_peer phase?

No, it's too early.

> Thank you very much.
> 
> Best Regards
> 
> --
> yingyuan
> 
> Igor Sysoev ??????:
> >On Wed, Oct 31, 2007 at 07:45:39PM +0800, Yingyuan Cheng wrote:
> >
> >  
> >>After changed the order of my filter module defined in
> >>objs/ngx_modules.c which should go after ngx_http_header_filter module,
> >>it works. But I still get a segment fault when calling
> >>ngx_list_push(&r->headers_out.headers) in filter hook function.
> >>
> >>Anyone could give me a explanation?
> >>
> >>Thanks very much.
> >>    
> >
> >ngx_list_push(&r->headers_out.headers) should not cause segfault in this 
> >phase.
> >Could you show more code ?
> >
> >
> >  
> 
> 

> ngx_addon_name=ngx_http_sessid_filter_module
> HTTP_MODULES="$HTTP_MODULES ngx_http_sessid_filter_module"
> NGX_ADDON_SRCS="$NGX_ADDON_SRCS /home/yingyuan/workspace/ngx_http_sessid_filter/ngx_http_sessid_filter_module.c"
> CORE_LIBS="$CORE_LIBS -lssl"
> 
> 

> /**
>  * Load balancer based on user session_id
>  *
>  * yingyuan at staff.sina.com.cn
>  * $Id$
>  *
>  */
> 
> #include <ngx_config.h>
> #include <ngx_core.h>
> #include <ngx_http.h>
> 
> #include <stdio.h>
> #include <openssl/md5.h>
> 
> #define SID_COOKIE_EXPIRES_MAX 2145916555
> #define SID_COOKIE_LEN	32
> #define SID_COOKIE_NAME "SGSID"
> #define SID_COOKIE_RND "dw3$32EtBXW24"__DATE__":"__TIME__
> #define SID_COOKIE_ID	"COOKIE"
> 
> typedef struct {
>     ngx_str_t   name;
>     ngx_str_t   domain;
>     ngx_str_t   path;
> 	ngx_str_t	  rnd;	/* random string to defend from attacking */
> 
>     time_t      expires;
> 
> } ngx_http_sessid_filter_conf_t;
> 
> typedef struct {
> 	/* Must be placed in first field to be compatible with upstream_rr */
>     ngx_http_upstream_rr_peer_data_t  rrp; 
> 
>     ngx_uint_t hash;
> 
> 	ngx_str_t cookie;
>     u_char tries;
> 
>     ngx_event_get_peer_pt              get_rr_peer;
> 
> 	u_char filter;	/* set cookie or not */
> 	
> } ngx_http_sessid_filter_peer_data_t;
> 
> static u_char expires[] = "; expires=Thu, 31-Dec-37 23:55:55 GMT";
> static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
> 
> static u_char cookie_key[] = SID_COOKIE_ID;
> static u_char cookie_rnd[] = SID_COOKIE_RND;
> 
> static void *ngx_http_sessid_filter_create_conf(ngx_conf_t *cf);
> static char *ngx_http_sessid_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child);
> static char *ngx_http_sessid_filter_conf_domain(ngx_conf_t *cf, void *post, void *data);
> static char *ngx_http_sessid_filter_conf_path(ngx_conf_t *cf, void *post, void *data);
> static char *ngx_http_sessid_filter_conf_expires(ngx_conf_t *cf, ngx_command_t *cmd, 
> 	void *conf);
> 
> static char *ngx_http_upstream_sessid_init_conf(ngx_conf_t *cf, 
> 	ngx_command_t *cmd, void *conf);
> static ngx_int_t ngx_http_upstream_sessid_init_hash(ngx_conf_t *cf, 
> 	ngx_http_upstream_srv_conf_t  *us);
> static ngx_int_t ngx_http_upstream_sessid_init_hash_peer(ngx_http_request_t *r, 
> 	ngx_http_upstream_srv_conf_t *us);
> static ngx_int_t ngx_http_upstream_sessid_get_hash_peer(ngx_peer_connection_t *pc, 
> 	void *data);
> 
> static ngx_int_t ngx_http_sessid_filter_init(ngx_conf_t *cf);
> static ngx_int_t ngx_http_sessid_filter_filter(ngx_http_request_t *r);
> 
> static ngx_int_t sessid_filter_get_sid(ngx_http_request_t *r, 
> 	ngx_http_sessid_filter_peer_data_t *ctx, 
> 	ngx_http_sessid_filter_conf_t *conf);
> static ngx_int_t sessid_filter_set_sid(ngx_http_request_t *r, 
> 	ngx_http_sessid_filter_peer_data_t *ctx, 
> 	ngx_http_sessid_filter_conf_t *conf);
> static ngx_int_t sessid_filter_make_sid(ngx_http_request_t *r, 
> 	ngx_http_sessid_filter_peer_data_t *ctx, 
> 	ngx_http_sessid_filter_conf_t *conf);
> static ngx_int_t sessid_filter_send_sid(ngx_http_request_t *r, 
> 	ngx_http_sessid_filter_peer_data_t *ctx, 
> 	ngx_http_sessid_filter_conf_t *conf);
> 
> static ngx_conf_post_handler_pt  ngx_http_sessid_filter_domain_p =
>     ngx_http_sessid_filter_conf_domain;
> static ngx_conf_post_handler_pt  ngx_http_sessid_filter_path_p = 
> 	ngx_http_sessid_filter_conf_path;
> 
> static ngx_command_t  ngx_http_sessid_filter_commands[] = {
> 
>     { ngx_string("sessid_hash"),
>       NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
>       ngx_http_upstream_sessid_init_conf,
>       0,
>       0,
>       NULL },
> 
>     { ngx_string("sessid_name"),
>       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_sessid_filter_conf_t, name),
>       NULL },
> 
>     { ngx_string("sessid_domain"),
>       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_sessid_filter_conf_t, domain),
>       &ngx_http_sessid_filter_domain_p },
> 
>     { ngx_string("sessid_path"),
>       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_sessid_filter_conf_t, path),
>       &ngx_http_sessid_filter_path_p },
> 
>     { ngx_string("sessid_rnd"),
>       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_sessid_filter_conf_t, rnd),
>       NULL },
> 
>     { ngx_string("sessid_expires"),
>       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
>       ngx_http_sessid_filter_conf_expires,
>       NGX_HTTP_LOC_CONF_OFFSET,
>       0,
>       NULL },
> 
>       ngx_null_command
> };
> 
> 
> static ngx_http_module_t  ngx_http_sessid_filter_module_ctx = {
>     NULL,                                  /* preconfiguration */
> 	ngx_http_sessid_filter_init,                  /* postconfiguration */
>     NULL,                                  /* create main configuration */
>     NULL,                                  /* init main configuration */
>     NULL,                                  /* create server configuration */
>     NULL,                                  /* merge server configuration */
>    ngx_http_sessid_filter_create_conf,       /* create location configuration */
>    ngx_http_sessid_filter_merge_conf      /* merge location configuration */
> };
> 
> 
> ngx_module_t  ngx_http_sessid_filter_module = {
>     NGX_MODULE_V1,
>     &ngx_http_sessid_filter_module_ctx, /* module context */
>     ngx_http_sessid_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 char *
> ngx_http_sessid_filter_conf_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
> {
>     ngx_http_sessid_filter_conf_t *ucf = conf;
> 
>     ngx_str_t  *value;
> 
>     if (ucf->expires != NGX_CONF_UNSET) {
>         return "is duplicate";
>     }
> 
>     value = cf->args->elts;
> 
>     if (ngx_strcmp(value[1].data, "max") == 0) {
>         ucf->expires = SID_COOKIE_EXPIRES_MAX;
>         return NGX_CONF_OK;
>     }
> 
>     if (ngx_strcmp(value[1].data, "off") == 0) {
>         ucf->expires = 0;
>         return NGX_CONF_OK;
>     }
> 
>     ucf->expires = ngx_parse_time(&value[1], 1);
>     if (ucf->expires == NGX_ERROR) {
>         return "invalid value";
>     }
> 
>     if (ucf->expires == NGX_PARSE_LARGE_TIME) {
>         return "value must be less than 68 years";
>     }
> 
>     return NGX_CONF_OK;
> }
> 
> 
> static char *
> ngx_http_sessid_filter_conf_domain(ngx_conf_t *cf, void *post, void *data)
> {
>     ngx_str_t  *domain = data;
> 
>     u_char  *p, *new;
> 
>     if (ngx_strcmp(domain->data, "none") == 0) {
>         domain->len = 0;
>         domain->data = (u_char *) "";
> 
>         return NGX_CONF_OK;
>     }
> 
>     new = ngx_palloc(cf->pool, sizeof("; domain=") - 1 + domain->len);
>     if (new == NULL) {
>         return NGX_CONF_ERROR;
>     }
> 
>     p = ngx_cpymem(new, "; domain=", sizeof("; domain=") - 1);
>     ngx_memcpy(p, domain->data, domain->len);
> 
>     domain->len += sizeof("; domain=") - 1;
>     domain->data = new;
> 
>     return NGX_CONF_OK;
> }
> 
> 
> static char *
> ngx_http_sessid_filter_conf_path(ngx_conf_t *cf, void *post, void *data)
> {
>     ngx_str_t  *path = data;
> 
>     u_char  *p, *new;
> 
>     new = ngx_palloc(cf->pool, sizeof("; path=") - 1 + path->len);
>     if (new == NULL) {
>         return NGX_CONF_ERROR;
>     }
> 
>     p = ngx_cpymem(new, "; path=", sizeof("; path=") - 1);
>     ngx_memcpy(p, path->data, path->len);
> 
>     path->len += sizeof("; path=") - 1;
>     path->data = new;
> 
>     return NGX_CONF_OK;
> }
> 
> 
> static void *
> ngx_http_sessid_filter_create_conf(ngx_conf_t *cf)
> {
>     ngx_http_sessid_filter_conf_t  *conf;
> 
>     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sessid_filter_conf_t));
>     if (conf == NULL) {
>         return NGX_CONF_ERROR;
>     }
> 
>     /*
>      * set by ngx_pcalloc():
>      *
>      *     conf->name.len = 0;
>      *     conf->name.data = NULL;
>      *     conf->domain.len = 0;
>      *     conf->domain.data = NULL;
>      *     conf->path.len = 0;
>      *     conf->path.data = NULL;
>      */
> 
>     return conf;
> }
> 
> 
> static char *
> ngx_http_sessid_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
> {
>     ngx_http_sessid_filter_conf_t *prev = parent;
>     ngx_http_sessid_filter_conf_t *conf = child;
> 
>     ngx_conf_merge_str_value(conf->name, prev->name, SID_COOKIE_NAME);
>     ngx_conf_merge_str_value(conf->domain, prev->domain, "");
>     ngx_conf_merge_str_value(conf->path, prev->path, "; path=/");
>     ngx_conf_merge_str_value(conf->rnd, prev->rnd, cookie_rnd);
>     ngx_conf_merge_sec_value(conf->expires, prev->expires, 0);
> 
>     return NGX_CONF_OK;
> }
> 
> 
> static char *
> ngx_http_upstream_sessid_init_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
> {
>     ngx_http_upstream_srv_conf_t  *uscf;
> 
>     uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
> 
>     uscf->peer.init_upstream = ngx_http_upstream_sessid_init_hash;
> 
>     uscf->flags = NGX_HTTP_UPSTREAM_CREATE
>                   |NGX_HTTP_UPSTREAM_MAX_FAILS
>                   |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
>                   |NGX_HTTP_UPSTREAM_DOWN;
> 
>     return NGX_CONF_OK;
> }
> 
> 
> static ngx_int_t
> ngx_http_upstream_sessid_init_hash(ngx_conf_t *cf, 
> 	ngx_http_upstream_srv_conf_t *us)
> {
>     if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
>         return NGX_ERROR;
>     }
> 
>     us->peer.init = ngx_http_upstream_sessid_init_hash_peer;
> 
>     return NGX_OK;
> }
> 
> 
> static ngx_int_t
> ngx_http_upstream_sessid_init_hash_peer(ngx_http_request_t *r,
>     ngx_http_upstream_srv_conf_t *us)
> {
>     ngx_http_sessid_filter_peer_data_t  *sidhp;
>     ngx_http_sessid_filter_conf_t  *conf;
> 
>     sidhp = ngx_palloc(r->pool, sizeof(ngx_http_sessid_filter_peer_data_t));
>     if (sidhp == NULL) {
>         return NGX_ERROR;
>     }
> 
> 	sidhp->hash = 89;
> 	sidhp->tries = 0;
> 	sidhp->get_rr_peer = ngx_http_upstream_get_round_robin_peer;
> 	sidhp->filter = 0;
> 
>     r->upstream->peer.data = &sidhp->rrp;
> 
>     if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
>         return NGX_ERROR;
>     }
> 
>     r->upstream->peer.get = ngx_http_upstream_sessid_get_hash_peer;
> 
> 	conf = ngx_http_get_module_loc_conf(r, ngx_http_sessid_filter_module);
> 	if (!sessid_filter_get_sid(r, sidhp, conf)) {
> 		if (!sessid_filter_set_sid(r, sidhp, conf)) {
> 			return NGX_ERROR;
> 
> 		}
> 		
> 		/* generated session_id should be sent to client */
> 		sidhp->filter = 1;
> 	}
> 
> 	/* sidhp would be reused in filter phase */
> 	ngx_http_set_ctx(r, sidhp, ngx_http_sessid_filter_module);
> 	
>     return NGX_OK;
> }
> 
> 
> static ngx_int_t
> ngx_http_upstream_sessid_get_hash_peer(ngx_peer_connection_t *pc, void *data)
> {
>     ngx_http_sessid_filter_peer_data_t  *sidhp = data;
> 
>     time_t                        now;
>     uintptr_t                     m;
>     ngx_uint_t                    i, n, p, hash;
>     ngx_http_upstream_rr_peer_t  *peer;
> 
>     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 
>                    "ngx_http_upstream_get_sessid_hash_peer: try %ui", pc->tries);
> 
>     /* TODO: cached */
> 
>     if (sidhp->tries > 20 || sidhp->rrp.peers->number == 1 || 
>     	sidhp->cookie.len < SID_COOKIE_LEN) {
>         return sidhp->get_rr_peer(pc, &sidhp->rrp);
>         
>     }
> 
>     now = ngx_time();
> 
>     pc->cached = 0;
>     pc->connection = NULL;
> 
>     hash = sidhp->hash;
> 
>     for ( ;; ) {
> 
>         for (i = 0; i < SID_COOKIE_LEN; i++) {
>             hash = (hash * 113 + sidhp->cookie.data[i]) % 6271;
>         }
> 
>         p = hash % sidhp->rrp.peers->number;
> 
>         n = p / (8 * sizeof(uintptr_t));
>         m = 1 << p % (8 * sizeof(uintptr_t));
> 
>         if (!(sidhp->rrp.tried[n] & m)) {
> 
>             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
> 				"ngx_http_upstream_get_sessid_hash_peer: hash: %ui %04XA", p, m);
> 
>             peer = &sidhp->rrp.peers->peer[p];
>             /* ngx_lock_mutex(sidhp->rrp.peers->mutex); */
> 
>             if (!peer->down) {
> 
>                 if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
>                     break;
>                 }
> 
>                 if (now - peer->accessed > peer->fail_timeout) {
>                     peer->fails = 0;
>                     break;
>                 }
>             }
> 
>             sidhp->rrp.tried[n] |= m;
>             /* ngx_unlock_mutex(sidhp->rrp.peers->mutex); */
>             pc->tries--;
>         }
> 
>         if (++sidhp->tries >= 20) {
>             return sidhp->get_rr_peer(pc, &sidhp->rrp);
>         }
>     }
> 
>     pc->sockaddr = peer->sockaddr;
>     pc->socklen = peer->socklen;
>     pc->name = &peer->name;
> 
>     /* ngx_unlock_mutex(sidhp->rrp.peers->mutex); */
>     sidhp->rrp.tried[n] |= m;
>     sidhp->hash = hash;
> 
>     return NGX_OK;
> }
> 
> 
> static ngx_int_t
> sessid_filter_get_sid(ngx_http_request_t *r, 	ngx_http_sessid_filter_peer_data_t *ctx, 
> 	ngx_http_sessid_filter_conf_t *conf)
> {
>     ngx_int_t          n;
>     ngx_table_elt_t  **cookies;
> 
>     n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, 
>     	&conf->name, &ctx->cookie);
>     if (n == NGX_DECLINED) {
>         return 0;
>     }
> 
>     if (ctx->cookie.len < SID_COOKIE_LEN) {
>         return 0;
>     }
>     
>     return 1;
> }
> 
> 
> static ngx_int_t
> sessid_filter_set_sid(ngx_http_request_t *r, 	
> 	ngx_http_sessid_filter_peer_data_t *ctx, 
> 	ngx_http_sessid_filter_conf_t *conf)
> {
> 	u_char *cookie, *p;
> 	ngx_table_elt_t     *set_cookie;
> 	u_char ch;
> 	int i, j;
> 
> 	if (!sessid_filter_make_sid(r, ctx, conf)) {
> 		return 0;
> 	}
> 
> 	ngx_list_part_t *part = &(r->headers_in.headers.part);
> 	ngx_table_elt_t *header = part->elts;
> 	set_cookie = NULL;
> 
> 	for (i = 0;/* void */; i++) {
>             if (i >= part->nelts) {
>                 if (part->next == NULL) {
>                     break;
>                 }
> 
>                 part = part->next;
>                 header = 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 = &header[i];
>             	
>             }
> 	}
> 	
> 	if (set_cookie == NULL) {
> 		set_cookie = ngx_list_push(&(r->headers_in.headers));
> 		if (set_cookie == NULL) {
> 		    return 0;
> 		}
> 
> 		set_cookie->hash = 1;
> 		set_cookie->key.len = sizeof(cookie_key) - 1;
> 		set_cookie->key.data = cookie_key;
> 
> 		cookie = ngx_palloc(r->pool, conf->name.len + 1 + ctx->cookie.len);
> 		if (cookie == NULL) {
> 		    return 0;
> 		}
> 		
> 		p = ngx_copy(cookie, conf->name.data, conf->name.len);
> 		*p++ = '=';
> 		p = ngx_copy(p, ctx->cookie.data, ctx->cookie.len);
> 		set_cookie->value.len = p - cookie;
> 		set_cookie->value.data = cookie;
> 
> 	} else {
> 		cookie = ngx_palloc(r->pool, set_cookie->value.len + 2 + conf->name.len + 1 + 
> 			ctx->cookie.len);
> 		if (cookie == NULL) {
> 		    return 0;
> 		}
> 
> 		p = ngx_copy(cookie, set_cookie->value.data, set_cookie->value.len);
> 		*p++ = ';';
> 		*p++ = ' ';
> 		p = ngx_copy(p, conf->name.data, conf->name.len);
> 		*p++ = '=';
> 		p = ngx_copy(p, ctx->cookie.data, ctx->cookie.len);
> 		set_cookie->value.len = p - cookie;
> 		set_cookie->value.data = cookie;
> 	}
> 	
> 	return 1;
> }
> 
> 
> static ngx_int_t
> sessid_filter_make_sid(ngx_http_request_t *r, 
> 	ngx_http_sessid_filter_peer_data_t *ctx, 
> 	ngx_http_sessid_filter_conf_t *conf)
> {
> 	int i, j;
> 	unsigned char digest[16];
> 	unsigned char buf[256];
> 	struct timeval tv;
> 	unsigned char ch;
> 	const char *hexdigitals = "0123456789abcdef";
> 	struct sockaddr_in *sin;
> 	u_char *p;
> 
> 	ctx->cookie.len = SID_COOKIE_LEN;
> 	
> 	ctx->cookie.data = ngx_palloc(r->pool, SID_COOKIE_LEN);
> 	if (ctx->cookie.data == NULL) {
> 		return 0;
> 	}
> 
> 	sin = (struct sockaddr_in *) r->connection->sockaddr;
> 	p = (u_char *) &sin->sin_addr.s_addr;
> 	gettimeofday(&tv, NULL);
> 
> 	i = sprintf(buf, "%lu:%lu:%02x%02x%02x%02x:%lu:%lu:", tv.tv_sec, tv.tv_usec, 
> 		p[0], p[1], p[2], p[3], ntohs(sin->sin_port),  rand());
> 	j = (256 - i < conf->rnd.len) ? (256 - i):conf->rnd.len;
> 	ngx_copy(buf+i, conf->rnd.data, j);
> 	buf[i + j] = '\0';
> 
> 	if (!MD5(buf, i+j, digest)) {
> 		return 0;
> 	}
> 
> 	/* TODO: SID_COOKIE_LEN is coupled with 32 */
> 	for (i = 0, j = 0; i < 16; i++) {
> 		    ch = digest[i];
> 		    ctx->cookie.data[j++] = hexdigitals[ch>>4];
> 		    ctx->cookie.data[j++] = hexdigitals[ch&15];
> 	}
> 
> 	return 1;
> }
> 
> 
> static ngx_int_t
> sessid_filter_send_sid(ngx_http_request_t *r, 
> 	ngx_http_sessid_filter_peer_data_t *ctx, 
> 	ngx_http_sessid_filter_conf_t *conf)
> {
> 	u_char *cookie, *p;
> 	size_t len;
> 	ngx_table_elt_t     *set_cookie;
> 
> 	len = conf->name.len + 1 + ctx->cookie.len + conf->path.len;
> 	
>    if (conf->expires) {
>         len += sizeof(expires) - 1 + 2;
>     }
> 
>     if (conf->domain.len) {
>         len += conf->domain.len;
>     }
> 
> 	cookie = ngx_palloc(r->pool, len);
> 	if (cookie == NULL) {
> 		return 0;
> 	}
> 
>     p = ngx_copy(cookie, conf->name.data, conf->name.len);
>     *p++ = '=';
> 	p = ngx_copy(p, ctx->cookie.data, ctx->cookie.len);
> 
>     if (conf->expires == SID_COOKIE_EXPIRES_MAX) {
>         p = ngx_cpymem(p, expires, sizeof(expires) - 1);
> 
>     } else if (conf->expires) {
>         p = ngx_cpymem(p, expires, sizeof("; expires=") - 1);
>         p = ngx_http_cookie_time(p, ngx_time() + conf->expires);
>     }
> 
>     p = ngx_copy(p, conf->domain.data, conf->domain.len);
>     p = ngx_copy(p, conf->path.data, conf->path.len);
> 
>     set_cookie = ngx_list_push(&r->headers_out.headers);
>     if (set_cookie == NULL) {
> 		return 0;
>     }
> 
>     set_cookie->hash = 1;
>     set_cookie->key.len = sizeof("Set-Cookie") - 1;
>     set_cookie->key.data = (u_char *) "Set-Cookie";
>     set_cookie->value.len = p - cookie;
>     set_cookie->value.data = cookie;
>     
>     return 1;
> }
> 
> 
> static ngx_int_t
> ngx_http_sessid_filter_init(ngx_conf_t *cf)
> {
>     ngx_http_next_header_filter = ngx_http_top_header_filter;
>     ngx_http_top_header_filter = ngx_http_sessid_filter_filter;
> 
>     return NGX_OK;
> }
> 
> 
> static ngx_int_t
> ngx_http_sessid_filter_filter(ngx_http_request_t *r)
> {
>     ngx_int_t                rc;
>     ngx_http_sessid_filter_peer_data_t   *ctx;
>     ngx_http_sessid_filter_conf_t  *conf;
> 
>     if (r != r->main) {
>         return ngx_http_next_header_filter(r);
>     }
> 
>     conf = ngx_http_get_module_loc_conf(r, ngx_http_sessid_filter_module);
> 	ctx = ngx_http_get_module_ctx(r, ngx_http_sessid_filter_module);
> 
>     if (!ctx || ctx->filter == 0) {
>         return ngx_http_next_header_filter(r);
>     }
> 
> 	sessid_filter_send_sid(r, ctx, conf);
> 	ctx->filter = 0;
> 
>     return ngx_http_next_header_filter(r);
> }
> 
> 


-- 
Igor Sysoev
http://sysoev.ru/en/





More information about the nginx mailing list