免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2600 | 回复: 1
打印 上一主题 下一主题

nginx代码分析之Empty Gif是如何工作的 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-22 08:54 |只看该作者 |倒序浏览
访问新浪时,时常会有一些网页返回空白(但不是“此页无法显示”),从浏览器的信息中可以知道此时服务器返回了一个1×1的空白gif图片。

这实际上是nginx实现的,nginx有一个名为Empty Gif的module,专门负责此项工作。

由于这个module比较简单,我们就先从它入手,来看看nginx的模块实现。

模块注册Empty Gif这个module只有一个文件——ngx_http_empty_gif_module.c

这个文件比较简单,一开始定义并初始化了3个变量。

static ngx_command_t  ngx_http_empty_gif_commands[] = {...};
static ngx_http_module_t  ngx_http_empty_gif_module_ctx = {...};
ngx_module_t  ngx_http_empty_gif_module = {...};

其中只有ngx_http_empty_gif_module是非静态的,我将暂时将其称为module主结构变量,
而其余两个变量都可以由它访问到。

但是如果继续查看nginx的源码,会发现没有其他地方引用ngx_http_empty_gif_module,
那这个module是怎么注册并应用起来的呢?

如果熟悉Apache的代码,会发现这和Apache 2.0的module机制非常类似——每个module都对应到一个module主结构变量,通过这个主结构变量可以访问到这个module的其他内容,该module所有的函数也用函数指针的方式存放在这些结构变量中。

而且Apache同样没有其他地方的代码引用到module主结构变量。这是因为module不是必须的,该module在某一个特定的编译版本里是可以不存在的。因此一个module是否有效,不是通过代码来决定,而是通过编译选项来实现。

nginx代码的auto目录中,有一个名为sources的文件,根据编译选项(configure的参数)的不同,m4宏变量HTTP_MODULES的值会发生变化:

如果指定了使用empty gif模块(默认就是使用了),则最终m4宏变量HTTP_MODULES的值可能如下:
HTTP_MODULES="ngx_http_module /
              ngx_http_core_module /
              ngx_http_log_module /
              ngx_http_upstream_module /
              ngx_http_empty_gif_module "

注意:这里的ngx_http_empty_gif_module字符串对应了ngx_http_empty_gif_module.c文件中的Module主结构变量名。

编译之前的configure结束后,会在objs目录下生成一个名为ngx_modules.c的文件,此文件的内容如下:
#include <ngx_config.h>
#include <ngx_core.h>

extern ngx_module_t  ngx_core_module;
extern ngx_module_t  ngx_errlog_module;
extern ngx_module_t  ngx_conf_module;
...
extern ngx_module_t  ngx_http_empty_gif_module;
...

ngx_module_t *ngx_modules[] = {
    &ngx_core_module,
    &ngx_errlog_module,
    &ngx_conf_module,
    ...
    &ngx_http_empty_gif_module,
    ...
    NULL
};

在此生成了对ngx_http_empty_gif_module变量的引用,并将其放到了ngx_modules表中,
通过相关函数可以进行存取。

这样,在编译时就完成了Empty Gif模块注册的过程。

模块的初始化和应用初始化一般都是根据配置文件的内容来进行,但和我们一般写程序的做法不同——nginx并没有在一个统一的地方处理所有的配置,而是让每个模块负责处理自己的配置项,如果没有编译这个模块,则其对应的配置项就无法处理,这也是又一个和Apache的相似之处。

nginx使用了ngx_command_t结构来描述某一个模块对应的配置项及处理函数。

以Empty Gif模块为例:
static ngx_command_t  ngx_http_empty_gif_commands[] = {

    { ngx_string("empty_gif"),
      NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
      ngx_http_empty_gif,
      0,
      0,
      NULL },

      ngx_null_command
};

上面的定义表明:
1.  Empty Gif模块只处理一个配置项——“empty_gif”
2.  这个配置是一个Location相关的配置(NGX_HTTP_LOC_CONF),
     即只有在处理某一个URL子集,如 /test_[0-9]*.gif时才生效。
  
     实际的配置文件可能如下:
      location ~ /test_[0-9].gif {
            empty_gif;
      }
3.  这个配置项不带参数(NGX_CONF_NOARGS)
4.  配置处理函数是ngx_http_empty_gif

ngx_http_empty_gif函数的实现很简单:

static char *
ngx_http_empty_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t  *clcf;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_empty_gif_handler;

    return NGX_CONF_OK;
}

ngx_http_conf_get_module_loc_conf是一个宏,用于获得Location相关的配置表cf中ngx_http_core_module对应的项,获取之后,Empty Gif模块将自己的处理函数挂到了ngx_http_core_module对应的handler上。

这样,nginx在处理HTTP请求时,如果发现其URL匹配到Empty Gif所属的Location,
如URL(/test_1.gif)匹配到Location(/test_[0-9].gif),
则使用ngx_http_empty_gif作为处理函数,这个函数直接向浏览器写回一幅1×1的空白gif图片。
以下是handler函数:

108 static ngx_int_t
109 ngx_http_empty_gif_handler(ngx_http_request_t *r)
110 {
111     ngx_int_t     rc;
112     ngx_buf_t    *b;
113     ngx_chain_t   out;
114
115     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
116         return NGX_HTTP_NOT_ALLOWED;
117     }
118
119     rc = ngx_http_discard_request_body(r);
120
121     if (rc != NGX_OK) {
122         return rc;
123     }
124
125     r->headers_out.content_type.len = sizeof("image/gif") - 1;
126     r->headers_out.content_type.data = (u_char *) "image/gif";
127
128     if (r->method == NGX_HTTP_HEAD) {
129         r->headers_out.status = NGX_HTTP_OK;
130         r->headers_out.content_length_n = sizeof(ngx_empty_gif);
131         r->headers_out.last_modified_time = 23349600;
132
133         return ngx_http_send_header(r);
134     }
135
136     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
137     if (b == NULL) {
138         return NGX_HTTP_INTERNAL_SERVER_ERROR;
139     }
140
141     out.buf = b;
142     out.next = NULL;
143
144     b->pos = ngx_empty_gif;
145     b->last = ngx_empty_gif + sizeof(ngx_empty_gif);
146     b->memory = 1;
147     b->last_buf = 1;
148
149     r->headers_out.status = NGX_HTTP_OK;
150     r->headers_out.content_length_n = sizeof(ngx_empty_gif);
151     r->headers_out.last_modified_time = 23349600;
152
153     rc = ngx_http_send_header(r);
154
155     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
156         return rc;
157     }
158
159     return ngx_http_output_filter(r, &out);
160 }
161
162
163 static char *
164 ngx_http_empty_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
165 {
166     ngx_http_core_loc_conf_t  *clcf;
167
168     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
169     clcf->handler = ngx_http_empty_gif_handler;
170
171     return NGX_CONF_OK;
172 }

论坛徽章:
1
双鱼座
日期:2014-01-21 18:52:34
2 [报告]
发表于 2013-02-21 21:05 |只看该作者
这个module现在么有了了?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP