3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
16 } ngx_http_chunked_filter_ctx_t
;
19 static ngx_int_t
ngx_http_chunked_filter_init(ngx_conf_t
*cf
);
22 static ngx_http_module_t ngx_http_chunked_filter_module_ctx
= {
23 NULL
, /* preconfiguration */
24 ngx_http_chunked_filter_init
, /* postconfiguration */
26 NULL
, /* create main configuration */
27 NULL
, /* init main configuration */
29 NULL
, /* create server configuration */
30 NULL
, /* merge server configuration */
32 NULL
, /* create location configuration */
33 NULL
/* merge location configuration */
37 ngx_module_t ngx_http_chunked_filter_module
= {
39 &ngx_http_chunked_filter_module_ctx
, /* module context */
40 NULL
, /* module directives */
41 NGX_HTTP_MODULE
, /* module type */
42 NULL
, /* init master */
43 NULL
, /* init module */
44 NULL
, /* init process */
45 NULL
, /* init thread */
46 NULL
, /* exit thread */
47 NULL
, /* exit process */
48 NULL
, /* exit master */
53 static ngx_http_output_header_filter_pt ngx_http_next_header_filter
;
54 static ngx_http_output_body_filter_pt ngx_http_next_body_filter
;
58 ngx_http_chunked_header_filter(ngx_http_request_t
*r
)
60 ngx_http_core_loc_conf_t
*clcf
;
61 ngx_http_chunked_filter_ctx_t
*ctx
;
63 if (r
->headers_out
.status
== NGX_HTTP_NOT_MODIFIED
64 || r
->headers_out
.status
== NGX_HTTP_NO_CONTENT
65 || r
->headers_out
.status
< NGX_HTTP_OK
67 || (r
->method
& NGX_HTTP_HEAD
))
69 return ngx_http_next_header_filter(r
);
72 if (r
->headers_out
.content_length_n
== -1) {
73 if (r
->http_version
< NGX_HTTP_VERSION_11
) {
77 clcf
= ngx_http_get_module_loc_conf(r
, ngx_http_core_module
);
79 if (clcf
->chunked_transfer_encoding
) {
82 ctx
= ngx_pcalloc(r
->pool
,
83 sizeof(ngx_http_chunked_filter_ctx_t
));
88 ngx_http_set_ctx(r
, ctx
, ngx_http_chunked_filter_module
);
96 return ngx_http_next_header_filter(r
);
101 ngx_http_chunked_body_filter(ngx_http_request_t
*r
, ngx_chain_t
*in
)
107 ngx_chain_t
*out
, *cl
, *tl
, **ll
;
108 ngx_http_chunked_filter_ctx_t
*ctx
;
110 if (in
== NULL
|| !r
->chunked
|| r
->header_only
) {
111 return ngx_http_next_body_filter(r
, in
);
114 ctx
= ngx_http_get_module_ctx(r
, ngx_http_chunked_filter_module
);
123 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
124 "http chunk: %d", ngx_buf_size(cl
->buf
));
126 size
+= ngx_buf_size(cl
->buf
);
130 || ngx_buf_in_memory(cl
->buf
)
133 tl
= ngx_alloc_chain_link(r
->pool
);
143 if (cl
->next
== NULL
) {
151 tl
= ngx_chain_get_free_buf(r
->pool
, &ctx
->free
);
160 /* the "0000000000000000" is 64-bit hexadecimal string */
162 chunk
= ngx_palloc(r
->pool
, sizeof("0000000000000000" CRLF
) - 1);
168 b
->end
= chunk
+ sizeof("0000000000000000" CRLF
) - 1;
171 b
->tag
= (ngx_buf_tag_t
) &ngx_http_chunked_filter_module
;
175 b
->last
= ngx_sprintf(chunk
, "%xO" CRLF
, size
);
181 if (cl
->buf
->last_buf
) {
182 tl
= ngx_chain_get_free_buf(r
->pool
, &ctx
->free
);
189 b
->tag
= (ngx_buf_tag_t
) &ngx_http_chunked_filter_module
;
193 b
->pos
= (u_char
*) CRLF
"0" CRLF CRLF
;
194 b
->last
= b
->pos
+ 7;
196 cl
->buf
->last_buf
= 0;
204 } else if (size
> 0) {
205 tl
= ngx_chain_get_free_buf(r
->pool
, &ctx
->free
);
212 b
->tag
= (ngx_buf_tag_t
) &ngx_http_chunked_filter_module
;
215 b
->pos
= (u_char
*) CRLF
;
216 b
->last
= b
->pos
+ 2;
224 rc
= ngx_http_next_body_filter(r
, out
);
226 ngx_chain_update_chains(r
->pool
, &ctx
->free
, &ctx
->busy
, &out
,
227 (ngx_buf_tag_t
) &ngx_http_chunked_filter_module
);
234 ngx_http_chunked_filter_init(ngx_conf_t
*cf
)
236 ngx_http_next_header_filter
= ngx_http_top_header_filter
;
237 ngx_http_top_header_filter
= ngx_http_chunked_header_filter
;
239 ngx_http_next_body_filter
= ngx_http_top_body_filter
;
240 ngx_http_top_body_filter
= ngx_http_chunked_body_filter
;