comparison src/http/ngx_http_output_filter.c @ 61:4f3e2abcc2c4

nginx-0.0.1-2003-02-11-19:42:23 import
author Igor Sysoev <igor@sysoev.ru>
date Tue, 11 Feb 2003 16:42:23 +0000
parents 50186b49f2ad
children 8ccba41a678e
comparison
equal deleted inserted replaced
60:50186b49f2ad 61:4f3e2abcc2c4
55 NGX_HTTP_MODULE_TYPE, /* module type */ 55 NGX_HTTP_MODULE_TYPE, /* module type */
56 NULL /* init module */ 56 NULL /* init module */
57 }; 57 };
58 58
59 59
60 #if 1
61 60
62 #define next_filter ngx_http_output_filter_module_ctx.next_output_body_filter 61 #define next_filter ngx_http_output_filter_module_ctx.next_output_body_filter
63 62
64 #define need_to_copy(r, hunk) \ 63 #define need_to_copy(r, hunk) \
65 (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) \ 64 (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) \
66 && (hunk->type & NGX_HUNK_FILE)) \ 65 && (hunk->type & NGX_HUNK_FILE)) \
67 || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) \ 66 || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) \
68 && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))) 67 && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP))))
68
69 69
70 int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk) 70 int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk)
71 { 71 {
72 int rc; 72 int rc;
73 size_t size; 73 size_t size;
82 if (ctx == NULL) { 82 if (ctx == NULL) {
83 ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module, 83 ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module,
84 sizeof(ngx_http_output_filter_ctx_t)); 84 sizeof(ngx_http_output_filter_ctx_t));
85 } 85 }
86 86
87 /* the incoming chain ctx->in is empty */ 87 /* the short path for the case when the chain ctx->incoming is empty
88 if (ctx->in == NULL) { 88 and there is no hunk or the hunk does not require the copy */
89 if (ctx->incoming == NULL) {
89 90
90 if (hunk == NULL) { 91 if (hunk == NULL) {
91 return next_filter(r, NULL); 92 return next_filter(r, NULL);
92 } 93 }
93 94
96 ctx->out.hunk = hunk; 97 ctx->out.hunk = hunk;
97 ctx->out.next = NULL; 98 ctx->out.next = NULL;
98 99
99 return next_filter(r, &ctx->out); 100 return next_filter(r, &ctx->out);
100 } 101 }
101 102 }
102 /* we need to copy the incoming hunk to our hunk */ 103
103 104 /* add the incoming hunk to the chain ctx->incoming */
104 /* allocate ctx->hunk if it's needed */ 105 if (hunk) {
105 if (ctx->hunk == NULL) { 106
106 107 /* the output of the only hunk is common case so we have
107 conf = (ngx_http_output_filter_conf_t *) 108 special chain entry ctx->in for it */
108 ngx_http_get_module_loc_conf(r->main ? r->main : r, 109 if (ctx->incoming == NULL) {
109 ngx_http_output_filter_module); 110 ctx->in.hunk = hunk;
110 111 ctx->in.next = NULL;
111 if (hunk->type & NGX_HUNK_LAST) { 112 ctx->incoming = &ctx->in;
112 size = hunk->last.mem - hunk->pos.mem; 113
113 if (size > conf->hunk_size) { 114 } else {
114 size = conf->hunk_size; 115 for (ce = ctx->incoming; ce->next; ce = ce->next) {
115 } 116 /* void */ ;
116 117 }
117 } else { 118
119 ngx_add_hunk_to_chain(ce->next, hunk, r->pool, NGX_ERROR);
120 }
121 }
122
123 /* allocate our hunk if it's needed */
124 if (ctx->hunk == NULL) {
125
126 conf = (ngx_http_output_filter_conf_t *)
127 ngx_http_get_module_loc_conf(r->main ? r->main : r,
128 ngx_http_output_filter_module);
129
130 if (hunk->type & NGX_HUNK_LAST) {
131 size = hunk->last.mem - hunk->pos.mem;
132 if (size > conf->hunk_size) {
118 size = conf->hunk_size; 133 size = conf->hunk_size;
119 } 134 }
120 135
121 ngx_test_null(ctx->hunk, 136 } else {
122 ngx_create_temp_hunk(r->pool, size, 50, 50), 137 size = conf->hunk_size;
123 NGX_ERROR); 138 }
124 139
125 ctx->hunk->type |= NGX_HUNK_RECYCLED; 140 ngx_test_null(ctx->hunk,
126 } 141 ngx_create_temp_hunk(r->pool, size, 50, 50),
127 142 NGX_ERROR);
128 /* copy the incoming hunk or its part to our hunk 143
129 and pass it to the next filter */ 144 ctx->hunk->type |= NGX_HUNK_RECYCLED;
130 145
146
147 /* our hunk is still busy */
148 } else if (ctx->hunk->pos.mem < ctx->hunk->last.mem) {
149 rc = next_filter(r, NULL);
150
151 if (rc == NGX_ERROR || rc == NGX_AGAIN) {
152 return rc;
153 }
154
155 /* NGX_OK */
156
157 /* set our hunk free */
158 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
159 }
160
161 #if (NGX_SUPPRESS_WARN)
162 pe = NULL;
163 #endif
164
165 /* process the chain ctx->incoming */
166 do {
167 /* find the hunks that do not need to be copied ... */
168 for (ce = ctx->incoming; ce; ce = ce->next) {
169 if (need_to_copy(r, ce->hunk)) {
170 break;
171 }
172 pe = ce;
173 }
174
175 /* ... and pass them to the next filter */
176 if (ctx->incoming != ce) {
177
178 ctx->out.hunk = ctx->incoming->hunk;
179 ctx->out.next = ctx->incoming->next;
180 ctx->incoming = ce;
181 pe->next = NULL;
182
183 rc = next_filter(r, &ctx->out);
184
185 if (rc == NGX_ERROR || rc == NGX_AGAIN) {
186 return rc;
187 }
188
189 /* NGX_OK */
190 if (ctx->incoming == NULL) {
191 return rc;
192 }
193 }
194
195 /* copy the first hunk or its part from the chain ctx->incoming
196 to our hunk and pass it to the next filter */
131 do { 197 do {
132 rc = ngx_http_output_filter_copy_hunk(ctx->hunk, hunk); 198 rc = ngx_http_output_filter_copy_hunk(ctx->hunk,
199 ctx->incoming->hunk);
133 200
134 if (rc == NGX_ERROR) { 201 if (rc == NGX_ERROR) {
135 return rc; 202 return rc;
136 } 203 }
137 204
138 #if (NGX_FILE_AIO_READ) 205 #if (NGX_FILE_AIO_READ)
139 206
140 if (rc == NGX_AGAIN) { 207 if (rc == NGX_AGAIN) {
141 /* add the incoming hunk to the incoming chain */
142 ngx_add_hunk_to_chain(ctx->in, hunk, r->pool, NGX_ERROR);
143 return rc; 208 return rc;
144 } 209 }
145 210
146 #endif 211 #endif
147 ctx->out.hunk = ctx->hunk; 212 ctx->out.hunk = ctx->hunk;
148 ctx->out.next = NULL; 213 ctx->out.next = NULL;
149 214
150 rc = next_filter(r, &ctx->out); 215 rc = next_filter(r, &ctx->out);
151 216
152 if (rc == NGX_ERROR) { 217 if (rc == NGX_ERROR || rc == NGX_AGAIN) {
153 return rc;
154 }
155
156 if (rc == NGX_AGAIN) {
157 /* add the incoming hunk to the incoming chain */
158 ngx_add_hunk_to_chain(ctx->in, hunk, r->pool, NGX_ERROR);
159 return rc; 218 return rc;
160 } 219 }
161 220
162 /* NGX_OK */ 221 /* NGX_OK */
163 222
164 /* set our hunk free */ 223 /* set our hunk free */
165 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start; 224 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
166 225
167 /* repeat until we will have copied the whole incoming hunk */
168 } while (hunk->pos.mem < hunk->last.mem);
169
170 return NGX_OK;
171 }
172
173 /* the incoming chain ctx->in is not empty */
174
175 /* add the incoming hunk to the incoming chain */
176 if (hunk) {
177 for (ce = ctx->in; ce->next; ce = ce->next) {
178 /* void */ ;
179 }
180
181 ngx_add_hunk_to_chain(ce->next, hunk, r->pool, NGX_ERROR);
182 }
183
184 /* our hunk is still busy */
185 if (ctx->hunk->pos.mem < ctx->hunk->last.mem) {
186 rc = next_filter(r, NULL);
187
188 if (rc == NGX_ERROR || rc == NGX_AGAIN) {
189 return rc;
190 }
191
192 /* NGX_OK */
193 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
194 }
195
196 #if (NGX_SUPPRESS_WARN)
197 pe = NULL;
198 #endif
199
200 /* process the incoming chain ctx->in */
201 do {
202 /* find the hunks that do not need to be copied ... */
203 for (ce = ctx->in; ce; ce = ce->next) {
204 if (need_to_copy(r, ce->hunk)) {
205 break;
206 }
207 pe = ce;
208 }
209
210 /* ... and pass them to the next filter */
211 if (ctx->in != ce) {
212
213 ctx->out.hunk = ctx->in->hunk;
214 ctx->out.next = ctx->in->next;
215 ctx->in = ce;
216 pe->next = NULL;
217
218 rc = next_filter(r, &ctx->out);
219
220 if (rc == NGX_ERROR || rc == NGX_AGAIN) {
221 return rc;
222 }
223
224 /* NGX_OK */
225 if (ctx->in == NULL) {
226 return rc;
227 }
228 }
229
230
231 /* copy the first hunk or its part from the incoming chain ctx->in
232 to our hunk and pass it to the next filter */
233 do {
234 rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk);
235
236 if (rc == NGX_ERROR) {
237 return rc;
238 }
239
240 #if (NGX_FILE_AIO_READ)
241
242 if (rc == NGX_AGAIN) {
243 return rc;
244 }
245
246 #endif
247 ctx->out.hunk = ctx->hunk;
248 ctx->out.next = NULL;
249
250 rc = next_filter(r, &ctx->out);
251
252 if (rc == NGX_ERROR || rc == NGX_AGAIN) {
253 return rc;
254 }
255
256 /* NGX_OK */
257
258 /* set our hunk free */
259 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
260
261 /* repeat until we will have copied the whole first hunk from 226 /* repeat until we will have copied the whole first hunk from
262 the incoming chain ctx->in */ 227 the chain ctx->incoming */
263 } while (ctx->in->hunk->pos.mem < ctx->in->hunk->last.mem); 228 } while (ctx->incoming->hunk->pos.mem < ctx->incoming->hunk->last.mem);
264 229
265 /* delete the completed hunk from the incoming chain */ 230 /* delete the completed hunk from the incoming chain */
266 ctx->in = ctx->in->next; 231 ctx->incoming = ctx->incoming->next;
267 232
268 /* repeat until we will have processed the whole incoming chain ctx->in */ 233 /* repeat until we will have processed the whole chain ctx->incoming */
269 } while (ctx->in); 234 } while (ctx->incoming);
270 235
271 return NGX_OK; 236 return NGX_OK;
272 } 237 }
273
274
275 #else
276
277
278 int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk)
279 {
280 int rc, once;
281 u_int flags;
282 size_t size;
283 ngx_chain_t *ce;
284 ngx_http_output_filter_ctx_t *ctx;
285 ngx_http_output_filter_conf_t *conf;
286
287 ctx = (ngx_http_output_filter_ctx_t *)
288 ngx_http_get_module_ctx(r->main ? r->main : r,
289 ngx_http_output_filter_module);
290
291 if (ctx == NULL) {
292 ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module,
293 sizeof(ngx_http_output_filter_ctx_t));
294 }
295
296 if (hunk && (hunk->type & NGX_HUNK_LAST)) {
297 ctx->last = 1;
298 }
299
300 #if (NGX_SUPPRESS_WARN)
301 rc = NGX_ALERT;
302 #endif
303
304 for (once = 1; once || ctx->in; once = 0) {
305
306 /* input chain is not empty */
307 if (ctx->in) {
308
309 /* add hunk to input chain */
310 if (once && hunk) {
311 for (ce = ctx->in; ce->next; ce = ce->next) {
312 /* void */ ;
313 }
314
315 ngx_add_hunk_to_chain(ce->next, hunk, r->pool, NGX_ERROR);
316 }
317
318 /* our hunk is still busy */
319 if (ctx->hunk->pos.mem < ctx->hunk->last.mem) {
320 rc = ngx_http_output_filter_module_ctx.
321 next_output_body_filter(r, NULL);
322
323 /* our hunk is free */
324 } else {
325 ctx->out.hunk = ctx->hunk;
326
327 /* XXX: should we check hunk type before copy it ? */
328 rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk);
329 #if (NGX_FILE_AIO_READ)
330 if (rc == NGX_AGAIN) {
331 return rc;
332 }
333 #endif
334 if (rc == NGX_ERROR) {
335 return rc;
336 }
337
338 /* NGX_OK */
339
340 /* whole hunk is copied so we send to next filter chain part
341 up to next hunk that need to be copied */
342 if (ctx->in->hunk->pos.mem == ctx->in->hunk->last.mem) {
343 ctx->out.next = ctx->in->next;
344
345 for (ce = ctx->in->next; ce; ce = ce->next) {
346 if (ce->hunk->type & NGX_HUNK_FILE) {
347 break;
348 }
349
350 if ((ce->hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP))
351 && (r->filter & NGX_HTTP_FILTER_NEED_TEMP))
352 {
353 break;
354 }
355 }
356
357 ctx->out.next = ce;
358
359 } else {
360 ctx->out.next = NULL;
361 }
362
363 rc = ngx_http_output_filter_module_ctx.
364 next_output_body_filter(r, &ctx->out);
365 }
366
367 /* delete completed hunks from input chain */
368 for (ce = ctx->in; ce; ce = ce->next) {
369 if (ce->hunk->pos.file == ce->hunk->last.file) {
370 ctx->in = ce->next;
371 }
372 }
373
374 if (rc == NGX_OK && ctx->hunk) {
375 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
376 } else {
377 return rc;
378 }
379
380 /* input chain is empty */
381 } else {
382
383 if (hunk == NULL) {
384 rc = ngx_http_output_filter_module_ctx.
385 next_output_body_filter(r, NULL);
386
387 } else {
388
389 /* we need to copy hunk to our hunk */
390 if (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)
391 && (hunk->type & NGX_HUNK_FILE))
392 || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP)
393 && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))
394 ) {
395
396 /* out hunk is still busy */
397 if (ctx->hunk && ctx->hunk->pos.mem < ctx->hunk->last.mem) {
398 ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
399 NGX_ERROR);
400
401 rc = ngx_http_output_filter_module_ctx.
402 next_output_body_filter(r, NULL);
403
404 } else {
405 if (ctx->hunk == NULL) {
406
407 conf = (ngx_http_output_filter_conf_t *)
408 ngx_http_get_module_loc_conf(
409 r->main ? r->main : r,
410 ngx_http_output_filter_module);
411
412 if (hunk->type & NGX_HUNK_LAST) {
413 size = hunk->last.mem - hunk->pos.mem;
414 if (size > conf->hunk_size) {
415 size = conf->hunk_size;
416 }
417
418 } else {
419 size = conf->hunk_size;
420 }
421
422 ngx_test_null(ctx->hunk,
423 ngx_create_temp_hunk(r->pool, size,
424 50, 50),
425 NGX_ERROR);
426 ctx->hunk->type |= NGX_HUNK_RECYCLED;
427
428 rc = ngx_http_output_filter_copy_hunk(ctx->hunk,
429 hunk);
430 #if (NGX_FILE_AIO_READ)
431 if (rc == NGX_AGAIN) {
432 /* add hunk to input chain */
433 ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
434 NGX_ERROR);
435
436 return rc;
437 }
438 #endif
439 if (rc == NGX_ERROR) {
440 return rc;
441 }
442
443 if (hunk->pos.mem < hunk->last.mem) {
444 ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
445 NGX_ERROR);
446 }
447
448 ctx->out.hunk = ctx->hunk;
449 ctx->out.next = NULL;
450
451 rc = ngx_http_output_filter_module_ctx.
452 next_output_body_filter(r, &ctx->out);
453 }
454 }
455
456 } else {
457 ctx->out.hunk = hunk;
458 ctx->out.next = NULL;
459
460 rc = ngx_http_output_filter_module_ctx.
461 next_output_body_filter(r, &ctx->out);
462 }
463 }
464 }
465
466 /* set free our hunk if operation has completed */
467 if (rc == NGX_OK && ctx->hunk) {
468 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
469 }
470 }
471
472 #if (NGX_SUPPRESS_WARN)
473 if (rc == NGX_ALERT) {
474 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
475 "ngx_http_output_filter: rc == NGX_ALERT");
476 return NGX_ERROR;
477 }
478 #endif
479
480 if (rc == NGX_OK && ctx->last) {
481 return NGX_OK;
482 }
483
484 if (rc == NGX_OK) {
485 if (ctx->hunk) { /* XXX: double upper code ? */
486 ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
487 }
488 #if (NGX_LEVEL_EVENT)
489 ngx_del_event(r->connection->write, NGX_WRITE_EVENT);
490 #endif
491 }
492
493 return rc;
494 }
495
496 #endif
497 238
498 239
499 static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src) 240 static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src)
500 { 241 {
501 ssize_t n, size; 242 ssize_t n, size;
508 if (src->type & NGX_HUNK_FILE) { 249 if (src->type & NGX_HUNK_FILE) {
509 n = ngx_read_file(src->file, dst->pos.mem, size, src->pos.file); 250 n = ngx_read_file(src->file, dst->pos.mem, size, src->pos.file);
510 251
511 if (n == NGX_ERROR) { 252 if (n == NGX_ERROR) {
512 return n; 253 return n;
254 }
513 255
514 #if (NGX_FILE_AIO_READ) 256 #if (NGX_FILE_AIO_READ)
515 } else if (n == NGX_AGAIN) { 257
258 if (n == NGX_AGAIN) {
516 return n; 259 return n;
260 }
261
517 #endif 262 #endif
518 263
519 } else { 264 if (n != size) {
520 ngx_assert((n == size), /* void */ ; , src->file->log, 265 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
521 ngx_read_file_n " reads only %d of %d" _ 266 ngx_read_file_n " reads only %d of %d from file",
522 n _ size); 267 n, size);
268 if (n == 0) {
269 return NGX_ERROR;
270 }
523 } 271 }
524 272
525 src->pos.mem += n; 273 src->pos.mem += n;
526 dst->last.mem += n; 274 dst->last.mem += n;
527 275