Nginx Modules 开发学习

     nginx 模块开发,咱们先从模块分析入手,nginx的模块支持hook(钩子功能),我们可以在以下几个地方添加钩子:

  • Just before the server reads the config file
    读取配置文件时
  • For every configuration directive for the location and server for which it appears;
    读取到server或是location 配置的时候
  • When Nginx initializes the main configuration
    初始化主配置的时候
  • When Nginx initializes the server (i.e., host/port) configuration
    初始化server 配置的时候
  • When Nginx merges the server configuration with the main configuration
    使用主配置,合并server配置的时候
  • When Nginx initializes the location configuration
    初始化location配置的时候
  • When Nginx merges the location configuration with its parent server configuration
    使用server配置,合并location配置的时候
  • When Nginx's master process starts
    nginx 主进程启动的时候
  • When a new worker process starts
    nginx 启动一个新的工作进程的时候
  • When a worker process exits
    nginx 工作进程退出的时候
  • When the master exits
    nginx 主进程退出的时候
  • Handling a request
    接收的请求的时候
  • Filtering response headers
    过滤 response headers 的时候,gzip就是这个时候hook的
  • Filtering the response body
    过滤 response body 的时候,gzip就是这个时候hook的
  • Picking a backend server
    选择一个后台服务器的时候,在upstream 中选择
  • Initiating a request to a backend server
    初始化一个访问后台服务器的请求的时候
  • Re-initiating a request to a backend server
    重新初始化一个访问后台服务器的请求的时候
  • Processing the response from a backend server
    处理从后台返回的response的时候
  • Finishing an interaction with a backend server
    与后台服务器交互结束的时候


下面我们分析以下nginx memcache的模块,下载nginx源码,cd src/http/modules/,在moudels 目录下,你能找到nginx所有core modules ,这里我们分析ngx_http_memcached_module.c 文件


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

//配置定义
typedef struct {
    ngx_http_upstream_conf_t   upstream;
    ngx_int_t                  index;
} ngx_http_memcached_loc_conf_t;

//request 定义
typedef struct {
    size_t                     rest;
    ngx_http_request_t        *request;
    ngx_str_t                  key;
} ngx_http_memcached_ctx_t;

已下是nginx 的 hood定义

static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_memcached_filter_init(void *data);
static ngx_int_t ngx_http_memcached_filter(void *data, ssize_t bytes);
static void ngx_http_memcached_abort_request(ngx_http_request_t *r);
static void ngx_http_memcached_finalize_request(ngx_http_request_t *r,
    ngx_int_t rc);
扫描二维码关注公众号,回复: 668657 查看本文章

使用upstream 时定义的参数

static ngx_conf_bitmask_t  ngx_http_memcached_next_upstream_masks[] = {
    { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
    { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
    { ngx_string("invalid_response"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
    { ngx_string("not_found"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
    { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
    { ngx_null_string, 0 }
};

memcache nginx  自定义命令

static ngx_command_t  ngx_http_memcached_commands[] = {

    { ngx_string("memcached_pass"),
      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
      ngx_http_memcached_pass,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

    { ngx_string("memcached_bind"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_http_upstream_bind_set_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_memcached_loc_conf_t, upstream.local),
      NULL },

    { ngx_string("memcached_connect_timeout"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_msec_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_memcached_loc_conf_t, upstream.connect_timeout),
      NULL },

    { ngx_string("memcached_send_timeout"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_msec_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_memcached_loc_conf_t, upstream.send_timeout),
      NULL },

    { ngx_string("memcached_buffer_size"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_size_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_memcached_loc_conf_t, upstream.buffer_size),
      NULL },

    { ngx_string("memcached_read_timeout"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_msec_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_memcached_loc_conf_t, upstream.read_timeout),
      NULL },

    { ngx_string("memcached_next_upstream"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
      ngx_conf_set_bitmask_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream),
      &ngx_http_memcached_next_upstream_masks },

      ngx_null_command
};
 

Nginx 命令结构

struct ngx_command_s {
    ngx_str_t             name;
    ngx_uint_t            type;
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};

自定义命令配置说明:

   type :

      NGX_HTTP_MAIN_CONF:可出现在 http 的主作用域;
      NGX_HTTP_SRV_CONF:可出现在 http 的 server 作用域;
      NGX_HTTP_LOC_CONF:可出现在 http 的 location 作用域;
      NGX_HTTP_UPS_CONF:可出现在 http 的 upstream 作用域;
      NGX_HTTP_SIF_CONF:可出现在判断语句里;
      NGX_CONF_NOARGS:指令没有参数;
      NGX_CONF_TAKE1:指令读入1个参数;
      NGX_CONF_TAKE2:指令读入2个参数;
      ......
      NGX_CONF_TAKE7:指令读入7个参数;
      NGX_CONF_FLAG:  指令读入1个布尔型数据(“on”或“off”);
      NGX_CONF_1MORE:指令至少读入1个参数;
      NGX_CONF_2MORE:指令至少读入2个参数;


 

http 上下文定义:

  • static ngx_http_module_t  ngx_http_memcached_module_ctx = {
        NULL,                                  /* preconfiguration */
        NULL,                                  /* postconfiguration */
    
        NULL,                                  /* create main configuration */
        NULL,                                  /* init main configuration */
    
        NULL,                                  /* create server configuration */
        NULL,                                  /* merge server configuration */
    
        ngx_http_memcached_create_loc_conf,    /* create location configuration */
        ngx_http_memcached_merge_loc_conf      /* merge location configuration */
    };
    
    
    ngx_module_t  ngx_http_memcached_module = {
        NGX_MODULE_V1,
        &ngx_http_memcached_module_ctx,        /* module context */
        ngx_http_memcached_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
    };
    
     

    http 上下文结构定义:

    typedef struct {
        ngx_int_t   (*preconfiguration)(ngx_conf_t *cf); 
        ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);
    
        void       *(*create_main_conf)(ngx_conf_t *cf);
        char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
    
        void       *(*create_srv_conf)(ngx_conf_t *cf);
        char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
    
        void       *(*create_loc_conf)(ngx_conf_t *cf);
        char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
    } ngx_http_module_t;
      
    我们跟进看一下 create  and merge loc config:

    static void *
    ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
    {
        ngx_http_memcached_loc_conf_t  *conf;
    
        conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t));
        if (conf == NULL) {
            return NULL;
        }
        /*
         * set by ngx_pcalloc():
         *
         *     conf->upstream.bufs.num = 0;
         *     conf->upstream.next_upstream = 0;
         *     conf->upstream.temp_path = NULL;
         *     conf->upstream.uri = { 0, NULL };
         *     conf->upstream.location = NULL;
         */
    
        conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
        conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
        conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
    
        conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
        /* the hardcoded values */
        conf->upstream.cyclic_temp_file = 0;
        conf->upstream.buffering = 0;
        conf->upstream.ignore_client_abort = 0;
        conf->upstream.send_lowat = 0;
        conf->upstream.bufs.num = 0;
        conf->upstream.busy_buffers_size = 0;
        conf->upstream.max_temp_file_size = 0;
        conf->upstream.temp_file_write_size = 0;
        conf->upstream.intercept_errors = 1;
        conf->upstream.intercept_404 = 1;
        conf->upstream.pass_request_headers = 0;
        conf->upstream.pass_request_body = 0;
        conf->index = NGX_CONF_UNSET;
        return conf;
    }
    
    
    static char *
    ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
    {
        ngx_http_memcached_loc_conf_t *prev = parent;
        ngx_http_memcached_loc_conf_t *conf = child;
        ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                                  prev->upstream.connect_timeout, 60000);
    
        ngx_conf_merge_msec_value(conf->upstream.send_timeout,
                                  prev->upstream.send_timeout, 60000);
    
        ngx_conf_merge_msec_value(conf->upstream.read_timeout,
                                  prev->upstream.read_timeout, 60000);
        ngx_conf_merge_size_value(conf->upstream.buffer_size,
                                  prev->upstream.buffer_size,
                                  (size_t) ngx_pagesize);
        ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
                                  prev->upstream.next_upstream,
                                  (NGX_CONF_BITMASK_SET
                                   |NGX_HTTP_UPSTREAM_FT_ERROR
                                   |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
        if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
            conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
                                           |NGX_HTTP_UPSTREAM_FT_OFF;
        }
        if (conf->upstream.upstream == NULL) {
            conf->upstream.upstream = prev->upstream.upstream;
        }
        if (conf->index == NGX_CONF_UNSET) {
            conf->index = prev->index;
        }
        return NGX_CONF_OK;
    }
    


    接下来我们进入handler:
    static char *
    ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
    {
        clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    
        clcf->handler = ngx_http_memcached_handler;
    
        return NGX_CONF_OK;
    }
      
    static ngx_int_t
    ngx_http_memcached_handler(ngx_http_request_t *r)
    {
        ngx_int_t                       rc;
        ngx_http_upstream_t            *u;
        ngx_http_memcached_ctx_t       *ctx;
        ngx_http_memcached_loc_conf_t  *mlcf;
    
        if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
            return NGX_HTTP_NOT_ALLOWED;
        }
    
        rc = ngx_http_discard_request_body(r);
    
        if (rc != NGX_OK) {
            return rc;
        }
    
        if (ngx_http_set_content_type(r) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    
        if (ngx_http_upstream_create(r) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    
        u = r->upstream;
    
        ngx_str_set(&u->schema, "memcached://");
        u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
    
        mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
    
        u->conf = &mlcf->upstream;
    
        u->create_request = ngx_http_memcached_create_request;
        u->reinit_request = ngx_http_memcached_reinit_request;
        u->process_header = ngx_http_memcached_process_header;
        u->abort_request = ngx_http_memcached_abort_request;
        u->finalize_request = ngx_http_memcached_finalize_request;
    
        ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
        ctx->rest = NGX_HTTP_MEMCACHED_END;
        ctx->request = r;
        ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
        u->input_filter_init = ngx_http_memcached_filter_init;
        u->input_filter = ngx_http_memcached_filter;
        u->input_filter_ctx = ctx;
        r->main->count++;
        ngx_http_upstream_init(r);
        return NGX_DONE;
    }
    
     
    以上 memcache处理均在以下方法中进行:
      u->create_request = ngx_http_memcached_create_request;
        u->reinit_request = ngx_http_memcached_reinit_request;
        u->process_header = ngx_http_memcached_process_header;
        u->abort_request = ngx_http_memcached_abort_request;
        u->finalize_request = ngx_http_memcached_finalize_request;
    
       u->input_filter_init = ngx_http_memcached_filter_init;
        u->input_filter = ngx_http_memcached_filter;
        u->input_filter_ctx = ctx;
     


    以上是对memcached nginx模块进行的分析,小刀我也是初始,有写的不好的地方,请大家多多指教,接下来我们在看一个 not modified moudel 这个相对就容易很多。
    /*
     * Copyright (C) Igor Sysoev
     * Copyright (C) Nginx, Inc.
     */
    
    
    #include <ngx_config.h>
    #include <ngx_core.h>
    #include <ngx_http.h>
    
    
    static ngx_int_t ngx_http_test_precondition(ngx_http_request_t *r);
    static ngx_int_t ngx_http_test_not_modified(ngx_http_request_t *r);
    static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf);
    
    
    static ngx_http_module_t  ngx_http_not_modified_filter_module_ctx = {
        NULL,                                  /* preconfiguration */
        ngx_http_not_modified_filter_init,     /* postconfiguration */
    
        NULL,                                  /* create main configuration */
        NULL,                                  /* init main configuration */
    
        NULL,                                  /* create server configuration */
        NULL,                                  /* merge server configuration */
    
        NULL,                                  /* create location configuration */
        NULL                                   /* merge location configuration */
    };
    
    
    ngx_module_t  ngx_http_not_modified_filter_module = {
        NGX_MODULE_V1,
        &ngx_http_not_modified_filter_module_ctx, /* module context */
        NULL,                                  /* 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_output_header_filter_pt  ngx_http_next_header_filter;
    
    
    static ngx_int_t
    ngx_http_not_modified_header_filter(ngx_http_request_t *r)
    {
        if (r->headers_out.status != NGX_HTTP_OK
            || r != r->main
            || r->headers_out.last_modified_time == -1)
        {
            return ngx_http_next_header_filter(r);
        }
    
        if (r->headers_in.if_unmodified_since) {
            return ngx_http_test_precondition(r);
        }
    
        if (r->headers_in.if_modified_since) {
            return ngx_http_test_not_modified(r);
        }
    
        return ngx_http_next_header_filter(r);
    }
    
    
    static ngx_int_t
    ngx_http_test_precondition(ngx_http_request_t *r)
    {
        time_t  iums;
    
        iums = ngx_http_parse_time(r->headers_in.if_unmodified_since->value.data,
                                   r->headers_in.if_unmodified_since->value.len);
    
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                     "http iums:%d lm:%d", iums, r->headers_out.last_modified_time);
    
        if (iums >= r->headers_out.last_modified_time) {
            return ngx_http_next_header_filter(r);
        }
    
        return ngx_http_filter_finalize_request(r, NULL,
                                                NGX_HTTP_PRECONDITION_FAILED);
    }
    
    
    static ngx_int_t
    ngx_http_test_not_modified(ngx_http_request_t *r)
    {
        time_t                     ims;
        ngx_http_core_loc_conf_t  *clcf;
    
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    
        if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
            return ngx_http_next_header_filter(r);
        }
    
        ims = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
                                  r->headers_in.if_modified_since->value.len);
    
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http ims:%d lm:%d", ims, r->headers_out.last_modified_time);
    
        if (ims != r->headers_out.last_modified_time) {
    
            if (clcf->if_modified_since == NGX_HTTP_IMS_EXACT
                || ims < r->headers_out.last_modified_time)
            {
                return ngx_http_next_header_filter(r);
            }
        }
    
        r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
        r->headers_out.status_line.len = 0;
        r->headers_out.content_type.len = 0;
        ngx_http_clear_content_length(r);
        ngx_http_clear_accept_ranges(r);
    
        if (r->headers_out.content_encoding) {
            r->headers_out.content_encoding->hash = 0;
            r->headers_out.content_encoding = NULL;
        }
    
        return ngx_http_next_header_filter(r);
    }
    
    
    static ngx_int_t
    ngx_http_not_modified_filter_init(ngx_conf_t *cf)
    {
        ngx_http_next_header_filter = ngx_http_top_header_filter;
        ngx_http_top_header_filter = ngx_http_not_modified_header_filter;
    
        return NGX_OK;
    }
    
     
    自定义返回时设置cookie:

    1. mkdir author
    2. cd author
    3. 创建一个文件叫 config 内容如下

    ngx_addon_name=nginx_add_author_filter_module
    HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES nginx_add_author_filter_module"
    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/author.c"
    4../configure --add-module=/Users/liuzheng/nginx/addOn/ 

    /*
    * Copy right (C) Liuzheng Wiyun author.c
    */
    
    #include <ngx_config.h>
    #include <ngx_core.h>
    #include <ngx_http.h>
    
    
    
    static ngx_int_t ngx_http_add_author_filter_init(ngx_conf_t *cf);
    static ngx_int_t ngx_http_add_author_header_filter(ngx_http_request_t *r);
    
    static ngx_http_module_t nginx_add_author_filter_module_ctx = {
        NULL,                                  /* preconfiguration */
        ngx_http_add_author_filter_init,     /* postconfiguration */
    
        NULL,                                  /* create main configuration */
        NULL,                                  /* init main configuration */
    
        NULL,                                  /* create server configuration */
        NULL,                                  /* merge server configuration */
    
        NULL,                                  /* create location configuration */
        NULL                                   /* merge location configuration */
    };
    
    
    ngx_module_t  nginx_add_author_filter_module = {
        NGX_MODULE_V1,
        &nginx_add_author_filter_module_ctx, /* module context */
        NULL,                                  /* 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_output_header_filter_pt  ngx_http_next_header_filter;
    
    
    static ngx_int_t
    ngx_http_add_author_header_filter(ngx_http_request_t *r)
    {
        ngx_table_elt_t  *set_cookie;
    
        set_cookie = 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");
        ngx_str_set(&set_cookie->value, "author=liuzheng");
    
        return ngx_http_next_header_filter(r);
    }
    
    
    static ngx_int_t
    ngx_http_add_author_filter_init(ngx_conf_t *cf)
    {
        ngx_http_next_header_filter = ngx_http_top_header_filter;
        ngx_http_top_header_filter = ngx_http_add_author_header_filter;
    
        return NGX_OK;
    }
    
     

    1. Connection:
      keep-alive
    2. Date:
      Mon, 13 Aug 2012 08:39:51 GMT
    3. Last-Modified:
      Mon, 27 Feb 2012 09:14:41 GMT
    4. Server:
      nginx/1.2.3
    5. Set-Cookie:
      author=liuzheng

猜你喜欢

转载自edisonlz.iteye.com/blog/1630283