blob: 23b7846b9ccd8b892dd927423f22962ed8bfa373 [file] [log] [blame]
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00007#include <ngx_config.h>
8#include <ngx_core.h>
Igor Sysoev2b0c76c2003-10-27 21:01:00 +00009#include <ngx_event.h>
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000010
11
12#define NGX_NONE 1
13
14
Igor Sysoev2f657222004-06-16 15:32:11 +000015ngx_inline static ngx_int_t
16 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
Igor Sysoev369145c2004-05-28 15:49:23 +000017static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
18 ngx_uint_t sendfile);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000019
20
Igor Sysoev2f657222004-06-16 15:32:11 +000021ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000022{
23 int rc, last;
Igor Sysoev369145c2004-05-28 15:49:23 +000024 size_t size, bsize;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000025 ngx_chain_t *cl, *out, **last_out;
26
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000027 if (ctx->in == NULL && ctx->busy == NULL) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000028
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000029 /*
30 * the short path for the case when the ctx->in and ctx->busy chains
31 * are empty, the incoming chain is empty too or has the single buf
32 * that does not require the copy
33 */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000034
35 if (in == NULL) {
Igor Sysoev89690bf2004-03-23 06:01:52 +000036 return ctx->output_filter(ctx->filter_ctx, in);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000037 }
38
Igor Sysoev2b0c76c2003-10-27 21:01:00 +000039 if (in->next == NULL
Igor Sysoev369145c2004-05-28 15:49:23 +000040 && (!ngx_output_chain_need_to_copy(ctx, in->buf)))
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000041 {
Igor Sysoev89690bf2004-03-23 06:01:52 +000042 return ctx->output_filter(ctx->filter_ctx, in);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000043 }
44 }
45
Igor Sysoev67f450d2004-06-01 06:04:46 +000046 /* add the incoming buf to the chain ctx->in */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000047
48 if (in) {
49 if (ngx_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
50 return NGX_ERROR;
51 }
52 }
53
54 last = NGX_NONE;
Igor Sysoevb5faed22003-10-29 08:30:44 +000055 out = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000056 last_out = &out;
57
58 for ( ;; ) {
59
60 while (ctx->in) {
61
Igor Sysoev9bfb4342004-04-18 19:06:02 +000062 /*
Igor Sysoev369145c2004-05-28 15:49:23 +000063 * cycle while there are the ctx->in bufs
64 * or there are the free output bufs to copy in
Igor Sysoev9bfb4342004-04-18 19:06:02 +000065 */
66
Igor Sysoev00d433f2004-07-28 19:21:26 +000067 bsize = ngx_buf_size(ctx->in->buf);
68
69 if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) {
70
71 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
72 "zero size buf");
73
74 ctx->in = ctx->in->next;
Igor Sysoeva2c81192004-09-19 18:27:00 +000075
Igor Sysoev00d433f2004-07-28 19:21:26 +000076 continue;
77 }
78
Igor Sysoev369145c2004-05-28 15:49:23 +000079 if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000080
Igor Sysoev9bfb4342004-04-18 19:06:02 +000081 /* move the chain link to the output chain */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000082
83 cl = ctx->in;
84 ctx->in = cl->next;
85
86 *last_out = cl;
87 last_out = &cl->next;
88 cl->next = NULL;
89
90 continue;
91 }
92
Igor Sysoev369145c2004-05-28 15:49:23 +000093 if (ctx->buf == NULL) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000094
Igor Sysoev369145c2004-05-28 15:49:23 +000095 /* get the free buf */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000096
97 if (ctx->free) {
Igor Sysoev369145c2004-05-28 15:49:23 +000098 ctx->buf = ctx->free->buf;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000099 ctx->free = ctx->free->next;
100
Igor Sysoev369145c2004-05-28 15:49:23 +0000101 } else if (out || ctx->allocated == ctx->bufs.num) {
Igor Sysoev31f7f6a2004-05-12 05:37:55 +0000102
103 break;
104
105 } else {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000106
107 size = ctx->bufs.size;
108
Igor Sysoev369145c2004-05-28 15:49:23 +0000109 if (ctx->in->buf->last_buf) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000110
Igor Sysoev369145c2004-05-28 15:49:23 +0000111 if (bsize < ctx->bufs.size) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000112
113 /*
Igor Sysoev369145c2004-05-28 15:49:23 +0000114 * allocate small temp buf for the small last buf
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000115 * or its small last part
116 */
117
Igor Sysoev369145c2004-05-28 15:49:23 +0000118 size = bsize;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000119
120 } else if (ctx->bufs.num == 1
Igor Sysoev369145c2004-05-28 15:49:23 +0000121 && (bsize < ctx->bufs.size
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000122 + (ctx->bufs.size >> 2)))
123 {
124 /*
Igor Sysoev369145c2004-05-28 15:49:23 +0000125 * allocate a temp buf that equals
126 * to the last buf if the last buf size is lesser
127 * than 1.25 of bufs.size and a temp buf is single
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000128 */
129
Igor Sysoev369145c2004-05-28 15:49:23 +0000130 size = bsize;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000131 }
132 }
133
Igor Sysoev369145c2004-05-28 15:49:23 +0000134 if (!(ctx->buf = ngx_create_temp_buf(ctx->pool, size))) {
135 return NGX_ERROR;
136 }
137
138 ctx->buf->tag = ctx->tag;
139 ctx->buf->recycled = 1;
140 ctx->allocated++;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000141 }
142 }
143
Igor Sysoev369145c2004-05-28 15:49:23 +0000144 rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf,
145 ctx->sendfile);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000146
147 if (rc == NGX_ERROR) {
148 return rc;
149 }
150
151 if (rc == NGX_AGAIN) {
152 if (out) {
153 break;
154 }
Igor Sysoeva2c81192004-09-19 18:27:00 +0000155
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000156 return rc;
157 }
158
Igor Sysoev369145c2004-05-28 15:49:23 +0000159 /* delete the completed buf from the ctx->in chain */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000160
Igor Sysoev369145c2004-05-28 15:49:23 +0000161 if (ngx_buf_size(ctx->in->buf) == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000162 ctx->in = ctx->in->next;
163 }
164
Igor Sysoev369145c2004-05-28 15:49:23 +0000165 ngx_alloc_link_and_set_buf(cl, ctx->buf, ctx->pool, NGX_ERROR);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000166 *last_out = cl;
167 last_out = &cl->next;
Igor Sysoev369145c2004-05-28 15:49:23 +0000168 ctx->buf = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000169 }
170
171 if (out == NULL && last != NGX_NONE) {
172 return last;
173 }
174
Igor Sysoev89690bf2004-03-23 06:01:52 +0000175 last = ctx->output_filter(ctx->filter_ctx, out);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000176
177 ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
178 last_out = &out;
Igor Sysoev9bfb4342004-04-18 19:06:02 +0000179
180 if (last == NGX_ERROR) {
181 return last;
182 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000183 }
184}
185
186
Igor Sysoev2f657222004-06-16 15:32:11 +0000187ngx_inline static ngx_int_t
188 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000189{
Igor Sysoev369145c2004-05-28 15:49:23 +0000190 if (ngx_buf_special(buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000191 return 0;
192 }
193
Igor Sysoev65977492003-11-02 22:56:18 +0000194 if (!ctx->sendfile) {
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000195
Igor Sysoev369145c2004-05-28 15:49:23 +0000196 if (!ngx_buf_in_memory(buf)) {
Igor Sysoev65977492003-11-02 22:56:18 +0000197 return 1;
198 }
199
Igor Sysoev369145c2004-05-28 15:49:23 +0000200 buf->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000201 }
202
Igor Sysoev369145c2004-05-28 15:49:23 +0000203 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000204 return 1;
205 }
206
Igor Sysoev369145c2004-05-28 15:49:23 +0000207 if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000208 return 1;
209 }
210
211 return 0;
212}
213
214
Igor Sysoev369145c2004-05-28 15:49:23 +0000215static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
216 ngx_uint_t sendfile)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000217{
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000218 size_t size;
219 ssize_t n;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000220
Igor Sysoev369145c2004-05-28 15:49:23 +0000221 size = ngx_buf_size(src);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000222
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000223 if (size > (size_t) (dst->end - dst->pos)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000224 size = dst->end - dst->pos;
225 }
226
Igor Sysoev369145c2004-05-28 15:49:23 +0000227 if (ngx_buf_in_memory(src)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000228 ngx_memcpy(dst->pos, src->pos, size);
229 src->pos += size;
230 dst->last += size;
231
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000232 if (src->in_file) {
233
234 if (sendfile) {
235 dst->in_file = 1;
236 dst->file = src->file;
237 dst->file_pos = src->file_pos;
238 dst->file_last = src->file_pos + size;
239
240 } else {
241 dst->in_file = 0;
242 }
243
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000244 src->file_pos += size;
Igor Sysoev924bd792004-10-11 15:07:03 +0000245
246 } else {
247 dst->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000248 }
249
Igor Sysoev369145c2004-05-28 15:49:23 +0000250 if (src->last_buf && src->pos == src->last) {
251 dst->last_buf = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000252 }
253
254 } else {
255 n = ngx_read_file(src->file, dst->pos, size, src->file_pos);
256
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000257 if (n == NGX_ERROR) {
258 return n;
259 }
260
261#if (NGX_FILE_AIO_READ)
262 if (n == NGX_AGAIN) {
263 return n;
264 }
265#endif
266
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000267 if ((size_t) n != size) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000268 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
269 ngx_read_file_n " reads only %d of %d from file",
270 n, size);
271 if (n == 0) {
272 return NGX_ERROR;
273 }
274 }
275
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000276 dst->last += n;
277
Igor Sysoev924bd792004-10-11 15:07:03 +0000278 if (sendfile) {
279 dst->in_file = 1;
280 dst->file = src->file;
281 dst->file_pos = src->file_pos;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000282 dst->file_last = src->file_pos + n;
Igor Sysoev924bd792004-10-11 15:07:03 +0000283
284 } else {
Igor Sysoev369145c2004-05-28 15:49:23 +0000285 dst->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000286 }
287
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000288 src->file_pos += n;
289
Igor Sysoev369145c2004-05-28 15:49:23 +0000290 if (src->last_buf && src->file_pos == src->file_last) {
291 dst->last_buf = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000292 }
293 }
294
295 return NGX_OK;
296}
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000297
298
Igor Sysoev369145c2004-05-28 15:49:23 +0000299ngx_int_t ngx_chain_writer(void *data, ngx_chain_t *in)
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000300{
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000301 ngx_chain_writer_ctx_t *ctx = data;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000302
303 ngx_chain_t *cl;
304
305
306 for (/* void */; in; in = in->next) {
Igor Sysoev967fd632004-08-27 15:40:59 +0000307
308 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
309 "WRITER buf: %d", ngx_buf_size(in->buf));
310
Igor Sysoev369145c2004-05-28 15:49:23 +0000311 ngx_alloc_link_and_set_buf(cl, in->buf, ctx->pool, NGX_ERROR);
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000312 *ctx->last = cl;
313 ctx->last = &cl->next;
314 }
315
Igor Sysoev9c610952004-03-16 13:35:20 +0000316 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
317 "WRITER0: %X", ctx->out);
318
Igor Sysoevf38e0462004-07-16 17:11:43 +0000319 ctx->out = ngx_send_chain(ctx->connection, ctx->out, ctx->limit);
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000320
Igor Sysoev9c610952004-03-16 13:35:20 +0000321 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
322 "WRITER1: %X", ctx->out);
323
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000324 if (ctx->out == NGX_CHAIN_ERROR) {
325 return NGX_ERROR;
326 }
327
328 if (ctx->out == NULL) {
329 ctx->last = &ctx->out;
330 return NGX_OK;
331 }
332
333 return NGX_AGAIN;
334}