ngx_http_request_t是在编写nginx模块中经常用到的结构体,大多的模块的工作都是基于该结构体的,该结构中的request_body是记录请求的数据主体,大部分情况在POST状态时有数据。实际情况下,如果需要HOOK上行的数据,即在提交给后端的SERVER前基于request_body进行处理,那么nginx现有提供的几个模块的注册位置都读取不到request_body,估计可能很多同学都碰到这个问题,我觉得很有必要加上一个阶段,呵呵。

当然nginx给我们提供了相应的函数来做这个事情,这个函数就是ngx_http_read_client_request_body。可采用如下方式进行调用:

static ngx_int_t
ngx_http_x_up_handler(ngx_http_request_t *r)
{
	ngx_int_t rc;
 
	if (r->method == NGX_HTTP_POST)
	{
		ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "post:%V", &r->uri);
		rc = ngx_http_read_client_request_body(r, ngx_http_x_up_body_handler);
 
		if (rc >= NGX_HTTP_SPECIAL_RESPONSE) 
			return rc;
		else
			return NGX_DECLINED;
	}
	else
		ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "get:%V", &r->uri);
 
	return NGX_DECLINED;
}
 
 
static void
ngx_http_x_up_body_handler(ngx_http_request_t *r)
{
	if (r->request_body) 
	{
		ngx_chain_t	*cl;
		for (cl = r->request_body->bufs; cl; cl = cl->next) 
		{
			ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "post request body:%s", cl->buf->pos);
		}
	}
 
}
 
 
static ngx_int_t
ngx_http_x_up_init(ngx_conf_t *cf)
{
	ngx_http_handler_pt        *h;
	ngx_http_core_main_conf_t  *cmcf;
 
	cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
	h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
	if (h == NULL) {
		return NGX_ERROR;
	}
 
	*h = ngx_http_x_up_handler;
 
	return NGX_OK;
}

至此,包括header/request_uri/request_body这些HTTP请求中的数据段都能获取了,基于POST的数据写个LB如何? :)

在编写nginx的http的模块的时候,需要在各个阶段对http请求做相应的处理,以达到不同的目的,比如请求发起的时候是否有访问权限、内容生成的时候进行过滤或者其它处理等等。如果在编译nginx模块内注册的处理阶段不正确会导致达不到想要的结果,比如你想处理内容的时候内容实际上这个时候是没有的,如此等等。

在nginx内部定义了多个阶段的类型以满足不同的处理要求(ngx_http_core_module.h中,不同版本不一样):

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,
 
    NGX_HTTP_SERVER_REWRITE_PHASE,
 
    NGX_HTTP_FIND_CONFIG_PHASE,
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE,
 
    NGX_HTTP_PREACCESS_PHASE,
 
    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE,
 
    NGX_HTTP_TRY_FILES_PHASE,
    NGX_HTTP_CONTENT_PHASE,
 
    NGX_HTTP_LOG_PHASE
} ngx_http_phases;

Read the rest of this entry »

nginx做透明代理

九月 10th, 2009

前一阵子在帮一朋友解决问题时,聊及nginx的透明代理的问题,当时就想修改nginx来实现透明代理,幸好一直没有付诸实现,不然又一次重造轮子.

下午在邮件列表中讨论到这个问题,nginx的作者Igor的回答让我茅塞顿开。看以下配置:

user  www;
worker_processes  1;
 
error_log  /var/log/nginx/error.log debug;
#pid        logs/nginx.pid;
 
 
events {
    use epoll;
    worker_connections  1024;
}
 
 
http {
    resolver 202.103.96.68;
    server {
        listen       81;
        location / {
                proxy_pass  http://$http_host$request_uri;
        }
    }
}

享受nginx给我们带来的快乐吧! :)

作者:张立冰
出处:http://www.libing.name/2009/06/08/understand-nginx-source-code-shared-memory.html

本文主要为分析nginx的共享内存机制,以及在对nginx进行hack的过程中如何使用共享内存.权当笔记,如有不正确之处,敬请留言! :)

因为nginx对于请求是统一分配和统一释放,同时为多进程程序,在很多情况下需要使用到共享内存,包括访问控制、负载均衡、健康检查等。而使用nginx的核心源码结构开发应用服务器程序时,共享内存的使用也非常的重要,幸好nginx已经为我们实现得很好了,我们只需明白它的机制就可以轻松拿来使用了。

与共享内存相关的几个结构体:
ngx_cycle.h:

typedef struct ngx_shm_zone_s  ngx_shm_zone_t;
 
typedef ngx_int_t(*ngx_shm_zone_init_pt)(ngx_shm_zone_t *zone,void *data);
 
struct ngx_shm_zone_s {
    void                     *data;
    ngx_shm_t                 shm;
    ngx_shm_zone_init_pt      init;
    ngx_str_t                 name;
    void                     *tag;
};

Read the rest of this entry »

nginx的最新的stable版本0.6.36添加了期待已久的特性:

    *) Feature: the "try_files" directive.
    *) Feature: the --with-pcre option in the configure.
    *) Feature: the "if_modified_since" directive.
    *) Feature: the "$cookie_..." variables.
    *) Feature: the "$arg_..." variables.
    *) Bugfix: compatibility with Tru64 UNIX.

通过这两个变量则可以在配置文件中做更多实际的与HTTP相关变量的控制了。于是前阵的用Nginx实现与应用结合的访问控制也变得更加容易实现了,而不依赖于mod_parsed_vars了,具体的配置和应用思路这里就不多描述了。

但是,一朋友让我帮助他实现通过COOKIE来获取http_accesskey_module的access key,而不是通过GET方式,于是便修改了下http_accesskey_module,让访问控制更加灵活的与默认的变量结合。于是便可以这样来配置http_accesskey_module了:

        location /download {
          accesskey             on;
          accesskey_hashmethod  md5;
          accesskey_arg         "$cookie_key";
          accesskey_signature   "46&j*$remote_addr";
        }

修改过后的下载地址:http_accesskey_module.tar.gz

另外如果你在编译其它三方模块不通过的情况下可以参考下面的config,注意HTTP_MODULES部分:

USE_MD5=YES
USE_SHA1=YES
ngx_addon_name=ngx_http_accesskey_module
HTTP_MODULES="$HTTP_MODULES ngx_xxx_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_xxx_module.c"