src/http/modules/ngx_http_chunked_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_chain_t         *free;
  10.     ngx_chain_t         *busy;
  11. } ngx_http_chunked_filter_ctx_t;


  12. static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf);


  13. static ngx_http_module_t  ngx_http_chunked_filter_module_ctx = {
  14.     NULL,                                  /* preconfiguration */
  15.     ngx_http_chunked_filter_init,          /* postconfiguration */

  16.     NULL,                                  /* create main configuration */
  17.     NULL,                                  /* init main configuration */

  18.     NULL,                                  /* create server configuration */
  19.     NULL,                                  /* merge server configuration */

  20.     NULL,                                  /* create location configuration */
  21.     NULL                                   /* merge location configuration */
  22. };


  23. ngx_module_t  ngx_http_chunked_filter_module = {
  24.     NGX_MODULE_V1,
  25.     &ngx_http_chunked_filter_module_ctx,   /* module context */
  26.     NULL,                                  /* module directives */
  27.     NGX_HTTP_MODULE,                       /* module type */
  28.     NULL,                                  /* init master */
  29.     NULL,                                  /* init module */
  30.     NULL,                                  /* init process */
  31.     NULL,                                  /* init thread */
  32.     NULL,                                  /* exit thread */
  33.     NULL,                                  /* exit process */
  34.     NULL,                                  /* exit master */
  35.     NGX_MODULE_V1_PADDING
  36. };


  37. static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
  38. static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;


  39. static ngx_int_t
  40. ngx_http_chunked_header_filter(ngx_http_request_t *r)
  41. {
  42.     ngx_http_core_loc_conf_t       *clcf;
  43.     ngx_http_chunked_filter_ctx_t  *ctx;

  44.     if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED
  45.         || r->headers_out.status == NGX_HTTP_NO_CONTENT
  46.         || r->headers_out.status < NGX_HTTP_OK
  47.         || r != r->main
  48.         || (r->method & NGX_HTTP_HEAD))
  49.     {
  50.         return ngx_http_next_header_filter(r);
  51.     }

  52.     if (r->headers_out.content_length_n == -1) {
  53.         if (r->http_version < NGX_HTTP_VERSION_11) {
  54.             r->keepalive = 0;

  55.         } else {
  56.             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  57.             if (clcf->chunked_transfer_encoding) {
  58.                 r->chunked = 1;

  59.                 ctx = ngx_pcalloc(r->pool,
  60.                                   sizeof(ngx_http_chunked_filter_ctx_t));
  61.                 if (ctx == NULL) {
  62.                     return NGX_ERROR;
  63.                 }

  64.                 ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module);

  65.             } else {
  66.                 r->keepalive = 0;
  67.             }
  68.         }
  69.     }

  70.     return ngx_http_next_header_filter(r);
  71. }


  72. static ngx_int_t
  73. ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
  74. {
  75.     u_char                         *chunk;
  76.     off_t                           size;
  77.     ngx_int_t                       rc;
  78.     ngx_buf_t                      *b;
  79.     ngx_chain_t                    *out, *cl, *tl, **ll;
  80.     ngx_http_chunked_filter_ctx_t  *ctx;

  81.     if (in == NULL || !r->chunked || r->header_only) {
  82.         return ngx_http_next_body_filter(r, in);
  83.     }

  84.     ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module);

  85.     out = NULL;
  86.     ll = &out;

  87.     size = 0;
  88.     cl = in;

  89.     for ( ;; ) {
  90.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  91.                        "http chunk: %d", ngx_buf_size(cl->buf));

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

  93.         if (cl->buf->flush
  94.             || cl->buf->sync
  95.             || ngx_buf_in_memory(cl->buf)
  96.             || cl->buf->in_file)
  97.         {
  98.             tl = ngx_alloc_chain_link(r->pool);
  99.             if (tl == NULL) {
  100.                 return NGX_ERROR;
  101.             }

  102.             tl->buf = cl->buf;
  103.             *ll = tl;
  104.             ll = &tl->next;
  105.         }

  106.         if (cl->next == NULL) {
  107.             break;
  108.         }

  109.         cl = cl->next;
  110.     }

  111.     if (size) {
  112.         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  113.         if (tl == NULL) {
  114.             return NGX_ERROR;
  115.         }

  116.         b = tl->buf;
  117.         chunk = b->start;

  118.         if (chunk == NULL) {
  119.             /* the "0000000000000000" is 64-bit hexadecimal string */

  120.             chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
  121.             if (chunk == NULL) {
  122.                 return NGX_ERROR;
  123.             }

  124.             b->start = chunk;
  125.             b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
  126.         }

  127.         b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
  128.         b->memory = 0;
  129.         b->temporary = 1;
  130.         b->pos = chunk;
  131.         b->last = ngx_sprintf(chunk, "%xO" CRLF, size);

  132.         tl->next = out;
  133.         out = tl;
  134.     }

  135.     if (cl->buf->last_buf) {
  136.         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  137.         if (tl == NULL) {
  138.             return NGX_ERROR;
  139.         }

  140.         b = tl->buf;

  141.         b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
  142.         b->temporary = 0;
  143.         b->memory = 1;
  144.         b->last_buf = 1;
  145.         b->pos = (u_char *) CRLF "0" CRLF CRLF;
  146.         b->last = b->pos + 7;

  147.         cl->buf->last_buf = 0;

  148.         *ll = tl;

  149.         if (size == 0) {
  150.             b->pos += 2;
  151.         }

  152.     } else if (size > 0) {
  153.         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  154.         if (tl == NULL) {
  155.             return NGX_ERROR;
  156.         }

  157.         b = tl->buf;

  158.         b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
  159.         b->temporary = 0;
  160.         b->memory = 1;
  161.         b->pos = (u_char *) CRLF;
  162.         b->last = b->pos + 2;

  163.         *ll = tl;

  164.     } else {
  165.         *ll = NULL;
  166.     }

  167.     rc = ngx_http_next_body_filter(r, out);

  168.     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
  169.                             (ngx_buf_tag_t) &ngx_http_chunked_filter_module);

  170.     return rc;
  171. }


  172. static ngx_int_t
  173. ngx_http_chunked_filter_init(ngx_conf_t *cf)
  174. {
  175.     ngx_http_next_header_filter = ngx_http_top_header_filter;
  176.     ngx_http_top_header_filter = ngx_http_chunked_header_filter;

  177.     ngx_http_next_body_filter = ngx_http_top_body_filter;
  178.     ngx_http_top_body_filter = ngx_http_chunked_body_filter;

  179.     return NGX_OK;
  180. }