src/http/ngx_http_write_filter_module.c - nginx-1.7.10

Global variables 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. static ngx_int_t ngx_http_write_filter_init(ngx_conf_t *cf);


  9. static ngx_http_module_t  ngx_http_write_filter_module_ctx = {
  10.     NULL,                                  /* preconfiguration */
  11.     ngx_http_write_filter_init,            /* postconfiguration */

  12.     NULL,                                  /* create main configuration */
  13.     NULL,                                  /* init main configuration */

  14.     NULL,                                  /* create server configuration */
  15.     NULL,                                  /* merge server configuration */

  16.     NULL,                                  /* create location configuration */
  17.     NULL,                                  /* merge location configuration */
  18. };


  19. ngx_module_t  ngx_http_write_filter_module = {
  20.     NGX_MODULE_V1,
  21.     &ngx_http_write_filter_module_ctx,     /* module context */
  22.     NULL,                                  /* module directives */
  23.     NGX_HTTP_MODULE,                       /* module type */
  24.     NULL,                                  /* init master */
  25.     NULL,                                  /* init module */
  26.     NULL,                                  /* init process */
  27.     NULL,                                  /* init thread */
  28.     NULL,                                  /* exit thread */
  29.     NULL,                                  /* exit process */
  30.     NULL,                                  /* exit master */
  31.     NGX_MODULE_V1_PADDING
  32. };


  33. ngx_int_t
  34. ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
  35. {
  36.     off_t                      size, sent, nsent, limit;
  37.     ngx_uint_t                 last, flush, sync;
  38.     ngx_msec_t                 delay;
  39.     ngx_chain_t               *cl, *ln, **ll, *chain;
  40.     ngx_connection_t          *c;
  41.     ngx_http_core_loc_conf_t  *clcf;

  42.     c = r->connection;

  43.     if (c->error) {
  44.         return NGX_ERROR;
  45.     }

  46.     size = 0;
  47.     flush = 0;
  48.     sync = 0;
  49.     last = 0;
  50.     ll = &r->out;

  51.     /* find the size, the flush point and the last link of the saved chain */

  52.     for (cl = r->out; cl; cl = cl->next) {
  53.         ll = &cl->next;

  54.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
  55.                        "write old buf t:%d f:%d %p, pos %p, size: %z "
  56.                        "file: %O, size: %z",
  57.                        cl->buf->temporary, cl->buf->in_file,
  58.                        cl->buf->start, cl->buf->pos,
  59.                        cl->buf->last - cl->buf->pos,
  60.                        cl->buf->file_pos,
  61.                        cl->buf->file_last - cl->buf->file_pos);

  62. #if 1
  63.         if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
  64.             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  65.                           "zero size buf in writer "
  66.                           "t:%d r:%d f:%d %p %p-%p %p %O-%O",
  67.                           cl->buf->temporary,
  68.                           cl->buf->recycled,
  69.                           cl->buf->in_file,
  70.                           cl->buf->start,
  71.                           cl->buf->pos,
  72.                           cl->buf->last,
  73.                           cl->buf->file,
  74.                           cl->buf->file_pos,
  75.                           cl->buf->file_last);

  76.             ngx_debug_point();
  77.             return NGX_ERROR;
  78.         }
  79. #endif

  80.         size += ngx_buf_size(cl->buf);

  81.         if (cl->buf->flush || cl->buf->recycled) {
  82.             flush = 1;
  83.         }

  84.         if (cl->buf->sync) {
  85.             sync = 1;
  86.         }

  87.         if (cl->buf->last_buf) {
  88.             last = 1;
  89.         }
  90.     }

  91.     /* add the new chain to the existent one */

  92.     for (ln = in; ln; ln = ln->next) {
  93.         cl = ngx_alloc_chain_link(r->pool);
  94.         if (cl == NULL) {
  95.             return NGX_ERROR;
  96.         }

  97.         cl->buf = ln->buf;
  98.         *ll = cl;
  99.         ll = &cl->next;

  100.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
  101.                        "write new buf t:%d f:%d %p, pos %p, size: %z "
  102.                        "file: %O, size: %z",
  103.                        cl->buf->temporary, cl->buf->in_file,
  104.                        cl->buf->start, cl->buf->pos,
  105.                        cl->buf->last - cl->buf->pos,
  106.                        cl->buf->file_pos,
  107.                        cl->buf->file_last - cl->buf->file_pos);

  108. #if 1
  109.         if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
  110.             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  111.                           "zero size buf in writer "
  112.                           "t:%d r:%d f:%d %p %p-%p %p %O-%O",
  113.                           cl->buf->temporary,
  114.                           cl->buf->recycled,
  115.                           cl->buf->in_file,
  116.                           cl->buf->start,
  117.                           cl->buf->pos,
  118.                           cl->buf->last,
  119.                           cl->buf->file,
  120.                           cl->buf->file_pos,
  121.                           cl->buf->file_last);

  122.             ngx_debug_point();
  123.             return NGX_ERROR;
  124.         }
  125. #endif

  126.         size += ngx_buf_size(cl->buf);

  127.         if (cl->buf->flush || cl->buf->recycled) {
  128.             flush = 1;
  129.         }

  130.         if (cl->buf->sync) {
  131.             sync = 1;
  132.         }

  133.         if (cl->buf->last_buf) {
  134.             last = 1;
  135.         }
  136.     }

  137.     *ll = NULL;

  138.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
  139.                    "http write filter: l:%d f:%d s:%O", last, flush, size);

  140.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  141.     /*
  142.      * avoid the output if there are no last buf, no flush point,
  143.      * there are the incoming bufs and the size of all bufs
  144.      * is smaller than "postpone_output" directive
  145.      */

  146.     if (!last && !flush && in && size < (off_t) clcf->postpone_output) {
  147.         return NGX_OK;
  148.     }

  149.     if (c->write->delayed) {
  150.         c->buffered |= NGX_HTTP_WRITE_BUFFERED;
  151.         return NGX_AGAIN;
  152.     }

  153.     if (size == 0
  154.         && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
  155.         && !(last && c->need_last_buf))
  156.     {
  157.         if (last || flush || sync) {
  158.             for (cl = r->out; cl; /* void */) {
  159.                 ln = cl;
  160.                 cl = cl->next;
  161.                 ngx_free_chain(r->pool, ln);
  162.             }

  163.             r->out = NULL;
  164.             c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;

  165.             return NGX_OK;
  166.         }

  167.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  168.                       "the http output chain is empty");

  169.         ngx_debug_point();

  170.         return NGX_ERROR;
  171.     }

  172.     if (r->limit_rate) {
  173.         if (r->limit_rate_after == 0) {
  174.             r->limit_rate_after = clcf->limit_rate_after;
  175.         }

  176.         limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1)
  177.                 - (c->sent - r->limit_rate_after);

  178.         if (limit <= 0) {
  179.             c->write->delayed = 1;
  180.             delay = (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1);
  181.             ngx_add_timer(c->write, delay);

  182.             c->buffered |= NGX_HTTP_WRITE_BUFFERED;

  183.             return NGX_AGAIN;
  184.         }

  185.         if (clcf->sendfile_max_chunk
  186.             && (off_t) clcf->sendfile_max_chunk < limit)
  187.         {
  188.             limit = clcf->sendfile_max_chunk;
  189.         }

  190.     } else {
  191.         limit = clcf->sendfile_max_chunk;
  192.     }

  193.     sent = c->sent;

  194.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  195.                    "http write filter limit %O", limit);

  196.     chain = c->send_chain(c, r->out, limit);

  197.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  198.                    "http write filter %p", chain);

  199.     if (chain == NGX_CHAIN_ERROR) {
  200.         c->error = 1;
  201.         return NGX_ERROR;
  202.     }

  203.     if (r->limit_rate) {

  204.         nsent = c->sent;

  205.         if (r->limit_rate_after) {

  206.             sent -= r->limit_rate_after;
  207.             if (sent < 0) {
  208.                 sent = 0;
  209.             }

  210.             nsent -= r->limit_rate_after;
  211.             if (nsent < 0) {
  212.                 nsent = 0;
  213.             }
  214.         }

  215.         delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate);

  216.         if (delay > 0) {
  217.             limit = 0;
  218.             c->write->delayed = 1;
  219.             ngx_add_timer(c->write, delay);
  220.         }
  221.     }

  222.     if (limit
  223.         && c->write->ready
  224.         && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize))
  225.     {
  226.         c->write->delayed = 1;
  227.         ngx_add_timer(c->write, 1);
  228.     }

  229.     for (cl = r->out; cl && cl != chain; /* void */) {
  230.         ln = cl;
  231.         cl = cl->next;
  232.         ngx_free_chain(r->pool, ln);
  233.     }

  234.     r->out = chain;

  235.     if (chain) {
  236.         c->buffered |= NGX_HTTP_WRITE_BUFFERED;
  237.         return NGX_AGAIN;
  238.     }

  239.     c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;

  240.     if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
  241.         return NGX_AGAIN;
  242.     }

  243.     return NGX_OK;
  244. }


  245. static ngx_int_t
  246. ngx_http_write_filter_init(ngx_conf_t *cf)
  247. {
  248.     ngx_http_top_body_filter = ngx_http_write_filter;

  249.     return NGX_OK;
  250. }