nginx的http模块开发(直接发送html文件方式)

14 篇文章 0 订阅
10 篇文章 0 订阅

自己写的一个简单返回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。现在已经成功收到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值