Mercurial > hg > nginx-quic
comparison src/event/ngx_event_proxy.c @ 75:869b10be682f
nginx-0.0.1-2003-04-14-21:04:58 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 14 Apr 2003 17:04:58 +0000 |
parents | |
children | 6127d7075471 |
comparison
equal
deleted
inserted
replaced
74:17ab1af8c3dd | 75:869b10be682f |
---|---|
1 | |
2 #include <ngx_event_proxy.h> | |
3 | |
4 | |
5 int ngx_event_proxy_read_upstream(ngx_event_proxy_t *p) | |
6 { | |
7 int n, rc, size; | |
8 ngx_hunk_t *h, *nh; | |
9 ngx_chain_t *chain, *temp, *entry, *next; | |
10 | |
11 p->level++; | |
12 | |
13 ngx_log_debug(p->log, "read upstream"); | |
14 | |
15 for ( ;; ) { | |
16 | |
17 /* use the free hunks if they exist */ | |
18 | |
19 if (p->free_hunks) { | |
20 chain = p->free_hunks; | |
21 p->free_hunks = NULL; | |
22 | |
23 ngx_log_debug(p->log, "free hunk: %08X:%d" _ chain->hunk _ | |
24 chain->hunk->end - chain->hunk->last); | |
25 | |
26 /* allocate a new hunk if it's still allowed */ | |
27 | |
28 } else if (p->allocated < p->max_block_size) { | |
29 ngx_test_null(h, | |
30 ngx_create_temp_hunk(p->pool, p->block_size, 20, 20), | |
31 NGX_ERROR); | |
32 | |
33 p->allocated += p->block_size; | |
34 | |
35 ngx_test_null(temp, ngx_alloc_chain_entry(p->pool), NGX_ERROR); | |
36 temp->hunk = h; | |
37 temp->next = NULL; | |
38 chain = temp; | |
39 | |
40 ngx_log_debug(p->log, "new hunk: %08X" _ chain->hunk); | |
41 | |
42 /* use the shadow hunks if they exist */ | |
43 | |
44 } else if (p->shadow_hunks) { | |
45 chain = p->shadow_hunks; | |
46 p->shadow_hunks = NULL; | |
47 | |
48 ngx_log_debug(p->log, "shadow hunk: %08X" _ chain->hunk); | |
49 | |
50 /* if it's allowed then save the incoming hunks to a temporary file, | |
51 move the saved hunks to a shadow chain, | |
52 and add the file hunks to an outgoing chain */ | |
53 | |
54 } else if (p->temp_offset < p->max_temp_size) { | |
55 rc = ngx_event_proxy_write_chain_to_temp_file(p); | |
56 | |
57 ngx_log_debug(p->log, "temp offset: %d" _ p->temp_offset); | |
58 | |
59 if (rc != NGX_OK) { | |
60 return rc; | |
61 } | |
62 | |
63 chain = p->shadow_hunks; | |
64 p->shadow_hunks = NULL; | |
65 | |
66 ngx_log_debug(p->log, "new shadow hunk: %08X" _ chain->hunk); | |
67 | |
68 /* if there're no hunks to read in then disable a level event */ | |
69 | |
70 } else { | |
71 if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { | |
72 p->block_upstream = 1; | |
73 } | |
74 | |
75 break; | |
76 } | |
77 | |
78 n = ngx_recv_chain(p->upstream, chain); | |
79 | |
80 ngx_log_debug(p->log, "recv_chain: %d" _ n); | |
81 | |
82 if (n == NGX_ERROR) { | |
83 p->upstream_error = 1; | |
84 return NGX_ERROR; | |
85 } | |
86 | |
87 if (n == NGX_AGAIN) { | |
88 if (p->upstream->read->blocked) { | |
89 if (ngx_add_event(p->upstream->read, NGX_READ_EVENT, | |
90 NGX_LEVEL_EVENT) == NGX_ERROR) { | |
91 return NGX_ERROR; | |
92 } | |
93 p->upstream->read->blocked = 0; | |
94 } | |
95 | |
96 return NGX_AGAIN; | |
97 } | |
98 | |
99 if (n == 0) { | |
100 p->free_hunks = chain; | |
101 p->upstream_eof = 1; | |
102 p->block_upstream = 0; | |
103 break; | |
104 } | |
105 | |
106 /* move the full hunks to a read chain | |
107 and the partial filled hunk to a free chain | |
108 and remove the shadow links for these hunks */ | |
109 | |
110 for (entry = chain; entry && n > 0; entry = next) { | |
111 next = entry->next; | |
112 entry->next = NULL; | |
113 | |
114 if (entry->hunk->shadow) { | |
115 for (h = entry->hunk->shadow; | |
116 (h->type & NGX_HUNK_LAST_SHADOW) == 0; | |
117 h = nh) | |
118 { | |
119 nh = h->shadow; | |
120 h->shadow = NULL; | |
121 h->type &= ~(NGX_HUNK_TEMP | |
122 |NGX_HUNK_IN_MEMORY | |
123 |NGX_HUNK_RECYCLED); | |
124 } | |
125 | |
126 h->shadow = NULL; | |
127 h->type &= ~(NGX_HUNK_TEMP | |
128 |NGX_HUNK_IN_MEMORY | |
129 |NGX_HUNK_RECYCLED | |
130 |NGX_HUNK_LAST_SHADOW); | |
131 entry->hunk->shadow = NULL; | |
132 } | |
133 | |
134 size = entry->hunk->end - entry->hunk->last; | |
135 | |
136 if (n >= size) { | |
137 entry->hunk->last = entry->hunk->end; | |
138 | |
139 if (p->read_hunks) { | |
140 p->last_read_hunk->next = entry; | |
141 | |
142 } else { | |
143 p->read_hunks = entry; | |
144 } | |
145 | |
146 p->last_read_hunk = entry; | |
147 | |
148 n -= size; | |
149 | |
150 /* the copy input filter */ | |
151 | |
152 if (p->input_filter == NULL) { | |
153 ngx_test_null(h, ngx_alloc_hunk(p->pool), NGX_ERROR); | |
154 ngx_memcpy(h, entry->hunk, sizeof(ngx_hunk_t)); | |
155 h->shadow = entry->hunk; | |
156 h->type |= NGX_HUNK_LAST_SHADOW; | |
157 | |
158 ngx_test_null(temp, ngx_alloc_chain_entry(p->pool), | |
159 NGX_ERROR); | |
160 temp->hunk = h; | |
161 temp->next = NULL; | |
162 | |
163 if (p->in_hunks) { | |
164 p->last_in_hunk->next = temp; | |
165 | |
166 } else { | |
167 p->in_hunks = temp; | |
168 } | |
169 | |
170 p->last_in_hunk = temp; | |
171 } | |
172 | |
173 } else { | |
174 entry->hunk->last += n; | |
175 p->free_hunks = entry; | |
176 | |
177 n = 0; | |
178 } | |
179 } | |
180 | |
181 ngx_log_debug(p->log, "rest chain: %08X" _ entry); | |
182 | |
183 /* if the rest hunks are shadow then move them to a shadow chain | |
184 otherwise add them to a free chain */ | |
185 | |
186 if (entry) { | |
187 if (entry->hunk->shadow) { | |
188 p->shadow_hunks = entry; | |
189 | |
190 } else { | |
191 if (p->free_hunks) { | |
192 p->free_hunks->next = entry; | |
193 | |
194 } else { | |
195 p->free_hunks = entry; | |
196 } | |
197 } | |
198 | |
199 p->block_upstream = 0; | |
200 break; | |
201 } | |
202 | |
203 /* the input filter i.e. that moves HTTP/1.1 chunks | |
204 from a read chain to an incoming chain */ | |
205 | |
206 if (p->input_filter) { | |
207 if (p->input_filter(p) == NGX_ERROR) { | |
208 return NGX_ERROR; | |
209 } | |
210 } | |
211 } | |
212 | |
213 ngx_log_debug(p->log, "eof: %d block: %d" _ | |
214 p->upstream_eof _ p->block_upstream); | |
215 | |
216 /* if there's the end of upstream response then move | |
217 the partially filled hunk from a free chain to an incoming chain */ | |
218 | |
219 if (p->upstream_eof) { | |
220 p->upstream->read->ready = 0; | |
221 | |
222 if (p->free_hunks | |
223 && p->free_hunks->hunk->pos < p->free_hunks->hunk->last) | |
224 { | |
225 if (p->input_filter) { | |
226 if (p->input_filter(p) == NGX_ERROR) { | |
227 return NGX_ERROR; | |
228 } | |
229 | |
230 } else { | |
231 entry = p->free_hunks; | |
232 | |
233 if (p->in_hunks) { | |
234 p->last_in_hunk->next = entry; | |
235 | |
236 } else { | |
237 p->in_hunks = entry; | |
238 } | |
239 | |
240 p->last_in_hunk = entry; | |
241 } | |
242 | |
243 p->free_hunks = entry->next; | |
244 entry->next = NULL; | |
245 } | |
246 | |
247 #if 0 | |
248 /* free the unneeded hunks */ | |
249 | |
250 for (entry = p->free_hunks; entry; entry = ce->next) { | |
251 ngx_free_hunk(p->pool, entry->hunk); | |
252 } | |
253 #endif | |
254 | |
255 if (p->in_hunks) { | |
256 p->last_in_hunk->hunk->type |= NGX_HUNK_LAST; | |
257 | |
258 } else if (p->out_hunks) { | |
259 p->last_out_hunk->hunk->type |= NGX_HUNK_LAST; | |
260 } | |
261 } | |
262 | |
263 if (p->cachable) { | |
264 if (p->in_hunks) { | |
265 rc = ngx_event_proxy_write_chain_to_temp_file(p); | |
266 if (rc != NGX_OK) { | |
267 return rc; | |
268 } | |
269 } | |
270 | |
271 if (p->out_hunks && p->client->write->ready) { | |
272 rc = ngx_event_proxy_write_to_client(p); | |
273 } | |
274 | |
275 } else if ((p->out_hunks || p->in_hunks) && p->client->write->ready) { | |
276 rc = ngx_event_proxy_write_to_client(p); | |
277 } | |
278 | |
279 p->level--; | |
280 | |
281 ngx_log_debug(p->log, "level: %d" _ p->level); | |
282 | |
283 if (p->level == 0 && p->block_upstream) { | |
284 p->upstream->read->blocked = 1; | |
285 if (ngx_del_event(p->upstream->read, NGX_READ_EVENT, 0) == NGX_ERROR) { | |
286 return NGX_ERROR; | |
287 } | |
288 | |
289 return NGX_AGAIN; | |
290 } | |
291 | |
292 if (p->upstream_eof) { | |
293 return NGX_OK; | |
294 } else { | |
295 return NGX_AGAIN; | |
296 } | |
297 } | |
298 | |
299 | |
300 int ngx_event_proxy_write_to_client(ngx_event_proxy_t *p) | |
301 { | |
302 int rc; | |
303 ngx_hunk_t *h; | |
304 ngx_chain_t *entry; | |
305 | |
306 ngx_log_debug(p->log, "write to client"); | |
307 | |
308 h = p->busy_hunk; | |
309 | |
310 for ( ;; ) { | |
311 | |
312 if (h == NULL) { | |
313 if (p->out_hunks) { | |
314 entry = p->out_hunks; | |
315 p->out_hunks = entry->next; | |
316 h = entry->hunk; | |
317 | |
318 if (p->shadow_hunks) { | |
319 if (p->shadow_hunks->hunk == h->shadow) { | |
320 p->shadow_hunks = p->shadow_hunks->next; | |
321 } | |
322 } | |
323 | |
324 entry->next = NULL; | |
325 | |
326 } else if (p->cachable == 0 && p->in_hunks) { | |
327 entry = p->in_hunks; | |
328 p->in_hunks = entry->next; | |
329 h = entry->hunk; | |
330 entry->next = NULL; | |
331 } | |
332 | |
333 ngx_log_debug(p->log, "event proxy write hunk: %08X:%08X" _ h _ h->pos); | |
334 | |
335 if (h == NULL) { | |
336 if (p->upstream->read->ready) { | |
337 rc = ngx_event_proxy_read_upstream(p); | |
338 } | |
339 | |
340 return NGX_OK; | |
341 } | |
342 } | |
343 | |
344 ngx_log_debug(p->log, "event proxy write: %d" _ h->last - h->pos); | |
345 | |
346 rc = p->output_filter(p->output_data, h); | |
347 | |
348 ngx_log_debug(p->log, "event proxy: %d" _ rc); | |
349 | |
350 if (rc == NGX_ERROR) { | |
351 return NGX_ERROR; | |
352 } | |
353 | |
354 if (rc == NGX_AGAIN | |
355 || (h->type & NGX_HUNK_IN_MEMORY && h->pos < h->last) | |
356 || (h->type & NGX_HUNK_FILE && h->file_pos < h->file_last)) | |
357 { | |
358 if (p->busy_hunk == NULL) { | |
359 p->busy_hunk = h; | |
360 } | |
361 return NGX_AGAIN; | |
362 } | |
363 | |
364 p->busy_hunk = NULL; | |
365 | |
366 /* if the complete hunk is the file hunk and it has a shadow hunk | |
367 then add a shadow hunk to a free chain */ | |
368 | |
369 if (h->type & NGX_HUNK_FILE) { | |
370 if (p->cachable == 0 && p->out_hunks == NULL) { | |
371 p->temp_offset = 0; | |
372 } | |
373 } | |
374 | |
375 if ((h->type & NGX_HUNK_LAST_SHADOW) == 0) { | |
376 h = NULL; | |
377 continue; | |
378 } | |
379 | |
380 | |
381 h->shadow->shadow = NULL; | |
382 h = h->shadow; | |
383 | |
384 #if 0 | |
385 /* free the unneeded hunk */ | |
386 | |
387 if (p->upstream_eof) { | |
388 ngx_free_hunk(p->pool, h); | |
389 continue; | |
390 } | |
391 #endif | |
392 | |
393 h->pos = h->last = h->start; | |
394 | |
395 entry->hunk = h; | |
396 | |
397 /* if the first hunk in a free chain is partially filled | |
398 then add the complete hunk after the first free hunk */ | |
399 | |
400 if (p->free_hunks | |
401 && p->free_hunks->hunk->start != p->free_hunks->hunk->last) | |
402 { | |
403 entry->next = p->free_hunks->next; | |
404 p->free_hunks->next = entry; | |
405 | |
406 } else { | |
407 entry->next = p->free_hunks; | |
408 p->free_hunks = entry; | |
409 } | |
410 | |
411 h = NULL; | |
412 } | |
413 } | |
414 | |
415 | |
416 int ngx_event_proxy_write_chain_to_temp_file(ngx_event_proxy_t *p) | |
417 { | |
418 int i, rc, size; | |
419 ngx_hunk_t *h; | |
420 ngx_chain_t *entry, *next, *saved_in, *saved_read; | |
421 | |
422 ngx_log_debug(p->log, "write to file"); | |
423 | |
424 if (p->temp_file->fd == NGX_INVALID_FILE) { | |
425 rc = ngx_create_temp_file(p->temp_file, p->temp_path, p->pool, | |
426 p->number, p->random, p->cachable); | |
427 | |
428 if (rc != NGX_OK) { | |
429 return rc; | |
430 } | |
431 | |
432 if (p->cachable == 0 && p->temp_file_warn) { | |
433 ngx_log_error(NGX_LOG_WARN, p->log, 0, p->temp_file_warn); | |
434 } | |
435 } | |
436 | |
437 if (p->cachable == 0) { | |
438 | |
439 entry = p->read_hunks; | |
440 size = 0; | |
441 | |
442 do { | |
443 size += entry->hunk->last - entry->hunk->pos; | |
444 if (size >= p->file_block_size) { | |
445 break; | |
446 } | |
447 entry = entry->next; | |
448 | |
449 } while (entry); | |
450 | |
451 saved_read = entry->next; | |
452 entry->next = NULL; | |
453 | |
454 if (saved_read) { | |
455 for (entry = p->in_hunks; entry->next; entry = entry->next) { | |
456 if (entry->next->hunk->shadow == saved_read->hunk) { | |
457 break; | |
458 } | |
459 } | |
460 saved_in = entry->next; | |
461 entry->next = NULL; | |
462 | |
463 } else { | |
464 saved_in = NULL; | |
465 } | |
466 | |
467 } else { | |
468 saved_read = NULL; | |
469 saved_in = NULL; | |
470 } | |
471 | |
472 if (ngx_write_chain_to_file(p->temp_file, p->in_hunks, p->temp_offset, | |
473 p->pool) == NGX_ERROR) { | |
474 return NGX_ERROR; | |
475 } | |
476 | |
477 for (entry = p->in_hunks; entry; entry = next) { | |
478 next = entry->next; | |
479 entry->next = NULL; | |
480 | |
481 h = entry->hunk; | |
482 h->type |= NGX_HUNK_FILE; | |
483 h->file = p->temp_file; | |
484 h->file_pos = p->temp_offset; | |
485 p->temp_offset += h->last - h->pos; | |
486 h->file_last = p->temp_offset; | |
487 | |
488 ngx_log_debug(p->log, "event proxy file hunk: %08X:%08X" _ h _ h->pos); | |
489 | |
490 if (entry->hunk->type & NGX_HUNK_LAST_SHADOW) { | |
491 entry->hunk->shadow->last = entry->hunk->shadow->pos; | |
492 } | |
493 | |
494 if (p->out_hunks) { | |
495 p->last_out_hunk->next = entry; | |
496 | |
497 } else { | |
498 p->out_hunks = entry; | |
499 } | |
500 | |
501 p->last_out_hunk = entry; | |
502 } | |
503 | |
504 p->shadow_hunks = p->read_hunks; | |
505 | |
506 p->read_hunks = saved_read; | |
507 p->in_hunks = saved_in; | |
508 | |
509 return NGX_OK; | |
510 } |