blob: 8efd369edca426bea592f2d23064e9dec0fbc1d0 [file] [log] [blame]
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001
2#include <ngx_config.h>
3#include <ngx_core.h>
Igor Sysoev2b0c76c2003-10-27 21:01:00 +00004#include <ngx_event.h>
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00005
6
7#define NGX_NONE 1
8
9
Igor Sysoev2f657222004-06-16 15:32:11 +000010ngx_inline static ngx_int_t
11 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
Igor Sysoev369145c2004-05-28 15:49:23 +000012static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
13 ngx_uint_t sendfile);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000014
15
Igor Sysoev2f657222004-06-16 15:32:11 +000016ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000017{
18 int rc, last;
Igor Sysoev369145c2004-05-28 15:49:23 +000019 size_t size, bsize;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000020 ngx_chain_t *cl, *out, **last_out;
21
22 /*
Igor Sysoev9bfb4342004-04-18 19:06:02 +000023 * the short path for the case when the ctx->in chain is empty
Igor Sysoev369145c2004-05-28 15:49:23 +000024 * and the incoming chain is empty too or it has the single buf
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000025 * that does not require the copy
26 */
27
28 if (ctx->in == NULL) {
29
30 if (in == NULL) {
Igor Sysoev89690bf2004-03-23 06:01:52 +000031 return ctx->output_filter(ctx->filter_ctx, in);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000032 }
33
Igor Sysoev2b0c76c2003-10-27 21:01:00 +000034 if (in->next == NULL
Igor Sysoev369145c2004-05-28 15:49:23 +000035 && (!ngx_output_chain_need_to_copy(ctx, in->buf)))
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000036 {
Igor Sysoev89690bf2004-03-23 06:01:52 +000037 return ctx->output_filter(ctx->filter_ctx, in);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000038 }
39 }
40
Igor Sysoev67f450d2004-06-01 06:04:46 +000041 /* add the incoming buf to the chain ctx->in */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000042
43 if (in) {
44 if (ngx_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
45 return NGX_ERROR;
46 }
47 }
48
49 last = NGX_NONE;
Igor Sysoevb5faed22003-10-29 08:30:44 +000050 out = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000051 last_out = &out;
52
53 for ( ;; ) {
54
55 while (ctx->in) {
56
Igor Sysoev9bfb4342004-04-18 19:06:02 +000057 /*
Igor Sysoev369145c2004-05-28 15:49:23 +000058 * cycle while there are the ctx->in bufs
59 * or there are the free output bufs to copy in
Igor Sysoev9bfb4342004-04-18 19:06:02 +000060 */
61
Igor Sysoev00d433f2004-07-28 19:21:26 +000062 bsize = ngx_buf_size(ctx->in->buf);
63
64 if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) {
65
66 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
67 "zero size buf");
68
69 ctx->in = ctx->in->next;
Igor Sysoeva2c81192004-09-19 18:27:00 +000070
Igor Sysoev00d433f2004-07-28 19:21:26 +000071 continue;
72 }
73
Igor Sysoev369145c2004-05-28 15:49:23 +000074 if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000075
Igor Sysoev9bfb4342004-04-18 19:06:02 +000076 /* move the chain link to the output chain */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000077
78 cl = ctx->in;
79 ctx->in = cl->next;
80
81 *last_out = cl;
82 last_out = &cl->next;
83 cl->next = NULL;
84
85 continue;
86 }
87
Igor Sysoev369145c2004-05-28 15:49:23 +000088 if (ctx->buf == NULL) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000089
Igor Sysoev369145c2004-05-28 15:49:23 +000090 /* get the free buf */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000091
92 if (ctx->free) {
Igor Sysoev369145c2004-05-28 15:49:23 +000093 ctx->buf = ctx->free->buf;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000094 ctx->free = ctx->free->next;
95
Igor Sysoev369145c2004-05-28 15:49:23 +000096 } else if (out || ctx->allocated == ctx->bufs.num) {
Igor Sysoev31f7f6a2004-05-12 05:37:55 +000097
98 break;
99
100 } else {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000101
102 size = ctx->bufs.size;
103
Igor Sysoev369145c2004-05-28 15:49:23 +0000104 if (ctx->in->buf->last_buf) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000105
Igor Sysoev369145c2004-05-28 15:49:23 +0000106 if (bsize < ctx->bufs.size) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000107
108 /*
Igor Sysoev369145c2004-05-28 15:49:23 +0000109 * allocate small temp buf for the small last buf
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000110 * or its small last part
111 */
112
Igor Sysoev369145c2004-05-28 15:49:23 +0000113 size = bsize;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000114
115 } else if (ctx->bufs.num == 1
Igor Sysoev369145c2004-05-28 15:49:23 +0000116 && (bsize < ctx->bufs.size
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000117 + (ctx->bufs.size >> 2)))
118 {
119 /*
Igor Sysoev369145c2004-05-28 15:49:23 +0000120 * allocate a temp buf that equals
121 * to the last buf if the last buf size is lesser
122 * than 1.25 of bufs.size and a temp buf is single
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000123 */
124
Igor Sysoev369145c2004-05-28 15:49:23 +0000125 size = bsize;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000126 }
127 }
128
Igor Sysoev369145c2004-05-28 15:49:23 +0000129 if (!(ctx->buf = ngx_create_temp_buf(ctx->pool, size))) {
130 return NGX_ERROR;
131 }
132
133 ctx->buf->tag = ctx->tag;
134 ctx->buf->recycled = 1;
135 ctx->allocated++;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000136 }
137 }
138
Igor Sysoev369145c2004-05-28 15:49:23 +0000139 rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf,
140 ctx->sendfile);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000141
142 if (rc == NGX_ERROR) {
143 return rc;
144 }
145
146 if (rc == NGX_AGAIN) {
147 if (out) {
148 break;
149 }
Igor Sysoeva2c81192004-09-19 18:27:00 +0000150
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000151 return rc;
152 }
153
Igor Sysoev369145c2004-05-28 15:49:23 +0000154 /* delete the completed buf from the ctx->in chain */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000155
Igor Sysoev369145c2004-05-28 15:49:23 +0000156 if (ngx_buf_size(ctx->in->buf) == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000157 ctx->in = ctx->in->next;
158 }
159
Igor Sysoev369145c2004-05-28 15:49:23 +0000160 ngx_alloc_link_and_set_buf(cl, ctx->buf, ctx->pool, NGX_ERROR);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000161 *last_out = cl;
162 last_out = &cl->next;
Igor Sysoev369145c2004-05-28 15:49:23 +0000163 ctx->buf = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000164 }
165
166 if (out == NULL && last != NGX_NONE) {
167 return last;
168 }
169
Igor Sysoev89690bf2004-03-23 06:01:52 +0000170 last = ctx->output_filter(ctx->filter_ctx, out);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000171
172 ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
173 last_out = &out;
Igor Sysoev9bfb4342004-04-18 19:06:02 +0000174
175 if (last == NGX_ERROR) {
176 return last;
177 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000178 }
179}
180
181
Igor Sysoev2f657222004-06-16 15:32:11 +0000182ngx_inline static ngx_int_t
183 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000184{
Igor Sysoev369145c2004-05-28 15:49:23 +0000185 if (ngx_buf_special(buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000186 return 0;
187 }
188
Igor Sysoev65977492003-11-02 22:56:18 +0000189 if (!ctx->sendfile) {
Igor Sysoev369145c2004-05-28 15:49:23 +0000190 if (!ngx_buf_in_memory(buf)) {
Igor Sysoev65977492003-11-02 22:56:18 +0000191 return 1;
192 }
193
Igor Sysoev369145c2004-05-28 15:49:23 +0000194 buf->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000195 }
196
Igor Sysoev369145c2004-05-28 15:49:23 +0000197 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000198 return 1;
199 }
200
Igor Sysoev369145c2004-05-28 15:49:23 +0000201 if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000202 return 1;
203 }
204
205 return 0;
206}
207
208
Igor Sysoev369145c2004-05-28 15:49:23 +0000209static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
210 ngx_uint_t sendfile)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000211{
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000212 size_t size;
213 ssize_t n;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000214
Igor Sysoev369145c2004-05-28 15:49:23 +0000215 size = ngx_buf_size(src);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000216
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000217 if (size > (size_t) (dst->end - dst->pos)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000218 size = dst->end - dst->pos;
219 }
220
Igor Sysoev369145c2004-05-28 15:49:23 +0000221 if (ngx_buf_in_memory(src)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000222 ngx_memcpy(dst->pos, src->pos, size);
223 src->pos += size;
224 dst->last += size;
225
Igor Sysoev369145c2004-05-28 15:49:23 +0000226 if (src->in_file) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000227 src->file_pos += size;
228 }
229
Igor Sysoev369145c2004-05-28 15:49:23 +0000230 if (src->last_buf && src->pos == src->last) {
231 dst->last_buf = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000232 }
233
234 } else {
235 n = ngx_read_file(src->file, dst->pos, size, src->file_pos);
236
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000237 if (n == NGX_ERROR) {
238 return n;
239 }
240
241#if (NGX_FILE_AIO_READ)
242 if (n == NGX_AGAIN) {
243 return n;
244 }
245#endif
246
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000247 if ((size_t) n != size) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000248 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
249 ngx_read_file_n " reads only %d of %d from file",
250 n, size);
251 if (n == 0) {
252 return NGX_ERROR;
253 }
254 }
255
256 src->file_pos += n;
257 dst->last += n;
258
259 if (!sendfile) {
Igor Sysoev369145c2004-05-28 15:49:23 +0000260 dst->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000261 }
262
Igor Sysoev369145c2004-05-28 15:49:23 +0000263 if (src->last_buf && src->file_pos == src->file_last) {
264 dst->last_buf = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000265 }
266 }
267
268 return NGX_OK;
269}
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000270
271
Igor Sysoev369145c2004-05-28 15:49:23 +0000272ngx_int_t ngx_chain_writer(void *data, ngx_chain_t *in)
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000273{
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000274 ngx_chain_writer_ctx_t *ctx = data;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000275
276 ngx_chain_t *cl;
277
278
279 for (/* void */; in; in = in->next) {
Igor Sysoev967fd632004-08-27 15:40:59 +0000280
281 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
282 "WRITER buf: %d", ngx_buf_size(in->buf));
283
Igor Sysoev369145c2004-05-28 15:49:23 +0000284 ngx_alloc_link_and_set_buf(cl, in->buf, ctx->pool, NGX_ERROR);
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000285 *ctx->last = cl;
286 ctx->last = &cl->next;
287 }
288
Igor Sysoev9c610952004-03-16 13:35:20 +0000289 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
290 "WRITER0: %X", ctx->out);
291
Igor Sysoevf38e0462004-07-16 17:11:43 +0000292 ctx->out = ngx_send_chain(ctx->connection, ctx->out, ctx->limit);
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000293
Igor Sysoev9c610952004-03-16 13:35:20 +0000294 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
295 "WRITER1: %X", ctx->out);
296
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000297 if (ctx->out == NGX_CHAIN_ERROR) {
298 return NGX_ERROR;
299 }
300
301 if (ctx->out == NULL) {
302 ctx->last = &ctx->out;
303 return NGX_OK;
304 }
305
306 return NGX_AGAIN;
307}