Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 typedef struct {
0014     ngx_chain_t         *free;
0015     ngx_chain_t         *busy;
0016 } ngx_http_chunked_filter_ctx_t;
0017 
0018 
0019 static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf);
0020 
0021 
0022 static ngx_http_module_t  ngx_http_chunked_filter_module_ctx = {
0023     NULL,                                  /* preconfiguration */
0024     ngx_http_chunked_filter_init,          /* postconfiguration */
0025 
0026     NULL,                                  /* create main configuration */
0027     NULL,                                  /* init main configuration */
0028 
0029     NULL,                                  /* create server configuration */
0030     NULL,                                  /* merge server configuration */
0031 
0032     NULL,                                  /* create location configuration */
0033     NULL                                   /* merge location configuration */
0034 };
0035 
0036 
0037 ngx_module_t  ngx_http_chunked_filter_module = {
0038     NGX_MODULE_V1,
0039     &ngx_http_chunked_filter_module_ctx,   /* module context */
0040     NULL,                                  /* module directives */
0041     NGX_HTTP_MODULE,                       /* module type */
0042     NULL,                                  /* init master */
0043     NULL,                                  /* init module */
0044     NULL,                                  /* init process */
0045     NULL,                                  /* init thread */
0046     NULL,                                  /* exit thread */
0047     NULL,                                  /* exit process */
0048     NULL,                                  /* exit master */
0049     NGX_MODULE_V1_PADDING
0050 };
0051 
0052 
0053 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
0054 static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
0055 
0056 
0057 static ngx_int_t
0058 ngx_http_chunked_header_filter(ngx_http_request_t *r)
0059 {
0060     ngx_http_core_loc_conf_t       *clcf;
0061     ngx_http_chunked_filter_ctx_t  *ctx;
0062 
0063     if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED
0064         || r->headers_out.status == NGX_HTTP_NO_CONTENT
0065         || r->headers_out.status < NGX_HTTP_OK
0066         || r != r->main
0067         || r->method == NGX_HTTP_HEAD)
0068     {
0069         return ngx_http_next_header_filter(r);
0070     }
0071 
0072     if (r->headers_out.content_length_n == -1) {
0073         if (r->http_version < NGX_HTTP_VERSION_11) {
0074             r->keepalive = 0;
0075 
0076         } else {
0077             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0078 
0079             if (clcf->chunked_transfer_encoding) {
0080                 r->chunked = 1;
0081 
0082                 ctx = ngx_pcalloc(r->pool,
0083                                   sizeof(ngx_http_chunked_filter_ctx_t));
0084                 if (ctx == NULL) {
0085                     return NGX_ERROR;
0086                 }
0087 
0088                 ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module);
0089 
0090             } else {
0091                 r->keepalive = 0;
0092             }
0093         }
0094     }
0095 
0096     return ngx_http_next_header_filter(r);
0097 }
0098 
0099 
0100 static ngx_int_t
0101 ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
0102 {
0103     u_char                         *chunk;
0104     off_t                           size;
0105     ngx_int_t                       rc;
0106     ngx_buf_t                      *b;
0107     ngx_chain_t                    *out, *cl, *tl, **ll;
0108     ngx_http_chunked_filter_ctx_t  *ctx;
0109 
0110     if (in == NULL || !r->chunked || r->header_only) {
0111         return ngx_http_next_body_filter(r, in);
0112     }
0113 
0114     ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module);
0115 
0116     out = NULL;
0117     ll = &out;
0118 
0119     size = 0;
0120     cl = in;
0121 
0122     for ( ;; ) {
0123         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0124                        "http chunk: %O", ngx_buf_size(cl->buf));
0125 
0126         size += ngx_buf_size(cl->buf);
0127 
0128         if (cl->buf->flush
0129             || cl->buf->sync
0130             || ngx_buf_in_memory(cl->buf)
0131             || cl->buf->in_file)
0132         {
0133             tl = ngx_alloc_chain_link(r->pool);
0134             if (tl == NULL) {
0135                 return NGX_ERROR;
0136             }
0137 
0138             tl->buf = cl->buf;
0139             *ll = tl;
0140             ll = &tl->next;
0141         }
0142 
0143         if (cl->next == NULL) {
0144             break;
0145         }
0146 
0147         cl = cl->next;
0148     }
0149 
0150     if (size) {
0151         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
0152         if (tl == NULL) {
0153             return NGX_ERROR;
0154         }
0155 
0156         b = tl->buf;
0157         chunk = b->start;
0158 
0159         if (chunk == NULL) {
0160             /* the "0000000000000000" is 64-bit hexadecimal string */
0161 
0162             chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
0163             if (chunk == NULL) {
0164                 return NGX_ERROR;
0165             }
0166 
0167             b->start = chunk;
0168             b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
0169         }
0170 
0171         b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
0172         b->memory = 0;
0173         b->temporary = 1;
0174         b->pos = chunk;
0175         b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
0176 
0177         tl->next = out;
0178         out = tl;
0179     }
0180 
0181     if (cl->buf->last_buf) {
0182         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
0183         if (tl == NULL) {
0184             return NGX_ERROR;
0185         }
0186 
0187         b = tl->buf;
0188 
0189         b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
0190         b->temporary = 0;
0191         b->memory = 1;
0192         b->last_buf = 1;
0193         b->pos = (u_char *) CRLF "0" CRLF CRLF;
0194         b->last = b->pos + 7;
0195 
0196         cl->buf->last_buf = 0;
0197 
0198         *ll = tl;
0199 
0200         if (size == 0) {
0201             b->pos += 2;
0202         }
0203 
0204     } else if (size > 0) {
0205         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
0206         if (tl == NULL) {
0207             return NGX_ERROR;
0208         }
0209 
0210         b = tl->buf;
0211 
0212         b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
0213         b->temporary = 0;
0214         b->memory = 1;
0215         b->pos = (u_char *) CRLF;
0216         b->last = b->pos + 2;
0217 
0218         *ll = tl;
0219 
0220     } else {
0221         *ll = NULL;
0222     }
0223 
0224     rc = ngx_http_next_body_filter(r, out);
0225 
0226     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
0227                             (ngx_buf_tag_t) &ngx_http_chunked_filter_module);
0228 
0229     return rc;
0230 }
0231 
0232 
0233 static ngx_int_t
0234 ngx_http_chunked_filter_init(ngx_conf_t *cf)
0235 {
0236     ngx_http_next_header_filter = ngx_http_top_header_filter;
0237     ngx_http_top_header_filter = ngx_http_chunked_header_filter;
0238 
0239     ngx_http_next_body_filter = ngx_http_top_body_filter;
0240     ngx_http_top_body_filter = ngx_http_chunked_body_filter;
0241 
0242     return NGX_OK;
0243 }