comparison src/http/modules/proxy/ngx_http_proxy_handler.c @ 170:c42be4185301

nginx-0.0.1-2003-11-03-01:56:18 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 02 Nov 2003 22:56:18 +0000
parents edf29bb717da
children aff0e5d32af8
comparison
equal deleted inserted replaced
169:edf29bb717da 170:c42be4185301
1 1
2 #include <ngx_config.h> 2 #include <ngx_config.h>
3 #include <ngx_core.h> 3 #include <ngx_core.h>
4 #include <ngx_event.h>
5 #include <ngx_event_connect.h>
6 #include <ngx_event_pipe.h>
7 #include <ngx_http.h> 4 #include <ngx_http.h>
8 #include <ngx_http_proxy_handler.h> 5 #include <ngx_http_proxy_handler.h>
9 6
10 7
11
12 static int ngx_http_proxy_handler(ngx_http_request_t *r); 8 static int ngx_http_proxy_handler(ngx_http_request_t *r);
9 static int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p);
13 static void ngx_http_proxy_init_request(void *data); 10 static void ngx_http_proxy_init_request(void *data);
14 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p); 11 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p);
15 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev); 12 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev);
13 static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p);
16 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p); 14 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p);
17 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev); 15 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev);
18 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev); 16 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev);
19 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *); 17 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *);
20 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p); 18 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
21 static void ngx_http_proxy_process_body(ngx_event_t *ev); 19 static void ngx_http_proxy_process_body(ngx_event_t *ev);
22 20 static int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p);
23 static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p); 21
24 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type); 22 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type);
25 static int ngx_http_proxy_log_state(ngx_http_proxy_ctx_t *p, int status); 23 static int ngx_http_proxy_log_state(ngx_http_proxy_ctx_t *p, int status);
26 static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc); 24 static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc);
27 static void ngx_http_proxy_close_connection(ngx_connection_t *c); 25 static void ngx_http_proxy_close_connection(ngx_connection_t *c);
28 26
40 38
41 39
42 static ngx_conf_bitmask_t next_upstream_masks[] = { 40 static ngx_conf_bitmask_t next_upstream_masks[] = {
43 { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR }, 41 { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR },
44 { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT }, 42 { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT },
45 { ngx_string("http_header"), NGX_HTTP_PROXY_FT_HTTP_HEADER }, 43 { ngx_string("invalid_header"), NGX_HTTP_PROXY_FT_INVALID_HEADER },
46 { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 }, 44 { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 },
45 { ngx_string("http_404"), NGX_HTTP_PROXY_FT_HTTP_404 },
46 { ngx_null_string, 0 }
47 };
48
49
50 static ngx_conf_bitmask_t use_stale_masks[] = {
51 { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR },
52 { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT },
53 { ngx_string("invalid_header"), NGX_HTTP_PROXY_FT_INVALID_HEADER },
54 { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 },
55 { ngx_string("busy_lock"), NGX_HTTP_PROXY_FT_BUSY_LOCK },
56 { ngx_string("max_waiting"), NGX_HTTP_PROXY_FT_MAX_WAITING },
47 { ngx_null_string, 0 } 57 { ngx_null_string, 0 }
48 }; 58 };
49 59
50 static ngx_command_t ngx_http_proxy_commands[] = { 60 static ngx_command_t ngx_http_proxy_commands[] = {
51 61
103 ngx_conf_set_size_slot, 113 ngx_conf_set_size_slot,
104 NGX_HTTP_LOC_CONF_OFFSET, 114 NGX_HTTP_LOC_CONF_OFFSET,
105 offsetof(ngx_http_proxy_loc_conf_t, busy_buffers_size), 115 offsetof(ngx_http_proxy_loc_conf_t, busy_buffers_size),
106 NULL }, 116 NULL },
107 117
118 { ngx_string("proxy_cache_path"),
119 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
120 ngx_conf_set_path_slot,
121 NGX_HTTP_LOC_CONF_OFFSET,
122 offsetof(ngx_http_proxy_loc_conf_t, cache_path),
123 NULL },
124
108 { ngx_string("proxy_temp_path"), 125 { ngx_string("proxy_temp_path"),
109 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, 126 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
110 ngx_conf_set_path_slot, 127 ngx_conf_set_path_slot,
111 NGX_HTTP_LOC_CONF_OFFSET, 128 NGX_HTTP_LOC_CONF_OFFSET,
112 offsetof(ngx_http_proxy_loc_conf_t, temp_path), 129 offsetof(ngx_http_proxy_loc_conf_t, temp_path),
117 ngx_conf_set_size_slot, 134 ngx_conf_set_size_slot,
118 NGX_HTTP_LOC_CONF_OFFSET, 135 NGX_HTTP_LOC_CONF_OFFSET,
119 offsetof(ngx_http_proxy_loc_conf_t, temp_file_write_size), 136 offsetof(ngx_http_proxy_loc_conf_t, temp_file_write_size),
120 NULL }, 137 NULL },
121 138
139 { ngx_string("proxy_cache"),
140 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
141 ngx_conf_set_flag_slot,
142 NGX_HTTP_LOC_CONF_OFFSET,
143 offsetof(ngx_http_proxy_loc_conf_t, cache),
144 NULL },
145
122 { ngx_string("proxy_pass_server"), 146 { ngx_string("proxy_pass_server"),
123 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 147 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
124 ngx_conf_set_flag_slot, 148 ngx_conf_set_flag_slot,
125 NGX_HTTP_LOC_CONF_OFFSET, 149 NGX_HTTP_LOC_CONF_OFFSET,
126 offsetof(ngx_http_proxy_loc_conf_t, pass_server), 150 offsetof(ngx_http_proxy_loc_conf_t, pass_server),
130 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, 154 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
131 ngx_conf_set_bitmask_slot, 155 ngx_conf_set_bitmask_slot,
132 NGX_HTTP_LOC_CONF_OFFSET, 156 NGX_HTTP_LOC_CONF_OFFSET,
133 offsetof(ngx_http_proxy_loc_conf_t, next_upstream), 157 offsetof(ngx_http_proxy_loc_conf_t, next_upstream),
134 &next_upstream_masks }, 158 &next_upstream_masks },
159
160 { ngx_string("proxy_use_stale"),
161 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
162 ngx_conf_set_bitmask_slot,
163 NGX_HTTP_LOC_CONF_OFFSET,
164 offsetof(ngx_http_proxy_loc_conf_t, use_stale),
165 &use_stale_masks },
135 166
136 ngx_null_command 167 ngx_null_command
137 }; 168 };
138 169
139 170
170 "upstream sent invalid header", 201 "upstream sent invalid header",
171 "upstream sent too long header line" 202 "upstream sent too long header line"
172 }; 203 };
173 204
174 205
175 static ngx_http_header_t headers_in[] = { 206 ngx_http_header_t ngx_http_proxy_headers_in[] = {
176 { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) }, 207 { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) },
177 { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) }, 208 { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) },
178 { ngx_string("Connection"), 209 { ngx_string("Connection"),
179 offsetof(ngx_http_proxy_headers_in_t, connection) }, 210 offsetof(ngx_http_proxy_headers_in_t, connection) },
180 { ngx_string("Content-Type"), 211 { ngx_string("Content-Type"),
196 227
197 228
198 229
199 static int ngx_http_proxy_handler(ngx_http_request_t *r) 230 static int ngx_http_proxy_handler(ngx_http_request_t *r)
200 { 231 {
201 ngx_http_proxy_ctx_t *p; 232 int rc;
233 char *last;
234 ngx_http_cache_ctx_t *cctx;
235 ngx_http_proxy_ctx_t *p;
236 ngx_http_proxy_upstream_t *u;
202 237
203 ngx_http_create_ctx(r, p, ngx_http_proxy_module, 238 ngx_http_create_ctx(r, p, ngx_http_proxy_module,
204 sizeof(ngx_http_proxy_ctx_t), 239 sizeof(ngx_http_proxy_ctx_t),
205 NGX_HTTP_INTERNAL_SERVER_ERROR); 240 NGX_HTTP_INTERNAL_SERVER_ERROR);
206 241
207 p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); 242 p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
243 p->request = r;
244
245 /* TODO: we currently support reverse proxy only */
246 p->accel = 1;
247
248 if (!p->lcf->cache || r->bypass_cache) {
249 return ngx_http_proxy_request_upstream(p);
250 }
251
252 rc = ngx_http_proxy_get_cached_response(p);
253
254 if (rc == NGX_OK) {
255 return ngx_http_proxy_process_cached_response(p);
256 }
257
258 if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
259 return rc;
260 }
261
262 if (rc == NGX_DECLINED || rc == NGX_STALE) {
263 return ngx_http_proxy_request_upstream(p);
264 }
265
266 return NGX_DONE;
267 }
268
269
270 static int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p)
271 {
272 ngx_http_request_t *r;
273
274 r = p->request;
275
208 p->upstream.peers = p->lcf->peers; 276 p->upstream.peers = p->lcf->peers;
209 p->upstream.tries = p->lcf->peers->number; 277 p->upstream.tries = p->lcf->peers->number;
210 278
211 ngx_init_array(p->states, r->pool, p->upstream.tries, 279 ngx_init_array(p->states, r->pool, p->upstream.tries,
212 sizeof(ngx_http_proxy_state_t), 280 sizeof(ngx_http_proxy_state_t),
213 NGX_HTTP_INTERNAL_SERVER_ERROR); 281 NGX_HTTP_INTERNAL_SERVER_ERROR);
214 282
215 p->request = r;
216 p->method = r->method; 283 p->method = r->method;
217 284
218 /* TODO: we currently support reverse proxy only */ 285 /* STUB */ p->cachable = p->lcf->cache;
219 p->accel = 1;
220 286
221 if (r->headers_in.content_length_n > 0) { 287 if (r->headers_in.content_length_n > 0) {
222 ngx_test_null(r->temp_file, 288 if (!(r->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
223 ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)), 289 return NGX_HTTP_INTERNAL_SERVER_ERROR;
224 NGX_HTTP_INTERNAL_SERVER_ERROR); 290 }
225 291
226 r->temp_file->file.fd = NGX_INVALID_FILE; 292 r->temp_file->file.fd = NGX_INVALID_FILE;
227 r->temp_file->file.log = r->connection->log; 293 r->temp_file->file.log = r->connection->log;
228 r->temp_file->path = *p->lcf->temp_path; 294 r->temp_file->path = p->lcf->temp_path;
229 r->temp_file->pool = r->pool; 295 r->temp_file->pool = r->pool;
230 r->temp_file->warn = "a client request body is buffered " 296 r->temp_file->warn = "a client request body is buffered "
231 "to a temporary file"; 297 "to a temporary file";
232 /* STUB */ r->temp_file->persistent = 1; 298 /* r->temp_file->persistent = 0; */
233 299
234 r->request_body_handler = ngx_http_proxy_init_request; 300 r->request_body_handler = ngx_http_proxy_init_request;
235 r->data = p; 301 r->data = p;
236 302
237 /* TODO: we ignore return value of ngx_http_read_client_request_body */ 303 /* TODO: we ignore return value of ngx_http_read_client_request_body,
304 probably we should not return anything */
238 ngx_http_read_client_request_body(r, p->lcf->request_buffer_size); 305 ngx_http_read_client_request_body(r, p->lcf->request_buffer_size);
239 306
240 return NGX_DONE; 307 return NGX_DONE;
241 } 308 }
242 309
252 319
253 ngx_chain_t *cl; 320 ngx_chain_t *cl;
254 ngx_http_request_t *r; 321 ngx_http_request_t *r;
255 ngx_output_chain_ctx_t *octx; 322 ngx_output_chain_ctx_t *octx;
256 ngx_chain_writer_ctx_t *wctx; 323 ngx_chain_writer_ctx_t *wctx;
257
258 324
259 r = p->request; 325 r = p->request;
260 326
261 ngx_log_debug(r->connection->log, "timer_set: %d" _ 327 ngx_log_debug(r->connection->log, "timer_set: %d" _
262 r->connection->read->timer_set); 328 r->connection->read->timer_set);
281 p->saved_handler = r->connection->log->handler; 347 p->saved_handler = r->connection->log->handler;
282 r->connection->log->data = p; 348 r->connection->log->data = p;
283 r->connection->log->handler = ngx_http_proxy_log_error; 349 r->connection->log->handler = ngx_http_proxy_log_error;
284 p->action = "connecting to upstream"; 350 p->action = "connecting to upstream";
285 351
286 octx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); 352 if (!(octx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)))) {
287 if (octx == NULL) {
288 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); 353 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
289 return; 354 return;
290 } 355 }
291 356
292 p->output_chain_ctx = octx; 357 p->output_chain_ctx = octx;
293
294 if (r->request_body_hunk) {
295 octx->free = ngx_alloc_chain_link(r->pool);
296 if (octx->free == NULL) {
297 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
298 }
299 octx->free->hunk = r->request_body_hunk;
300 octx->free->next = NULL;
301 }
302
303 octx->sendfile = r->sendfile; 358 octx->sendfile = r->sendfile;
304 octx->pool = r->pool; 359 octx->pool = r->pool;
305 octx->bufs.num = 1; 360 octx->bufs.num = 1;
306 octx->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module; 361 octx->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
307 octx->output_filter = (ngx_output_chain_filter_pt) ngx_chain_writer; 362 octx->output_filter = (ngx_output_chain_filter_pt) ngx_chain_writer;
308 363
309 wctx = ngx_pcalloc(r->pool, sizeof(ngx_chain_writer_ctx_t)); 364 if (!(wctx = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)))) {
310 if (wctx == NULL) {
311 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); 365 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
312 return; 366 return;
313 } 367 }
314 368
315 octx->output_ctx = wctx; 369 octx->output_ctx = wctx;
316 wctx->pool = r->pool; 370 wctx->pool = r->pool;
317 wctx->last = &wctx->out; 371
318 372 ngx_http_proxy_connect(p);
319 ngx_http_proxy_send_request(p);
320 } 373 }
321 374
322 375
323 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) 376 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
324 { 377 {
439 ngx_http_proxy_ctx_t *p; 492 ngx_http_proxy_ctx_t *p;
440 493
441 c = wev->data; 494 c = wev->data;
442 p = c->data; 495 p = c->data;
443 496
444 p->action = "sending request to upstream";
445
446 if (wev->timedout) { 497 if (wev->timedout) {
447 p->timedout = 1; 498 p->action = "sending request to upstream";
448 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); 499 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
449 return; 500 return;
450 } 501 }
451 502
452 ngx_http_proxy_send_request(p); 503 ngx_http_proxy_send_request(p);
453 504 }
454 return; 505
455 } 506
456 507 static void ngx_http_proxy_dummy_handler(ngx_event_t *wev)
457 508 {
458 #if 0 509 ngx_log_debug(wev->log, "dummy handler");
459 510 }
460 static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p) 511
461 { 512
462 int rc; 513 static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
463 ngx_chain_t *cl; 514 {
464 ngx_connection_t *c; 515 int rc;
465 516 ngx_chain_t *cl;
466 for ( ;; ) { 517 ngx_connection_t *c;
467 p->action = "connecting to upstream"; 518 ngx_http_request_t *r;
468 519 ngx_output_chain_ctx_t *octx;
469 rc = ngx_event_connect_peer(&p->upstream); 520
470 521 p->action = "connecting to upstream";
471 if (rc == NGX_ERROR) { 522
523 rc = ngx_event_connect_peer(&p->upstream);
524
525 if (rc == NGX_ERROR) {
526 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
527 return;
528 }
529
530 if (rc == NGX_CONNECT_ERROR) {
531 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
532 return;
533 }
534
535 p->upstream.connection->data = p;
536 p->upstream.connection->write->event_handler =
537 ngx_http_proxy_send_request_handler;
538 p->upstream.connection->read->event_handler =
539 ngx_http_proxy_process_upstream_status_line;
540
541 r = p->request;
542 c = p->upstream.connection;
543 c->pool = r->pool;
544 c->read->log = c->write->log = c->log = r->connection->log;
545
546 octx = p->output_chain_ctx;
547
548 if (p->upstream.tries > 1 && p->request_sent) {
549 ngx_http_proxy_reinit_upstream(p);
550 }
551
552 /* init or reinit ngx_output_chain() context */
553
554 if (r->request_body_hunk) {
555 if (!(octx->free = ngx_alloc_chain_link(r->pool))) {
472 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); 556 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
473 return NGX_DONE; 557 return;
474 } 558 }
475 559
476 if (rc == NGX_CONNECT_ERROR) { 560 octx->free->hunk = r->request_body_hunk;
477 ngx_event_connect_peer_failed(&p->upstream); 561 octx->free->next = NULL;
478 562 octx->hunks = 1;
479 if (ngx_http_proxy_log_state(p, NGX_HTTP_BAD_GATEWAY) == NGX_ERROR) 563
480 { 564 r->request_body_hunk->pos = r->request_body_hunk->start;
481 ngx_http_proxy_finalize_request(p, 565 r->request_body_hunk->last = r->request_body_hunk->start;
482 NGX_HTTP_INTERNAL_SERVER_ERROR); 566 }
483 return NGX_DONE; 567
484 } 568 p->request_sent = 0;
485 569
486 if (p->upstream.tries == 0) { 570 if (rc == NGX_AGAIN) {
487 ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
488 return NGX_DONE;
489 }
490
491 continue;
492 }
493
494 p->upstream.connection->data = p;
495 p->upstream.connection->write->event_handler =
496 ngx_http_proxy_send_request_handler;
497 p->upstream.connection->read->event_handler =
498 ngx_http_proxy_process_upstream_status_line;
499
500 c = p->upstream.connection;
501 c->pool = p->request->pool;
502 c->read->log = c->write->log = c->log = p->request->connection->log;
503
504 if (p->upstream.tries > 1 && p->request_sent) {
505
506 /* reinit the request chain */
507
508 for (cl = p->request->request_hunks; cl; cl = cl->next) {
509 cl->hunk->pos = cl->hunk->start;
510 }
511 }
512
513 p->request_sent = 0;
514 p->timedout = 0;
515
516 if (rc == NGX_OK) {
517 return ngx_http_proxy_send_request0(p);
518 }
519
520 /* rc == NGX_AGAIN */
521
522 ngx_add_timer(c->write, p->lcf->connect_timeout); 571 ngx_add_timer(c->write, p->lcf->connect_timeout);
523 572 return;
524 return NGX_AGAIN; 573 }
525 } 574
526 } 575 /* rc == NGX_OK */
527 576
528 577 #if 1 /* test only */
529 static int ngx_http_proxy_send_request0(ngx_http_proxy_ctx_t *p) 578
530 { 579 if (c->read->ready) {
580 /* post aio operation */
581 ngx_http_proxy_process_upstream_status_line(c->read);
582 return;
583 }
584 #endif
585
586 ngx_http_proxy_send_request(p);
587 }
588
589
590 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p)
591 {
592 int rc;
531 ngx_connection_t *c; 593 ngx_connection_t *c;
532 ngx_chain_writer_ctx_t *wctx; 594 ngx_chain_writer_ctx_t *wctx;
533 595
534 c = p->upstream.connection; 596 c = p->upstream.connection;
535 597
598 #if (HAVE_KQUEUE)
599
600 if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT)
601 && !p->request_sent
602 && c->write->kq_eof)
603 {
604 ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno,
605 "connect() failed");
606
607 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
608 return;
609 }
610
611 #endif
612
536 p->action = "sending request to upstream"; 613 p->action = "sending request to upstream";
614
537 wctx = p->output_chain_ctx->output_ctx; 615 wctx = p->output_chain_ctx->output_ctx;
616 wctx->out = NULL;
617 wctx->last = &wctx->out;
538 wctx->connection = c; 618 wctx->connection = c;
619
539 rc = ngx_output_chain(p->output_chain_ctx, 620 rc = ngx_output_chain(p->output_chain_ctx,
540 !p->request_sent ? p->request->request_hunks: 621 p->request_sent ? NULL : p->request->request_hunks);
541 NULL); 622
542 if (rc == NGX_ERROR) { 623 if (rc == NGX_ERROR) {
543 return ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); 624 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
625 return;
544 } 626 }
545 627
546 p->request_sent = 1; 628 p->request_sent = 1;
547 629
548 if (c->write->timer_set) { 630 if (c->write->timer_set) {
556 { 638 {
557 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); 639 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
558 return; 640 return;
559 } 641 }
560 642
561 return NGX_AGAIN; 643 return;
562 } 644 }
563 645
564 /* rc == NGX_OK */ 646 /* rc == NGX_OK */
565 647
648 if (c->tcp_nopush) {
649 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
650 ngx_log_error(NGX_LOG_CRIT, c->log,
651 ngx_socket_errno,
652 ngx_tcp_push_n " failed");
653 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
654 return;
655 }
656
657 c->tcp_nopush = 0;
658 return;
659 }
660
661 #if 0
566 if (c->read->ready) { 662 if (c->read->ready) {
663
567 /* post aio operation */ 664 /* post aio operation */
665
666 /*
667 * although we can post aio operation just in the end
668 * of ngx_http_proxy_connect() CHECK IT !!!
669 * it's better to do here because we postpone header buffer allocation
670 */
671
568 ngx_http_proxy_process_upstream_status_line(c->read); 672 ngx_http_proxy_process_upstream_status_line(c->read);
569 } 673 return;
570 674 }
571 if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
572 ngx_http_proxy_finalize_request(p,
573 NGX_HTTP_INTERNAL_SERVER_ERROR);
574 return;
575 }
576
577 if (c->tcp_nopush) {
578 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
579 ngx_log_error(NGX_LOG_CRIT, c->log,
580 ngx_socket_errno,
581 ngx_tcp_push_n " failed");
582 ngx_http_proxy_finalize_request(p,
583 NGX_HTTP_INTERNAL_SERVER_ERROR);
584 return;
585 }
586
587 c->tcp_nopush = 0;
588 }
589 }
590
591 return;
592 }
593
594 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
595
596 return NGX_OK;
597 }
598
599
600 #endif 675 #endif
601 676
602 677 p->upstream.connection->write->event_handler = ngx_http_proxy_dummy_handler;
603 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p) 678
604 { 679 if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
605 int rc; 680 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
606 ngx_chain_t *cl; 681 return;
607 ngx_connection_t *c;
608 ngx_chain_writer_ctx_t *wctx;
609
610 c = p->upstream.connection;
611
612 for ( ;; ) {
613
614 if (c) {
615 p->action = "sending request to upstream";
616 wctx = p->output_chain_ctx->output_ctx;
617 wctx->connection = c;
618 rc = ngx_output_chain(p->output_chain_ctx,
619 !p->request_sent ? p->request->request_hunks:
620 NULL);
621
622 if (rc != NGX_ERROR) {
623 p->request_sent = 1;
624
625 if (c->write->timer_set) {
626 ngx_del_timer(c->write);
627 }
628
629 if (rc == NGX_AGAIN) {
630 ngx_add_timer(c->write, p->lcf->send_timeout);
631
632 if (ngx_handle_write_event(c->write, /* STUB: lowat */ 0)
633 == NGX_ERROR)
634 {
635 ngx_http_proxy_finalize_request(p,
636 NGX_HTTP_INTERNAL_SERVER_ERROR);
637 return;
638 }
639
640 } else {
641
642 /* rc == NGX_OK */
643
644 if (c->read->ready) {
645 /* post aio operation */
646 ngx_http_proxy_process_upstream_status_line(c->read);
647 }
648
649 if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
650 ngx_http_proxy_finalize_request(p,
651 NGX_HTTP_INTERNAL_SERVER_ERROR);
652 return;
653 }
654
655 if (c->tcp_nopush) {
656 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
657 ngx_log_error(NGX_LOG_CRIT, c->log,
658 ngx_socket_errno,
659 ngx_tcp_push_n " failed");
660 ngx_http_proxy_finalize_request(p,
661 NGX_HTTP_INTERNAL_SERVER_ERROR);
662 return;
663 }
664 c->tcp_nopush = 0;
665 }
666 }
667
668 return;
669 }
670
671 ngx_event_connect_peer_failed(&p->upstream);
672 ngx_http_proxy_close_connection(c);
673
674 if (p->upstream.tries == 0
675 || !(p->lcf->next_upstream & NGX_HTTP_PROXY_FT_ERROR))
676 {
677 ngx_http_proxy_finalize_request(p,
678 p->timedout ? NGX_HTTP_GATEWAY_TIME_OUT:
679 NGX_HTTP_BAD_GATEWAY);
680 return;
681 }
682
683 if (!p->fatal_error) {
684 ngx_http_proxy_send_request(p);
685 return;
686 }
687 }
688
689 for ( ;; ) {
690 p->action = "connecting to upstream";
691
692 rc = ngx_event_connect_peer(&p->upstream);
693
694 if (rc == NGX_ERROR) {
695 ngx_http_proxy_finalize_request(p,
696 NGX_HTTP_INTERNAL_SERVER_ERROR);
697 return;
698 }
699
700 if (rc == NGX_CONNECT_ERROR) {
701 ngx_event_connect_peer_failed(&p->upstream);
702
703 if (p->upstream.tries == 0) {
704 ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
705 return;
706 }
707
708 continue;
709 }
710
711 p->upstream.connection->data = p;
712 p->upstream.connection->write->event_handler =
713 ngx_http_proxy_send_request_handler;
714 p->upstream.connection->read->event_handler =
715 ngx_http_proxy_process_upstream_status_line;
716
717 c = p->upstream.connection;
718 c->pool = p->request->pool;
719 c->read->log = c->write->log = c->log = p->request->connection->log;
720
721 if (p->upstream.tries > 1 && p->request_sent) {
722
723 /* reinit the request chain */
724
725 for (cl = p->request->request_hunks; cl; cl = cl->next) {
726 cl->hunk->pos = cl->hunk->start;
727 }
728 }
729
730 p->request_sent = 0;
731 p->timedout = 0;
732
733 if (rc == NGX_OK) {
734 break;
735 }
736
737 /* rc == NGX_AGAIN */
738
739 ngx_add_timer(c->write, p->lcf->connect_timeout);
740
741 return;
742 }
743 } 682 }
744 } 683 }
745 684
746 685
747 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev) 686 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
751 ngx_connection_t *c; 690 ngx_connection_t *c;
752 ngx_http_proxy_ctx_t *p; 691 ngx_http_proxy_ctx_t *p;
753 692
754 c = rev->data; 693 c = rev->data;
755 p = c->data; 694 p = c->data;
756
757 p->action = "reading upstream status line"; 695 p->action = "reading upstream status line";
758 696
759 ngx_log_debug(rev->log, "http proxy process status line"); 697 ngx_log_debug(rev->log, "http proxy process status line");
760 698
761 if (rev->timedout) { 699 if (rev->timedout) {
762 p->timedout = 1;
763 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); 700 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
764 return; 701 return;
765 } 702 }
766 703
767 if (p->header_in == NULL) { 704 if (p->header_in == NULL) {
770 if (p->header_in == NULL) { 707 if (p->header_in == NULL) {
771 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); 708 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
772 return; 709 return;
773 } 710 }
774 p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module; 711 p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
712
713 if (p->cache) {
714 p->header_in->pos += p->cache->ctx.header.size;
715 p->header_in->last = p->header_in->pos;
716 }
775 } 717 }
776 718
777 n = ngx_http_proxy_read_upstream_header(p); 719 n = ngx_http_proxy_read_upstream_header(p);
778 720
779 if (n == NGX_ERROR) { 721 if (n == NGX_AGAIN) {
722 return;
723 }
724
725 if (n == 0) {
726 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
727 "upstream prematurely closed connection");
728 }
729
730 if (n == NGX_ERROR || n == 0) {
780 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); 731 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
781 return; 732 return;
782 } 733 }
783 734
784 if (n == NGX_AGAIN) { 735 p->upstream.cached = 0;
785 return;
786 }
787 736
788 rc = ngx_http_proxy_parse_status_line(p); 737 rc = ngx_http_proxy_parse_status_line(p);
789 738
790 if (rc == NGX_AGAIN) { 739 if (rc == NGX_AGAIN) {
791 if (p->header_in->pos == p->header_in->last) { 740 if (p->header_in->pos == p->header_in->last) {
792 ngx_log_error(NGX_LOG_ERR, rev->log, 0, 741 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
793 "upstream sent too long status line"); 742 "upstream sent too long status line");
794 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER); 743 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
795 } 744 }
796
797 return; 745 return;
798 } 746 }
799 747
800 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { 748 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
801 ngx_log_error(NGX_LOG_ERR, rev->log, 0, 749 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
802 "upstream sent no valid HTTP/1.0 header"); 750 "upstream sent no valid HTTP/1.0 header");
803 751
804 if (p->accel) { 752 if (p->accel) {
805 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER); 753 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
806 754
807 } else { 755 } else {
808 p->request->http_version = NGX_HTTP_VERSION_9; 756 p->request->http_version = NGX_HTTP_VERSION_9;
809 p->status = NGX_HTTP_OK; 757 p->status = NGX_HTTP_OK;
810 ngx_http_proxy_send_response(p); 758 ngx_http_proxy_send_response(p);
813 return; 761 return;
814 } 762 }
815 763
816 /* rc == NGX_OK */ 764 /* rc == NGX_OK */
817 765
818 if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR 766 if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR) {
819 && p->upstream.tries > 1 767
820 && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500)) 768 if (p->upstream.tries > 1
821 { 769 && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500))
822 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500); 770 {
823 return; 771 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500);
772 return;
773 }
774
775 if (p->upstream.tries == 0
776 && p->stale
777 && (p->lcf->use_stale & NGX_HTTP_PROXY_FT_HTTP_500))
778 {
779 /*
780 * TODO: use stale cached response if it exists and enabled
781 */
782
783 return;
784 }
824 } 785 }
825 786
826 p->status_line.len = p->status_end - p->status_start; 787 p->status_line.len = p->status_end - p->status_start;
827 p->status_line.data = ngx_palloc(p->request->pool, p->status_line.len + 1); 788 p->status_line.data = ngx_palloc(p->request->pool, p->status_line.len + 1);
828 if (p->status_line.data == NULL) { 789 if (p->status_line.data == NULL) {
840 p->headers_in.headers = ngx_create_table(p->request->pool, 20); 801 p->headers_in.headers = ngx_create_table(p->request->pool, 20);
841 } 802 }
842 803
843 c->read->event_handler = ngx_http_proxy_process_upstream_headers; 804 c->read->event_handler = ngx_http_proxy_process_upstream_headers;
844 ngx_http_proxy_process_upstream_headers(rev); 805 ngx_http_proxy_process_upstream_headers(rev);
845
846 return;
847 } 806 }
848 807
849 808
850 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev) 809 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
851 { 810 {
857 ngx_http_proxy_ctx_t *p; 816 ngx_http_proxy_ctx_t *p;
858 817
859 c = rev->data; 818 c = rev->data;
860 p = c->data; 819 p = c->data;
861 r = p->request; 820 r = p->request;
862
863 p->action = "reading upstream headers"; 821 p->action = "reading upstream headers";
864 822
865 ngx_log_debug(rev->log, "http proxy process header line"); 823 ngx_log_debug(rev->log, "http proxy process header line");
866 824
867 if (rev->timedout) { 825 if (rev->timedout) {
868 p->timedout = 1;
869 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); 826 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
870 return; 827 return;
871 } 828 }
872 829
873 rc = NGX_AGAIN; 830 rc = NGX_AGAIN;
874 831
875 for ( ;; ) { 832 for ( ;; ) {
876 if (rc == NGX_AGAIN) { 833 if (rc == NGX_AGAIN) {
877 n = ngx_http_proxy_read_upstream_header(p); 834 n = ngx_http_proxy_read_upstream_header(p);
878 835
879 if (n == NGX_ERROR) { 836 if (n == 0) {
837 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
838 "upstream prematurely closed connection");
839 }
840
841 if (n == NGX_ERROR || n == 0) {
880 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); 842 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
881 return; 843 return;
882 } 844 }
883 845
884 if (n == NGX_AGAIN) { 846 if (n == NGX_AGAIN) {
890 852
891 if (rc == NGX_OK) { 853 if (rc == NGX_OK) {
892 854
893 /* a header line has been parsed successfully */ 855 /* a header line has been parsed successfully */
894 856
895 if (!(h = ngx_http_add_header(&p->headers_in, headers_in))) { 857 h = ngx_http_add_header(&p->headers_in, ngx_http_proxy_headers_in);
858 if (h == NULL) {
896 ngx_http_proxy_finalize_request(p, 859 ngx_http_proxy_finalize_request(p,
897 NGX_HTTP_INTERNAL_SERVER_ERROR); 860 NGX_HTTP_INTERNAL_SERVER_ERROR);
898 return; 861 return;
899 } 862 }
900 863
911 874
912 h->value.data = h->key.data + h->key.len + 1; 875 h->value.data = h->key.data + h->key.len + 1;
913 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); 876 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
914 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); 877 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
915 878
916 for (i = 0; headers_in[i].name.len != 0; i++) { 879 for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
917 if (headers_in[i].name.len != h->key.len) { 880 if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
918 continue; 881 continue;
919 } 882 }
920 883
921 if (ngx_strcasecmp(headers_in[i].name.data, h->key.data) == 0) { 884 if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
922 *((ngx_table_elt_t **) 885 h->key.data) == 0)
923 ((char *) &p->headers_in + headers_in[i].offset)) = h; 886 {
887 *((ngx_table_elt_t **) ((char *) &p->headers_in
888 + ngx_http_proxy_headers_in[i].offset)) = h;
924 break; 889 break;
925 } 890 }
926 } 891 }
927 892
928 ngx_log_debug(c->log, "HTTP proxy header: '%s: %s'" _ 893 ngx_log_debug(c->log, "HTTP proxy header: '%s: %s'" _
935 /* a whole header has been parsed successfully */ 900 /* a whole header has been parsed successfully */
936 901
937 ngx_log_debug(c->log, "HTTP header done"); 902 ngx_log_debug(c->log, "HTTP header done");
938 903
939 ngx_http_proxy_send_response(p); 904 ngx_http_proxy_send_response(p);
940
941 return; 905 return;
942 906
943 } else if (rc != NGX_AGAIN) { 907 } else if (rc != NGX_AGAIN) {
944 908
945 /* there was error while a header line parsing */ 909 /* there was error while a header line parsing */
946 910
947 ngx_log_error(NGX_LOG_ERR, rev->log, 0, 911 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
948 upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]); 912 upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]);
949 913
950 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER); 914 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
951 return; 915 return;
952 } 916 }
953 917
954 /* rc == NGX_AGAIN: a header line parsing is still not complete */ 918 /* rc == NGX_AGAIN: a header line parsing is still not complete */
955 919
956 if (p->header_in->last == p->header_in->end) { 920 if (p->header_in->last == p->header_in->end) {
957 ngx_log_error(NGX_LOG_ERR, rev->log, 0, 921 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
958 "upstream sent too big header"); 922 "upstream sent too big header");
959 923
960 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER); 924 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
961 return; 925 return;
962 } 926 }
963 } 927 }
964 } 928 }
965 929
1006 } 970 }
1007 971
1008 972
1009 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p) 973 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p)
1010 { 974 {
1011 int rc, i; 975 int rc, i;
1012 ngx_table_elt_t *ho, *h; 976 ngx_table_elt_t *ho, *h;
1013 ngx_event_pipe_t *ep; 977 ngx_event_pipe_t *ep;
1014 ngx_http_request_t *r; 978 ngx_http_request_t *r;
1015 ngx_http_core_loc_conf_t *clcf; 979 ngx_http_bin_cache_t *header;
980 ngx_http_core_loc_conf_t *clcf;
1016 981
1017 r = p->request; 982 r = p->request;
1018 983
1019 r->headers_out.status = p->status; 984 r->headers_out.status = p->status;
1020 985
986 #if 0
1021 r->headers_out.content_length_n = -1; 987 r->headers_out.content_length_n = -1;
1022 r->headers_out.content_length = NULL; 988 r->headers_out.content_length = NULL;
989 #endif
1023 990
1024 /* copy an upstream header to r->headers_out */ 991 /* copy an upstream header to r->headers_out */
1025 992
1026 h = p->headers_in.headers->elts; 993 if (ngx_http_proxy_copy_header(p, &p->headers_in) == NGX_ERROR) {
1027 for (i = 0; i < p->headers_in.headers->nelts; i++) { 994 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
1028 995 return;
1029 if (&h[i] == p->headers_in.connection) { 996 }
1030 continue;
1031 }
1032
1033 if (p->accel) {
1034 if (&h[i] == p->headers_in.date
1035 || &h[i] == p->headers_in.accept_ranges) {
1036 continue;
1037 }
1038
1039 if (&h[i] == p->headers_in.server && !p->lcf->pass_server) {
1040 continue;
1041 }
1042 }
1043
1044 if (&h[i] == p->headers_in.content_type) {
1045 r->headers_out.content_type = &h[i];
1046 r->headers_out.content_type->key.len = 0;
1047 continue;
1048 }
1049
1050 if (!(ho = ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
1051 {
1052 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
1053 return;
1054 }
1055
1056 *ho = h[i];
1057
1058 /*
1059 * ngx_http_header_filter() output the following headers
1060 * from r->headers_out.headers if they are set:
1061 * r->headers_out.server,
1062 * r->headers_out.date,
1063 * r->headers_out.content_length
1064 */
1065
1066 if (&h[i] == p->headers_in.server) {
1067 r->headers_out.server = ho;
1068 continue;
1069 }
1070
1071 if (&h[i] == p->headers_in.date) {
1072 r->headers_out.date = ho;
1073 continue;
1074 }
1075
1076 if (&h[i] == p->headers_in.content_length) {
1077 r->headers_out.content_length = ho;
1078 r->headers_out.content_length_n = ngx_atoi(ho->value.data,
1079 ho->value.len);
1080 continue;
1081 }
1082 }
1083
1084 997
1085 /* TODO: preallocate event_pipe hunks, look "Content-Length" */ 998 /* TODO: preallocate event_pipe hunks, look "Content-Length" */
1086 999
1087 rc = ngx_http_send_header(r); 1000 rc = ngx_http_send_header(r);
1088 1001
1089 p->header_sent = 1; 1002 p->header_sent = 1;
1003
1004 if (p->cache) {
1005 header = (ngx_http_bin_cache_t *) p->header_in->start;
1006 header->type = 0x42424242; /* "BBBB" */
1007 header->header.length = r->headers_out.content_length_n;
1008 header->key_len = p->cache->ctx.key.len;
1009 ngx_memcpy(&header->key, p->cache->ctx.key.data, header->key_len);
1010 header->key[header->key_len] = LF;
1011 }
1090 1012
1091 ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); 1013 ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
1092 if (ep == NULL) { 1014 if (ep == NULL) {
1093 ngx_http_proxy_finalize_request(p, 0); 1015 ngx_http_proxy_finalize_request(p, 0);
1094 return; 1016 return;
1103 ep->busy_size = p->lcf->busy_buffers_size; 1025 ep->busy_size = p->lcf->busy_buffers_size;
1104 ep->upstream = p->upstream.connection; 1026 ep->upstream = p->upstream.connection;
1105 ep->downstream = r->connection; 1027 ep->downstream = r->connection;
1106 ep->pool = r->pool; 1028 ep->pool = r->pool;
1107 ep->log = r->connection->log; 1029 ep->log = r->connection->log;
1108 ep->temp_path = p->lcf->temp_path; 1030
1109 1031 if (!(ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
1110 ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
1111 if (ep->temp_file == NULL) {
1112 ngx_http_proxy_finalize_request(p, 0); 1032 ngx_http_proxy_finalize_request(p, 0);
1113 return; 1033 return;
1114 } 1034 }
1115 1035
1116 ep->temp_file->fd = NGX_INVALID_FILE; 1036 ep->temp_file->file.fd = NGX_INVALID_FILE;
1117 ep->temp_file->log = r->connection->log; 1037 ep->temp_file->file.log = r->connection->log;
1038 ep->temp_file->path = p->lcf->temp_path;
1039 ep->temp_file->pool = r->pool;
1040 ep->temp_file->warn = "an upstream response is buffered "
1041 "to a temporary file";
1118 1042
1119 ep->max_temp_file_size = p->lcf->max_temp_file_size; 1043 ep->max_temp_file_size = p->lcf->max_temp_file_size;
1120 ep->temp_file_write_size = p->lcf->temp_file_write_size; 1044 ep->temp_file_write_size = p->lcf->temp_file_write_size;
1121 ep->temp_file_warn = "an upstream response is buffered "
1122 "to a temporary file";
1123 1045
1124 ep->preread_hunks = ngx_alloc_chain_link(r->pool); 1046 ep->preread_hunks = ngx_alloc_chain_link(r->pool);
1125 if (ep->preread_hunks == NULL) { 1047 if (ep->preread_hunks == NULL) {
1126 ngx_http_proxy_finalize_request(p, 0); 1048 ngx_http_proxy_finalize_request(p, 0);
1127 return; 1049 return;
1128 } 1050 }
1129 ep->preread_hunks->hunk = p->header_in; 1051 ep->preread_hunks->hunk = p->header_in;
1130 ep->preread_hunks->next = NULL; 1052 ep->preread_hunks->next = NULL;
1053 p->header_in->type |= NGX_HUNK_PREREAD;
1131 1054
1132 ep->preread_size = p->header_in->last - p->header_in->pos; 1055 ep->preread_size = p->header_in->last - p->header_in->pos;
1133 1056
1134 if (ngx_event_flags & NGX_USE_AIO_EVENT) { 1057 if (ngx_event_flags & NGX_USE_AIO_EVENT) {
1135 1058
1144 * event_pipe would do p->header_in->last += ep->preread_size 1067 * event_pipe would do p->header_in->last += ep->preread_size
1145 * as though these bytes were read. 1068 * as though these bytes were read.
1146 */ 1069 */
1147 p->header_in->last = p->header_in->pos; 1070 p->header_in->last = p->header_in->pos;
1148 1071
1149 /* STUB */ ep->cachable = 0; 1072 ep->cachable = p->cachable;
1150 1073
1151 if (p->lcf->cyclic_temp_file) { 1074 if (p->lcf->cyclic_temp_file) {
1152 1075
1153 /* 1076 /*
1154 * we need to disable the use of sendfile() if we use cyclic temp file 1077 * we need to disable the use of sendfile() if we use cyclic temp file
1224 } 1147 }
1225 } 1148 }
1226 1149
1227 if (p->upstream.connection) { 1150 if (p->upstream.connection) {
1228 if (ep->upstream_done) { 1151 if (ep->upstream_done) {
1229 /* TODO: update cache */ 1152 if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
1153 ngx_http_proxy_finalize_request(p, 0);
1154 return;
1155 }
1230 1156
1231 } else if (ep->upstream_eof) { 1157 } else if (ep->upstream_eof) {
1158
1232 /* TODO: check length & update cache */ 1159 /* TODO: check length & update cache */
1160
1161 if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
1162 ngx_http_proxy_finalize_request(p, 0);
1163 return;
1164 }
1233 } 1165 }
1234 1166
1235 if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) { 1167 if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) {
1236 ngx_http_proxy_close_connection(p->upstream.connection); 1168 ngx_http_proxy_close_connection(p->upstream.connection);
1237 p->upstream.connection = NULL; 1169 p->upstream.connection = NULL;
1257 1189
1258 return; 1190 return;
1259 } 1191 }
1260 1192
1261 1193
1262 static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p) 1194 static int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p)
1263 { 1195 {
1264 char ch; 1196 if (p->cache == NULL) {
1265 char *pos;
1266 enum {
1267 sw_start = 0,
1268 sw_H,
1269 sw_HT,
1270 sw_HTT,
1271 sw_HTTP,
1272 sw_first_major_digit,
1273 sw_major_digit,
1274 sw_first_minor_digit,
1275 sw_minor_digit,
1276 sw_status,
1277 sw_space_after_status,
1278 sw_status_text,
1279 sw_almost_done,
1280 sw_done
1281 } state;
1282
1283 state = p->state;
1284 pos = p->header_in->pos;
1285
1286 while (pos < p->header_in->last && state < sw_done) {
1287 ch = *pos++;
1288
1289 switch (state) {
1290
1291 /* "HTTP/" */
1292 case sw_start:
1293 switch (ch) {
1294 case 'H':
1295 state = sw_H;
1296 break;
1297 default:
1298 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1299 }
1300 break;
1301
1302 case sw_H:
1303 switch (ch) {
1304 case 'T':
1305 state = sw_HT;
1306 break;
1307 default:
1308 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1309 }
1310 break;
1311
1312 case sw_HT:
1313 switch (ch) {
1314 case 'T':
1315 state = sw_HTT;
1316 break;
1317 default:
1318 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1319 }
1320 break;
1321
1322 case sw_HTT:
1323 switch (ch) {
1324 case 'P':
1325 state = sw_HTTP;
1326 break;
1327 default:
1328 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1329 }
1330 break;
1331
1332 case sw_HTTP:
1333 switch (ch) {
1334 case '/':
1335 state = sw_first_major_digit;
1336 break;
1337 default:
1338 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1339 }
1340 break;
1341
1342 /* the first digit of major HTTP version */
1343 case sw_first_major_digit:
1344 if (ch < '1' || ch > '9') {
1345 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1346 }
1347
1348 state = sw_major_digit;
1349 break;
1350
1351 /* the major HTTP version or dot */
1352 case sw_major_digit:
1353 if (ch == '.') {
1354 state = sw_first_minor_digit;
1355 break;
1356 }
1357
1358 if (ch < '0' || ch > '9') {
1359 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1360 }
1361
1362 break;
1363
1364 /* the first digit of minor HTTP version */
1365 case sw_first_minor_digit:
1366 if (ch < '0' || ch > '9') {
1367 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1368 }
1369
1370 state = sw_minor_digit;
1371 break;
1372
1373 /* the minor HTTP version or the end of the request line */
1374 case sw_minor_digit:
1375 if (ch == ' ') {
1376 state = sw_status;
1377 break;
1378 }
1379
1380 if (ch < '0' || ch > '9') {
1381 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1382 }
1383
1384 break;
1385
1386 /* HTTP status code */
1387 case sw_status:
1388 if (ch < '0' || ch > '9') {
1389 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1390 }
1391
1392 p->status = p->status * 10 + ch - '0';
1393
1394 if (++p->status_count == 3) {
1395 state = sw_space_after_status;
1396 p->status_start = pos - 3;
1397 }
1398
1399 break;
1400
1401 /* space or end of line */
1402 case sw_space_after_status:
1403 switch (ch) {
1404 case ' ':
1405 state = sw_status_text;
1406 break;
1407 case CR:
1408 state = sw_almost_done;
1409 break;
1410 case LF:
1411 state = sw_done;
1412 break;
1413 default:
1414 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1415 }
1416 break;
1417
1418 /* any text until end of line */
1419 case sw_status_text:
1420 switch (ch) {
1421 case CR:
1422 state = sw_almost_done;
1423
1424 break;
1425 case LF:
1426 state = sw_done;
1427 break;
1428 }
1429 break;
1430
1431 /* end of request line */
1432 case sw_almost_done:
1433 p->status_end = pos - 2;
1434 switch (ch) {
1435 case LF:
1436 state = sw_done;
1437 break;
1438 default:
1439 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1440 }
1441 break;
1442 }
1443 }
1444
1445 p->header_in->pos = pos;
1446
1447 if (state == sw_done) {
1448 if (p->status_end == NULL) {
1449 p->status_end = pos - 1;
1450 }
1451
1452 p->state = sw_start;
1453 return NGX_OK; 1197 return NGX_OK;
1454 } 1198 }
1455 1199
1456 p->state = state; 1200 return ngx_http_cache_update_file(p->request, &p->cache->ctx,
1457 return NGX_AGAIN; 1201 &p->event_pipe->temp_file->file.name);
1458 } 1202 }
1459 1203
1460 1204
1461 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type) 1205 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type)
1462 { 1206 {
1463 int status; 1207 int status;
1464 1208
1465 ngx_event_connect_peer_failed(&p->upstream); 1209 ngx_log_debug(p->request->connection->log, "next upstream: %d" _ ft_type);
1466 1210
1467 if (p->timedout) { 1211 if (ft_type != NGX_HTTP_PROXY_FT_HTTP_404) {
1212 ngx_event_connect_peer_failed(&p->upstream);
1213 }
1214
1215 if (ft_type == NGX_HTTP_PROXY_FT_TIMEOUT) {
1468 ngx_log_error(NGX_LOG_ERR, p->request->connection->log, NGX_ETIMEDOUT, 1216 ngx_log_error(NGX_LOG_ERR, p->request->connection->log, NGX_ETIMEDOUT,
1469 "upstream timed out"); 1217 "upstream timed out");
1218 }
1219
1220 if (p->upstream.cached && ft_type == NGX_HTTP_PROXY_FT_ERROR) {
1221 status = 0;
1222
1223 } else {
1224 switch(ft_type) {
1225 case NGX_HTTP_PROXY_FT_TIMEOUT:
1226 status = NGX_HTTP_GATEWAY_TIME_OUT;
1227 break;
1228
1229 case NGX_HTTP_PROXY_FT_HTTP_500:
1230 status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1231 break;
1232
1233 case NGX_HTTP_PROXY_FT_HTTP_404:
1234 status = NGX_HTTP_NOT_FOUND;
1235 break;
1236
1237 /*
1238 * NGX_HTTP_PROXY_FT_BUSY_LOCK and NGX_HTTP_PROXY_FT_MAX_WAITING
1239 * never reach here
1240 */
1241
1242 default:
1243 status = NGX_HTTP_BAD_GATEWAY;
1244 }
1470 } 1245 }
1471 1246
1472 if (p->upstream.connection) { 1247 if (p->upstream.connection) {
1473 ngx_http_proxy_close_connection(p->upstream.connection); 1248 ngx_http_proxy_close_connection(p->upstream.connection);
1474 p->upstream.connection = NULL; 1249 p->upstream.connection = NULL;
1475 } 1250 }
1476 1251
1477 if (ft_type == NGX_HTTP_PROXY_FT_TIMEOUT) { 1252 if (status) {
1478 status = NGX_HTTP_GATEWAY_TIME_OUT; 1253 if (ngx_http_proxy_log_state(p, status) == NGX_ERROR) {
1479 1254 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
1480 } else { 1255 return;
1481 status = NGX_HTTP_BAD_GATEWAY; 1256 }
1482 } 1257
1483 1258 if (p->upstream.tries == 0 || !(p->lcf->next_upstream & ft_type)) {
1484 if (ngx_http_proxy_log_state(p, status) == NGX_ERROR) { 1259
1485 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); 1260 if (p->stale && (p->lcf->use_stale & ft_type)) {
1486 return; 1261 /*
1487 } 1262 * TODO: use stale cached response if it exists and enabled
1488 1263 */
1489 if (p->upstream.tries == 0 || !(p->lcf->next_upstream & ft_type)) { 1264 }
1490 ngx_http_proxy_finalize_request(p, status); 1265
1491 return; 1266 ngx_http_proxy_finalize_request(p, status);
1492 } 1267 return;
1493 1268 }
1494 if (!p->fatal_error) { 1269 }
1495 ngx_http_proxy_send_request(p); 1270
1496 return; 1271 ngx_http_proxy_connect(p);
1497 }
1498
1499 ngx_log_debug(p->request->connection->log, "FATAL ERROR IN NEXT UPSTREAM");
1500
1501 return;
1502 } 1272 }
1503 1273
1504 1274
1505 static int ngx_http_proxy_log_state(ngx_http_proxy_ctx_t *p, int status) 1275 static int ngx_http_proxy_log_state(ngx_http_proxy_ctx_t *p, int status)
1506 { 1276 {
1536 1306
1537 p->request->connection->log->data = p->saved_ctx; 1307 p->request->connection->log->data = p->saved_ctx;
1538 p->request->connection->log->handler = p->saved_handler; 1308 p->request->connection->log->handler = p->saved_handler;
1539 1309
1540 ngx_http_finalize_request(p->request, rc); 1310 ngx_http_finalize_request(p->request, rc);
1541
1542 p->fatal_error = 1;
1543
1544 return;
1545 } 1311 }
1546 1312
1547 1313
1548 static void ngx_http_proxy_close_connection(ngx_connection_t *c) 1314 static void ngx_http_proxy_close_connection(ngx_connection_t *c)
1549 { 1315 {
1550 ngx_log_debug(c->log, "close connection: %d" _ c->fd); 1316 ngx_log_debug(c->log, "proxy close connection: %d" _ c->fd);
1551 1317
1552 if (c->fd == -1) { 1318 if (c->fd == -1) {
1553 #if 0 1319 #if 0
1554 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); 1320 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
1555 #endif 1321 #endif
1583 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, 1349 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
1584 ngx_close_socket_n " failed"); 1350 ngx_close_socket_n " failed");
1585 } 1351 }
1586 1352
1587 c->fd = -1; 1353 c->fd = -1;
1588
1589 return;
1590 } 1354 }
1591 1355
1592 1356
1593 static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len) 1357 static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len)
1594 { 1358 {
1620 conf->bufs.num = 0; 1384 conf->bufs.num = 0;
1621 1385
1622 conf->path = NULL; 1386 conf->path = NULL;
1623 1387
1624 conf->next_upstream = 0; 1388 conf->next_upstream = 0;
1389 conf->use_stale = 0;
1625 1390
1626 conf->upstreams = NULL; 1391 conf->upstreams = NULL;
1627 conf->peers = NULL; 1392 conf->peers = NULL;
1393
1394 conf->cache_path = NULL;
1395 conf->temp_path = NULL;
1628 1396
1629 */ 1397 */
1630 1398
1631 conf->request_buffer_size = NGX_CONF_UNSET; 1399 conf->request_buffer_size = NGX_CONF_UNSET;
1632 conf->connect_timeout = NGX_CONF_UNSET; 1400 conf->connect_timeout = NGX_CONF_UNSET;
1643 1411
1644 conf->temp_file_write_size = NGX_CONF_UNSET; 1412 conf->temp_file_write_size = NGX_CONF_UNSET;
1645 1413
1646 /* "proxy_cyclic_temp_file" is disabled */ 1414 /* "proxy_cyclic_temp_file" is disabled */
1647 conf->cyclic_temp_file = 0; 1415 conf->cyclic_temp_file = 0;
1416
1417 conf->cache = NGX_CONF_UNSET;
1648 1418
1649 conf->pass_server = NGX_CONF_UNSET; 1419 conf->pass_server = NGX_CONF_UNSET;
1650 1420
1651 return conf; 1421 return conf;
1652 } 1422 }
1679 1449
1680 ngx_conf_merge_size_value(conf->temp_file_write_size, 1450 ngx_conf_merge_size_value(conf->temp_file_write_size,
1681 prev->temp_file_write_size, 16384); 1451 prev->temp_file_write_size, 16384);
1682 1452
1683 ngx_conf_merge_bitmask_value(conf->next_upstream, prev->next_upstream, 1453 ngx_conf_merge_bitmask_value(conf->next_upstream, prev->next_upstream,
1684 (NGX_HTTP_PROXY_FT_ERROR|NGX_HTTP_PROXY_FT_TIMEOUT)); 1454 (NGX_CONF_BITMASK_SET
1455 |NGX_HTTP_PROXY_FT_ERROR
1456 |NGX_HTTP_PROXY_FT_TIMEOUT));
1457
1458 ngx_conf_merge_bitmask_value(conf->use_stale, prev->use_stale,
1459 NGX_CONF_BITMASK_SET);
1460
1461 ngx_conf_merge_path_value(conf->cache_path, prev->cache_path,
1462 "cache", 1, 2, 0, cf->pool);
1685 1463
1686 ngx_conf_merge_path_value(conf->temp_path, prev->temp_path, 1464 ngx_conf_merge_path_value(conf->temp_path, prev->temp_path,
1687 "temp", 1, 2, 0, cf->pool); 1465 "temp", 1, 2, 0, cf->pool);
1466
1467 ngx_conf_merge_value(conf->cache, prev->cache, 0);
1688 1468
1689 ngx_conf_merge_value(conf->pass_server, prev->pass_server, 0); 1469 ngx_conf_merge_value(conf->pass_server, prev->pass_server, 0);
1690 1470
1691 return NULL; 1471 return NULL;
1692 } 1472 }
1715 1495
1716 ngx_test_null(lcf->upstream, 1496 ngx_test_null(lcf->upstream,
1717 ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_upstream_t)), 1497 ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_upstream_t)),
1718 NGX_CONF_ERROR); 1498 NGX_CONF_ERROR);
1719 1499
1500 lcf->upstream->url.len = value[1].len;
1501 if (!(lcf->upstream->url.data = ngx_palloc(cf->pool, value[1].len + 1))) {
1502 return NGX_CONF_ERROR;
1503 }
1504 ngx_cpystrn(lcf->upstream->url.data, value[1].data, value[1].len + 1);
1505
1720 value[1].data += 7; 1506 value[1].data += 7;
1721 value[1].len -= 7; 1507 value[1].len -= 7;
1722 1508
1723 err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream); 1509 err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream);
1724 1510