1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.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, 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) {
189 r->out = NULL;
190 c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
191
192 return NGX_OK;
193 }
194
195 if (flush) {
196 do {
197 r->out = r->out->next;
198 } while (r->out);
199
200 c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
201
202 return NGX_OK;
203 }
204
205 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
206 "the http output chain is empty");
207
208 ngx_debug_point();
209
210 return NGX_ERROR;
211 }
212
213 if (r->limit_rate) {
214 limit = r->limit_rate * (ngx_time() - r->start_sec + 1) - c->sent;
215
216 if (limit <= 0) {
217 c->write->delayed = 1;
218 ngx_add_timer(c->write,
219 (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1));
220
221 c->buffered |= NGX_HTTP_WRITE_BUFFERED;
222
223 return NGX_AGAIN;
224 }
225
226 } else if (clcf->sendfile_max_chunk) {
227 limit = clcf->sendfile_max_chunk;
228
229 } else {
230 limit = 0;
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 delay = (ngx_msec_t) ((c->sent - sent) * 1000 / r->limit_rate + 1);
250
251 if (delay > 0) {
252 c->write->delayed = 1;
253 ngx_add_timer(c->write, delay);
254 }
255
256 } else if (c->write->ready
257 && clcf->sendfile_max_chunk
258 && (size_t) (c->sent - sent)
259 >= clcf->sendfile_max_chunk - 2 * ngx_pagesize)
260 {
261 c->write->delayed = 1;
262 ngx_add_timer(c->write, 1);
263 }
264
265 for (cl = r->out; cl && cl != chain; /* void */) {
266 ln = cl;
267 cl = cl->next;
268 ngx_free_chain(r->pool, ln);
269 }
270
271 r->out = chain;
272
273 if (chain) {
274 c->buffered |= NGX_HTTP_WRITE_BUFFERED;
275 return NGX_AGAIN;
276 }
277
278 c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
279
280 if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
281 return NGX_AGAIN;
282 }
283
284 return NGX_OK;
285 }
286
287
288 static ngx_int_t
289 ngx_http_write_filter_init(ngx_conf_t *cf)
290 {
291 ngx_http_top_body_filter = ngx_http_write_filter;
292
293 return NGX_OK;
294 }
295
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.