【nginx源码学习与运用 十】第二个http模块——发送磁盘文件

【nginx源码学习与运用】系列博客中的示例代码在csdn的代码托管服务器CODE上,地址https://code.csdn.net/u012819339/nginx_study ,你可以将其自由的下载到本地,或者通过Git来实时获取更新


步骤和前一篇博客类似,不再赘述,这里贴出代码,解释也在代码中

ngx_http_filetest_module.c源码如下:

//该示例代码演示如何发送磁盘中的文件

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

//文件描述符清理函数,nginx在处理完本次请求释放内存池的时候会同步调用该函数释放资源
void ngx_pool_cleanup_mytest_file(void *data)
{
    ngx_pool_cleanup_file_t *c = data;

    ngx_close_file(c->fd);
}


static ngx_int_t ngx_http_filetest_handler(ngx_http_request_t *r)
{
    //设定mytest模块只处理GET或HEAD请求
    if(!(r->method &(NGX_HTTP_GET|NGX_HTTP_HEAD)))
        return NGX_HTTP_NOT_ALLOWED;

    //丢弃请求中的包体
    ngx_int_t rc = ngx_http_discard_request_body(r);
    if(rc != NGX_OK)
        return rc;

    ngx_buf_t *b;
    b = ngx_palloc(r->pool, sizeof(ngx_buf_t));
    u_char *filename = (u_char *)"/tmp/filetest.txt";
    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_NONBLOCK, NGX_FILE_OPEN, 0);
    b->file->log = r->connection->log;
    b->file->name.data = filename;
    b->file->name.len = ngx_strlen(filename);
    if(b->file->fd <= 0)
        return NGX_HTTP_NOT_FOUND;

    if(ngx_file_info(filename, &b->file->info) == NGX_FILE_ERROR )
    {
        ngx_close_file(b->file->fd);
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->headers_out.content_length_n = b->file->info.st_size;
    b->file_pos = 0;
    b->file_last = b->file->info.st_size; 

    //注册文件描述符清理函数
    ngx_pool_cleanup_t *cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
    if(cln == NULL)
    {
        ngx_close_file(b->file->fd);
        return NGX_ERROR;
    }
    cln->handler = ngx_pool_cleanup_mytest_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;

    ngx_str_t type = ngx_string("text/html");
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_type = type;
    //发送HTTP头部
    rc = ngx_http_send_header(r);
    if(rc == NGX_ERROR || rc > NGX_OK || r->header_only)
    {
        ngx_close_file(b->file->fd);
        return rc;
    }

    //发送body
    ngx_chain_t out;
    out.buf = b;
    out.next = NULL;

    //如果要支持断点续传就解注释下面语句
    //r->allow_ranges = 1; 

    return ngx_http_output_filter(r, &out);
}


static char *ngx_http_filetest(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_filetest_handler;

    return NGX_CONF_OK;
}


static ngx_command_t ngx_http_filetest_commands[] =
{
    {
        ngx_string("filetest"),
        NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,
        ngx_http_filetest,
        NGX_HTTP_LOC_CONF_OFFSET,
        0,
        NULL
    },
    ngx_null_command
};

//模块接口描述的8个阶段,在http框架初始化的时候完成,函数指针都可置NULL
static ngx_http_module_t ngx_http_filetest_module_ctx = 
{
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
};

ngx_module_t ngx_http_filetest_module = 
{
    NGX_MODULE_V1,
    &ngx_http_filetest_module_ctx,
    ngx_http_filetest_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};

添加filetest模块后的config文件:

ngx_addon_name="ngx_http_mytest_module ngx_http_filetest_module"
HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module ngx_http_filetest_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c $ngx_addon_dir/ngx_http_filetest_module.c"

测试文件:
磁盘测试文件/tmp/filetest.txt内容如下:

<html>
<head>
        <title>filetest</title>
<head>

<body>
        <p>arvik filetest module!</p>
</body>

</html>

运行结果截图:
这里写图片描述

代码已经存上传到这个位置 https://code.csdn.net/u012819339/nginx_study ,在项目的test9目录中,童鞋们可自行下载演示

猜你喜欢

转载自blog.csdn.net/u012819339/article/details/53888550