Mercurial > hg > nginx
comparison src/http/ngx_http_output_filter.c @ 141:656d468f4ead
nginx-0.0.1-2003-10-08-19:32:54 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Wed, 08 Oct 2003 15:32:54 +0000 |
parents | e29909bd9b8a |
children | cb77c084acdb |
comparison
equal
deleted
inserted
replaced
140:e32405df0e77 | 141:656d468f4ead |
---|---|
3 #include <ngx_core.h> | 3 #include <ngx_core.h> |
4 #include <ngx_http.h> | 4 #include <ngx_http.h> |
5 | 5 |
6 | 6 |
7 typedef struct { | 7 typedef struct { |
8 ssize_t hunk_size; | 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 { | 12 typedef struct { |
13 ngx_hunk_t *hunk; /* the temporary hunk to copy */ | 13 |
14 ngx_chain_t *incoming; | 14 /* |
15 ngx_chain_t in; /* one chain entry for input */ | 15 * NOTE: we do not need now to store hunk in ctx, |
16 ngx_chain_t out; /* one chain entry for output */ | 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 ngx_chain_t *out; | |
23 ngx_chain_t **last_out; | |
24 ngx_chain_t *free; | |
25 ngx_chain_t *busy; | |
26 | |
27 int hunks; | |
17 } ngx_http_output_filter_ctx_t; | 28 } ngx_http_output_filter_ctx_t; |
18 | 29 |
19 | 30 |
20 static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src); | 31 static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src); |
21 static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf); | 32 static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf); |
23 void *parent, void *child); | 34 void *parent, void *child); |
24 | 35 |
25 | 36 |
26 static ngx_command_t ngx_http_output_filter_commands[] = { | 37 static ngx_command_t ngx_http_output_filter_commands[] = { |
27 | 38 |
28 {ngx_string("output_buffer"), | 39 {ngx_string("output_buffers"), |
29 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | 40 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, |
30 ngx_conf_set_size_slot, | 41 ngx_conf_set_bufs_slot, |
31 NGX_HTTP_LOC_CONF_OFFSET, | 42 NGX_HTTP_LOC_CONF_OFFSET, |
32 offsetof(ngx_http_output_filter_conf_t, hunk_size), | 43 offsetof(ngx_http_output_filter_conf_t, bufs), |
33 NULL}, | 44 NULL}, |
34 | 45 |
35 ngx_null_command | 46 ngx_null_command |
36 }; | 47 }; |
37 | 48 |
56 NULL, /* init module */ | 67 NULL, /* init module */ |
57 NULL /* init child */ | 68 NULL /* init child */ |
58 }; | 69 }; |
59 | 70 |
60 | 71 |
61 #define next_filter (*ngx_http_top_body_filter) | 72 #define ngx_next_filter (*ngx_http_top_body_filter) |
62 | 73 |
63 #define need_to_copy(r, hunk) \ | 74 #define need_to_copy(r, hunk) \ |
64 (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) \ | 75 (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) \ |
65 && (hunk->type & NGX_HUNK_IN_MEMORY) == 0) \ | 76 && (hunk->type & NGX_HUNK_IN_MEMORY) == 0) \ |
66 || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) \ | 77 || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) \ |
67 && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))) | 78 && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))) |
68 | 79 |
69 | 80 |
81 | |
70 int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk) | 82 int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk) |
71 { | 83 { |
72 int rc; | 84 int rc, last; |
73 ssize_t size; | 85 ssize_t size; |
74 ngx_chain_t *ce, *le; | 86 ngx_chain_t out, *ce, **le; |
75 ngx_http_output_filter_ctx_t *ctx; | 87 ngx_http_output_filter_ctx_t *ctx; |
76 ngx_http_output_filter_conf_t *conf; | 88 ngx_http_output_filter_conf_t *conf; |
77 | 89 |
78 ctx = ngx_http_get_module_ctx(r->main ? r->main : r, | 90 ctx = ngx_http_get_module_ctx(r->main ? r->main : r, |
79 ngx_http_output_filter_module); | 91 ngx_http_output_filter_module); |
80 | 92 |
81 if (ctx == NULL) { | 93 if (ctx == NULL) { |
82 ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module, | 94 ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module, |
83 sizeof(ngx_http_output_filter_ctx_t), NGX_ERROR); | 95 sizeof(ngx_http_output_filter_ctx_t), NGX_ERROR); |
84 } | 96 ctx->last_out = &ctx->out; |
85 | 97 } |
86 /* the short path for the case when the chain ctx->incoming is empty | 98 |
87 and there is no hunk or the hunk does not require the copy */ | 99 /* |
88 if (ctx->incoming == NULL) { | 100 * the short path for the case when the chain ctx->in is empty |
101 * and there's no hunk or the hunk does not require the copy | |
102 */ | |
103 | |
104 if (ctx->in == NULL) { | |
89 | 105 |
90 if (hunk == NULL) { | 106 if (hunk == NULL) { |
91 return next_filter(r, NULL); | 107 return ngx_next_filter(r, NULL); |
92 } | 108 } |
93 | 109 |
94 /* we do not need to copy the incoming hunk to our hunk */ | |
95 if (!need_to_copy(r, hunk)) { | 110 if (!need_to_copy(r, hunk)) { |
96 ctx->out.hunk = hunk; | 111 out.hunk = hunk; |
97 ctx->out.next = NULL; | 112 out.next = NULL; |
98 return next_filter(r, &ctx->out); | 113 return ngx_next_filter(r, &out); |
99 } | 114 } |
100 } | 115 } |
101 | 116 |
102 /* add the incoming hunk to the chain ctx->incoming */ | 117 /* add the incoming hunk to the chain ctx->in */ |
118 | |
103 if (hunk) { | 119 if (hunk) { |
104 | 120 le = &ctx->in; |
105 /* the output of the only hunk is common case so we have | 121 |
106 the special chain entry ctx->in for it */ | 122 for (ce = ctx->in; ce; ce = ce->next) { |
107 if (ctx->incoming == NULL) { | 123 le = &ce->next; |
108 ctx->in.hunk = hunk; | 124 } |
109 ctx->in.next = NULL; | 125 |
110 ctx->incoming = &ctx->in; | 126 ngx_add_hunk_to_chain(ce, hunk, r->pool, NGX_ERROR); |
111 | 127 *le = ce; |
112 } else { | 128 } |
113 for (ce = ctx->incoming; ce->next; ce = ce->next) { /* void */ ; } | 129 |
114 ngx_add_hunk_to_chain(ce->next, hunk, r->pool, NGX_ERROR); | 130 conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, |
115 } | 131 ngx_http_output_filter_module); |
116 } | 132 |
117 | 133 last = NGX_NONE; |
118 /* allocate our hunk if it's needed */ | 134 |
119 if (ctx->hunk == NULL) { | 135 for ( ;; ) { |
120 | 136 |
121 conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, | 137 while (ctx->in) { |
122 ngx_http_output_filter_module); | 138 |
123 | 139 if (!need_to_copy(r, ctx->in->hunk)) { |
124 if (hunk->type & NGX_HUNK_LAST) { | 140 |
125 if (hunk->type & NGX_HUNK_IN_MEMORY) { | 141 /* move the chain entry to the chain ctx->out */ |
126 size = hunk->last - hunk->pos; | 142 |
127 } else { | 143 ce = ctx->in; |
128 size = (size_t) (hunk->file_last - hunk->file_pos); | 144 ctx->in = ce->next; |
129 } | 145 |
130 | 146 *ctx->last_out = ce; |
131 if (size > conf->hunk_size) { | 147 ctx->last_out = &ce->next; |
132 size = conf->hunk_size; | 148 ce->next = NULL; |
133 } | 149 |
134 | 150 continue; |
135 } else { | 151 } |
136 size = conf->hunk_size; | 152 |
137 } | 153 if (ctx->hunk == NULL) { |
138 | 154 |
139 ngx_test_null(ctx->hunk, | 155 /* get the free hunk */ |
140 ngx_create_temp_hunk(r->pool, size, 50, 50), | 156 |
141 NGX_ERROR); | 157 if (ctx->free) { |
142 ctx->hunk->type |= NGX_HUNK_RECYCLED; | 158 ctx->hunk = ctx->free->hunk; |
143 | 159 ctx->free = ctx->free->next; |
144 | 160 |
145 /* our hunk is still busy */ | 161 } else if (ctx->hunks < conf->bufs.num) { |
146 } else if (ctx->hunk->pos < ctx->hunk->last) { | 162 ngx_test_null(ctx->hunk, |
147 rc = next_filter(r, NULL); | 163 ngx_create_temp_hunk(r->pool, conf->bufs.size, |
148 | 164 0, 0), |
149 if (rc == NGX_ERROR || rc == NGX_AGAIN) { | 165 NGX_ERROR); |
150 return rc; | 166 ctx->hunk->type |= NGX_HUNK_RECYCLED; |
151 } | 167 ctx->hunks++; |
152 | 168 |
153 /* NGX_OK */ | 169 } else { |
154 #if 1 | 170 break; |
155 /* set our hunk free */ | 171 } |
156 ctx->hunk->pos = ctx->hunk->last = ctx->hunk->start; | 172 } |
157 #endif | 173 |
158 } | 174 rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk); |
159 | 175 |
160 #if (NGX_SUPPRESS_WARN) | |
161 le = NULL; | |
162 #endif | |
163 | |
164 /* process the chain ctx->incoming */ | |
165 do { | |
166 /* find the hunks that do not need to be copied ... */ | |
167 for (ce = ctx->incoming; ce; ce = ce->next) { | |
168 if (need_to_copy(r, ce->hunk)) { | |
169 break; | |
170 } | |
171 le = ce; | |
172 } | |
173 | |
174 /* ... and pass them to the next filter */ | |
175 if (ctx->incoming != ce) { | |
176 | |
177 ctx->out.hunk = ctx->incoming->hunk; | |
178 ctx->out.next = ctx->incoming->next; | |
179 ctx->incoming = ce; | |
180 le->next = NULL; | |
181 | |
182 rc = next_filter(r, &ctx->out); | |
183 if (rc == NGX_ERROR || rc == NGX_AGAIN) { | |
184 return rc; | |
185 } | |
186 | |
187 /* NGX_OK */ | |
188 if (ctx->incoming == NULL) { | |
189 return rc; | |
190 } | |
191 } | |
192 | |
193 /* copy the first hunk or its part from the chain ctx->incoming | |
194 to our hunk and pass it to the next filter */ | |
195 do { | |
196 rc = ngx_http_output_filter_copy_hunk(ctx->hunk, | |
197 ctx->incoming->hunk); | |
198 if (rc == NGX_ERROR) { | 176 if (rc == NGX_ERROR) { |
199 return rc; | 177 return rc; |
200 } | 178 } |
201 | 179 |
202 #if (NGX_FILE_AIO_READ) | 180 #if (NGX_FILE_AIO_READ) |
203 if (rc == NGX_AGAIN) { | 181 if (rc == NGX_AGAIN) { |
204 return rc; | 182 return rc; |
205 } | 183 } |
206 #endif | 184 #endif |
207 | 185 |
208 if (ctx->incoming->hunk->type & NGX_HUNK_IN_MEMORY) { | 186 if (ctx->in->hunk->type & NGX_HUNK_IN_MEMORY) { |
209 size = ctx->incoming->hunk->last - ctx->incoming->hunk->pos; | 187 size = ctx->in->hunk->last - ctx->in->hunk->pos; |
210 | 188 |
211 } else { | 189 } else { |
212 size = (size_t) (ctx->incoming->hunk->file_last | 190 size = (size_t) (ctx->in->hunk->file_last |
213 - ctx->incoming->hunk->file_pos); | 191 - ctx->in->hunk->file_pos); |
214 } | 192 } |
215 | 193 |
216 /* delete the completed hunk from the incoming chain */ | 194 /* delete the completed hunk from the chain ctx->in */ |
195 | |
217 if (size == 0) { | 196 if (size == 0) { |
218 ctx->incoming = ctx->incoming->next; | 197 ctx->in = ctx->in->next; |
219 } | 198 } |
220 | 199 |
221 ctx->out.hunk = ctx->hunk; | 200 ngx_add_hunk_to_chain(ce, ctx->hunk, r->pool, NGX_ERROR); |
222 ctx->out.next = NULL; | 201 *ctx->last_out = ce; |
223 | 202 ctx->last_out = &ce->next; |
224 rc = next_filter(r, &ctx->out); | 203 ctx->hunk = NULL; |
225 if (rc == NGX_ERROR || rc == NGX_AGAIN) { | 204 } |
226 return rc; | 205 |
227 } | 206 if (ctx->out == NULL && last != NGX_NONE) { |
228 | 207 return last; |
229 /* NGX_OK */ | 208 } |
230 #if 1 | 209 |
231 /* set our hunk free */ | 210 last = ngx_next_filter(r, ctx->out); |
232 ctx->hunk->pos = ctx->hunk->last = ctx->hunk->start; | 211 |
233 #endif | 212 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out); |
234 | 213 ctx->last_out = &ctx->out; |
235 /* repeat until we will have copied the whole first hunk from | 214 } |
236 the chain ctx->incoming */ | |
237 | |
238 } while (size); | |
239 | |
240 /* repeat until we will have processed the whole chain ctx->incoming */ | |
241 } while (ctx->incoming); | |
242 | |
243 return NGX_OK; | |
244 } | 215 } |
245 | 216 |
246 | 217 |
247 static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src) | 218 static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src) |
248 { | 219 { |
317 | 288 |
318 ngx_test_null(conf, | 289 ngx_test_null(conf, |
319 ngx_palloc(cf->pool, sizeof(ngx_http_output_filter_conf_t)), | 290 ngx_palloc(cf->pool, sizeof(ngx_http_output_filter_conf_t)), |
320 NULL); | 291 NULL); |
321 | 292 |
322 conf->hunk_size = NGX_CONF_UNSET; | 293 conf->bufs.num = 0; |
323 | 294 |
324 return conf; | 295 return conf; |
325 } | 296 } |
326 | 297 |
327 | 298 |
329 void *parent, void *child) | 300 void *parent, void *child) |
330 { | 301 { |
331 ngx_http_output_filter_conf_t *prev = parent; | 302 ngx_http_output_filter_conf_t *prev = parent; |
332 ngx_http_output_filter_conf_t *conf = child; | 303 ngx_http_output_filter_conf_t *conf = child; |
333 | 304 |
334 ngx_conf_merge_size_value(conf->hunk_size, prev->hunk_size, 32768); | 305 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 2, 32768); |
335 | 306 |
336 return NULL; | 307 return NULL; |
337 } | 308 } |