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 }