Mercurial > hg > nginx
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 |