Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

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 static ngx_chain_t *ngx_http_chunked_create_trailers(ngx_http_request_t *r,
0021     ngx_http_chunked_filter_ctx_t *ctx);
0022 
0023 
0024 static ngx_http_module_t  ngx_http_chunked_filter_module_ctx = {
0025     NULL,                                  /* preconfiguration */
0026     ngx_http_chunked_filter_init,          /* postconfiguration */
0027 
0028     NULL,                                  /* create main configuration */
0029     NULL,                                  /* init main configuration */
0030 
0031     NULL,                                  /* create server configuration */
0032     NULL,                                  /* merge server configuration */
0033 
0034     NULL,                                  /* create location configuration */
0035     NULL                                   /* merge location configuration */
0036 };
0037 
0038 
0039 ngx_module_t  ngx_http_chunked_filter_module = {
0040     NGX_MODULE_V1,
0041     &ngx_http_chunked_filter_module_ctx,   /* module context */
0042     NULL,                                  /* module directives */
0043     NGX_HTTP_MODULE,                       /* module type */
0044     NULL,                                  /* init master */
0045     NULL,                                  /* init module */
0046     NULL,                                  /* init process */
0047     NULL,                                  /* init thread */
0048     NULL,                                  /* exit thread */
0049     NULL,                                  /* exit process */
0050     NULL,                                  /* exit master */
0051     NGX_MODULE_V1_PADDING
0052 };
0053 
0054 
0055 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
0056 static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
0057 
0058 
0059 static ngx_int_t
0060 ngx_http_chunked_header_filter(ngx_http_request_t *r)
0061 {
0062     ngx_http_core_loc_conf_t       *clcf;
0063     ngx_http_chunked_filter_ctx_t  *ctx;
0064 
0065     if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED
0066         || r->headers_out.status == NGX_HTTP_NO_CONTENT
0067         || r->headers_out.status < NGX_HTTP_OK
0068         || r != r->main
0069         || r->method == NGX_HTTP_HEAD)
0070     {
0071         return ngx_http_next_header_filter(r);
0072     }
0073 
0074     if (r->headers_out.content_length_n == -1
0075         || r->expect_trailers)
0076     {
0077         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0078 
0079         if (r->http_version >= NGX_HTTP_VERSION_11
0080             && clcf->chunked_transfer_encoding)
0081         {
0082             if (r->expect_trailers) {
0083                 ngx_http_clear_content_length(r);
0084             }
0085 
0086             r->chunked = 1;
0087 
0088             ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_filter_ctx_t));
0089             if (ctx == NULL) {
0090                 return NGX_ERROR;
0091             }
0092 
0093             ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module);
0094 
0095         } else if (r->headers_out.content_length_n == -1) {
0096             r->keepalive = 0;
0097         }
0098     }
0099 
0100     return ngx_http_next_header_filter(r);
0101 }
0102 
0103 
0104 static ngx_int_t
0105 ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
0106 {
0107     u_char                         *chunk;
0108     off_t                           size;
0109     ngx_int_t                       rc;
0110     ngx_buf_t                      *b;
0111     ngx_chain_t                    *out, *cl, *tl, **ll;
0112     ngx_http_chunked_filter_ctx_t  *ctx;
0113 
0114     if (in == NULL || !r->chunked || r->header_only) {
0115         return ngx_http_next_body_filter(r, in);
0116     }
0117 
0118     ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module);
0119 
0120     out = NULL;
0121     ll = &out;
0122 
0123     size = 0;
0124     cl = in;
0125 
0126     for ( ;; ) {
0127         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0128                        "http chunk: %O", ngx_buf_size(cl->buf));
0129 
0130         size += ngx_buf_size(cl->buf);
0131 
0132         if (cl->buf->flush
0133             || cl->buf->sync
0134             || ngx_buf_in_memory(cl->buf)
0135             || cl->buf->in_file)
0136         {
0137             tl = ngx_alloc_chain_link(r->pool);
0138             if (tl == NULL) {
0139                 return NGX_ERROR;
0140             }
0141 
0142             tl->buf = cl->buf;
0143             *ll = tl;
0144             ll = &tl->next;
0145         }
0146 
0147         if (cl->next == NULL) {
0148             break;
0149         }
0150 
0151         cl = cl->next;
0152     }
0153 
0154     if (size) {
0155         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
0156         if (tl == NULL) {
0157             return NGX_ERROR;
0158         }
0159 
0160         b = tl->buf;
0161         chunk = b->start;
0162 
0163         if (chunk == NULL) {
0164             /* the "0000000000000000" is 64-bit hexadecimal string */
0165 
0166             chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
0167             if (chunk == NULL) {
0168                 return NGX_ERROR;
0169             }
0170 
0171             b->start = chunk;
0172             b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
0173         }
0174 
0175         b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
0176         b->memory = 0;
0177         b->temporary = 1;
0178         b->pos = chunk;
0179         b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
0180 
0181         tl->next = out;
0182         out = tl;
0183     }
0184 
0185     if (cl->buf->last_buf) {
0186         tl = ngx_http_chunked_create_trailers(r, ctx);
0187         if (tl == NULL) {
0188             return NGX_ERROR;
0189         }
0190 
0191         cl->buf->last_buf = 0;
0192 
0193         *ll = tl;
0194 
0195         if (size == 0) {
0196             tl->buf->pos += 2;
0197         }
0198 
0199     } else if (size > 0) {
0200         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
0201         if (tl == NULL) {
0202             return NGX_ERROR;
0203         }
0204 
0205         b = tl->buf;
0206 
0207         b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
0208         b->temporary = 0;
0209         b->memory = 1;
0210         b->pos = (u_char *) CRLF;
0211         b->last = b->pos + 2;
0212 
0213         *ll = tl;
0214 
0215     } else {
0216         *ll = NULL;
0217     }
0218 
0219     rc = ngx_http_next_body_filter(r, out);
0220 
0221     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
0222                             (ngx_buf_tag_t) &ngx_http_chunked_filter_module);
0223 
0224     return rc;
0225 }
0226 
0227 
0228 static ngx_chain_t *
0229 ngx_http_chunked_create_trailers(ngx_http_request_t *r,
0230     ngx_http_chunked_filter_ctx_t *ctx)
0231 {
0232     size_t            len;
0233     ngx_buf_t        *b;
0234     ngx_uint_t        i;
0235     ngx_chain_t      *cl;
0236     ngx_list_part_t  *part;
0237     ngx_table_elt_t  *header;
0238 
0239     len = 0;
0240 
0241     part = &r->headers_out.trailers.part;
0242     header = part->elts;
0243 
0244     for (i = 0; /* void */; i++) {
0245 
0246         if (i >= part->nelts) {
0247             if (part->next == NULL) {
0248                 break;
0249             }
0250 
0251             part = part->next;
0252             header = part->elts;
0253             i = 0;
0254         }
0255 
0256         if (header[i].hash == 0) {
0257             continue;
0258         }
0259 
0260         len += header[i].key.len + sizeof(": ") - 1
0261                + header[i].value.len + sizeof(CRLF) - 1;
0262     }
0263 
0264     cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
0265     if (cl == NULL) {
0266         return NULL;
0267     }
0268 
0269     b = cl->buf;
0270 
0271     b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
0272     b->temporary = 0;
0273     b->memory = 1;
0274     b->last_buf = 1;
0275 
0276     if (len == 0) {
0277         b->pos = (u_char *) CRLF "0" CRLF CRLF;
0278         b->last = b->pos + sizeof(CRLF "0" CRLF CRLF) - 1;
0279         return cl;
0280     }
0281 
0282     len += sizeof(CRLF "0" CRLF CRLF) - 1;
0283 
0284     b->pos = ngx_palloc(r->pool, len);
0285     if (b->pos == NULL) {
0286         return NULL;
0287     }
0288 
0289     b->last = b->pos;
0290 
0291     *b->last++ = CR; *b->last++ = LF;
0292     *b->last++ = '0';
0293     *b->last++ = CR; *b->last++ = LF;
0294 
0295     part = &r->headers_out.trailers.part;
0296     header = part->elts;
0297 
0298     for (i = 0; /* void */; i++) {
0299 
0300         if (i >= part->nelts) {
0301             if (part->next == NULL) {
0302                 break;
0303             }
0304 
0305             part = part->next;
0306             header = part->elts;
0307             i = 0;
0308         }
0309 
0310         if (header[i].hash == 0) {
0311             continue;
0312         }
0313 
0314         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0315                        "http trailer: \"%V: %V\"",
0316                        &header[i].key, &header[i].value);
0317 
0318         b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
0319         *b->last++ = ':'; *b->last++ = ' ';
0320 
0321         b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
0322         *b->last++ = CR; *b->last++ = LF;
0323     }
0324 
0325     *b->last++ = CR; *b->last++ = LF;
0326 
0327     return cl;
0328 }
0329 
0330 
0331 static ngx_int_t
0332 ngx_http_chunked_filter_init(ngx_conf_t *cf)
0333 {
0334     ngx_http_next_header_filter = ngx_http_top_header_filter;
0335     ngx_http_top_header_filter = ngx_http_chunked_header_filter;
0336 
0337     ngx_http_next_body_filter = ngx_http_top_body_filter;
0338     ngx_http_top_body_filter = ngx_http_chunked_body_filter;
0339 
0340     return NGX_OK;
0341 }