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 }