自己写的一个简单返回html文件的模块,但是返回不成功,需要学习一下filter模块的工作细节才能知道原因。
不多说,放代码
ngx_http_echo_module.c
/*
zhuheming 20160811
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static ngx_int_t
ngx_http_echo_handler(ngx_http_request_t *r);
typedef struct{
ngx_str_t ed;
}ngx_http_echo_loc_conf_t;
static char *
ngx_http_echo(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_echo_handler;
return NGX_CONF_OK;
}
static ngx_command_t ngx_http_echo_commands[]={
{ngx_string("echo"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_echo,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_echo_loc_conf_t,ed),
NULL
},
ngx_null_command
};
static ngx_http_module_t ngx_http_echo_module_ctx ={
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
ngx_module_t ngx_http_echo_module = {
NGX_MODULE_V1,
&ngx_http_echo_module_ctx,
ngx_http_echo_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_echo_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t out;
if(!(r->method & (NGX_HTTP_HEAD|NGX_HTTP_GET|NGX_HTTP_POST)))
{
return NGX_HTTP_NOT_ALLOWED;
}
//设置报文头
r->headers_out.content_type.len = sizeof("text/html") - 1;
r->headers_out.content_type.data = (u_char *) "text/html";
r->headers_out.status = NGX_HTTP_OK;
if(r->method == NGX_HTTP_HEAD)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send head method to client!");
rc = ngx_http_send_header(r);
if(rc != NGX_OK)
{
return rc;
}
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send not head method to client!");
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if(b == NULL)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
//直接指定文件位置,后续可以加入到配置文件中
u_char *filename=(u_char *)"html/echotest.html";
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send %s to client!",filename);
out.buf = b;
out.next = NULL;
//设置buf的方式为file方式,设置文件句柄,文件名
b->in_file=1;
b->file=ngx_pcalloc(r->pool,sizeof(ngx_file_t));
b->file->fd=ngx_open_file(filename,NGX_FILE_RDONLY,NGX_FILE_OPEN,0);
b->file->name.data=filename;
b->file->name.len=strlen(filename);
b->file->log=r->connection->log;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send file fd : %d!",b->file->fd);
if(b->file->fd<0){
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "open file error!");
return NGX_HTTP_NOT_FOUND;
}
if(ngx_file_info(filename,&b->file->info)==NGX_FILE_ERROR){
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "get file info error!");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
//设置文件开始读取和结束位置
b->file_pos=0;
b->file_last=b->file->info.st_size;
//加入到文件句柄清除
if(b->file->fd!=NGX_INVALID_FILE){
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "add file to pool_cleanup!");
ngx_pool_cleanup_t *cln=ngx_pool_cleanup_add(r->pool,sizeof(ngx_pool_cleanup_t));
cln->handler=ngx_pool_cleanup_file;
ngx_pool_cleanup_file_t *clnf=cln->data;
clnf->fd=b->file->fd;
clnf->name=b->file->name.data;
clnf->log=r->pool->log;
}
r->headers_out.content_length_n=b->file->info.st_size;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send http is file : %1d!",b->in_file);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send http file name : %s!",b->file->name.data);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send http file_last : %d!",b->file_last);
rc = ngx_http_send_header(r);
if(rc != NGX_OK)
{
return rc;
}
//设置最后一个chain标志,还少一个b->lastbuf=1
//这样nginx认为没有读取完成,不会发送报文体
b->last_in_chain=1;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "send http outputfilter !");
return ngx_http_output_filter(r, &out);
}
nginx.conf里是这样加的
location /echo {
echo ;
}
只有命令,没有用到参数,也不用解析参数
另外就是增加一个config文件,内容如下
ngx_addon_name=ngx_http_echo_module
HTTP_MODULES="$HTTP_MODULES ngx_http_echo_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_echo_module.c"
ngx_addon_name是模块名称
HTTP_MODULES是所有http模块,所以在后面添加一个新模块
NGX_ADDON_SRCS是新增模块的源代码,$ngx_addon_dir值取自configure中的参数
文件放在和源代码同一个目录下
这几块添加之后,就可以开始执行configure命令了
添加模块之后需要增加参数
–add-module=PATH PATH是新增模块config和源代码存放的目录
执行之后nginx会生成一些makefile文件,ngx_modules.c文件之类的,里面就已经将这个模块包含在内了
后来经过跟踪,发现ngx_http_write_filter_module.c中的ngx_http_write_filter函数中cl->buf->last_buf为0,就是说在ngx_http_echo_module.c中,需要加一个b->lastbuf=1,来表示这是最后一块buf。现在已经成功收到。