blob: 7ab202cefd2dafb126dc9941ceffe161d3e2cff6 [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 Sysoev369145c2004-05-28 15:49:23 +000062 if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000063
Igor Sysoev9bfb4342004-04-18 19:06:02 +000064 /* move the chain link to the output chain */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000065
66 cl = ctx->in;
67 ctx->in = cl->next;
68
69 *last_out = cl;
70 last_out = &cl->next;
71 cl->next = NULL;
72
73 continue;
74 }
75
Igor Sysoev369145c2004-05-28 15:49:23 +000076 if (ctx->buf == NULL) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000077
Igor Sysoev369145c2004-05-28 15:49:23 +000078 /* get the free buf */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000079
80 if (ctx->free) {
Igor Sysoev369145c2004-05-28 15:49:23 +000081 ctx->buf = ctx->free->buf;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000082 ctx->free = ctx->free->next;
83
Igor Sysoev369145c2004-05-28 15:49:23 +000084 } else if (out || ctx->allocated == ctx->bufs.num) {
Igor Sysoev31f7f6a2004-05-12 05:37:55 +000085
86 break;
87
88 } else {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000089
90 size = ctx->bufs.size;
91
Igor Sysoev369145c2004-05-28 15:49:23 +000092 if (ctx->in->buf->last_buf) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000093
Igor Sysoev369145c2004-05-28 15:49:23 +000094 bsize = ngx_buf_size(ctx->in->buf);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000095
Igor Sysoev369145c2004-05-28 15:49:23 +000096 if (bsize < ctx->bufs.size) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000097
98 /*
Igor Sysoev369145c2004-05-28 15:49:23 +000099 * allocate small temp buf for the small last buf
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000100 * or its small last part
101 */
102
Igor Sysoev369145c2004-05-28 15:49:23 +0000103 size = bsize;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000104
105 } else if (ctx->bufs.num == 1
Igor Sysoev369145c2004-05-28 15:49:23 +0000106 && (bsize < ctx->bufs.size
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000107 + (ctx->bufs.size >> 2)))
108 {
109 /*
Igor Sysoev369145c2004-05-28 15:49:23 +0000110 * allocate a temp buf that equals
111 * to the last buf if the last buf size is lesser
112 * than 1.25 of bufs.size and a temp buf is single
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000113 */
114
Igor Sysoev369145c2004-05-28 15:49:23 +0000115 size = bsize;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000116 }
117 }
118
Igor Sysoev369145c2004-05-28 15:49:23 +0000119 if (!(ctx->buf = ngx_create_temp_buf(ctx->pool, size))) {
120 return NGX_ERROR;
121 }
122
123 ctx->buf->tag = ctx->tag;
124 ctx->buf->recycled = 1;
125 ctx->allocated++;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000126 }
127 }
128
Igor Sysoev369145c2004-05-28 15:49:23 +0000129 rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf,
130 ctx->sendfile);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000131
132 if (rc == NGX_ERROR) {
133 return rc;
134 }
135
136 if (rc == NGX_AGAIN) {
137 if (out) {
138 break;
139 }
140 return rc;
141 }
142
Igor Sysoev369145c2004-05-28 15:49:23 +0000143 /* delete the completed buf from the ctx->in chain */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000144
Igor Sysoev369145c2004-05-28 15:49:23 +0000145 if (ngx_buf_size(ctx->in->buf) == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000146 ctx->in = ctx->in->next;
147 }
148
Igor Sysoev369145c2004-05-28 15:49:23 +0000149 ngx_alloc_link_and_set_buf(cl, ctx->buf, ctx->pool, NGX_ERROR);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000150 *last_out = cl;
151 last_out = &cl->next;
Igor Sysoev369145c2004-05-28 15:49:23 +0000152 ctx->buf = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000153 }
154
155 if (out == NULL && last != NGX_NONE) {
156 return last;
157 }
158
Igor Sysoev89690bf2004-03-23 06:01:52 +0000159 last = ctx->output_filter(ctx->filter_ctx, out);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000160
161 ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
162 last_out = &out;
Igor Sysoev9bfb4342004-04-18 19:06:02 +0000163
164 if (last == NGX_ERROR) {
165 return last;
166 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000167 }
168}
169
170
Igor Sysoev2f657222004-06-16 15:32:11 +0000171ngx_inline static ngx_int_t
172 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000173{
Igor Sysoev369145c2004-05-28 15:49:23 +0000174 if (ngx_buf_special(buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000175 return 0;
176 }
177
Igor Sysoev65977492003-11-02 22:56:18 +0000178 if (!ctx->sendfile) {
Igor Sysoev369145c2004-05-28 15:49:23 +0000179 if (!ngx_buf_in_memory(buf)) {
Igor Sysoev65977492003-11-02 22:56:18 +0000180 return 1;
181 }
182
Igor Sysoev369145c2004-05-28 15:49:23 +0000183 buf->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000184 }
185
Igor Sysoev369145c2004-05-28 15:49:23 +0000186 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000187 return 1;
188 }
189
Igor Sysoev369145c2004-05-28 15:49:23 +0000190 if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000191 return 1;
192 }
193
194 return 0;
195}
196
197
Igor Sysoev369145c2004-05-28 15:49:23 +0000198static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
199 ngx_uint_t sendfile)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000200{
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000201 size_t size;
202 ssize_t n;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000203
Igor Sysoev369145c2004-05-28 15:49:23 +0000204 size = ngx_buf_size(src);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000205
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000206 if (size > (size_t) (dst->end - dst->pos)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000207 size = dst->end - dst->pos;
208 }
209
Igor Sysoev369145c2004-05-28 15:49:23 +0000210 if (ngx_buf_in_memory(src)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000211 ngx_memcpy(dst->pos, src->pos, size);
212 src->pos += size;
213 dst->last += size;
214
Igor Sysoev369145c2004-05-28 15:49:23 +0000215 if (src->in_file) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000216 src->file_pos += size;
217 }
218
Igor Sysoev369145c2004-05-28 15:49:23 +0000219 if (src->last_buf && src->pos == src->last) {
220 dst->last_buf = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000221 }
222
223 } else {
224 n = ngx_read_file(src->file, dst->pos, size, src->file_pos);
225
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000226 if (n == NGX_ERROR) {
227 return n;
228 }
229
230#if (NGX_FILE_AIO_READ)
231 if (n == NGX_AGAIN) {
232 return n;
233 }
234#endif
235
Igor Sysoevd9d0ca12003-11-21 06:30:49 +0000236 if ((size_t) n != size) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000237 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
238 ngx_read_file_n " reads only %d of %d from file",
239 n, size);
240 if (n == 0) {
241 return NGX_ERROR;
242 }
243 }
244
245 src->file_pos += n;
246 dst->last += n;
247
248 if (!sendfile) {
Igor Sysoev369145c2004-05-28 15:49:23 +0000249 dst->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000250 }
251
Igor Sysoev369145c2004-05-28 15:49:23 +0000252 if (src->last_buf && src->file_pos == src->file_last) {
253 dst->last_buf = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000254 }
255 }
256
257 return NGX_OK;
258}
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000259
260
Igor Sysoev369145c2004-05-28 15:49:23 +0000261ngx_int_t ngx_chain_writer(void *data, ngx_chain_t *in)
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000262{
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000263 ngx_chain_writer_ctx_t *ctx = data;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000264
265 ngx_chain_t *cl;
266
267
268 for (/* void */; in; in = in->next) {
Igor Sysoev369145c2004-05-28 15:49:23 +0000269 ngx_alloc_link_and_set_buf(cl, in->buf, ctx->pool, NGX_ERROR);
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000270 *ctx->last = cl;
271 ctx->last = &cl->next;
272 }
273
Igor Sysoev9c610952004-03-16 13:35:20 +0000274 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
275 "WRITER0: %X", ctx->out);
276
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000277 ctx->out = ngx_write_chain(ctx->connection, ctx->out);
278
Igor Sysoev9c610952004-03-16 13:35:20 +0000279 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
280 "WRITER1: %X", ctx->out);
281
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000282 if (ctx->out == NGX_CHAIN_ERROR) {
283 return NGX_ERROR;
284 }
285
286 if (ctx->out == NULL) {
287 ctx->last = &ctx->out;
288 return NGX_OK;
289 }
290
291 return NGX_AGAIN;
292}