blob: 71016996d1779adce430117b9cf2cdd7da0e03c7 [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
Igor Sysoevf6906042004-11-25 16:17:31 +000012#if 0
13#define NGX_SENDFILE_LIMIT 4096
14#endif
15
Igor Sysoev7f3c0482008-11-20 16:21:39 +000016/*
17 * When DIRECTIO is enabled FreeBSD, Solaris, and MacOSX read directly
18 * to an application memory from a device if parameters are aligned
19 * to device sector boundary(512 bytes). They fallback to usual read
20 * operation if the parameters are not aligned.
21 * Linux allows DIRECTIO only if the parameters are aligned to a filesystem
22 * sector boundary, otherwise it returns EINVAL. The sector size is
23 * usually 512 bytes, however, on XFS it may be 4096 bytes.
24 */
25#define NGX_DIRECTIO_BLOCK 4096
26
Igor Sysoevf6906042004-11-25 16:17:31 +000027
28#define NGX_NONE 1
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000029
30
Igor Sysoevd43bee82004-11-20 19:52:20 +000031static ngx_inline ngx_int_t
Igor Sysoev8633e1f2008-09-05 14:48:47 +000032 ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
Igor Sysoevf6906042004-11-25 16:17:31 +000033static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool,
Igor Sysoev8184d1b2005-03-04 14:06:57 +000034 ngx_chain_t **chain, ngx_chain_t *in);
Igor Sysoev8633e1f2008-09-05 14:48:47 +000035static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx,
36 off_t bsize);
Igor Sysoev98007c12008-09-03 10:01:29 +000037static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx,
38 off_t bsize);
Igor Sysoev8633e1f2008-09-05 14:48:47 +000039static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000040
41
Igor Sysoev8184d1b2005-03-04 14:06:57 +000042ngx_int_t
43ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000044{
Igor Sysoev42b12b32004-12-02 18:40:46 +000045 off_t bsize;
Igor Sysoevdf3254a2006-01-11 15:26:57 +000046 ngx_int_t rc, last;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000047 ngx_chain_t *cl, *out, **last_out;
48
Igor Sysoevc0edbcc2004-10-21 15:34:38 +000049 if (ctx->in == NULL && ctx->busy == NULL) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000050
Igor Sysoevf6906042004-11-25 16:17:31 +000051 /*
52 * the short path for the case when the ctx->in and ctx->busy chains
53 * are empty, the incoming chain is empty too or has the single buf
54 * that does not require the copy
55 */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000056
57 if (in == NULL) {
Igor Sysoev89690bf2004-03-23 06:01:52 +000058 return ctx->output_filter(ctx->filter_ctx, in);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000059 }
60
Igor Sysoev2b0c76c2003-10-27 21:01:00 +000061 if (in->next == NULL
Igor Sysoevf6906042004-11-25 16:17:31 +000062#if (NGX_SENDFILE_LIMIT)
63 && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
64#endif
Igor Sysoev8633e1f2008-09-05 14:48:47 +000065 && ngx_output_chain_as_is(ctx, in->buf))
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000066 {
Igor Sysoev89690bf2004-03-23 06:01:52 +000067 return ctx->output_filter(ctx->filter_ctx, in);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000068 }
69 }
70
Igor Sysoev67f450d2004-06-01 06:04:46 +000071 /* add the incoming buf to the chain ctx->in */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000072
73 if (in) {
Igor Sysoevf6906042004-11-25 16:17:31 +000074 if (ngx_output_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000075 return NGX_ERROR;
76 }
77 }
78
Igor Sysoevb5faed22003-10-29 08:30:44 +000079 out = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000080 last_out = &out;
Igor Sysoev8184d1b2005-03-04 14:06:57 +000081 last = NGX_NONE;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000082
83 for ( ;; ) {
84
85 while (ctx->in) {
86
Igor Sysoev9bfb4342004-04-18 19:06:02 +000087 /*
Igor Sysoev369145c2004-05-28 15:49:23 +000088 * cycle while there are the ctx->in bufs
Igor Sysoev8633e1f2008-09-05 14:48:47 +000089 * and there are the free output bufs to copy in
Igor Sysoev9bfb4342004-04-18 19:06:02 +000090 */
91
Igor Sysoev00d433f2004-07-28 19:21:26 +000092 bsize = ngx_buf_size(ctx->in->buf);
93
94 if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) {
95
96 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
Igor Sysoeve5a222c2005-01-25 12:27:35 +000097 "zero size buf in output "
98 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
99 ctx->in->buf->temporary,
100 ctx->in->buf->recycled,
101 ctx->in->buf->in_file,
102 ctx->in->buf->start,
103 ctx->in->buf->pos,
104 ctx->in->buf->last,
105 ctx->in->buf->file,
106 ctx->in->buf->file_pos,
107 ctx->in->buf->file_last);
Igor Sysoev00d433f2004-07-28 19:21:26 +0000108
Igor Sysoev42b12b32004-12-02 18:40:46 +0000109 ngx_debug_point();
110
Igor Sysoev00d433f2004-07-28 19:21:26 +0000111 ctx->in = ctx->in->next;
Igor Sysoeva2c81192004-09-19 18:27:00 +0000112
Igor Sysoev00d433f2004-07-28 19:21:26 +0000113 continue;
114 }
115
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000116 if (ngx_output_chain_as_is(ctx, ctx->in->buf)) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000117
Igor Sysoev9bfb4342004-04-18 19:06:02 +0000118 /* move the chain link to the output chain */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000119
120 cl = ctx->in;
121 ctx->in = cl->next;
122
123 *last_out = cl;
124 last_out = &cl->next;
125 cl->next = NULL;
126
127 continue;
128 }
129
Igor Sysoev369145c2004-05-28 15:49:23 +0000130 if (ctx->buf == NULL) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000131
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000132 rc = ngx_output_chain_align_file_buf(ctx, bsize);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000133
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000134 if (rc == NGX_ERROR) {
Igor Sysoev98007c12008-09-03 10:01:29 +0000135 return NGX_ERROR;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000136 }
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000137
138 if (rc != NGX_OK) {
139
140 if (ctx->free) {
141
142 /* get the free buf */
143
144 cl = ctx->free;
145 ctx->buf = cl->buf;
146 ctx->free = cl->next;
147
148 ngx_free_chain(ctx->pool, cl);
149
150 } else if (out || ctx->allocated == ctx->bufs.num) {
151
152 break;
153
154 } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
155 return NGX_ERROR;
156 }
157 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000158 }
159
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000160 rc = ngx_output_chain_copy_buf(ctx);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000161
162 if (rc == NGX_ERROR) {
163 return rc;
164 }
165
166 if (rc == NGX_AGAIN) {
167 if (out) {
168 break;
169 }
Igor Sysoeva2c81192004-09-19 18:27:00 +0000170
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000171 return rc;
172 }
173
Igor Sysoev369145c2004-05-28 15:49:23 +0000174 /* delete the completed buf from the ctx->in chain */
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000175
Igor Sysoev369145c2004-05-28 15:49:23 +0000176 if (ngx_buf_size(ctx->in->buf) == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000177 ctx->in = ctx->in->next;
178 }
179
Igor Sysoevc1571722005-03-19 12:38:37 +0000180 cl = ngx_alloc_chain_link(ctx->pool);
181 if (cl == NULL) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000182 return NGX_ERROR;
183 }
Igor Sysoevc1571722005-03-19 12:38:37 +0000184
Igor Sysoev1b735832004-11-11 14:07:14 +0000185 cl->buf = ctx->buf;
186 cl->next = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000187 *last_out = cl;
188 last_out = &cl->next;
Igor Sysoev369145c2004-05-28 15:49:23 +0000189 ctx->buf = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000190 }
191
192 if (out == NULL && last != NGX_NONE) {
Igor Sysoev899b44e2005-05-12 14:58:06 +0000193
194 if (ctx->in) {
195 return NGX_AGAIN;
196 }
197
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000198 return last;
199 }
200
Igor Sysoev89690bf2004-03-23 06:01:52 +0000201 last = ctx->output_filter(ctx->filter_ctx, out);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000202
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000203 if (last == NGX_ERROR || last == NGX_DONE) {
Igor Sysoev9bfb4342004-04-18 19:06:02 +0000204 return last;
205 }
Igor Sysoev9ac946b2005-10-24 15:09:41 +0000206
207 ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
208 last_out = &out;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000209 }
210}
211
212
Igor Sysoevd43bee82004-11-20 19:52:20 +0000213static ngx_inline ngx_int_t
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000214ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000215{
Igor Sysoevf6906042004-11-25 16:17:31 +0000216 ngx_uint_t sendfile;
217
Igor Sysoev369145c2004-05-28 15:49:23 +0000218 if (ngx_buf_special(buf)) {
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000219 return 1;
220 }
221
222 if (buf->in_file && buf->file->directio) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000223 return 0;
224 }
225
Igor Sysoevf6906042004-11-25 16:17:31 +0000226 sendfile = ctx->sendfile;
227
228#if (NGX_SENDFILE_LIMIT)
229
230 if (buf->in_file && buf->file_pos >= NGX_SENDFILE_LIMIT) {
231 sendfile = 0;
232 }
233
234#endif
235
236 if (!sendfile) {
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000237
Igor Sysoev369145c2004-05-28 15:49:23 +0000238 if (!ngx_buf_in_memory(buf)) {
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000239 return 0;
Igor Sysoev65977492003-11-02 22:56:18 +0000240 }
241
Igor Sysoev369145c2004-05-28 15:49:23 +0000242 buf->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000243 }
244
Igor Sysoev369145c2004-05-28 15:49:23 +0000245 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000246 return 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000247 }
248
Igor Sysoev369145c2004-05-28 15:49:23 +0000249 if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000250 return 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000251 }
252
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000253 return 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000254}
255
256
Igor Sysoev8184d1b2005-03-04 14:06:57 +0000257static ngx_int_t
258ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
259 ngx_chain_t *in)
Igor Sysoevf6906042004-11-25 16:17:31 +0000260{
261 ngx_chain_t *cl, **ll;
262#if (NGX_SENDFILE_LIMIT)
263 ngx_buf_t *b, *buf;
264#endif
265
266 ll = chain;
267
268 for (cl = *chain; cl; cl = cl->next) {
269 ll = &cl->next;
270 }
271
272 while (in) {
273
Igor Sysoevc1571722005-03-19 12:38:37 +0000274 cl = ngx_alloc_chain_link(pool);
275 if (cl == NULL) {
Igor Sysoevf6906042004-11-25 16:17:31 +0000276 return NGX_ERROR;
277 }
278
279#if (NGX_SENDFILE_LIMIT)
280
281 buf = in->buf;
282
283 if (buf->in_file
284 && buf->file_pos < NGX_SENDFILE_LIMIT
285 && buf->file_last > NGX_SENDFILE_LIMIT)
286 {
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000287 /* split a file buf on two bufs by the sendfile limit */
288
Igor Sysoevc1571722005-03-19 12:38:37 +0000289 b = ngx_calloc_buf(pool);
290 if (b == NULL) {
Igor Sysoevf6906042004-11-25 16:17:31 +0000291 return NGX_ERROR;
292 }
293
294 ngx_memcpy(b, buf, sizeof(ngx_buf_t));
295
296 if (ngx_buf_in_memory(buf)) {
297 buf->pos += (ssize_t) (NGX_SENDFILE_LIMIT - buf->file_pos);
298 b->last = buf->pos;
299 }
300
301 buf->file_pos = NGX_SENDFILE_LIMIT;
302 b->file_last = NGX_SENDFILE_LIMIT;
303
304 cl->buf = b;
305
306 } else {
307 cl->buf = buf;
308 in = in->next;
309 }
310
311#else
312 cl->buf = in->buf;
313 in = in->next;
314
315#endif
316
317 *ll = cl;
318 ll = &cl->next;
319 }
320
321 *ll = NULL;
322
323 return NGX_OK;
324}
325
326
Igor Sysoev8184d1b2005-03-04 14:06:57 +0000327static ngx_int_t
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000328ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
329{
330 size_t size;
331 ngx_buf_t *in;
332
333 in = ctx->in->buf;
334
335 if (in->file == NULL || !in->file->directio) {
336 return NGX_DECLINED;
337 }
338
339 ctx->directio = 1;
340
Igor Sysoev7f3c0482008-11-20 16:21:39 +0000341 size = (size_t) (in->file_pos - (in->file_pos & ~(NGX_DIRECTIO_BLOCK - 1)));
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000342
343 if (size == 0) {
344
Igor Sysoeva19c7b52008-09-08 09:33:37 +0000345 if (bsize >= (off_t) ctx->bufs.size) {
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000346 return NGX_DECLINED;
347 }
348
349 size = (size_t) bsize;
350
351 } else {
Igor Sysoev7f3c0482008-11-20 16:21:39 +0000352 size = NGX_DIRECTIO_BLOCK - size;
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000353
Igor Sysoeva19c7b52008-09-08 09:33:37 +0000354 if ((off_t) size > bsize) {
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000355 size = (size_t) bsize;
356 }
357 }
358
359 ctx->buf = ngx_create_temp_buf(ctx->pool, size);
360 if (ctx->buf == NULL) {
361 return NGX_ERROR;
362 }
363
364 /*
365 * we do not set ctx->buf->tag, because we do not want
366 * to reuse the buf via ctx->free list
367 */
368
Igor Sysoevfae2c002008-09-12 13:50:12 +0000369#if (NGX_HAVE_ALIGNED_DIRECTIO)
370 ctx->unaligned = 1;
371#endif
372
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000373 return NGX_OK;
374}
375
376
377static ngx_int_t
Igor Sysoev98007c12008-09-03 10:01:29 +0000378ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
379{
380 size_t size;
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000381 ngx_buf_t *b, *in;
Igor Sysoev98007c12008-09-03 10:01:29 +0000382 ngx_uint_t recycled;
383
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000384 in = ctx->in->buf;
Igor Sysoev98007c12008-09-03 10:01:29 +0000385 size = ctx->bufs.size;
386 recycled = 1;
387
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000388 if (in->last_in_chain) {
Igor Sysoev98007c12008-09-03 10:01:29 +0000389
390 if (bsize < (off_t) size) {
391
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000392 /*
393 * allocate a small temp buf for a small last buf
394 * or its small last part
395 */
Igor Sysoev98007c12008-09-03 10:01:29 +0000396
397 size = (size_t) bsize;
398 recycled = 0;
399
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000400 } else if (!ctx->directio
401 && ctx->bufs.num == 1
402 && (bsize < (off_t) (size + size / 4)))
403 {
Igor Sysoev98007c12008-09-03 10:01:29 +0000404 /*
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000405 * allocate a temp buf that equals to a last buf,
406 * if there is no directio, the last buf size is lesser
407 * than 1.25 of bufs.size and the temp buf is single
Igor Sysoev98007c12008-09-03 10:01:29 +0000408 */
409
410 size = (size_t) bsize;
411 recycled = 0;
412 }
413 }
414
415 b = ngx_calloc_buf(ctx->pool);
416 if (b == NULL) {
417 return NGX_ERROR;
418 }
419
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000420 if (ctx->directio) {
Igor Sysoev98007c12008-09-03 10:01:29 +0000421
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000422 /*
423 * allocate block aligned to a disk sector size to enable
424 * userland buffer direct usage conjunctly with directio
425 */
426
Igor Sysoev7f3c0482008-11-20 16:21:39 +0000427 b->start = ngx_pmemalign(ctx->pool, size, NGX_DIRECTIO_BLOCK);
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000428 if (b->start == NULL) {
429 return NGX_ERROR;
430 }
431
432 } else {
433 b->start = ngx_palloc(ctx->pool, size);
434 if (b->start == NULL) {
435 return NGX_ERROR;
436 }
Igor Sysoev98007c12008-09-03 10:01:29 +0000437 }
438
439 b->pos = b->start;
440 b->last = b->start;
441 b->end = b->last + size;
442 b->temporary = 1;
443 b->tag = ctx->tag;
444 b->recycled = recycled;
445
446 ctx->buf = b;
447 ctx->allocated++;
448
449 return NGX_OK;
450}
451
452
453static ngx_int_t
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000454ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000455{
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000456 off_t size;
457 ssize_t n;
458 ngx_buf_t *src, *dst;
459 ngx_uint_t sendfile;
460
461 src = ctx->in->buf;
462 dst = ctx->buf;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000463
Igor Sysoev369145c2004-05-28 15:49:23 +0000464 size = ngx_buf_size(src);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000465
Igor Sysoev42b12b32004-12-02 18:40:46 +0000466 if (size > dst->end - dst->pos) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000467 size = dst->end - dst->pos;
468 }
469
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000470 sendfile = ctx->sendfile & !ctx->directio;
471
Igor Sysoevf6906042004-11-25 16:17:31 +0000472#if (NGX_SENDFILE_LIMIT)
473
474 if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) {
475 sendfile = 0;
476 }
477
478#endif
479
Igor Sysoev369145c2004-05-28 15:49:23 +0000480 if (ngx_buf_in_memory(src)) {
Igor Sysoev42b12b32004-12-02 18:40:46 +0000481 ngx_memcpy(dst->pos, src->pos, (size_t) size);
482 src->pos += (size_t) size;
483 dst->last += (size_t) size;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000484
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000485 if (src->in_file) {
486
487 if (sendfile) {
488 dst->in_file = 1;
489 dst->file = src->file;
490 dst->file_pos = src->file_pos;
491 dst->file_last = src->file_pos + size;
492
493 } else {
494 dst->in_file = 0;
495 }
496
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000497 src->file_pos += size;
Igor Sysoev924bd792004-10-11 15:07:03 +0000498
499 } else {
500 dst->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000501 }
502
Igor Sysoevb2c5db52007-06-03 19:58:30 +0000503 if (src->pos == src->last) {
504 dst->flush = src->flush;
505 dst->last_buf = src->last_buf;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000506 }
507
508 } else {
Igor Sysoevfae2c002008-09-12 13:50:12 +0000509
510#if (NGX_HAVE_ALIGNED_DIRECTIO)
511
512 if (ctx->unaligned) {
513 if (ngx_directio_off(src->file->fd) == -1) {
514 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
515 ngx_directio_off_n " \"%s\" failed",
516 src->file->name.data);
517 }
518 }
519
520#endif
521
Igor Sysoev42b12b32004-12-02 18:40:46 +0000522 n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000523
Igor Sysoevfae2c002008-09-12 13:50:12 +0000524#if (NGX_HAVE_ALIGNED_DIRECTIO)
525
526 if (ctx->unaligned) {
527 ngx_err_t err;
528
529 err = ngx_errno;
530
531 if (ngx_directio_on(src->file->fd) == -1) {
532 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
533 ngx_directio_on_n " \"%s\" failed",
534 src->file->name.data);
535 }
536
537 ngx_set_errno(err);
538
539 ctx->unaligned = 0;
540 }
541
542#endif
543
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000544 if (n == NGX_ERROR) {
Igor Sysoev4959ec42005-05-23 12:07:45 +0000545 return (ngx_int_t) n;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000546 }
547
548#if (NGX_FILE_AIO_READ)
549 if (n == NGX_AGAIN) {
Igor Sysoev4959ec42005-05-23 12:07:45 +0000550 return (ngx_int_t) n;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000551 }
552#endif
553
Igor Sysoev42b12b32004-12-02 18:40:46 +0000554 if (n != size) {
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000555 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
Igor Sysoevd0df2952008-09-11 15:52:11 +0000556 ngx_read_file_n " read only %z of %O from \"%s\"",
557 n, size, src->file->name.data);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000558 if (n == 0) {
559 return NGX_ERROR;
560 }
561 }
562
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000563 dst->last += n;
564
Igor Sysoev924bd792004-10-11 15:07:03 +0000565 if (sendfile) {
566 dst->in_file = 1;
567 dst->file = src->file;
568 dst->file_pos = src->file_pos;
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000569 dst->file_last = src->file_pos + n;
Igor Sysoev924bd792004-10-11 15:07:03 +0000570
571 } else {
Igor Sysoev369145c2004-05-28 15:49:23 +0000572 dst->in_file = 0;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000573 }
574
Igor Sysoevc0edbcc2004-10-21 15:34:38 +0000575 src->file_pos += n;
576
Igor Sysoev52a93432007-06-06 05:56:51 +0000577 if (src->file_pos == src->file_last) {
Igor Sysoevb2c5db52007-06-03 19:58:30 +0000578 dst->flush = src->flush;
579 dst->last_buf = src->last_buf;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000580 }
581 }
582
583 return NGX_OK;
584}
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000585
586
Igor Sysoev8184d1b2005-03-04 14:06:57 +0000587ngx_int_t
588ngx_chain_writer(void *data, ngx_chain_t *in)
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000589{
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000590 ngx_chain_writer_ctx_t *ctx = data;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000591
Igor Sysoev693bf6d2008-04-09 18:56:36 +0000592 off_t size;
593 ngx_chain_t *cl;
594 ngx_connection_t *c;
595
596 c = ctx->connection;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000597
Igor Sysoev42b12b32004-12-02 18:40:46 +0000598 for (size = 0; in; in = in->next) {
599
600#if 1
601 if (ngx_buf_size(in->buf) == 0 && !ngx_buf_special(in->buf)) {
602 ngx_debug_point();
603 }
604#endif
605
606 size += ngx_buf_size(in->buf);
Igor Sysoev967fd632004-08-27 15:40:59 +0000607
Igor Sysoev693bf6d2008-04-09 18:56:36 +0000608 ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
Igor Sysoev70c1d0f2007-06-03 19:56:27 +0000609 "chain writer buf fl:%d s:%uO",
610 in->buf->flush, ngx_buf_size(in->buf));
Igor Sysoev967fd632004-08-27 15:40:59 +0000611
Igor Sysoevc1571722005-03-19 12:38:37 +0000612 cl = ngx_alloc_chain_link(ctx->pool);
613 if (cl == NULL) {
Igor Sysoev1b735832004-11-11 14:07:14 +0000614 return NGX_ERROR;
615 }
Igor Sysoevc1571722005-03-19 12:38:37 +0000616
Igor Sysoev1b735832004-11-11 14:07:14 +0000617 cl->buf = in->buf;
618 cl->next = NULL;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000619 *ctx->last = cl;
620 ctx->last = &cl->next;
621 }
622
Igor Sysoev693bf6d2008-04-09 18:56:36 +0000623 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
Igor Sysoev1b735832004-11-11 14:07:14 +0000624 "chain writer in: %p", ctx->out);
Igor Sysoev9c610952004-03-16 13:35:20 +0000625
Igor Sysoev42b12b32004-12-02 18:40:46 +0000626 for (cl = ctx->out; cl; cl = cl->next) {
627
628#if 1
Igor Sysoev42b12b32004-12-02 18:40:46 +0000629 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
630 ngx_debug_point();
631 }
632
633#endif
634
635 size += ngx_buf_size(cl->buf);
636 }
637
Igor Sysoev693bf6d2008-04-09 18:56:36 +0000638 if (size == 0 && !c->buffered) {
Igor Sysoev42b12b32004-12-02 18:40:46 +0000639 return NGX_OK;
640 }
641
Igor Sysoev693bf6d2008-04-09 18:56:36 +0000642 ctx->out = c->send_chain(c, ctx->out, ctx->limit);
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000643
Igor Sysoev693bf6d2008-04-09 18:56:36 +0000644 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
Igor Sysoev1b735832004-11-11 14:07:14 +0000645 "chain writer out: %p", ctx->out);
Igor Sysoev9c610952004-03-16 13:35:20 +0000646
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000647 if (ctx->out == NGX_CHAIN_ERROR) {
648 return NGX_ERROR;
649 }
650
651 if (ctx->out == NULL) {
652 ctx->last = &ctx->out;
Igor Sysoevb8ddf752007-05-28 11:09:18 +0000653
Igor Sysoev693bf6d2008-04-09 18:56:36 +0000654 if (!c->buffered) {
Igor Sysoevacac0032007-05-29 12:06:42 +0000655 return NGX_OK;
656 }
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000657 }
658
659 return NGX_AGAIN;
660}