Annotation of embedaddon/nginx/src/http/ngx_http_write_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: static ngx_int_t ngx_http_write_filter_init(ngx_conf_t *cf);
14:
15:
16: static ngx_http_module_t ngx_http_write_filter_module_ctx = {
17: NULL, /* preconfiguration */
18: ngx_http_write_filter_init, /* postconfiguration */
19:
20: NULL, /* create main configuration */
21: NULL, /* init main configuration */
22:
23: NULL, /* create server configuration */
24: NULL, /* merge server configuration */
25:
26: NULL, /* create location configuration */
27: NULL, /* merge location configuration */
28: };
29:
30:
31: ngx_module_t ngx_http_write_filter_module = {
32: NGX_MODULE_V1,
33: &ngx_http_write_filter_module_ctx, /* module context */
34: NULL, /* module directives */
35: NGX_HTTP_MODULE, /* module type */
36: NULL, /* init master */
37: NULL, /* init module */
38: NULL, /* init process */
39: NULL, /* init thread */
40: NULL, /* exit thread */
41: NULL, /* exit process */
42: NULL, /* exit master */
43: NGX_MODULE_V1_PADDING
44: };
45:
46:
47: ngx_int_t
48: ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
49: {
50: off_t size, sent, nsent, limit;
51: ngx_uint_t last, flush;
52: ngx_msec_t delay;
53: ngx_chain_t *cl, *ln, **ll, *chain;
54: ngx_connection_t *c;
55: ngx_http_core_loc_conf_t *clcf;
56:
57: c = r->connection;
58:
59: if (c->error) {
60: return NGX_ERROR;
61: }
62:
63: size = 0;
64: flush = 0;
65: last = 0;
66: ll = &r->out;
67:
68: /* find the size, the flush point and the last link of the saved chain */
69:
70: for (cl = r->out; cl; cl = cl->next) {
71: ll = &cl->next;
72:
73: ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
74: "write old buf t:%d f:%d %p, pos %p, size: %z "
75: "file: %O, size: %z",
76: cl->buf->temporary, cl->buf->in_file,
77: cl->buf->start, cl->buf->pos,
78: cl->buf->last - cl->buf->pos,
79: cl->buf->file_pos,
80: cl->buf->file_last - cl->buf->file_pos);
81:
82: #if 1
83: if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
84: ngx_log_error(NGX_LOG_ALERT, c->log, 0,
85: "zero size buf in writer "
86: "t:%d r:%d f:%d %p %p-%p %p %O-%O",
87: cl->buf->temporary,
88: cl->buf->recycled,
89: cl->buf->in_file,
90: cl->buf->start,
91: cl->buf->pos,
92: cl->buf->last,
93: cl->buf->file,
94: cl->buf->file_pos,
95: cl->buf->file_last);
96:
97: ngx_debug_point();
98: return NGX_ERROR;
99: }
100: #endif
101:
102: size += ngx_buf_size(cl->buf);
103:
104: if (cl->buf->flush || cl->buf->recycled) {
105: flush = 1;
106: }
107:
108: if (cl->buf->last_buf) {
109: last = 1;
110: }
111: }
112:
113: /* add the new chain to the existent one */
114:
115: for (ln = in; ln; ln = ln->next) {
116: cl = ngx_alloc_chain_link(r->pool);
117: if (cl == NULL) {
118: return NGX_ERROR;
119: }
120:
121: cl->buf = ln->buf;
122: *ll = cl;
123: ll = &cl->next;
124:
125: ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
126: "write new buf t:%d f:%d %p, pos %p, size: %z "
127: "file: %O, size: %z",
128: cl->buf->temporary, cl->buf->in_file,
129: cl->buf->start, cl->buf->pos,
130: cl->buf->last - cl->buf->pos,
131: cl->buf->file_pos,
132: cl->buf->file_last - cl->buf->file_pos);
133:
134: #if 1
135: if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
136: ngx_log_error(NGX_LOG_ALERT, c->log, 0,
137: "zero size buf in writer "
138: "t:%d r:%d f:%d %p %p-%p %p %O-%O",
139: cl->buf->temporary,
140: cl->buf->recycled,
141: cl->buf->in_file,
142: cl->buf->start,
143: cl->buf->pos,
144: cl->buf->last,
145: cl->buf->file,
146: cl->buf->file_pos,
147: cl->buf->file_last);
148:
149: ngx_debug_point();
150: return NGX_ERROR;
151: }
152: #endif
153:
154: size += ngx_buf_size(cl->buf);
155:
156: if (cl->buf->flush || cl->buf->recycled) {
157: flush = 1;
158: }
159:
160: if (cl->buf->last_buf) {
161: last = 1;
162: }
163: }
164:
165: *ll = NULL;
166:
167: ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
168: "http write filter: l:%d f:%d s:%O", last, flush, size);
169:
170: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
171:
172: /*
173: * avoid the output if there are no last buf, no flush point,
174: * there are the incoming bufs and the size of all bufs
175: * is smaller than "postpone_output" directive
176: */
177:
178: if (!last && !flush && in && size < (off_t) clcf->postpone_output) {
179: return NGX_OK;
180: }
181:
182: if (c->write->delayed) {
183: c->buffered |= NGX_HTTP_WRITE_BUFFERED;
184: return NGX_AGAIN;
185: }
186:
187: if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)) {
188: if (last || flush) {
189: for (cl = r->out; cl; /* void */) {
190: ln = cl;
191: cl = cl->next;
192: ngx_free_chain(r->pool, ln);
193: }
194:
195: r->out = NULL;
196: c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
197:
198: return NGX_OK;
199: }
200:
201: ngx_log_error(NGX_LOG_ALERT, c->log, 0,
202: "the http output chain is empty");
203:
204: ngx_debug_point();
205:
206: return NGX_ERROR;
207: }
208:
209: if (r->limit_rate) {
210: limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1)
211: - (c->sent - clcf->limit_rate_after);
212:
213: if (limit <= 0) {
214: c->write->delayed = 1;
215: ngx_add_timer(c->write,
216: (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1));
217:
218: c->buffered |= NGX_HTTP_WRITE_BUFFERED;
219:
220: return NGX_AGAIN;
221: }
222:
223: if (clcf->sendfile_max_chunk
224: && (off_t) clcf->sendfile_max_chunk < limit)
225: {
226: limit = clcf->sendfile_max_chunk;
227: }
228:
229: } else {
230: limit = clcf->sendfile_max_chunk;
231: }
232:
233: sent = c->sent;
234:
235: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
236: "http write filter limit %O", limit);
237:
238: chain = c->send_chain(c, r->out, limit);
239:
240: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
241: "http write filter %p", chain);
242:
243: if (chain == NGX_CHAIN_ERROR) {
244: c->error = 1;
245: return NGX_ERROR;
246: }
247:
248: if (r->limit_rate) {
249:
250: nsent = c->sent;
251:
252: if (clcf->limit_rate_after) {
253:
254: sent -= clcf->limit_rate_after;
255: if (sent < 0) {
256: sent = 0;
257: }
258:
259: nsent -= clcf->limit_rate_after;
260: if (nsent < 0) {
261: nsent = 0;
262: }
263: }
264:
265: delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate);
266:
267: if (delay > 0) {
268: limit = 0;
269: c->write->delayed = 1;
270: ngx_add_timer(c->write, delay);
271: }
272: }
273:
274: if (limit
275: && c->write->ready
276: && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize))
277: {
278: c->write->delayed = 1;
279: ngx_add_timer(c->write, 1);
280: }
281:
282: for (cl = r->out; cl && cl != chain; /* void */) {
283: ln = cl;
284: cl = cl->next;
285: ngx_free_chain(r->pool, ln);
286: }
287:
288: r->out = chain;
289:
290: if (chain) {
291: c->buffered |= NGX_HTTP_WRITE_BUFFERED;
292: return NGX_AGAIN;
293: }
294:
295: c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
296:
297: if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
298: return NGX_AGAIN;
299: }
300:
301: return NGX_OK;
302: }
303:
304:
305: static ngx_int_t
306: ngx_http_write_filter_init(ngx_conf_t *cf)
307: {
308: ngx_http_top_body_filter = ngx_http_write_filter;
309:
310: return NGX_OK;
311: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>