blob: d2fbf12fb06382c3179eba84dd3c7d9c67c33102 [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 Sysoevd43bee82004-11-20 19:52:20 +000015static ngx_inline ngx_int_t
Igor Sysoev2f657222004-06-16 15:32:11 +000016 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 Sysoev1b735832004-11-11 14:07:14 +0000165 if (!(cl = ngx_alloc_chain_link(ctx->pool))) {
166 return NGX_ERROR;
167 }
168 cl->buf = ctx->buf;
169 cl->next = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000170 *last_out = cl;
171 last_out = &cl->next;
Igor Sysoev369145c2004-05-28 15:49:23 +0000172 ctx->buf = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000173 }
174
175 if (out == NULL && last != NGX_NONE) {
176 return last;
177 }
178
Igor Sysoev89690bf2004-03-23 06:01:52 +0000179 last = ctx->output_filter(ctx->filter_ctx, out);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000180
181 ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
182 last_out = &out;
Igor Sysoev9bfb4342004-04-18 19:06:02 +0000183
184 if (last == NGX_ERROR) {
185 return last;
186 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000187 }
188}
189
190
Igor Sysoevd43bee82004-11-20 19:52:20 +0000191static ngx_inline ngx_int_t
Igor Sysoev2f657222004-06-16 15:32:11 +0000192 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000193{
Igor Sysoev369145c2004-05-28 15:49:23 +0000194 if (ngx_buf_special(buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000195 return 0;
196 }
197
Igor Sysoev65977492003-11-02 22:56:18 +0000198 if (!ctx->sendfile) {
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000199
Igor Sysoev369145c2004-05-28 15:49:23 +0000200 if (!ngx_buf_in_memory(buf)) {
Igor Sysoev65977492003-11-02 22:56:18 +0000201 return 1;
202 }
203
Igor Sysoev369145c2004-05-28 15:49:23 +0000204 buf->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000205 }
206
Igor Sysoev369145c2004-05-28 15:49:23 +0000207 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000208 return 1;
209 }
210
Igor Sysoev369145c2004-05-28 15:49:23 +0000211 if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000212 return 1;
213 }
214
215 return 0;
216}
217
218
Igor Sysoev369145c2004-05-28 15:49:23 +0000219static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
220 ngx_uint_t sendfile)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000221{
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000222 size_t size;
223 ssize_t n;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000224
Igor Sysoev369145c2004-05-28 15:49:23 +0000225 size = ngx_buf_size(src);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000226
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000227 if (size > (size_t) (dst->end - dst->pos)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000228 size = dst->end - dst->pos;
229 }
230
Igor Sysoev369145c2004-05-28 15:49:23 +0000231 if (ngx_buf_in_memory(src)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000232 ngx_memcpy(dst->pos, src->pos, size);
233 src->pos += size;
234 dst->last += size;
235
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000236 if (src->in_file) {
237
238 if (sendfile) {
239 dst->in_file = 1;
240 dst->file = src->file;
241 dst->file_pos = src->file_pos;
242 dst->file_last = src->file_pos + size;
243
244 } else {
245 dst->in_file = 0;
246 }
247
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000248 src->file_pos += size;
Igor Sysoev924bd792004-10-11 15:07:03 +0000249
250 } else {
251 dst->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000252 }
253
Igor Sysoev369145c2004-05-28 15:49:23 +0000254 if (src->last_buf && src->pos == src->last) {
255 dst->last_buf = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000256 }
257
258 } else {
259 n = ngx_read_file(src->file, dst->pos, size, src->file_pos);
260
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000261 if (n == NGX_ERROR) {
262 return n;
263 }
264
265#if (NGX_FILE_AIO_READ)
266 if (n == NGX_AGAIN) {
267 return n;
268 }
269#endif
270
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000271 if ((size_t) n != size) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000272 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
Igor Sysoev1b735832004-11-11 14:07:14 +0000273 ngx_read_file_n " reads only %z of %uz from file",
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000274 n, size);
275 if (n == 0) {
276 return NGX_ERROR;
277 }
278 }
279
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000280 dst->last += n;
281
Igor Sysoev924bd792004-10-11 15:07:03 +0000282 if (sendfile) {
283 dst->in_file = 1;
284 dst->file = src->file;
285 dst->file_pos = src->file_pos;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000286 dst->file_last = src->file_pos + n;
Igor Sysoev924bd792004-10-11 15:07:03 +0000287
288 } else {
Igor Sysoev369145c2004-05-28 15:49:23 +0000289 dst->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000290 }
291
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000292 src->file_pos += n;
293
Igor Sysoev369145c2004-05-28 15:49:23 +0000294 if (src->last_buf && src->file_pos == src->file_last) {
295 dst->last_buf = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000296 }
297 }
298
299 return NGX_OK;
300}
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000301
302
Igor Sysoev369145c2004-05-28 15:49:23 +0000303ngx_int_t ngx_chain_writer(void *data, ngx_chain_t *in)
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000304{
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000305 ngx_chain_writer_ctx_t *ctx = data;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000306
307 ngx_chain_t *cl;
308
309
310 for (/* void */; in; in = in->next) {
Igor Sysoev967fd632004-08-27 15:40:59 +0000311
312 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
Igor Sysoev1b735832004-11-11 14:07:14 +0000313 "chain writer buf size: %uz", ngx_buf_size(in->buf));
Igor Sysoev967fd632004-08-27 15:40:59 +0000314
Igor Sysoev1b735832004-11-11 14:07:14 +0000315 if (!(cl = ngx_alloc_chain_link(ctx->pool))) {
316 return NGX_ERROR;
317 }
318 cl->buf = in->buf;
319 cl->next = NULL;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000320 *ctx->last = cl;
321 ctx->last = &cl->next;
322 }
323
Igor Sysoev9c610952004-03-16 13:35:20 +0000324 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
Igor Sysoev1b735832004-11-11 14:07:14 +0000325 "chain writer in: %p", ctx->out);
Igor Sysoev9c610952004-03-16 13:35:20 +0000326
Igor Sysoevf38e0462004-07-16 17:11:43 +0000327 ctx->out = ngx_send_chain(ctx->connection, ctx->out, ctx->limit);
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000328
Igor Sysoev9c610952004-03-16 13:35:20 +0000329 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
Igor Sysoev1b735832004-11-11 14:07:14 +0000330 "chain writer out: %p", ctx->out);
Igor Sysoev9c610952004-03-16 13:35:20 +0000331
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000332 if (ctx->out == NGX_CHAIN_ERROR) {
333 return NGX_ERROR;
334 }
335
336 if (ctx->out == NULL) {
337 ctx->last = &ctx->out;
338 return NGX_OK;
339 }
340
341 return NGX_AGAIN;
342}