3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
13 static ngx_int_t
ngx_http_write_filter_init(ngx_conf_t
*cf
);
16 static ngx_http_module_t ngx_http_write_filter_module_ctx
= {
17 NULL
, /* preconfiguration */
18 ngx_http_write_filter_init
, /* postconfiguration */
20 NULL
, /* create main configuration */
21 NULL
, /* init main configuration */
23 NULL
, /* create server configuration */
24 NULL
, /* merge server configuration */
26 NULL
, /* create location configuration */
27 NULL
, /* merge location configuration */
31 ngx_module_t ngx_http_write_filter_module
= {
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 */
48 ngx_http_write_filter(ngx_http_request_t
*r
, ngx_chain_t
*in
)
50 off_t size
, sent
, nsent
, limit
;
51 ngx_uint_t last
, flush
;
53 ngx_chain_t
*cl
, *ln
, **ll
, *chain
;
55 ngx_http_core_loc_conf_t
*clcf
;
68 /* find the size, the flush point and the last link of the saved chain */
70 for (cl
= r
->out
; cl
; cl
= cl
->next
) {
73 ngx_log_debug7(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
74 "write old buf t:%d f:%d %p, pos %p, size: %z "
76 cl
->buf
->temporary
, cl
->buf
->in_file
,
77 cl
->buf
->start
, cl
->buf
->pos
,
78 cl
->buf
->last
- cl
->buf
->pos
,
80 cl
->buf
->file_last
- cl
->buf
->file_pos
);
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",
102 size
+= ngx_buf_size(cl
->buf
);
104 if (cl
->buf
->flush
|| cl
->buf
->recycled
) {
108 if (cl
->buf
->last_buf
) {
113 /* add the new chain to the existent one */
115 for (ln
= in
; ln
; ln
= ln
->next
) {
116 cl
= ngx_alloc_chain_link(r
->pool
);
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
,
132 cl
->buf
->file_last
- cl
->buf
->file_pos
);
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",
154 size
+= ngx_buf_size(cl
->buf
);
156 if (cl
->buf
->flush
|| cl
->buf
->recycled
) {
160 if (cl
->buf
->last_buf
) {
167 ngx_log_debug3(NGX_LOG_DEBUG_HTTP
, c
->log
, 0,
168 "http write filter: l:%d f:%d s:%O", last
, flush
, size
);
170 clcf
= ngx_http_get_module_loc_conf(r
, ngx_http_core_module
);
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
178 if (!last
&& !flush
&& in
&& size
< (off_t
) clcf
->postpone_output
) {
182 if (c
->write
->delayed
) {
183 c
->buffered
|= NGX_HTTP_WRITE_BUFFERED
;
187 if (size
== 0 && !(c
->buffered
& NGX_LOWLEVEL_BUFFERED
)) {
189 for (cl
= r
->out
; cl
; /* void */) {
192 ngx_free_chain(r
->pool
, ln
);
196 c
->buffered
&= ~NGX_HTTP_WRITE_BUFFERED
;
201 ngx_log_error(NGX_LOG_ALERT
, c
->log
, 0,
202 "the http output chain is empty");
210 limit
= (off_t
) r
->limit_rate
* (ngx_time() - r
->start_sec
+ 1)
211 - (c
->sent
- clcf
->limit_rate_after
);
214 c
->write
->delayed
= 1;
215 ngx_add_timer(c
->write
,
216 (ngx_msec_t
) (- limit
* 1000 / r
->limit_rate
+ 1));
218 c
->buffered
|= NGX_HTTP_WRITE_BUFFERED
;
223 if (clcf
->sendfile_max_chunk
224 && (off_t
) clcf
->sendfile_max_chunk
< limit
)
226 limit
= clcf
->sendfile_max_chunk
;
230 limit
= clcf
->sendfile_max_chunk
;
235 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, c
->log
, 0,
236 "http write filter limit %O", limit
);
238 chain
= c
->send_chain(c
, r
->out
, limit
);
240 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, c
->log
, 0,
241 "http write filter %p", chain
);
243 if (chain
== NGX_CHAIN_ERROR
) {
252 if (clcf
->limit_rate_after
) {
254 sent
-= clcf
->limit_rate_after
;
259 nsent
-= clcf
->limit_rate_after
;
265 delay
= (ngx_msec_t
) ((nsent
- sent
) * 1000 / r
->limit_rate
);
269 c
->write
->delayed
= 1;
270 ngx_add_timer(c
->write
, delay
);
276 && c
->sent
- sent
>= limit
- (off_t
) (2 * ngx_pagesize
))
278 c
->write
->delayed
= 1;
279 ngx_add_timer(c
->write
, 1);
282 for (cl
= r
->out
; cl
&& cl
!= chain
; /* void */) {
285 ngx_free_chain(r
->pool
, ln
);
291 c
->buffered
|= NGX_HTTP_WRITE_BUFFERED
;
295 c
->buffered
&= ~NGX_HTTP_WRITE_BUFFERED
;
297 if ((c
->buffered
& NGX_LOWLEVEL_BUFFERED
) && r
->postponed
== NULL
) {
306 ngx_http_write_filter_init(ngx_conf_t
*cf
)
308 ngx_http_top_body_filter
= ngx_http_write_filter
;