1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
13 static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
14 static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
15 static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
16 ngx_event_t *ev);
17 static void ngx_http_upstream_connect(ngx_http_request_t *r,
18 ngx_http_upstream_t *u);
19 static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r,
20 ngx_http_upstream_t *u);
21 static void ngx_http_upstream_send_request(ngx_http_request_t *r,
22 ngx_http_upstream_t *u);
23 static void ngx_http_upstream_send_request_handler(ngx_event_t *wev);
24 static void ngx_http_upstream_process_header(ngx_event_t *rev);
25 static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
26 static void ngx_http_upstream_process_body_in_memory(ngx_event_t *rev);
27 static void ngx_http_upstream_send_response(ngx_http_request_t *r,
28 ngx_http_upstream_t *u);
29 static void
30 ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r);
31 static void ngx_http_upstream_process_non_buffered_body(ngx_event_t *ev);
32 static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
33 static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
34 ssize_t bytes);
35 static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
36 static void ngx_http_upstream_process_body(ngx_event_t *ev);
37 static void ngx_http_upstream_store(ngx_http_request_t *r,
38 ngx_http_upstream_t *u);
39 static void ngx_http_upstream_dummy_handler(ngx_event_t *wev);
40 static void ngx_http_upstream_next(ngx_http_request_t *r,
41 ngx_http_upstream_t *u, ngx_uint_t ft_type);
42 static void ngx_http_upstream_cleanup(void *data);
43 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
44 ngx_http_upstream_t *u, ngx_int_t rc);
45
46 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
47 ngx_table_elt_t *h, ngx_uint_t offset);
48 static ngx_int_t
49 ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
50 ngx_table_elt_t *h, ngx_uint_t offset);
51 static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
52 ngx_table_elt_t *h, ngx_uint_t offset);
53 static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
54 ngx_table_elt_t *h, ngx_uint_t offset);
55 static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
56 ngx_table_elt_t *h, ngx_uint_t offset);
57 static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
58 ngx_table_elt_t *h, ngx_uint_t offset);
59 static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
60 ngx_table_elt_t *h, ngx_uint_t offset);
61 static ngx_int_t
62 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
63 ngx_table_elt_t *h, ngx_uint_t offset);
64 static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
65 ngx_table_elt_t *h, ngx_uint_t offset);
66 static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r,
67 ngx_table_elt_t *h, ngx_uint_t offset);
68 static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
69 ngx_table_elt_t *h, ngx_uint_t offset);
70 static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
71 ngx_table_elt_t *h, ngx_uint_t offset);
72 #if (NGX_HTTP_GZIP)
73 static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
74 ngx_table_elt_t *h, ngx_uint_t offset);
75 #endif
76
77 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
78 static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
79 ngx_http_variable_value_t *v, uintptr_t data);
80 static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
81 ngx_http_variable_value_t *v, uintptr_t data);
82 static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
83 ngx_http_variable_value_t *v, uintptr_t data);
84
85 static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
86 static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
87 void *conf);
88
89 static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
90 static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
91
92 #if (NGX_HTTP_SSL)
93 static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
94 ngx_http_upstream_t *u, ngx_connection_t *c);
95 static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
96 #endif
97
98
99 ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
100
101 { ngx_string("Status"),
102 ngx_http_upstream_process_header_line,
103 offsetof(ngx_http_upstream_headers_in_t, status),
104 ngx_http_upstream_copy_header_line, 0, 0 },
105
106 { ngx_string("Content-Type"),
107 ngx_http_upstream_process_header_line,
108 offsetof(ngx_http_upstream_headers_in_t, content_type),
109 ngx_http_upstream_copy_content_type, 0, 1 },
110
111 { ngx_string("Content-Length"),
112 ngx_http_upstream_process_header_line,
113 offsetof(ngx_http_upstream_headers_in_t, content_length),
114 ngx_http_upstream_copy_content_length, 0, 0 },
115
116 { ngx_string("Date"),
117 ngx_http_upstream_process_header_line,
118 offsetof(ngx_http_upstream_headers_in_t, date),
119 ngx_http_upstream_copy_header_line,
120 offsetof(ngx_http_headers_out_t, date), 0 },
121
122 { ngx_string("Last-Modified"),
123 ngx_http_upstream_process_header_line,
124 offsetof(ngx_http_upstream_headers_in_t, last_modified),
125 ngx_http_upstream_copy_header_line,
126 offsetof(ngx_http_headers_out_t, last_modified), 0 },
127
128 { ngx_string("Server"),
129 ngx_http_upstream_process_header_line,
130 offsetof(ngx_http_upstream_headers_in_t, server),
131 ngx_http_upstream_copy_header_line,
132 offsetof(ngx_http_headers_out_t, server), 0 },
133
134 { ngx_string("WWW-Authenticate"),
135 ngx_http_upstream_process_header_line,
136 offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
137 ngx_http_upstream_copy_header_line, 0, 0 },
138
139 { ngx_string("Location"),
140 ngx_http_upstream_ignore_header_line, 0,
141 ngx_http_upstream_rewrite_location, 0, 0 },
142
143 { ngx_string("Refresh"),
144 ngx_http_upstream_ignore_header_line, 0,
145 ngx_http_upstream_rewrite_refresh, 0, 0 },
146
147 { ngx_string("Set-Cookie"),
148 ngx_http_upstream_ignore_header_line, 0,
149 ngx_http_upstream_copy_header_line, 0, 1 },
150
151 { ngx_string("Content-Disposition"),
152 ngx_http_upstream_ignore_header_line, 0,
153 ngx_http_upstream_copy_header_line, 0, 1 },
154
155 { ngx_string("Cache-Control"),
156 ngx_http_upstream_process_multi_header_lines,
157 offsetof(ngx_http_upstream_headers_in_t, cache_control),
158 ngx_http_upstream_copy_multi_header_lines,
159 offsetof(ngx_http_headers_out_t, cache_control), 1 },
160
161 { ngx_string("Expires"),
162 ngx_http_upstream_process_header_line,
163 offsetof(ngx_http_upstream_headers_in_t, expires),
164 ngx_http_upstream_copy_header_line,
165 offsetof(ngx_http_headers_out_t, expires), 1 },
166
167 { ngx_string("Accept-Ranges"),
168 ngx_http_upstream_process_header_line,
169 offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
170 ngx_http_upstream_copy_header_line,
171 offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
172
173 { ngx_string("Connection"),
174 ngx_http_upstream_ignore_header_line, 0,
175 ngx_http_upstream_ignore_header_line, 0, 0 },
176
177 { ngx_string("Keep-Alive"),
178 ngx_http_upstream_ignore_header_line, 0,
179 ngx_http_upstream_ignore_header_line, 0, 0 },
180
181 { ngx_string("X-Powered-By"),
182 ngx_http_upstream_ignore_header_line, 0,
183 ngx_http_upstream_copy_header_line, 0, 0 },
184
185 { ngx_string("X-Accel-Expires"),
186 ngx_http_upstream_process_header_line,
187 offsetof(ngx_http_upstream_headers_in_t, x_accel_expires),
188 ngx_http_upstream_copy_header_line, 0, 0 },
189
190 { ngx_string("X-Accel-Redirect"),
191 ngx_http_upstream_process_header_line,
192 offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
193 ngx_http_upstream_ignore_header_line, 0, 0 },
194
195 { ngx_string("X-Accel-Limit-Rate"),
196 ngx_http_upstream_process_limit_rate, 0,
197 ngx_http_upstream_ignore_header_line, 0, 0 },
198
199 { ngx_string("X-Accel-Buffering"),
200 ngx_http_upstream_process_buffering, 0,
201 ngx_http_upstream_ignore_header_line, 0, 0 },
202
203 { ngx_string("X-Accel-Charset"),
204 ngx_http_upstream_process_charset, 0,
205 ngx_http_upstream_ignore_header_line, 0, 0 },
206
207 #if (NGX_HTTP_GZIP)
208 { ngx_string("Content-Encoding"),
209 ngx_http_upstream_process_header_line,
210 offsetof(ngx_http_upstream_headers_in_t, content_encoding),
211 ngx_http_upstream_copy_content_encoding, 0, 0 },
212 #endif
213
214 { ngx_null_string, NULL, 0, NULL, 0, 0 }
215 };
216
217
218 static ngx_command_t ngx_http_upstream_commands[] = {
219
220 { ngx_string("upstream"),
221 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
222 ngx_http_upstream,
223 0,
224 0,
225 NULL },
226
227 { ngx_string("server"),
228 NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
229 ngx_http_upstream_server,
230 NGX_HTTP_SRV_CONF_OFFSET,
231 0,
232 NULL },
233
234 ngx_null_command
235 };
236
237
238 static ngx_http_module_t ngx_http_upstream_module_ctx = {
239 ngx_http_upstream_add_variables, /* preconfiguration */
240 NULL, /* postconfiguration */
241
242 ngx_http_upstream_create_main_conf, /* create main configuration */
243 ngx_http_upstream_init_main_conf, /* init main configuration */
244
245 NULL, /* create server configuration */
246 NULL, /* merge server configuration */
247
248 NULL, /* create location configuration */
249 NULL /* merge location configuration */
250 };
251
252
253 ngx_module_t ngx_http_upstream_module = {
254 NGX_MODULE_V1,
255 &ngx_http_upstream_module_ctx, /* module context */
256 ngx_http_upstream_commands, /* module directives */
257 NGX_HTTP_MODULE, /* module type */
258 NULL, /* init master */
259 NULL, /* init module */
260 NULL, /* init process */
261 NULL, /* init thread */
262 NULL, /* exit thread */
263 NULL, /* exit process */
264 NULL, /* exit master */
265 NGX_MODULE_V1_PADDING
266 };
267
268
269 static ngx_http_variable_t ngx_http_upstream_vars[] = {
270
271 { ngx_string("upstream_addr"), NULL,
272 ngx_http_upstream_addr_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
273
274 { ngx_string("upstream_status"), NULL,
275 ngx_http_upstream_status_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
276
277 { ngx_string("upstream_response_time"), NULL,
278 ngx_http_upstream_response_time_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
279
280 { ngx_null_string, NULL, NULL, 0, 0, 0 }
281 };
282
283
284 void
285 ngx_http_upstream_init(ngx_http_request_t *r)
286 {
287 ngx_str_t *host;
288 ngx_uint_t i;
289 ngx_connection_t *c;
290 ngx_resolver_ctx_t *ctx, temp;
291 ngx_http_cleanup_t *cln;
292 ngx_http_upstream_t *u;
293 ngx_http_core_loc_conf_t *clcf;
294 ngx_http_upstream_srv_conf_t *uscf, **uscfp;
295 ngx_http_upstream_main_conf_t *umcf;
296
297 c = r->connection;
298
299 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
300 "http init upstream, client timer: %d", c->read->timer_set);
301
302 if (c->read->timer_set) {
303 ngx_del_timer(c->read);
304 }
305
306 u = r->upstream;
307
308 if (!r->post_action && !u->conf->ignore_client_abort) {
309 r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
310 r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
311 }
312
313 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
314
315 if (!c->write->active) {
316 if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
317 == NGX_ERROR)
318 {
319 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
320 return;
321 }
322 }
323 }
324
325 if (r->request_body) {
326 u->request_bufs = r->request_body->bufs;
327 }
328
329 if (u->create_request(r) != NGX_OK) {
330 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
331 return;
332 }
333
334 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
335
336 u->output.sendfile = c->sendfile;
337 u->output.pool = r->pool;
338 u->output.bufs.num = 1;
339 u->output.bufs.size = clcf->client_body_buffer_size;
340 u->output.output_filter = ngx_chain_writer;
341 u->output.filter_ctx = &u->writer;
342
343 u->writer.pool = r->pool;
344
345 if (r->upstream_states == NULL) {
346
347 r->upstream_states = ngx_array_create(r->pool, 1,
348 sizeof(ngx_http_upstream_state_t));
349 if (r->upstream_states == NULL) {
350 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
351 return;
352 }
353
354 } else {
355
356 u->state = ngx_array_push(r->upstream_states);
357 if (u->state == NULL) {
358 ngx_http_upstream_finalize_request(r, u,
359 NGX_HTTP_INTERNAL_SERVER_ERROR);
360 return;
361 }
362
363 ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
364 }
365
366 cln = ngx_http_cleanup_add(r, 0);
367 if (cln == NULL) {
368 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
369 return;
370 }
371
372 cln->handler = ngx_http_upstream_cleanup;
373 cln->data = r;
374 u->cleanup = &cln->handler;
375
376 u->store = (u->conf->store || u->conf->store_lengths);
377
378 if (u->resolved == NULL) {
379
380 uscf = u->conf->upstream;
381
382 } else {
383
384 host = &u->resolved->host;
385
386 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
387
388 uscfp = umcf->upstreams.elts;
389
390 for (i = 0; i < umcf->upstreams.nelts; i++) {
391
392 uscf = uscfp[i];
393
394 if (uscf->host.len == host->len
395 && ngx_memcmp(uscf->host.data, host->data, host->len) == 0)
396 {
397 goto found;
398 }
399 }
400
401 temp.name = *host;
402
403 ctx = ngx_resolve_start(clcf->resolver, &temp);
404 if (ctx == NULL) {
405 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
406 return;
407 }
408
409 if (ctx == NGX_NO_RESOLVER) {
410 ngx_log_error(NGX_LOG_ERR, c->log, 0,
411 "no resolver defined to resolve %V", host);
412
413 ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
414 return;
415 }
416
417 ctx->name = *host;
418 ctx->type = NGX_RESOLVE_A;
419 ctx->handler = ngx_http_upstream_resolve_handler;
420 ctx->data = r;
421 ctx->timeout = clcf->resolver_timeout;
422
423 u->resolved->ctx = ctx;
424
425 if (ngx_resolve_name(ctx) != NGX_OK) {
426 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
427 return;
428 }
429
430 return;
431 }
432
433 found:
434
435 if (uscf->peer.init(r, uscf) != NGX_OK) {
436 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
437 return;
438 }
439
440 ngx_http_upstream_connect(r, u);
441 }
442
443
444 static void
445 ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
446 {
447 ngx_http_request_t *r;
448 ngx_http_upstream_resolved_t *ur;
449
450 r = ctx->data;
451
452 r->upstream->resolved->ctx = NULL;
453
454 if (ctx->state) {
455 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
456 "%V could not be resolved (%i: %s)",
457 &ctx->name, ctx->state,
458 ngx_resolver_strerror(ctx->state));
459
460 ngx_resolve_name_done(ctx);
461 ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
462 return;
463 }
464
465 ur = r->upstream->resolved;
466 ur->naddrs = ctx->naddrs;
467 ur->addrs = ctx->addrs;
468
469 #if (NGX_DEBUG)
470 {
471 in_addr_t addr;
472 ngx_uint_t i;
473
474 for (i = 0; i < ctx->naddrs; i++) {
475 addr = ntohl(ur->addrs[i]);
476
477 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
478 "name was resolved to %ud.%ud.%ud.%ud",
479 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
480 (addr >> 8) & 0xff, addr & 0xff);
481 }
482 }
483 #endif
484
485 if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
486 ngx_resolve_name_done(ctx);
487 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
488 return;
489 }
490
491 ngx_resolve_name_done(ctx);
492
493 ngx_http_upstream_connect(r, r->upstream);
494 }
495
496
497 static void
498 ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
499 {
500 ngx_http_upstream_check_broken_connection(r, r->connection->read);
501 }
502
503
504 static void
505 ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
506 {
507 ngx_http_upstream_check_broken_connection(r, r->connection->write);
508 }
509
510
511 static void
512 ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
513 ngx_event_t *ev)
514 {
515 int n;
516 char buf[1];
517 ngx_err_t err;
518 ngx_connection_t *c;
519 ngx_http_upstream_t *u;
520
521 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
522 "http upstream check client, write event:%d, \"%V\"",
523 ev->write, &r->uri);
524
525 c = r->connection;
526 u = r->upstream;
527
528 if (c->error) {
529 ngx_http_upstream_finalize_request(r, u,
530 NGX_HTTP_CLIENT_CLOSED_REQUEST);
531 return;
532 }
533
534 if (u->peer.connection == NULL) {
535 return;
536 }
537
538 #if (NGX_HAVE_KQUEUE)
539
540 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
541
542 if (!ev->pending_eof) {
543 return;
544 }
545
546 ev->eof = 1;
547 c->error = 1;
548
549 if (ev->kq_errno) {
550 ev->error = 1;
551 }
552
553 if (!u->cacheable && !u->store && u->peer.connection) {
554 ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
555 "kevent() reported that client closed prematurely "
556 "connection, so upstream connection is closed too");
557 ngx_http_upstream_finalize_request(r, u,
558 NGX_HTTP_CLIENT_CLOSED_REQUEST);
559 return;
560 }
561
562 ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
563 "kevent() reported that client closed "
564 "prematurely connection");
565
566 if (u->peer.connection == NULL) {
567 ngx_http_upstream_finalize_request(r, u,
568 NGX_HTTP_CLIENT_CLOSED_REQUEST);
569 return;
570 }
571
572 return;
573 }
574
575 #endif
576
577 n = recv(c->fd, buf, 1, MSG_PEEK);
578
579 err = ngx_socket_errno;
580
581 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
582 "http upstream recv(): %d", n);
583
584 /*
585 * we do not need to disable the write event because
586 * that event has NGX_USE_CLEAR_EVENT type
587 */
588
589 if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
590 return;
591 }
592
593 if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
594 if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
595 ngx_http_upstream_finalize_request(r, u,
596 NGX_HTTP_INTERNAL_SERVER_ERROR);
597 return;
598 }
599 }
600
601 if (n > 0) {
602 return;
603 }
604
605 if (n == -1) {
606 if (err == NGX_EAGAIN) {
607 return;
608 }
609
610 ev->error = 1;
611
612 } else { /* n == 0 */
613 err = 0;
614 }
615
616 ev->eof = 1;
617 c->error = 1;
618
619 if (!u->cacheable && !u->store && u->peer.connection) {
620 ngx_log_error(NGX_LOG_INFO, ev->log, err,
621 "client closed prematurely connection, "
622 "so upstream connection is closed too");
623 ngx_http_upstream_finalize_request(r, u,
624 NGX_HTTP_CLIENT_CLOSED_REQUEST);
625 return;
626 }
627
628 ngx_log_error(NGX_LOG_INFO, ev->log, err,
629 "client closed prematurely connection");
630
631 if (u->peer.connection == NULL) {
632 ngx_http_upstream_finalize_request(r, u,
633 NGX_HTTP_CLIENT_CLOSED_REQUEST);
634 return;
635 }
636 }
637
638
639 static void
640 ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
641 {
642 ngx_int_t rc;
643 ngx_time_t *tp;
644 ngx_connection_t *c;
645
646 r->connection->log->action = "connecting to upstream";
647
648 r->connection->single_connection = 0;
649
650 if (u->state && u->state->response_sec) {
651 tp = ngx_timeofday();
652 u->state->response_sec = tp->sec - u->state->response_sec;
653 u->state->response_msec = tp->msec - u->state->response_msec;
654 }
655
656 u->state = ngx_array_push(r->upstream_states);
657 if (u->state == NULL) {
658 ngx_http_upstream_finalize_request(r, u,
659 NGX_HTTP_INTERNAL_SERVER_ERROR);
660 return;
661 }
662
663 ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
664
665 tp = ngx_timeofday();
666 u->state->response_sec = tp->sec;
667 u->state->response_msec = tp->msec;
668
669 rc = ngx_event_connect_peer(&u->peer);
670
671 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
672 "http upstream connect: %i", rc);
673
674 if (rc == NGX_ERROR) {
675 ngx_http_upstream_finalize_request(r, u,
676 NGX_HTTP_INTERNAL_SERVER_ERROR);
677 return;
678 }
679
680 u->state->peer = u->peer.name;
681
682 if (rc == NGX_BUSY) {
683 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
684 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
685 return;
686 }
687
688 if (rc == NGX_DECLINED) {
689 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
690 return;
691 }
692
693 /* rc == NGX_OK || rc == NGX_AGAIN */
694
695 c = u->peer.connection;
696
697 c->data = r;
698
699 c->write->handler = ngx_http_upstream_send_request_handler;
700 c->read->handler = ngx_http_upstream_process_header;
701
702 c->sendfile &= r->connection->sendfile;
703
704 c->pool = r->pool;
705 c->read->log = c->write->log = c->log = r->connection->log;
706
707 /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
708
709 u->writer.out = NULL;
710 u->writer.last = &u->writer.out;
711 u->writer.connection = c;
712 u->writer.limit = 0;
713
714 if (u->request_sent) {
715 if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
716 ngx_http_upstream_finalize_request(r, u,
717 NGX_HTTP_INTERNAL_SERVER_ERROR);
718 return;
719 }
720 }
721
722 if (r->request_body
723 && r->request_body->buf
724 && r->request_body->temp_file
725 && r == r->main)
726 {
727 /*
728 * the r->request_body->buf can be reused for one request only,
729 * the subrequests should allocate their own temporay bufs
730 */
731
732 u->output.free = ngx_alloc_chain_link(r->pool);
733 if (u->output.free == NULL) {
734 ngx_http_upstream_finalize_request(r, u,
735 NGX_HTTP_INTERNAL_SERVER_ERROR);
736 return;
737 }
738
739 u->output.free->buf = r->request_body->buf;
740 u->output.free->next = NULL;
741 u->output.allocated = 1;
742
743 r->request_body->buf->pos = r->request_body->buf->start;
744 r->request_body->buf->last = r->request_body->buf->start;
745 r->request_body->buf->tag = u->output.tag;
746 }
747
748 u->request_sent = 0;
749
750 if (rc == NGX_AGAIN) {
751 ngx_add_timer(c->write, u->conf->connect_timeout);
752 return;
753 }
754
755 #if (NGX_HTTP_SSL)
756
757 if (u->ssl && c->ssl == NULL) {
758 ngx_http_upstream_ssl_init_connection(r, u, c);
759 return;
760 }
761
762 #endif
763
764 ngx_http_upstream_send_request(r, u);
765 }
766
767
768 #if (NGX_HTTP_SSL)
769
770 static void
771 ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
772 ngx_http_upstream_t *u, ngx_connection_t *c)
773 {
774 ngx_int_t rc;
775
776 if (ngx_ssl_create_connection(u->conf->ssl, c,
777 NGX_SSL_BUFFER|NGX_SSL_CLIENT)
778 == NGX_ERROR)
779 {
780 ngx_http_upstream_finalize_request(r, u,
781 NGX_HTTP_INTERNAL_SERVER_ERROR);
782 return;
783 }
784
785 c->sendfile = 0;
786 u->output.sendfile = 0;
787
788 if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
789 ngx_http_upstream_finalize_request(r, u,
790 NGX_HTTP_INTERNAL_SERVER_ERROR);
791 return;
792 }
793
794 r->connection->log->action = "SSL handshaking to upstream";
795
796 rc = ngx_ssl_handshake(c);
797
798 if (rc == NGX_AGAIN) {
799 c->ssl->handler = ngx_http_upstream_ssl_handshake;
800 return;
801 }
802
803 ngx_http_upstream_ssl_handshake(c);
804 }
805
806
807 static void
808 ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
809 {
810 ngx_http_request_t *r;
811 ngx_http_upstream_t *u;
812
813 r = c->data;
814 u = r->upstream;
815
816 if (c->ssl->handshaked) {
817
818 u->peer.save_session(&u->peer, u->peer.data);
819
820 c->write->handler = ngx_http_upstream_send_request_handler;
821 c->read->handler = ngx_http_upstream_process_header;
822
823 ngx_http_upstream_send_request(r, u);
824
825 return;
826 }
827
828 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
829
830 }
831
832 #endif
833
834
835 static ngx_int_t
836 ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
837 {
838 ngx_chain_t *cl;
839
840 if (u->reinit_request(r) != NGX_OK) {
841 return NGX_ERROR;
842 }
843
844 ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
845
846 if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
847 sizeof(ngx_table_elt_t))
848 != NGX_OK)
849 {
850 return NGX_ERROR;
851 }
852
853 /* reinit the request chain */
854
855 for (cl = u->request_bufs; cl; cl = cl->next) {
856 cl->buf->pos = cl->buf->start;
857 cl->buf->file_pos = 0;
858 }
859
860 /* reinit the subrequest's ngx_output_chain() context */
861
862 if (r->request_body && r->request_body->temp_file
863 && r != r->main && u->output.buf)
864 {
865 u->output.free = ngx_alloc_chain_link(r->pool);
866 if (u->output.free == NULL) {
867 return NGX_ERROR;
868 }
869
870 u->output.free->buf = u->output.buf;
871 u->output.free->next = NULL;
872
873 u->output.buf->pos = u->output.buf->start;
874 u->output.buf->last = u->output.buf->start;
875 }
876
877 u->output.buf = NULL;
878 u->output.in = NULL;
879 u->output.busy = NULL;
880
881 /* reinit u->buffer */
882
883 #if 0
884 if (u->cache) {
885 u->buffer.pos = u->buffer.start + u->cache->ctx.header_size;
886 u->buffer.last = u->buffer.pos;
887
888 } else {
889 u->buffer.pos = u->buffer.start;
890 u->buffer.last = u->buffer.start;
891 }
892 #else
893
894 u->buffer.pos = u->buffer.start;
895 u->buffer.last = u->buffer.start;
896
897 #endif
898
899 return NGX_OK;
900 }
901
902
903 static void
904 ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
905 {
906 ngx_int_t rc;
907 ngx_connection_t *c;
908
909 c = u->peer.connection;
910
911 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
912 "http upstream send request");
913
914 if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
915 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
916 return;
917 }
918
919 c->log->action = "sending request to upstream";
920
921 rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
922
923 u->request_sent = 1;
924
925 if (rc == NGX_ERROR) {
926 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
927 return;
928 }
929
930 if (c->write->timer_set) {
931 ngx_del_timer(c->write);
932 }
933
934 if (rc == NGX_AGAIN) {
935 ngx_add_timer(c->write, u->conf->send_timeout);
936
937 if (ngx_handle_write_event(c->write, u->conf->send_lowat) == NGX_ERROR)
938 {
939 ngx_http_upstream_finalize_request(r, u,
940 NGX_HTTP_INTERNAL_SERVER_ERROR);
941 return;
942 }
943
944 return;
945 }
946
947 /* rc == NGX_OK */
948
949 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
950 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
951 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
952 ngx_tcp_push_n " failed");
953 ngx_http_upstream_finalize_request(r, u,
954 NGX_HTTP_INTERNAL_SERVER_ERROR);
955 return;
956 }
957
958 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
959 }
960
961 ngx_add_timer(c->read, u->conf->read_timeout);
962