Annotation of embedaddon/nginx/src/http/modules/ngx_http_chunked_filter_module.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (C) Igor Sysoev
4: * Copyright (C) Nginx, Inc.
5: */
6:
7:
8: #include <ngx_config.h>
9: #include <ngx_core.h>
10: #include <ngx_http.h>
11:
12:
13: typedef struct {
14: ngx_chain_t *free;
15: ngx_chain_t *busy;
16: } ngx_http_chunked_filter_ctx_t;
17:
18:
19: static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf);
20:
21:
22: static ngx_http_module_t ngx_http_chunked_filter_module_ctx = {
23: NULL, /* preconfiguration */
24: ngx_http_chunked_filter_init, /* postconfiguration */
25:
26: NULL, /* create main configuration */
27: NULL, /* init main configuration */
28:
29: NULL, /* create server configuration */
30: NULL, /* merge server configuration */
31:
32: NULL, /* create location configuration */
33: NULL /* merge location configuration */
34: };
35:
36:
37: ngx_module_t ngx_http_chunked_filter_module = {
38: NGX_MODULE_V1,
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 */
49: NGX_MODULE_V1_PADDING
50: };
51:
52:
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;
55:
56:
57: static ngx_int_t
58: ngx_http_chunked_header_filter(ngx_http_request_t *r)
59: {
60: ngx_http_core_loc_conf_t *clcf;
61: ngx_http_chunked_filter_ctx_t *ctx;
62:
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
66: || r != r->main
67: || (r->method & NGX_HTTP_HEAD))
68: {
69: return ngx_http_next_header_filter(r);
70: }
71:
72: if (r->headers_out.content_length_n == -1) {
73: if (r->http_version < NGX_HTTP_VERSION_11) {
74: r->keepalive = 0;
75:
76: } else {
77: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
78:
79: if (clcf->chunked_transfer_encoding) {
80: r->chunked = 1;
81:
82: ctx = ngx_pcalloc(r->pool,
83: sizeof(ngx_http_chunked_filter_ctx_t));
84: if (ctx == NULL) {
85: return NGX_ERROR;
86: }
87:
88: ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module);
89:
90: } else {
91: r->keepalive = 0;
92: }
93: }
94: }
95:
96: return ngx_http_next_header_filter(r);
97: }
98:
99:
100: static ngx_int_t
101: ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
102: {
103: u_char *chunk;
104: off_t size;
105: ngx_int_t rc;
106: ngx_buf_t *b;
107: ngx_chain_t *out, *cl, *tl, **ll;
108: ngx_http_chunked_filter_ctx_t *ctx;
109:
110: if (in == NULL || !r->chunked || r->header_only) {
111: return ngx_http_next_body_filter(r, in);
112: }
113:
114: ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module);
115:
116: out = NULL;
117: ll = &out;
118:
119: size = 0;
120: cl = in;
121:
122: for ( ;; ) {
123: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
124: "http chunk: %d", ngx_buf_size(cl->buf));
125:
126: size += ngx_buf_size(cl->buf);
127:
128: if (cl->buf->flush
129: || cl->buf->sync
130: || ngx_buf_in_memory(cl->buf)
131: || cl->buf->in_file)
132: {
133: tl = ngx_alloc_chain_link(r->pool);
134: if (tl == NULL) {
135: return NGX_ERROR;
136: }
137:
138: tl->buf = cl->buf;
139: *ll = tl;
140: ll = &tl->next;
141: }
142:
143: if (cl->next == NULL) {
144: break;
145: }
146:
147: cl = cl->next;
148: }
149:
150: if (size) {
151: tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
152: if (tl == NULL) {
153: return NGX_ERROR;
154: }
155:
156: b = tl->buf;
157: chunk = b->start;
158:
159: if (chunk == NULL) {
160: /* the "0000000000000000" is 64-bit hexadecimal string */
161:
162: chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
163: if (chunk == NULL) {
164: return NGX_ERROR;
165: }
166:
167: b->start = chunk;
168: b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
169: }
170:
171: b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
172: b->memory = 0;
173: b->temporary = 1;
174: b->pos = chunk;
175: b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
176:
177: tl->next = out;
178: out = tl;
179: }
180:
181: if (cl->buf->last_buf) {
182: tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
183: if (tl == NULL) {
184: return NGX_ERROR;
185: }
186:
187: b = tl->buf;
188:
189: b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
190: b->temporary = 0;
191: b->memory = 1;
192: b->last_buf = 1;
193: b->pos = (u_char *) CRLF "0" CRLF CRLF;
194: b->last = b->pos + 7;
195:
196: cl->buf->last_buf = 0;
197:
198: *ll = tl;
199:
200: if (size == 0) {
201: b->pos += 2;
202: }
203:
204: } else if (size > 0) {
205: tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
206: if (tl == NULL) {
207: return NGX_ERROR;
208: }
209:
210: b = tl->buf;
211:
212: b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module;
213: b->temporary = 0;
214: b->memory = 1;
215: b->pos = (u_char *) CRLF;
216: b->last = b->pos + 2;
217:
218: *ll = tl;
219:
220: } else {
221: *ll = NULL;
222: }
223:
224: rc = ngx_http_next_body_filter(r, out);
225:
226: ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
227: (ngx_buf_tag_t) &ngx_http_chunked_filter_module);
228:
229: return rc;
230: }
231:
232:
233: static ngx_int_t
234: ngx_http_chunked_filter_init(ngx_conf_t *cf)
235: {
236: ngx_http_next_header_filter = ngx_http_top_header_filter;
237: ngx_http_top_header_filter = ngx_http_chunked_header_filter;
238:
239: ngx_http_next_body_filter = ngx_http_top_body_filter;
240: ngx_http_top_body_filter = ngx_http_chunked_body_filter;
241:
242: return NGX_OK;
243: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>