Mercurial > hg > nginx
comparison src/http/ngx_http_output_filter.c @ 160:e7e094d34162
nginx-0.0.1-2003-10-27-11:53:49 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 27 Oct 2003 08:53:49 +0000 |
parents | 46eb23d9471d |
children | 4db54fdbcbe7 |
comparison
equal
deleted
inserted
replaced
159:981e4af2a425 | 160:e7e094d34162 |
---|---|
7 typedef struct { | 7 typedef struct { |
8 ngx_bufs_t bufs; | 8 ngx_bufs_t bufs; |
9 } ngx_http_output_filter_conf_t; | 9 } ngx_http_output_filter_conf_t; |
10 | 10 |
11 | 11 |
12 typedef struct { | |
13 | |
14 /* | |
15 * NOTE: we do not need now to store hunk in ctx, | |
16 * it's needed for the future NGX_FILE_AIO_READ support only | |
17 */ | |
18 | |
19 ngx_hunk_t *hunk; | |
20 | |
21 ngx_chain_t *in; | |
22 | |
23 /* TODO: out and last_out should be local variables */ | |
24 ngx_chain_t *out; | |
25 ngx_chain_t **last_out; | |
26 /* */ | |
27 | |
28 ngx_chain_t *free; | |
29 ngx_chain_t *busy; | |
30 | |
31 int hunks; | |
32 } ngx_http_output_filter_ctx_t; | |
33 | |
34 | |
35 ngx_inline static int ngx_http_output_filter_need_to_copy(ngx_http_request_t *r, | |
36 ngx_hunk_t *hunk); | |
37 static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src, | |
38 int sendfile); | |
39 static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf); | 12 static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf); |
40 static char *ngx_http_output_filter_merge_conf(ngx_conf_t *cf, | 13 static char *ngx_http_output_filter_merge_conf(ngx_conf_t *cf, |
41 void *parent, void *child); | 14 void *parent, void *child); |
42 | 15 |
43 | 16 |
77 | 50 |
78 | 51 |
79 | 52 |
80 int ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) | 53 int ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) |
81 { | 54 { |
82 int rc, last; | 55 ngx_output_chain_ctx_t *ctx; |
83 ssize_t size; | |
84 ngx_chain_t *cl; | |
85 ngx_http_output_filter_ctx_t *ctx; | |
86 ngx_http_output_filter_conf_t *conf; | 56 ngx_http_output_filter_conf_t *conf; |
87 | 57 |
88 ctx = ngx_http_get_module_ctx(r->main ? r->main : r, | 58 ctx = ngx_http_get_module_ctx(r->main ? r->main : r, |
89 ngx_http_output_filter_module); | 59 ngx_http_output_filter_module); |
90 | 60 |
91 if (ctx == NULL) { | 61 if (ctx == NULL) { |
62 conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, | |
63 ngx_http_output_filter_module); | |
64 | |
92 ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module, | 65 ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module, |
93 sizeof(ngx_http_output_filter_ctx_t), NGX_ERROR); | 66 sizeof(ngx_output_chain_ctx_t), NGX_ERROR); |
94 ctx->last_out = &ctx->out; | 67 |
68 ctx->sendfile = r->sendfile; | |
69 ctx->need_in_memory = r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY; | |
70 ctx->need_in_temp = r->filter & NGX_HTTP_FILTER_NEED_TEMP; | |
71 | |
72 ctx->pool = r->pool; | |
73 ctx->bufs = conf->bufs; | |
74 ctx->tag = (ngx_hunk_tag_t) &ngx_http_output_filter_module; | |
75 | |
76 ctx->output_filter = (ngx_output_chain_filter_pt) | |
77 ngx_http_top_body_filter; | |
78 ctx->output_ctx = r; | |
79 | |
95 } | 80 } |
96 | 81 |
97 /* | 82 return ngx_output_chain(ctx, in); |
98 * the short path for the case when the chain ctx->in is empty | |
99 * and the incoming chain is empty too or it has the single hunk | |
100 * that does not require the copy | |
101 */ | |
102 | |
103 if (ctx->in == NULL) { | |
104 | |
105 if (in == NULL) { | |
106 return ngx_http_top_body_filter(r, in); | |
107 } | |
108 | |
109 if (in->next == NULL | |
110 && (!ngx_http_output_filter_need_to_copy(r, in->hunk))) | |
111 { | |
112 return ngx_http_top_body_filter(r, in); | |
113 } | |
114 } | |
115 | |
116 /* add the incoming hunk to the chain ctx->in */ | |
117 | |
118 if (in) { | |
119 if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { | |
120 return NGX_ERROR; | |
121 } | |
122 } | |
123 | |
124 conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, | |
125 ngx_http_output_filter_module); | |
126 | |
127 last = NGX_NONE; | |
128 | |
129 for ( ;; ) { | |
130 | |
131 while (ctx->in) { | |
132 | |
133 if (!ngx_http_output_filter_need_to_copy(r, ctx->in->hunk)) { | |
134 | |
135 /* move the chain link to the chain ctx->out */ | |
136 | |
137 cl = ctx->in; | |
138 ctx->in = cl->next; | |
139 | |
140 *ctx->last_out = cl; | |
141 ctx->last_out = &cl->next; | |
142 cl->next = NULL; | |
143 | |
144 continue; | |
145 } | |
146 | |
147 if (ctx->hunk == NULL) { | |
148 | |
149 /* get the free hunk */ | |
150 | |
151 if (ctx->free) { | |
152 ctx->hunk = ctx->free->hunk; | |
153 ctx->free = ctx->free->next; | |
154 | |
155 } else if (ctx->hunks < conf->bufs.num) { | |
156 ngx_test_null(ctx->hunk, | |
157 ngx_create_temp_hunk(r->pool, conf->bufs.size, | |
158 0, 0), | |
159 NGX_ERROR); | |
160 ctx->hunk->tag = (ngx_hunk_tag_t) | |
161 &ngx_http_output_filter_module; | |
162 ctx->hunk->type |= NGX_HUNK_RECYCLED; | |
163 ctx->hunks++; | |
164 | |
165 } else { | |
166 break; | |
167 } | |
168 } | |
169 | |
170 rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk, | |
171 r->sendfile); | |
172 | |
173 if (rc == NGX_ERROR) { | |
174 return rc; | |
175 } | |
176 | |
177 #if (NGX_FILE_AIO_READ) | |
178 if (rc == NGX_AGAIN) { | |
179 if (ctx->out) { | |
180 break; | |
181 } | |
182 return rc; | |
183 } | |
184 #endif | |
185 | |
186 if (ctx->in->hunk->type & NGX_HUNK_IN_MEMORY) { | |
187 size = ctx->in->hunk->last - ctx->in->hunk->pos; | |
188 | |
189 } else { | |
190 size = (size_t) (ctx->in->hunk->file_last | |
191 - ctx->in->hunk->file_pos); | |
192 } | |
193 | |
194 /* delete the completed hunk from the chain ctx->in */ | |
195 | |
196 if (size == 0) { | |
197 ctx->in = ctx->in->next; | |
198 } | |
199 | |
200 ngx_alloc_link_and_set_hunk(cl, ctx->hunk, r->pool, NGX_ERROR); | |
201 *ctx->last_out = cl; | |
202 ctx->last_out = &cl->next; | |
203 ctx->hunk = NULL; | |
204 | |
205 if (ctx->free == NULL) { | |
206 break; | |
207 } | |
208 } | |
209 | |
210 if (ctx->out == NULL && last != NGX_NONE) { | |
211 return last; | |
212 } | |
213 | |
214 last = ngx_http_top_body_filter(r, ctx->out); | |
215 | |
216 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out, | |
217 (ngx_hunk_tag_t) &ngx_http_output_filter_module); | |
218 ctx->last_out = &ctx->out; | |
219 } | |
220 } | |
221 | |
222 | |
223 ngx_inline static int ngx_http_output_filter_need_to_copy(ngx_http_request_t *r, | |
224 ngx_hunk_t *hunk) | |
225 { | |
226 if (ngx_hunk_special(hunk)) { | |
227 return 0; | |
228 } | |
229 | |
230 if (!r->sendfile) { | |
231 return 1; | |
232 } | |
233 | |
234 if ((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) | |
235 && (!(hunk->type & NGX_HUNK_IN_MEMORY))) | |
236 { | |
237 return 1; | |
238 } | |
239 | |
240 | |
241 if ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) | |
242 && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP))) | |
243 { | |
244 return 1; | |
245 } | |
246 | |
247 return 0; | |
248 } | |
249 | |
250 | |
251 static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src, | |
252 int sendfile) | |
253 { | |
254 ssize_t n, size; | |
255 | |
256 if (src->type & NGX_HUNK_IN_MEMORY) { | |
257 size = src->last - src->pos; | |
258 } else { | |
259 size = (size_t) (src->file_last - src->file_pos); | |
260 } | |
261 | |
262 if (size > (dst->end - dst->pos)) { | |
263 size = dst->end - dst->pos; | |
264 } | |
265 | |
266 if (src->type & NGX_HUNK_IN_MEMORY) { | |
267 ngx_memcpy(dst->pos, src->pos, size); | |
268 src->pos += size; | |
269 dst->last += size; | |
270 | |
271 if (src->type & NGX_HUNK_FILE) { | |
272 src->file_pos += size; | |
273 } | |
274 | |
275 if ((src->type & NGX_HUNK_LAST) && src->pos == src->last) { | |
276 dst->type |= NGX_HUNK_LAST; | |
277 } | |
278 | |
279 } else { | |
280 n = ngx_read_file(src->file, dst->pos, size, src->file_pos); | |
281 | |
282 if (n == 0) { | |
283 ngx_log_debug(src->file->log, "READ: %qd:%qd %X:%X %X:%X" _ | |
284 src->file_pos _ src->file_last _ | |
285 dst->pos _ dst->last _ dst->start _ dst->end); | |
286 } | |
287 | |
288 if (n == NGX_ERROR) { | |
289 return n; | |
290 } | |
291 | |
292 #if (NGX_FILE_AIO_READ) | |
293 if (n == NGX_AGAIN) { | |
294 return n; | |
295 } | |
296 #endif | |
297 | |
298 if (n != size) { | |
299 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0, | |
300 ngx_read_file_n " reads only %d of %d from file", | |
301 n, size); | |
302 if (n == 0) { | |
303 return NGX_ERROR; | |
304 } | |
305 } | |
306 | |
307 src->file_pos += n; | |
308 dst->last += n; | |
309 | |
310 if (!sendfile) { | |
311 dst->type &= ~NGX_HUNK_FILE; | |
312 } | |
313 | |
314 if ((src->type & NGX_HUNK_LAST) && src->file_pos == src->file_last) { | |
315 dst->type |= NGX_HUNK_LAST; | |
316 } | |
317 } | |
318 | |
319 return NGX_OK; | |
320 } | 83 } |
321 | 84 |
322 | 85 |
323 static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf) | 86 static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf) |
324 { | 87 { |
338 void *parent, void *child) | 101 void *parent, void *child) |
339 { | 102 { |
340 ngx_http_output_filter_conf_t *prev = parent; | 103 ngx_http_output_filter_conf_t *prev = parent; |
341 ngx_http_output_filter_conf_t *conf = child; | 104 ngx_http_output_filter_conf_t *conf = child; |
342 | 105 |
343 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 2, 32768); | 106 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768); |
344 | 107 |
345 return NULL; | 108 return NULL; |
346 } | 109 } |