src/http/ngx_http_copy_filter_module.c - nginx-1.7.10

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. typedef struct {
  9.     ngx_bufs_t  bufs;
  10. } ngx_http_copy_filter_conf_t;


  11. #if (NGX_HAVE_FILE_AIO)
  12. static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx,
  13.     ngx_file_t *file);
  14. static void ngx_http_copy_aio_event_handler(ngx_event_t *ev);
  15. #if (NGX_HAVE_AIO_SENDFILE)
  16. static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev);
  17. #endif
  18. #endif

  19. static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf);
  20. static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf,
  21.     void *parent, void *child);
  22. static ngx_int_t ngx_http_copy_filter_init(ngx_conf_t *cf);


  23. static ngx_command_t  ngx_http_copy_filter_commands[] = {

  24.     { ngx_string("output_buffers"),
  25.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  26.       ngx_conf_set_bufs_slot,
  27.       NGX_HTTP_LOC_CONF_OFFSET,
  28.       offsetof(ngx_http_copy_filter_conf_t, bufs),
  29.       NULL },

  30.       ngx_null_command
  31. };


  32. static ngx_http_module_t  ngx_http_copy_filter_module_ctx = {
  33.     NULL,                                  /* preconfiguration */
  34.     ngx_http_copy_filter_init,             /* postconfiguration */

  35.     NULL,                                  /* create main configuration */
  36.     NULL,                                  /* init main configuration */

  37.     NULL,                                  /* create server configuration */
  38.     NULL,                                  /* merge server configuration */

  39.     ngx_http_copy_filter_create_conf,      /* create location configuration */
  40.     ngx_http_copy_filter_merge_conf        /* merge location configuration */
  41. };


  42. ngx_module_t  ngx_http_copy_filter_module = {
  43.     NGX_MODULE_V1,
  44.     &ngx_http_copy_filter_module_ctx,      /* module context */
  45.     ngx_http_copy_filter_commands,         /* module directives */
  46.     NGX_HTTP_MODULE,                       /* module type */
  47.     NULL,                                  /* init master */
  48.     NULL,                                  /* init module */
  49.     NULL,                                  /* init process */
  50.     NULL,                                  /* init thread */
  51.     NULL,                                  /* exit thread */
  52.     NULL,                                  /* exit process */
  53.     NULL,                                  /* exit master */
  54.     NGX_MODULE_V1_PADDING
  55. };


  56. static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;


  57. static ngx_int_t
  58. ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
  59. {
  60.     ngx_int_t                     rc;
  61.     ngx_connection_t             *c;
  62.     ngx_output_chain_ctx_t       *ctx;
  63.     ngx_http_core_loc_conf_t     *clcf;
  64.     ngx_http_copy_filter_conf_t  *conf;

  65.     c = r->connection;

  66.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
  67.                    "http copy filter: \"%V?%V\"", &r->uri, &r->args);

  68.     ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);

  69.     if (ctx == NULL) {
  70.         ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
  71.         if (ctx == NULL) {
  72.             return NGX_ERROR;
  73.         }

  74.         ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module);

  75.         conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module);
  76.         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  77.         ctx->sendfile = c->sendfile;
  78.         ctx->need_in_memory = r->main_filter_need_in_memory
  79.                               || r->filter_need_in_memory;
  80.         ctx->need_in_temp = r->filter_need_temporary;

  81.         ctx->alignment = clcf->directio_alignment;

  82.         ctx->pool = r->pool;
  83.         ctx->bufs = conf->bufs;
  84.         ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module;

  85.         ctx->output_filter = (ngx_output_chain_filter_pt)
  86.                                   ngx_http_next_body_filter;
  87.         ctx->filter_ctx = r;

  88. #if (NGX_HAVE_FILE_AIO)
  89.         if (ngx_file_aio) {
  90.             if (clcf->aio) {
  91.                 ctx->aio_handler = ngx_http_copy_aio_handler;
  92.             }
  93. #if (NGX_HAVE_AIO_SENDFILE)
  94.             c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE);
  95. #endif
  96.         }
  97. #endif

  98.         if (in && in->buf && ngx_buf_size(in->buf)) {
  99.             r->request_output = 1;
  100.         }
  101.     }

  102. #if (NGX_HAVE_FILE_AIO)
  103.     ctx->aio = r->aio;
  104. #endif

  105.     for ( ;; ) {
  106.         rc = ngx_output_chain(ctx, in);

  107.         if (ctx->in == NULL) {
  108.             r->buffered &= ~NGX_HTTP_COPY_BUFFERED;

  109.         } else {
  110.             r->buffered |= NGX_HTTP_COPY_BUFFERED;
  111.         }

  112.         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
  113.                        "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);

  114. #if (NGX_HAVE_FILE_AIO && NGX_HAVE_AIO_SENDFILE)

  115.         if (c->busy_sendfile) {
  116.             ssize_t                n;
  117.             off_t                  offset;
  118.             ngx_file_t            *file;
  119.             ngx_http_ephemeral_t  *e;

  120.             if (r->aio) {
  121.                 c->busy_sendfile = NULL;
  122.                 return rc;
  123.             }

  124.             file = c->busy_sendfile->file;
  125.             offset = c->busy_sendfile->file_pos;

  126.             if (file->aio) {
  127.                 c->busy_count = (offset == file->aio->last_offset) ?
  128.                                 c->busy_count + 1 : 0;
  129.                 file->aio->last_offset = offset;

  130.                 if (c->busy_count > 2) {
  131.                     ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  132.                                   "sendfile(%V) returned busy again",
  133.                                   &file->name);
  134.                     c->aio_sendfile = 0;
  135.                 }
  136.             }

  137.             c->busy_sendfile = NULL;
  138.             e = (ngx_http_ephemeral_t *) &r->uri_start;

  139.             n = ngx_file_aio_read(file, &e->aio_preload, 1, offset, r->pool);

  140.             if (n > 0) {
  141.                 in = NULL;
  142.                 continue;
  143.             }

  144.             rc = n;

  145.             if (rc == NGX_AGAIN) {
  146.                 file->aio->data = r;
  147.                 file->aio->handler = ngx_http_copy_aio_sendfile_event_handler;

  148.                 r->main->blocked++;
  149.                 r->aio = 1;
  150.             }
  151.         }
  152. #endif

  153.         return rc;
  154.     }
  155. }


  156. #if (NGX_HAVE_FILE_AIO)

  157. static void
  158. ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file)
  159. {
  160.     ngx_http_request_t *r;

  161.     r = ctx->filter_ctx;

  162.     file->aio->data = r;
  163.     file->aio->handler = ngx_http_copy_aio_event_handler;

  164.     r->main->blocked++;
  165.     r->aio = 1;
  166.     ctx->aio = 1;
  167. }


  168. static void
  169. ngx_http_copy_aio_event_handler(ngx_event_t *ev)
  170. {
  171.     ngx_event_aio_t     *aio;
  172.     ngx_http_request_t  *r;

  173.     aio = ev->data;
  174.     r = aio->data;

  175.     r->main->blocked--;
  176.     r->aio = 0;

  177.     r->connection->write->handler(r->connection->write);
  178. }


  179. #if (NGX_HAVE_AIO_SENDFILE)

  180. static void
  181. ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev)
  182. {
  183.     ngx_event_aio_t     *aio;
  184.     ngx_http_request_t  *r;

  185.     aio = ev->data;
  186.     r = aio->data;

  187.     r->main->blocked--;
  188.     r->aio = 0;
  189.     ev->complete = 0;

  190.     r->connection->write->handler(r->connection->write);
  191. }

  192. #endif
  193. #endif


  194. static void *
  195. ngx_http_copy_filter_create_conf(ngx_conf_t *cf)
  196. {
  197.     ngx_http_copy_filter_conf_t *conf;

  198.     conf = ngx_palloc(cf->pool, sizeof(ngx_http_copy_filter_conf_t));
  199.     if (conf == NULL) {
  200.         return NULL;
  201.     }

  202.     conf->bufs.num = 0;

  203.     return conf;
  204. }


  205. static char *
  206. ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
  207. {
  208.     ngx_http_copy_filter_conf_t *prev = parent;
  209.     ngx_http_copy_filter_conf_t *conf = child;

  210.     ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768);

  211.     return NULL;
  212. }


  213. static ngx_int_t
  214. ngx_http_copy_filter_init(ngx_conf_t *cf)
  215. {
  216.     ngx_http_next_body_filter = ngx_http_top_body_filter;
  217.     ngx_http_top_body_filter = ngx_http_copy_filter;

  218.     return NGX_OK;
  219. }