~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/ngx_http_upstream.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  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 #if (NGX_HTTP_CACHE)
 13 static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
 14     ngx_http_upstream_t *u);
 15 static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
 16     ngx_http_upstream_t *u);
 17 static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
 18     ngx_http_variable_value_t *v, uintptr_t data);
 19 #endif
 20 
 21 static void ngx_http_upstream_init_request(ngx_http_request_t *r);
 22 static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
 23 static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
 24 static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
 25 static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
 26     ngx_event_t *ev);
 27 static void ngx_http_upstream_connect(ngx_http_request_t *r,
 28     ngx_http_upstream_t *u);
 29 static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r,
 30     ngx_http_upstream_t *u);
 31 static void ngx_http_upstream_send_request(ngx_http_request_t *r,
 32     ngx_http_upstream_t *u);
 33 static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
 34     ngx_http_upstream_t *u);
 35 static void ngx_http_upstream_process_header(ngx_http_request_t *r,
 36     ngx_http_upstream_t *u);
 37 static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
 38     ngx_http_upstream_t *u);
 39 static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
 40     ngx_http_upstream_t *u);
 41 static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
 42 static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r,
 43     ngx_http_upstream_t *u);
 44 static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
 45     ngx_http_upstream_t *u);
 46 static void ngx_http_upstream_send_response(ngx_http_request_t *r,
 47     ngx_http_upstream_t *u);
 48 static void
 49     ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r);
 50 static void
 51     ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
 52     ngx_http_upstream_t *u);
 53 static void
 54     ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
 55     ngx_uint_t do_write);
 56 static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
 57 static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
 58     ssize_t bytes);
 59 static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
 60 static void ngx_http_upstream_process_upstream(ngx_http_request_t *r,
 61     ngx_http_upstream_t *u);
 62 static void ngx_http_upstream_process_request(ngx_http_request_t *r);
 63 static void ngx_http_upstream_store(ngx_http_request_t *r,
 64     ngx_http_upstream_t *u);
 65 static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r,
 66     ngx_http_upstream_t *u);
 67 static void ngx_http_upstream_next(ngx_http_request_t *r,
 68     ngx_http_upstream_t *u, ngx_uint_t ft_type);
 69 static void ngx_http_upstream_cleanup(void *data);
 70 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
 71     ngx_http_upstream_t *u, ngx_int_t rc);
 72 
 73 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
 74     ngx_table_elt_t *h, ngx_uint_t offset);
 75 static ngx_int_t
 76     ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
 77     ngx_table_elt_t *h, ngx_uint_t offset);
 78 static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
 79     ngx_table_elt_t *h, ngx_uint_t offset);
 80 static ngx_int_t ngx_http_upstream_process_expires(ngx_http_request_t *r,
 81     ngx_table_elt_t *h, ngx_uint_t offset);
 82 static ngx_int_t ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
 83     ngx_table_elt_t *h, ngx_uint_t offset);
 84 static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
 85     ngx_table_elt_t *h, ngx_uint_t offset);
 86 static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
 87     ngx_table_elt_t *h, ngx_uint_t offset);
 88 static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
 89     ngx_table_elt_t *h, ngx_uint_t offset);
 90 static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
 91     ngx_table_elt_t *h, ngx_uint_t offset);
 92 static ngx_int_t
 93     ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
 94     ngx_table_elt_t *h, ngx_uint_t offset);
 95 static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
 96     ngx_table_elt_t *h, ngx_uint_t offset);
 97 static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r,
 98     ngx_table_elt_t *h, ngx_uint_t offset);
 99 static ngx_int_t ngx_http_upstream_copy_last_modified(ngx_http_request_t *r,
100     ngx_table_elt_t *h, ngx_uint_t offset);
101 static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
102     ngx_table_elt_t *h, ngx_uint_t offset);
103 static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
104     ngx_table_elt_t *h, ngx_uint_t offset);
105 static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
106     ngx_table_elt_t *h, ngx_uint_t offset);
107 
108 #if (NGX_HTTP_GZIP)
109 static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
110     ngx_table_elt_t *h, ngx_uint_t offset);
111 #endif
112 
113 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
114 static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
115     ngx_http_variable_value_t *v, uintptr_t data);
116 static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
117     ngx_http_variable_value_t *v, uintptr_t data);
118 static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
119     ngx_http_variable_value_t *v, uintptr_t data);
120 static ngx_int_t ngx_http_upstream_response_length_variable(
121     ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
122 
123 static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
124 static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
125     void *conf);
126 
127 static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
128 static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
129 
130 #if (NGX_HTTP_SSL)
131 static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
132     ngx_http_upstream_t *u, ngx_connection_t *c);
133 static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
134 #endif
135 
136 
137 ngx_http_upstream_header_t  ngx_http_upstream_headers_in[] = {
138 
139     { ngx_string("Status"),
140                  ngx_http_upstream_process_header_line,
141                  offsetof(ngx_http_upstream_headers_in_t, status),
142                  ngx_http_upstream_copy_header_line, 0, 0 },
143 
144     { ngx_string("Content-Type"),
145                  ngx_http_upstream_process_header_line,
146                  offsetof(ngx_http_upstream_headers_in_t, content_type),
147                  ngx_http_upstream_copy_content_type, 0, 1 },
148 
149     { ngx_string("Content-Length"),
150                  ngx_http_upstream_process_header_line,
151                  offsetof(ngx_http_upstream_headers_in_t, content_length),
152                  ngx_http_upstream_copy_content_length, 0, 0 },
153 
154     { ngx_string("Date"),
155                  ngx_http_upstream_process_header_line,
156                  offsetof(ngx_http_upstream_headers_in_t, date),
157                  ngx_http_upstream_copy_header_line,
158                  offsetof(ngx_http_headers_out_t, date), 0 },
159 
160     { ngx_string("Last-Modified"),
161                  ngx_http_upstream_process_header_line,
162                  offsetof(ngx_http_upstream_headers_in_t, last_modified),
163                  ngx_http_upstream_copy_last_modified, 0, 0 },
164 
165     { ngx_string("ETag"),
166                  ngx_http_upstream_process_header_line,
167                  offsetof(ngx_http_upstream_headers_in_t, etag),
168                  ngx_http_upstream_copy_header_line,
169                  offsetof(ngx_http_headers_out_t, etag), 0 },
170 
171     { ngx_string("Server"),
172                  ngx_http_upstream_process_header_line,
173                  offsetof(ngx_http_upstream_headers_in_t, server),
174                  ngx_http_upstream_copy_header_line,
175                  offsetof(ngx_http_headers_out_t, server), 0 },
176 
177     { ngx_string("WWW-Authenticate"),
178                  ngx_http_upstream_process_header_line,
179                  offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
180                  ngx_http_upstream_copy_header_line, 0, 0 },
181 
182     { ngx_string("Location"),
183                  ngx_http_upstream_process_header_line,
184                  offsetof(ngx_http_upstream_headers_in_t, location),
185                  ngx_http_upstream_rewrite_location, 0, 0 },
186 
187     { ngx_string("Refresh"),
188                  ngx_http_upstream_ignore_header_line, 0,
189                  ngx_http_upstream_rewrite_refresh, 0, 0 },
190 
191     { ngx_string("Set-Cookie"),
192                  ngx_http_upstream_ignore_header_line, 0,
193                  ngx_http_upstream_copy_header_line, 0, 1 },
194 
195     { ngx_string("Content-Disposition"),
196                  ngx_http_upstream_ignore_header_line, 0,
197                  ngx_http_upstream_copy_header_line, 0, 1 },
198 
199     { ngx_string("Cache-Control"),
200                  ngx_http_upstream_process_cache_control, 0,
201                  ngx_http_upstream_copy_multi_header_lines,
202                  offsetof(ngx_http_headers_out_t, cache_control), 1 },
203 
204     { ngx_string("Expires"),
205                  ngx_http_upstream_process_expires, 0,
206                  ngx_http_upstream_copy_header_line,
207                  offsetof(ngx_http_headers_out_t, expires), 1 },
208 
209     { ngx_string("Accept-Ranges"),
210                  ngx_http_upstream_process_header_line,
211                  offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
212                  ngx_http_upstream_copy_allow_ranges,
213                  offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
214 
215     { ngx_string("Connection"),
216                  ngx_http_upstream_ignore_header_line, 0,
217                  ngx_http_upstream_ignore_header_line, 0, 0 },
218 
219     { ngx_string("Keep-Alive"),
220                  ngx_http_upstream_ignore_header_line, 0,
221                  ngx_http_upstream_ignore_header_line, 0, 0 },
222 
223     { ngx_string("X-Powered-By"),
224                  ngx_http_upstream_ignore_header_line, 0,
225                  ngx_http_upstream_copy_header_line, 0, 0 },
226 
227     { ngx_string("X-Accel-Expires"),
228                  ngx_http_upstream_process_accel_expires, 0,
229                  ngx_http_upstream_copy_header_line, 0, 0 },
230 
231     { ngx_string("X-Accel-Redirect"),
232                  ngx_http_upstream_process_header_line,
233                  offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
234                  ngx_http_upstream_copy_header_line, 0, 0 },
235 
236     { ngx_string("X-Accel-Limit-Rate"),
237                  ngx_http_upstream_process_limit_rate, 0,
238                  ngx_http_upstream_copy_header_line, 0, 0 },
239 
240     { ngx_string("X-Accel-Buffering"),
241                  ngx_http_upstream_process_buffering, 0,
242                  ngx_http_upstream_copy_header_line, 0, 0 },
243 
244     { ngx_string("X-Accel-Charset"),
245                  ngx_http_upstream_process_charset, 0,
246                  ngx_http_upstream_copy_header_line, 0, 0 },
247 
248 #if (NGX_HTTP_GZIP)
249     { ngx_string("Content-Encoding"),
250                  ngx_http_upstream_process_header_line,
251                  offsetof(ngx_http_upstream_headers_in_t, content_encoding),
252                  ngx_http_upstream_copy_content_encoding, 0, 0 },
253 #endif
254 
255     { ngx_null_string, NULL, 0, NULL, 0, 0 }
256 };
257 
258 
259 static ngx_command_t  ngx_http_upstream_commands[] = {
260 
261     { ngx_string("upstream"),
262       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
263       ngx_http_upstream,
264       0,
265       0,
266       NULL },
267 
268     { ngx_string("server"),
269       NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
270       ngx_http_upstream_server,
271       NGX_HTTP_SRV_CONF_OFFSET,
272       0,
273       NULL },
274 
275       ngx_null_command
276 };
277 
278 
279 static ngx_http_module_t  ngx_http_upstream_module_ctx = {
280     ngx_http_upstream_add_variables,       /* preconfiguration */
281     NULL,                                  /* postconfiguration */
282 
283     ngx_http_upstream_create_main_conf,    /* create main configuration */
284     ngx_http_upstream_init_main_conf,      /* init main configuration */
285 
286     NULL,                                  /* create server configuration */
287     NULL,                                  /* merge server configuration */
288 
289     NULL,                                  /* create location configuration */
290     NULL                                   /* merge location configuration */
291 };
292 
293 
294 ngx_module_t  ngx_http_upstream_module = {
295     NGX_MODULE_V1,
296     &ngx_http_upstream_module_ctx,         /* module context */
297     ngx_http_upstream_commands,            /* module directives */
298     NGX_HTTP_MODULE,                       /* module type */
299     NULL,                                  /* init master */
300     NULL,                                  /* init module */
301     NULL,                                  /* init process */
302     NULL,                                  /* init thread */
303     NULL,                                  /* exit thread */
304     NULL,                                  /* exit process */
305     NULL,                                  /* exit master */
306     NGX_MODULE_V1_PADDING
307 };
308 
309 
310 static ngx_http_variable_t  ngx_http_upstream_vars[] = {
311 
312     { ngx_string("upstream_addr"), NULL,
313       ngx_http_upstream_addr_variable, 0,
314       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
315 
316     { ngx_string("upstream_status"), NULL,
317       ngx_http_upstream_status_variable, 0,
318       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
319 
320     { ngx_string("upstream_response_time"), NULL,
321       ngx_http_upstream_response_time_variable, 0,
322       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
323 
324     { ngx_string("upstream_response_length"), NULL,
325       ngx_http_upstream_response_length_variable, 0,
326       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
327 
328 #if (NGX_HTTP_CACHE)
329 
330     { ngx_string("upstream_cache_status"), NULL,
331       ngx_http_upstream_cache_status, 0,
332       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
333 
334 #endif
335 
336     { ngx_null_string, NULL, NULL, 0, 0, 0 }
337 };
338 
339 
340 static ngx_http_upstream_next_t  ngx_http_upstream_next_errors[] = {
341     { 500, NGX_HTTP_UPSTREAM_FT_HTTP_500 },
342     { 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 },
343     { 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 },
344     { 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 },
345     { 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 },
346     { 0, 0 }
347 };
348 
349 
350 ngx_conf_bitmask_t  ngx_http_upstream_cache_method_mask[] = {
351    { ngx_string("GET"),  NGX_HTTP_GET},
352    { ngx_string("HEAD"), NGX_HTTP_HEAD },
353    { ngx_string("POST"), NGX_HTTP_POST },
354    { ngx_null_string, 0 }
355 };
356 
357 
358 ngx_int_t
359 ngx_http_upstream_create(ngx_http_request_t *r)
360 {
361     ngx_http_upstream_t  *u;
362 
363     u = r->upstream;
364 
365     if (u && u->cleanup) {
366         r->main->count++;
367         ngx_http_upstream_cleanup(r);
368         *u->cleanup = NULL;
369     }
370 
371     u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
372     if (u == NULL) {
373         return NGX_ERROR;
374     }
375 
376     r->upstream = u;
377 
378     u->peer.log = r->connection->log;
379     u->peer.log_error = NGX_ERROR_ERR;
380 #if (NGX_THREADS)
381     u->peer.lock = &r->connection->lock;
382 #endif
383 
384 #if (NGX_HTTP_CACHE)
385     r->cache = NULL;
386 #endif
387 
388     return NGX_OK;
389 }
390 
391 
392 void
393 ngx_http_upstream_init(ngx_http_request_t *r)
394 {
395     ngx_connection_t     *c;
396 
397     c = r->connection;
398 
399     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
400                    "http init upstream, client timer: %d", c->read->timer_set);
401 
402     if (c->read->timer_set) {
403         ngx_del_timer(c->read);
404     }
405 
406     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
407 
408         if (!c->write->active) {
409             if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
410                 == NGX_ERROR)
411             {
412                 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
413                 return;
414             }
415         }
416     }
417 
418     ngx_http_upstream_init_request(r);
419 }
420 
421 
422 static void
423 ngx_http_upstream_init_request(ngx_http_request_t *r)
424 {
425     ngx_str_t                      *host;
426     ngx_uint_t                      i;
427     ngx_resolver_ctx_t             *ctx, temp;
428     ngx_http_cleanup_t             *cln;
429     ngx_http_upstream_t            *u;
430     ngx_http_core_loc_conf_t       *clcf;
431     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
432     ngx_http_upstream_main_conf_t  *umcf;
433 
434     if (r->aio) {
435         return;
436     }
437 
438     u = r->upstream;
439 
440 #if (NGX_HTTP_CACHE)
441 
442     if (u->conf->cache) {
443         ngx_int_t  rc;
444 
445         rc = ngx_http_upstream_cache(r, u);
446 
447         if (rc == NGX_BUSY) {
448             r->write_event_handler = ngx_http_upstream_init_request;
449             return;
450         }
451 
452         r->write_event_handler = ngx_http_request_empty_handler;
453 
454         if (rc == NGX_DONE) {
455             return;
456         }
457 
458         if (rc != NGX_DECLINED) {
459             ngx_http_finalize_request(r, rc);
460             return;
461         }
462     }
463 
464 #endif
465 
466     u->store = (u->conf->store || u->conf->store_lengths);
467 
468     if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
469         r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
470         r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
471     }
472 
473     if (r->request_body) {
474         u->request_bufs = r->request_body->bufs;
475     }
476 
477     if (u->create_request(r) != NGX_OK) {
478         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
479         return;
480     }
481 
482     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
483 
484     u->output.alignment = clcf->directio_alignment;
485     u->output.pool = r->pool;
486     u->output.bufs.num = 1;
487     u->output.bufs.size = clcf->client_body_buffer_size;
488     u->output.output_filter = ngx_chain_writer;
489     u->output.filter_ctx = &u->writer;
490 
491     u->writer.pool = r->pool;
492 
493     if (r->upstream_states == NULL) {
494 
495         r->upstream_states = ngx_array_create(r->pool, 1,
496                                             sizeof(ngx_http_upstream_state_t));
497         if (r->upstream_states == NULL) {
498             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
499             return;
500         }
501 
502     } else {
503 
504         u->state = ngx_array_push(r->upstream_states);
505         if (u->state == NULL) {
506             ngx_http_upstream_finalize_request(r, u,
507                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
508             return;
509         }
510 
511         ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
512     }
513 
514     cln = ngx_http_cleanup_add(r, 0);
515     if (cln == NULL) {
516         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
517         return;
518     }
519 
520     cln->handler = ngx_http_upstream_cleanup;
521     cln->data = r;
522     u->cleanup = &cln->handler;
523 
524     if (u->resolved == NULL) {
525 
526         uscf = u->conf->upstream;
527 
528     } else {
529 
530         if (u->resolved->sockaddr) {
531 
532             if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
533                 != NGX_OK)
534             {
535                 ngx_http_upstream_finalize_request(r, u,
536                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
537                 return;
538             }
539 
540             ngx_http_upstream_connect(r, u);
541 
542             return;
543         }
544 
545         host = &u->resolved->host;
546 
547         umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
548 
549         uscfp = umcf->upstreams.elts;
550 
551         for (i = 0; i < umcf->upstreams.nelts; i++) {
552 
553             uscf = uscfp[i];
554 
555             if (uscf->host.len == host->len
556                 && ((uscf->port == 0 && u->resolved->no_port)
557                      || uscf->port == u->resolved->port)
558                 && ngx_memcmp(uscf->host.data, host->data, host->len) == 0)
559             {
560                 goto found;
561             }
562         }
563 
564         temp.name = *host;
565 
566         ctx = ngx_resolve_start(clcf->resolver, &temp);
567         if (ctx == NULL) {
568             ngx_http_upstream_finalize_request(r, u,
569                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
570             return;
571         }
572 
573         if (ctx == NGX_NO_RESOLVER) {
574             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
575                           "no resolver defined to resolve %V", host);
576 
577             ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
578             return;
579         }
580 
581         ctx->name = *host;
582         ctx->type = NGX_RESOLVE_A;
583         ctx->handler = ngx_http_upstream_resolve_handler;
584         ctx->data = r;
585         ctx->timeout = clcf->resolver_timeout;
586 
587         u->resolved->ctx = ctx;
588 
589         if (ngx_resolve_name(ctx) != NGX_OK) {
590             u->resolved->ctx = NULL;
591             ngx_http_upstream_finalize_request(r, u,
592                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
593             return;
594         }
595 
596         return;
597     }
598 
599 found:
600 
601     if (uscf->peer.init(r, uscf) != NGX_OK) {
602         ngx_http_upstream_finalize_request(r, u,
603                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
604         return;
605     }
606 
607     ngx_http_upstream_connect(r, u);
608 }
609 
610 
611 #if (NGX_HTTP_CACHE)
612 
613 static ngx_int_t
614 ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
615 {
616     ngx_int_t          rc;
617     ngx_http_cache_t  *c;
618 
619     c = r->cache;
620 
621     if (c == NULL) {
622 
623         if (!(r->method & u->conf->cache_methods)) {
624             return NGX_DECLINED;
625         }
626 
627         if (r->method & NGX_HTTP_HEAD) {
628             u->method = ngx_http_core_get_method;
629         }
630 
631         c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
632         if (c == NULL) {
633             return NGX_ERROR;
634         }
635 
636         if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
637             return NGX_ERROR;
638         }
639 
640         r->cache = c;
641         c->file.log = r->connection->log;
642 
643         if (u->create_key(r) != NGX_OK) {
644             return NGX_ERROR;
645         }
646 
647         /* TODO: add keys */
648 
649         ngx_http_file_cache_create_key(r);
650 
651         u->cacheable = 1;
652 
653         c->min_uses = u->conf->cache_min_uses;
654         c->body_start = u->conf->buffer_size;
655         c->file_cache = u->conf->cache->data;
656 
657         u->cache_status = NGX_HTTP_CACHE_MISS;
658     }
659 
660     rc = ngx_http_file_cache_open(r);
661 
662     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
663                    "http upstream cache: %i", rc);
664 
665     switch (rc) {
666 
667     case NGX_HTTP_CACHE_UPDATING:
668 
669         if (u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) {
670             u->cache_status = rc;
671             rc = NGX_OK;
672 
673         } else {
674             rc = NGX_HTTP_CACHE_STALE;
675         }
676 
677         break;
678 
679     case NGX_OK:
680         u->cache_status = NGX_HTTP_CACHE_HIT;
681     }
682 
683     switch (rc) {
684 
685     case NGX_OK:
686 
687         rc = ngx_http_upstream_cache_send(r, u);
688 
689         if (rc != NGX_HTTP_UPSTREAM_INVALID_HEADER) {
690             return rc;
691         }
692 
693         break;
694 
695     case NGX_HTTP_CACHE_STALE:
696 
697         c->valid_sec = 0;
698         u->buffer.start = NULL;
699         u->cache_status = NGX_HTTP_CACHE_EXPIRED;
700 
701         break;
702 
703     case NGX_DECLINED:
704 
705         if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {
706             u->buffer.start = NULL;
707 
708         } else {
709             u->buffer.pos = u->buffer.start + c->header_start;
710             u->buffer.last = u->buffer.pos;
711         }
712 
713         break;
714 
715     case NGX_HTTP_CACHE_SCARCE:
716 
717         u->cacheable = 0;
718 
719         break;
720 
721     case NGX_AGAIN:
722 
723         return NGX_BUSY;
724 
725     case NGX_ERROR:
726 
727         return NGX_ERROR;
728 
729     default:
730 
731         /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
732 
733         u->cache_status = NGX_HTTP_CACHE_HIT;
734 
735         return rc;
736     }
737 
738     r->cached = 0;
739 
740     return NGX_DECLINED;
741 }
742 
743 
744 static ngx_int_t
745 ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
746 {
747     ngx_int_t          rc;
748     ngx_http_cache_t  *c;
749 
750     r->cached = 1;
751     c = r->cache;
752 
753     /* TODO: cache stack */
754 
755     u->buffer = *c->buf;
756     u->buffer.pos += c->header_start;
757 
758     ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
759 
760     if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
761                       sizeof(ngx_table_elt_t))
762         != NGX_OK)
763     {
764         return NGX_ERROR;
765     }
766 
767     rc = u->process_header(r);
768 
769     if (rc == NGX_OK) {
770 
771         if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
772             return NGX_DONE;
773         }
774 
775         return ngx_http_cache_send(r);
776     }
777 
778     if (rc == NGX_ERROR) {
779         return NGX_ERROR;
780     }
781 
782     /* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */
783 
784     /* TODO: delete file */
785 
786     return rc;
787 }
788 
789 #endif
790 
791 
792 static void
793 ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
794 {
795     ngx_http_request_t            *r;
796     ngx_http_upstream_t           *u;
797     ngx_http_upstream_resolved_t  *ur;
798 
799     r = ctx->data;
800 
801     u = r->upstream;
802     ur = u->resolved;
803 
804     if (ctx->state) {
805         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
806                       "%V could not be resolved (%i: %s)",
807                       &ctx->name, ctx->state,
808                       ngx_resolver_strerror(ctx->state));
809 
810         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
811         return;
812     }
813 
814     ur->naddrs = ctx->naddrs;
815     ur->addrs = ctx->addrs;
816 
817 #if (NGX_DEBUG)
818     {
819     in_addr_t   addr;
820     ngx_uint_t  i;
821 
822     for (i = 0; i < ctx->naddrs; i++) {
823         addr = ntohl(ur->addrs[i]);
824 
825         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
826                        "name was resolved to %ud.%ud.%ud.%ud",
827                        (addr >> 24) & 0xff, (addr >> 16) & 0xff,
828                        (addr >> 8) & 0xff, addr & 0xff);
829     }
830     }
831 #endif
832 
833     if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
834         ngx_http_upstream_finalize_request(r, u,
835                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
836         return;
837     }
838 
839     ngx_resolve_name_done(ctx);
840     ur->ctx = NULL;
841 
842     ngx_http_upstream_connect(r, u);
843 }
844 
845 
846 static void
847 ngx_http_upstream_handler(ngx_event_t *ev)
848 {
849     ngx_connection_t     *c;
850     ngx_http_request_t   *r;
851     ngx_http_log_ctx_t   *ctx;
852     ngx_http_upstream_t  *u;
853 
854     c = ev->data;
855     r = c->data;
856 
857     u = r->upstream;
858     c = r->connection;
859 
860     ctx = c->log->data;
861     ctx->current_request = r;
862 
863     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
864                    "http upstream request: \"%V?%V\"", &r->uri, &r->args);
865 
866     if (ev->write) {
867         u->write_event_handler(r, u);
868 
869     } else {
870         u->read_event_handler(r, u);
871     }
872 
873     ngx_http_run_posted_requests(c);
874 }
875 
876 
877 static void
878 ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
879 {
880     ngx_http_upstream_check_broken_connection(r, r->connection->read);
881 }
882 
883 
884 static void
885 ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
886 {
887     ngx_http_upstream_check_broken_connection(r, r->connection->write);
888 }
889 
890 
891 static void
892 ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
893     ngx_event_t *ev)
894 {
895     int                  n;
896     char                 buf[1];
897     ngx_err_t            err;
898     ngx_int_t            event;
899     ngx_connection_t     *c;
900     ngx_http_upstream_t  *u;
901 
902     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
903                    "http upstream check client, write event:%d, \"%V\"",
904                    ev->write, &r->uri);
905 
906     c = r->connection;
907     u = r->upstream;
908 
909     if (c->error) {
910         if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
911 
912             event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
913 
914             if (ngx_del_event(ev, event, 0) != NGX_OK) {
915                 ngx_http_upstream_finalize_request(r, u,
916                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
917                 return;
918             }
919         }
920 
921         if (!u->cacheable) {
922             ngx_http_upstream_finalize_request(r, u,
923                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
924         }
925 
926         return;
927     }
928 
929 #if (NGX_HAVE_KQUEUE)
930 
931     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
932 
933         if (!ev->pending_eof) {
934             return;
935         }
936 
937         ev->eof = 1;
938         c->error = 1;
939 
940         if (ev->kq_errno) {
941             ev->error = 1;
942         }
943 
944         if (!u->cacheable && u->peer.connection) {
945             ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
946                           "kevent() reported that client closed prematurely "
947                           "connection, so upstream connection is closed too");
948             ngx_http_upstream_finalize_request(r, u,
949                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
950             return;
951         }
952 
953         ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
954                       "kevent() reported that client closed "
955                       "prematurely connection");
956 
957         if (u->peer.connection == NULL) {
958             ngx_http_upstream_finalize_request(r, u,
959                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
960         }
961 
962         return;
963     }
964 
965 #endif
966 
967     n = recv(c->fd, buf, 1, MSG_PEEK);
968 
969     err = ngx_socket_errno;
970 
971     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
972                    "http upstream recv(): %d", n);
973 
974     if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
975         return;
976     }
977 
978     if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
979 
980         event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
981 
982         if (ngx_del_event(ev, event, 0) != NGX_OK) {
983             ngx_http_upstream_finalize_request(r, u,
984                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
985             return;
986         }
987     }
988 
989     if (n > 0) {
990         return;
991     }
992 
993     if (n == -1) {
994         if (err == NGX_EAGAIN) {
995             return;
996         }
997 
998         ev->error = 1;
999 
1000     } else { /* n == 0 */
1001         err = 0;
1002     }
1003 
1004     ev->eof = 1;
1005     c->error = 1;
1006 
1007     if (!u->cacheable && u->peer.connection) {
1008         ngx_log_error(NGX_LOG_INFO, ev->log, err,
1009                       "client closed prematurely connection, "
1010                       "so upstream connection is closed too");
1011         ngx_http_upstream_finalize_request(r, u,
1012                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
1013         return;
1014     }
1015 
1016     ngx_log_error(NGX_LOG_INFO, ev->log, err,
1017                   "client closed prematurely connection");
1018 
1019     if (u->peer.connection == NULL) {
1020         ngx_http_upstream_finalize_request(r, u,
1021                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
1022     }
1023 }
1024 
1025 
1026 static void
1027 ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
1028 {
1029     ngx_int_t          rc;
1030     ngx_time_t        *tp;
1031     ngx_connection_t  *c;
1032 
1033     r->connection->log->action = "connecting to upstream";
1034 
1035     r->connection->single_connection = 0;
1036 
1037     if (u->state && u->state->response_sec) {
1038         tp = ngx_timeofday();
1039         u->state->response_sec = tp->sec - u->state->response_sec;
1040         u->state->response_msec = tp->msec - u->state->response_msec;
1041     }
1042 
1043     u->state = ngx_array_push(r->upstream_states);
1044     if (u->state == NULL) {
1045         ngx_http_upstream_finalize_request(r, u,
1046                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1047         return;
1048     }
1049 
1050     ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
1051 
1052     tp = ngx_timeofday();
1053     u->state->response_sec = tp->sec;
1054     u->state->response_msec = tp->msec;
1055 
1056     rc = ngx_event_connect_peer(&u->peer);
1057 
1058     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1059                    "http upstream connect: %i", rc);
1060 
1061     if (rc == NGX_ERROR) {
1062         ngx_http_upstream_finalize_request(r, u,
1063                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1064         return;
1065     }
1066 
1067     u->state->peer = u->peer.name;
1068 
1069     if (rc == NGX_BUSY) {
1070         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
1071         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
1072         return;
1073     }
1074 
1075     if (rc == NGX_DECLINED) {
1076         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1077         return;
1078     }
1079 
1080     /* rc == NGX_OK || rc == NGX_AGAIN */
1081 
1082     c = u->peer.connection;
1083 
1084     c->data = r;
1085 
1086     c->write->handler = ngx_http_upstream_handler;
1087     c->read->handler = ngx_http_upstream_handler;
1088 
1089     u->write_event_handler = ngx_http_upstream_send_request_handler;
1090     u->read_event_handler = ngx_http_upstream_process_header;
1091 
1092     c->sendfile &= r->connection->sendfile;
1093     u->output.sendfile = c->sendfile;
1094 
1095     c->pool = r->pool;
1096     c->log = r->connection->log;
1097     c->read->log = c->log;
1098     c->write->log = c->log;
1099 
1100     /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
1101 
1102     u->writer.out = NULL;
1103     u->writer.last = &u->writer.out;
1104     u->writer.connection = c;
1105     u->writer.limit = 0;
1106 
1107     if (u->request_sent) {
1108         if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
1109             ngx_http_upstream_finalize_request(r, u,
1110                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1111             return;
1112         }
1113     }
1114 
1115     if (r->request_body
1116         && r->request_body->buf
1117         && r->request_body->temp_file
1118         && r == r->main)
1119     {
1120         /*
1121          * the r->request_body->buf can be reused for one request only,
1122          * the subrequests should allocate their own temporay bufs
1123          */
1124 
1125         u->output.free = ngx_alloc_chain_link(r->pool);
1126         if (u->output.free == NULL) {
1127             ngx_http_upstream_finalize_request(r, u,
1128                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1129             return;
1130         }
1131 
1132         u->output.free->buf = r->request_body->buf;
1133         u->output.free->next = NULL;
1134         u->output.allocated = 1;
1135 
1136         r->request_body->buf->pos = r->request_body->buf->start;
1137         r->request_body->buf->last = r->request_body->buf->start;
1138         r->request_body->buf->tag = u->output.tag;
1139     }
1140 
1141     u->request_sent = 0;
1142 
1143     if (rc == NGX_AGAIN) {
1144         ngx_add_timer(c->write, u->conf->connect_timeout);
1145         return;
1146     }
1147 
1148 #if (NGX_HTTP_SSL)
1149 
1150     if (u->ssl && c->ssl == NULL) {
1151         ngx_http_upstream_ssl_init_connection(r, u, c);
1152         return;
1153     }
1154 
1155 #endif
1156 
1157     ngx_http_upstream_send_request(r, u);
1158 }
1159 
1160 
1161 #if (NGX_HTTP_SSL)
1162 
1163 static void
1164 ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
1165     ngx_http_upstream_t *u, ngx_connection_t *c)
1166 {
1167     ngx_int_t   rc;
1168 
1169     if (ngx_ssl_create_connection(u->conf->ssl, c,
1170                                   NGX_SSL_BUFFER|NGX_SSL_CLIENT)
1171         != NGX_OK)
1172     {
1173         ngx_http_upstream_finalize_request(r, u,
1174                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1175         return;
1176     }
1177 
1178     c->sendfile = 0;
1179     u->output.sendfile = 0;
1180 
1181     if (u->conf->ssl_session_reuse) {
1182         if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
1183             ngx_http_upstream_finalize_request(r, u,
1184                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1185             return;
1186         }
1187     }
1188 
1189     r->connection->log->action = "SSL handshaking to upstream";
1190 
1191     rc = ngx_ssl_handshake(c);
1192 
1193     if (rc == NGX_AGAIN) {
1194         c->ssl->handler = ngx_http_upstream_ssl_handshake;
1195         return;
1196     }
1197 
1198     ngx_http_upstream_ssl_handshake(c);
1199 }
1200 
1201 
1202 static void
1203 ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
1204 {
1205     ngx_http_request_t   *r;
1206     ngx_http_upstream_t  *u;
1207 
1208     r = c->data;
1209     u = r->upstream;
1210 
1211     if (c->ssl->handshaked) {
1212 
1213         if (u->conf->ssl_session_reuse) {
1214             u->peer.save_session(&u->peer, u->peer.data);
1215         }
1216 
1217         c->write->handler = ngx_http_upstream_handler;
1218         c->read->handler = ngx_http_upstream_handler;
1219 
1220         ngx_http_upstream_send_request(r, u);
1221 
1222         return;
1223     }
1224 
1225     ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1226 
1227 }
1228 
1229 #endif
1230 
1231 
1232 static ngx_int_t
1233 ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
1234 {
1235     ngx_chain_t  *cl;
1236 
1237     if (u->reinit_request(r) != NGX_OK) {
1238         return NGX_ERROR;
1239     }
1240 
1241     ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
1242 
1243     if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
1244                       sizeof(ngx_table_elt_t))
1245         != NGX_OK)
1246     {
1247         return NGX_ERROR;
1248     }
1249 
1250     /* reinit the request chain */
1251 
1252     for (cl = u->request_bufs; cl; cl = cl->next) {
1253         cl->buf->pos = cl->buf->start;
1254         cl->buf->file_pos = 0;
1255     }
1256 
1257     /* reinit the subrequest's ngx_output_chain() context */
1258 
1259     if (r->request_body && r->request_body->temp_file
1260         && r != r->main && u->output.buf)
1261     {
1262         u->output.free = ngx_alloc_chain_link(r->pool);
1263         if (u->output.free == NULL) {
1264             return NGX_ERROR;
1265         }
1266 
1267         u->output.free->buf = u->output.buf;
1268         u->output.free->next = NULL;
1269 
1270         u->output.buf->pos = u->output.buf->start;
1271         u->output.buf->last = u->output.buf->start;
1272     }
1273 
1274     u->output.buf = NULL;
1275     u->output.in = NULL;
1276     u->output.busy = NULL;
1277 
1278     /* reinit u->buffer */
1279 
1280     u->buffer.pos = u->buffer.start;
1281 
1282 #if (NGX_HTTP_CACHE)
1283 
1284     if (r->cache) {
1285         u->buffer.pos += r->cache->header_start;
1286     }
1287 
1288 #endif
1289 
1290     u->buffer.last = u->buffer.pos;
1291 
1292     return NGX_OK;
1293 }
1294 
1295 
1296 static void
1297 ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
1298 {
1299     ngx_int_t          rc;
1300     ngx_connection_t  *c;
1301 
1302     c = u->peer.connection;
1303 
1304     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1305                    "http upstream send request");
1306 
1307     if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
1308         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1309         return;
1310     }
1311 
1312     c->log->action = "sending request to upstream";
1313 
1314     rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
1315 
1316     u->request_sent = 1;
1317 
1318     if (rc == NGX_ERROR) {
1319         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1320         return;
1321     }
1322 
1323     if (c->write->timer_set) {
1324         ngx_del_timer(c->write);
1325     }
1326 
1327     if (rc == NGX_AGAIN) {
1328         ngx_add_timer(c->write, u->conf->send_timeout);
1329 
1330         if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) {
1331             ngx_http_upstream_finalize_request(r, u,
1332                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1333             return;
1334         }
1335 
1336         return;
1337     }
1338 
1339     /* rc == NGX_OK */
1340 
1341     if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
1342         if (ngx_tcp_push(c->fd) == NGX_ERROR) {
1343             ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
1344                           ngx_tcp_push_n " failed");
1345             ngx_http_upstream_finalize_request(r, u,
1346                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1347             return;
1348         }
1349 
1350         c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
1351     }
1352 
1353     ngx_add_timer(c->read, u->conf->read_timeout);
1354 
1355 #if 1
1356     if (c->read->ready) {
1357 
1358         /* post aio operation */
1359 
1360         /*
1361          * TODO comment
1362          * although we can post aio operation just in the end
1363          * of ngx_http_upstream_connect() CHECK IT !!!
1364          * it's better to do here because we postpone header buffer allocation
1365          */
1366 
1367         ngx_http_upstream_process_header(r, u);
1368         return;
1369     }
1370 #endif
1371 
1372     u->write_event_handler = ngx_http_upstream_dummy_handler;
1373 
1374     if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1375         ngx_http_upstream_finalize_request(r, u,
1376                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1377         return;
1378     }
1379 }
1380 
1381 
1382 static void
1383 ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
1384     ngx_http_upstream_t *u)
1385 {
1386     ngx_connection_t  *c;
1387 
1388     c = u->peer.connection;
1389 
1390     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1391                    "http upstream send request handler");
1392 
1393     if (c->write->timedout) {
1394         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1395         return;
1396     }
1397 
1398 #if (NGX_HTTP_SSL)
1399 
1400     if (u->ssl && c->ssl == NULL) {
1401         ngx_http_upstream_ssl_init_connection(r, u, c);
1402         return;
1403     }
1404 
1405 #endif
1406 
1407     if (u->header_sent) {
1408         u->write_event_handler = ngx_http_upstream_dummy_handler;
1409 
1410         (void) ngx_handle_write_event(c->write, 0);
1411 
1412         return;
1413     }
1414 
1415     ngx_http_upstream_send_request(r, u);
1416 }
1417 
1418 
1419 static void
1420 ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
1421 {
1422     ssize_t            n;
1423     ngx_int_t          rc;
1424     ngx_connection_t  *c;
1425 
1426     c = u->peer.connection;
1427 
1428     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1429                    "http upstream process header");
1430 
1431     c->log->action = "reading response header from upstream";
1432 
1433     if (c->read->timedout) {
1434         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1435         return;
1436     }
1437 
1438     if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
1439         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1440         return;
1441     }
1442 
1443     if (u->buffer.start == NULL) {
1444         u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size);
1445         if (u->buffer.start == NULL) {
1446             ngx_http_upstream_finalize_request(r, u,
1447                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1448             return;
1449         }
1450 
1451         u->buffer.pos = u->buffer.start;
1452         u->buffer.last = u->buffer.start;
1453         u->buffer.end = u->buffer.start + u->conf->buffer_size;
1454         u->buffer.temporary = 1;
1455 
1456         u->buffer.tag = u->output.tag;
1457 
1458         if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
1459                           sizeof(ngx_table_elt_t))
1460             != NGX_OK)
1461         {
1462             ngx_http_upstream_finalize_request(r, u,
1463                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1464             return;
1465         }
1466 
1467 #if (NGX_HTTP_CACHE)
1468 
1469         if (r->cache) {
1470             u->buffer.pos += r->cache->header_start;
1471             u->buffer.last = u->buffer.pos;
1472         }
1473 #endif
1474     }
1475 
1476     for ( ;; ) {
1477 
1478         n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);
1479 
1480         if (n == NGX_AGAIN) {
1481 #if 0
1482             ngx_add_timer(rev, u->read_timeout);
1483 #endif
1484 
1485             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1486                 ngx_http_upstream_finalize_request(r, u,
1487                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1488                 return;
1489             }
1490 
1491             return;
1492         }
1493 
1494         if (n == 0) {
1495             ngx_log_error(NGX_LOG_ERR, c->log, 0,
1496                           "upstream prematurely closed connection");
1497         }
1498 
1499         if (n == NGX_ERROR || n == 0) {
1500             ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1501             return;
1502         }
1503 
1504         u->buffer.last += n;
1505 
1506 #if 0
1507         u->valid_header_in = 0;
1508 
1509         u->peer.cached = 0;
1510 #endif
1511 
1512         rc = u->process_header(r);
1513 
1514         if (rc == NGX_AGAIN) {
1515 
1516             if (u->buffer.pos == u->buffer.end) {
1517                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
1518                               "upstream sent too big header");
1519 
1520                 ngx_http_upstream_next(r, u,
1521                                        NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
1522                 return;
1523             }
1524 
1525             continue;
1526         }
1527 
1528         break;
1529     }
1530 
1531     if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
1532         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
1533         return;
1534     }
1535 
1536     if (rc == NGX_ERROR) {
1537         ngx_http_upstream_finalize_request(r, u,
1538                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1539         return;
1540     }
1541 
1542     /* rc == NGX_OK */
1543 
1544     if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST) {
1545 
1546         if (r->subrequest_in_memory) {
1547             u->buffer.last = u->buffer.pos;
1548         }
1549 
1550         if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
1551             return;
1552         }
1553 
1554         if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) {
1555             return;
1556         }
1557     }
1558 
1559     if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
1560         return;
1561     }
1562 
1563     if (!r->subrequest_in_memory) {
1564         ngx_http_upstream_send_response(r, u);
1565         return;
1566     }
1567 
1568     /* subrequest content in memory */
1569 
1570     if (u->input_filter == NULL) {
1571         u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
1572         u->input_filter = ngx_http_upstream_non_buffered_filter;
1573         u->input_filter_ctx = r;
1574     }
1575 
1576     if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
1577         ngx_http_upstream_finalize_request(r, u,
1578                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1579         return;
1580     }
1581 
1582     n = u->buffer.last - u->buffer.pos;
1583 
1584     if (n) {
1585         u->buffer.last -= n;
1586 
1587         u->state->response_length += n;
1588 
1589         if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1590             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1591             return;
1592         }
1593 
1594         if (u->length == 0) {
1595             ngx_http_upstream_finalize_request(r, u, 0);
1596             return;
1597         }
1598     }
1599 
1600     u->read_event_handler = ngx_http_upstream_process_body_in_memory;
1601 
1602     ngx_http_upstream_process_body_in_memory(r, u);
1603 }
1604 
1605 
1606 static ngx_int_t
1607 ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
1608 {
1609     ngx_uint_t                 status;
1610     ngx_http_upstream_next_t  *un;
1611 
1612     status = u->headers_in.status_n;
1613 
1614     for (un = ngx_http_upstream_next_errors; un->status; un++) {
1615 
1616         if (status != un->status) {
1617             continue;
1618         }
1619 
1620         if (u->peer.tries > 1 && (u->conf->next_upstream & un->mask)) {
1621             ngx_http_upstream_next(r, u, un->mask);
1622             return NGX_OK;
1623         }
1624 
1625 #if (NGX_HTTP_CACHE)
1626 
1627         if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
1628             && (u->conf->cache_use_stale & un->mask))
1629         {
1630             ngx_int_t  rc;
1631 
1632             rc = u->reinit_request(r);
1633 
1634             if (rc == NGX_OK) {
1635                 u->cache_status = NGX_HTTP_CACHE_STALE;
1636                 rc = ngx_http_upstream_cache_send(r, u);
1637             }
1638 
1639             ngx_http_upstream_finalize_request(r, u, rc);
1640             return NGX_OK;
1641         }
1642 
1643 #endif
1644     }
1645 
1646     return NGX_DECLINED;
1647 }
1648 
1649 
1650 static ngx_int_t
1651 ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
1652     ngx_http_upstream_t *u)
1653 {
1654     ngx_int_t                  status;
1655     ngx_uint_t                 i;
1656     ngx_table_elt_t           *h;
1657     ngx_http_err_page_t       *err_page;
1658     ngx_http_core_loc_conf_t  *clcf;
1659 
1660     status = u->headers_in.status_n;
1661 
1662     if (status == NGX_HTTP_NOT_FOUND && u->conf->intercept_404) {
1663         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
1664         return NGX_OK;
1665     }
1666 
1667     if (!u->conf->intercept_errors) {
1668         return NGX_DECLINED;
1669     }
1670 
1671     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1672 
1673     if (clcf->error_pages == NULL) {
1674         return NGX_DECLINED;
1675     }
1676 
1677     err_page = clcf->error_pages->elts;
1678     for (i = 0; i < clcf->error_pages->nelts; i++) {
1679 
1680         if (err_page[i].status == status) {
1681 
1682             if (status == NGX_HTTP_UNAUTHORIZED
1683                 && u->headers_in.www_authenticate)
1684             {
1685                 h = ngx_list_push(&r->headers_out.headers);
1686 
1687                 if (h == NULL) {
1688                     ngx_http_upstream_finalize_request(r, u,
1689                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1690                     return NGX_OK;
1691                 }
1692 
1693                 *h = *u->headers_in.www_authenticate;
1694 
1695                 r->headers_out.www_authenticate = h;
1696             }
1697 
1698             ngx_http_upstream_finalize_request(r, u, status);
1699 
1700             return NGX_OK;
1701         }
1702     }
1703 
1704     return NGX_DECLINED;
1705 }
1706 
1707 
1708 static ngx_int_t
1709 ngx_http_upstream_test_connect(ngx_connection_t *c)
1710 {
1711     int        err;
1712     socklen_t  len;
1713 
1714 #if (NGX_HAVE_KQUEUE)
1715 
1716     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT)  {
1717         if (c->write->pending_eof) {
1718             c->log->action = "connecting to upstream";
1719             (void) ngx_connection_error(c, c->write->kq_errno,
1720                                     "kevent() reported that connect() failed");
1721             return NGX_ERROR;
1722         }
1723 
1724     } else
1725 #endif
1726     {
1727         err = 0;
1728         len = sizeof(int);
1729 
1730         /*
1731          * BSDs and Linux return 0 and set a pending error in err
1732          * Solaris returns -1 and sets errno
1733          */
1734 
1735         if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
1736             == -1)
1737         {
1738             err = ngx_errno;
1739         }
1740 
1741         if (err) {
1742             c->log->action = "connecting to upstream";
1743             (void) ngx_connection_error(c, err, "connect() failed");
1744             return NGX_ERROR;
1745         }
1746     }
1747 
1748     return NGX_OK;
1749 }
1750 
1751 
1752 static ngx_int_t
1753 ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
1754 {
1755     ngx_str_t                      *uri, args;
1756     ngx_uint_t                      i, flags;
1757     ngx_list_part_t                *part;
1758     ngx_table_elt_t                *h;
1759     ngx_http_upstream_header_t     *hh;
1760     ngx_http_upstream_main_conf_t  *umcf;
1761 
1762     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1763 
1764     if (u->headers_in.x_accel_redirect
1765         && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
1766     {
1767         ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
1768 
1769         part = &u->headers_in.headers.part;
1770         h = part->elts;
1771 
1772         for (i = 0; /* void */; i++) {
1773 
1774             if (i >= part->nelts) {
1775                 if (part->next == NULL) {
1776                     break;
1777                 }
1778 
1779                 part = part->next;
1780                 h = part->elts;
1781                 i = 0;
1782             }
1783 
1784             hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
1785                                h[i].lowcase_key, h[i].key.len);
1786 
1787             if (hh && hh->redirect) {
1788                 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
1789                     ngx_http_finalize_request(r,
1790                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1791                     return NGX_DONE;
1792                 }
1793             }
1794         }
1795 
1796         uri = &u->headers_in.x_accel_redirect->value;
1797         args.len = 0;
1798         args.data = NULL;
1799         flags = NGX_HTTP_LOG_UNSAFE;
1800 
1801         if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
1802             ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
1803             return NGX_DONE;
1804         }
1805 
1806         if (flags & NGX_HTTP_ZERO_IN_URI) {
1807             r->zero_in_uri = 1;
1808         }
1809 
1810         if (r->method != NGX_HTTP_HEAD) {
1811             r->method = NGX_HTTP_GET;
1812         }
1813 
1814         r->valid_unparsed_uri = 0;
1815 
1816         ngx_http_internal_redirect(r, uri, &args);
1817         ngx_http_finalize_request(r, NGX_DONE);
1818         return NGX_DONE;
1819     }
1820 
1821     part = &u->headers_in.headers.part;
1822     h = part->elts;
1823 
1824     for (i = 0; /* void */; i++) {
1825 
1826         if (i >= part->nelts) {
1827             if (part->next == NULL) {
1828                 break;
1829             }
1830 
1831             part = part->next;
1832             h = part->elts;
1833             i = 0;
1834         }
1835 
1836         if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
1837                           h[i].lowcase_key, h[i].key.len))
1838         {
1839             continue;
1840         }
1841 
1842         hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
1843                            h[i].lowcase_key, h[i].key.len);
1844 
1845         if (hh) {
1846             if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
1847                 ngx_http_upstream_finalize_request(r, u,
1848                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1849                 return NGX_DONE;
1850             }
1851 
1852             continue;
1853         }
1854 
1855         if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
1856             ngx_http_upstream_finalize_request(r, u,
1857                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1858             return NGX_DONE;
1859         }
1860     }
1861 
1862     if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
1863         r->headers_out.server->hash = 0;
1864     }
1865 
1866     if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
1867         r->headers_out.date->hash = 0;
1868     }
1869 
1870     r->headers_out.status = u->headers_in.status_n;
1871     r->headers_out.status_line = u->headers_in.status_line;
1872 
1873     u->headers_in.content_length_n = r->headers_out.content_length_n;
1874 
1875     if (r->headers_out.content_length_n != -1) {
1876         u->length = (size_t) r->headers_out.content_length_n;
1877 
1878     } else {
1879         u->length = NGX_MAX_SIZE_T_VALUE;
1880     }
1881 
1882     return NGX_OK;
1883 }
1884 
1885 
1886 static void
1887 ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
1888     ngx_http_upstream_t *u)
1889 {
1890     size_t             size;
1891     ssize_t            n;
1892     ngx_buf_t         *b;
1893     ngx_event_t       *rev;
1894     ngx_connection_t  *c;
1895 
1896     c = u->peer.connection;
1897     rev = c->read;
1898 
1899     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1900                    "http upstream process body on memory");
1901 
1902     if (rev->timedout) {
1903         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
1904         ngx_http_upstream_finalize_request(r, u, NGX_ETIMEDOUT);
1905         return;
1906     }
1907 
1908     b = &u->buffer;
1909 
1910     for ( ;; ) {
1911 
1912         size = b->end - b->last;
1913 
1914         if (size == 0) {
1915             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
1916                           "upstream buffer is too small to read repsonse");
1917             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1918             return;
1919         }
1920 
1921         n = c->recv(c, b->last, size);
1922 
1923         if (n == NGX_AGAIN) {
1924             break;
1925         }
1926 
1927         if (n == 0 || n == NGX_ERROR) {
1928             ngx_http_upstream_finalize_request(r, u, n);
1929             return;
1930         }
1931 
1932         u->state->response_length += n;
1933 
1934         if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1935             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1936             return;
1937         }
1938 
1939         if (!rev->ready) {
1940             break;
1941         }
1942     }
1943 
1944     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1945         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1946         return;
1947     }
1948 
1949     if (rev->active) {
1950         ngx_add_timer(rev, u->conf->read_timeout);
1951 
1952     } else if (rev->timer_set) {
1953         ngx_del_timer(rev);
1954     }
1955 }
1956 
1957 
1958 static void
1959 ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
1960 {
1961     int                        tcp_nodelay;
1962     ssize_t                    n;
1963     ngx_int_t                  rc;
1964     ngx_event_pipe_t          *p;
1965     ngx_connection_t          *c;
1966     ngx_http_core_loc_conf_t  *clcf;
1967 
1968     rc = ngx_http_send_header(r);
1969 
1970     if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
1971         ngx_http_upstream_finalize_request(r, u, rc);
1972         return;
1973     }
1974 
1975     c = r->connection;
1976 
1977     if (r->header_only) {
1978 
1979         if (u->cacheable || u->store) {
1980 
1981             if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
1982                 ngx_connection_error(c, ngx_socket_errno,
1983                                      ngx_shutdown_socket_n " failed");
1984             }
1985 
1986             r->read_event_handler = ngx_http_request_empty_handler;
1987             r->write_event_handler = ngx_http_request_empty_handler;
1988             c->error = 1;
1989 
1990         } else {
1991             ngx_http_upstream_finalize_request(r, u, rc);
1992             return;
1993         }
1994     }
1995 
1996     u->header_sent = 1;
1997 
1998     if (r->request_body && r->request_body->temp_file) {
1999         ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd);
2000         r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
2001     }
2002 
2003     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2004 
2005     if (!u->buffering) {
2006 
2007         if (u->input_filter == NULL) {
2008             u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
2009             u->input_filter = ngx_http_upstream_non_buffered_filter;
2010             u->input_filter_ctx = r;
2011         }
2012 
2013         u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;
2014         r->write_event_handler =
2015                              ngx_http_upstream_process_non_buffered_downstream;
2016 
2017         r->limit_rate = 0;
2018 
2019         if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
2020             ngx_http_upstream_finalize_request(r, u, 0);
2021             return;
2022         }
2023 
2024         if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
2025             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
2026 
2027             tcp_nodelay = 1;
2028 
2029             if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
2030                                (const void *) &tcp_nodelay, sizeof(int)) == -1)
2031             {
2032                 ngx_connection_error(c, ngx_socket_errno,
2033                                      "setsockopt(TCP_NODELAY) failed");
2034                 ngx_http_upstream_finalize_request(r, u, 0);
2035                 return;
2036             }
2037 
2038             c->tcp_nodelay = NGX_TCP_NODELAY_SET;
2039         }
2040 
2041         n = u->buffer.last - u->buffer.pos;
2042 
2043         if (n) {
2044             u->buffer.last = u->buffer.pos;
2045 
2046             u->state->response_length += n;
2047 
2048             if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
2049                 ngx_http_upstream_finalize_request(r, u, 0);
2050                 return;
2051             }
2052 
2053             ngx_http_upstream_process_non_buffered_downstream(r);
2054 
2055         } else {
2056             u->buffer.pos = u->buffer.start;
2057             u->buffer.last = u->buffer.start;
2058 
2059             if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
2060                 ngx_http_upstream_finalize_request(r, u, 0);
2061                 return;
2062             }
2063 
2064             if (u->peer.connection->read->ready) {
2065                 ngx_http_upstream_process_non_buffered_upstream(r, u);
2066             }
2067         }
2068 
2069         return;
2070     }
2071 
2072     /* TODO: preallocate event_pipe bufs, look "Content-Length" */
2073 
2074 #if (NGX_HTTP_CACHE)
2075 
2076     if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) {
2077         ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd);
2078         r->cache->file.fd = NGX_INVALID_FILE;
2079     }
2080 
2081     if (u->cacheable) {
2082         time_t  now, valid;
2083 
2084         now = ngx_time();
2085 
2086         valid = r->cache->valid_sec;
2087 
2088         if (valid == 0) {
2089             valid = ngx_http_file_cache_valid(u->conf->cache_valid,
2090                                               u->headers_in.status_n);
2091             if (valid) {
2092                 r->cache->valid_sec = now + valid;
2093             }
2094         }
2095 
2096         if (valid) {
2097             r->cache->last_modified = r->headers_out.last_modified_time;
2098             r->cache->date = now;
2099             r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
2100 
2101             ngx_http_file_cache_set_header(r, u->buffer.start);
2102 
2103         } else {
2104             u->cacheable = 0;
2105             r->headers_out.last_modified_time = -1;
2106         }
2107     }
2108 
2109     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
2110                    "http cacheable: %d", u->cacheable);
2111 
2112     if (u->cacheable == 0 && r->cache) {
2113         ngx_http_file_cache_free(r, u->pipe->temp_file);
2114     }
2115 
2116 #endif
2117 
2118     p = u->pipe;
2119 
2120     p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter;
2121     p->output_ctx = r;
2122     p->tag = u->output.tag;
2123     p->bufs = u->conf->bufs;
2124     p->busy_size = u->conf->busy_buffers_size;
2125     p->upstream = u->peer.connection;
2126     p->downstream = c;
2127     p->pool = r->pool;
2128     p->log = c->log;
2129 
2130     p->cacheable = u->cacheable || u->store;
2131 
2132     p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
2133     if (p->temp_file == NULL) {
2134         ngx_http_upstream_finalize_request(r, u, 0);
2135         return;
2136     }
2137 
2138     p->temp_file->file.fd = NGX_INVALID_FILE;
2139     p->temp_file->file.log = c->log;
2140     p->temp_file->path = u->conf->temp_path;
2141     p->temp_file->pool = r->pool;
2142 
2143     if (p->cacheable) {
2144         p->temp_file->persistent = 1;
2145 
2146     } else {
2147         p->temp_file->log_level = NGX_LOG_WARN;
2148         p->temp_file->warn = "an upstream response is buffered "
2149                              "to a temporary file";
2150     }
2151 
2152     p->max_temp_file_size = u->conf->max_temp_file_size;
2153     p->temp_file_write_size = u->conf->temp_file_write_size;
2154 
2155     p->preread_bufs = ngx_alloc_chain_link(r->pool);
2156     if (p->preread_bufs == NULL) {
2157         ngx_http_upstream_finalize_request(r, u, 0);
2158         return;
2159     }
2160 
2161     p->preread_bufs->buf = &u->buffer;
2162     p->preread_bufs->next = NULL;
2163     u->buffer.recycled = 1;
2164 
2165     p->preread_size = u->buffer.last - u->buffer.pos;
2166 
2167     if (u->cacheable) {
2168 
2169         p->buf_to_file = ngx_calloc_buf(r->pool);
2170         if (p->buf_to_file == NULL) {
2171             ngx_http_upstream_finalize_request(r, u, 0);
2172             return;
2173         }
2174 
2175         p->buf_to_file->pos = u->buffer.start;
2176         p->buf_to_file->last = u->buffer.pos;
2177         p->buf_to_file->temporary = 1;
2178     }
2179 
2180     if (ngx_event_flags & NGX_USE_AIO_EVENT) {
2181         /* the posted aio operation may currupt a shadow buffer */
2182         p->single_buf = 1;
2183     }
2184 
2185     /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
2186     p->free_bufs = 1;
2187 
2188     /*
2189      * event_pipe would do u->buffer.last += p->preread_size
2190      * as though these bytes were read
2191      */
2192     u->buffer.last = u->buffer.pos;
2193 
2194     if (u->conf->cyclic_temp_file) {
2195 
2196         /*
2197          * we need to disable the use of sendfile() if we use cyclic temp file
2198          * because the writing a new data may interfere with sendfile()
2199          * that uses the same kernel file pages (at least on FreeBSD)
2200          */
2201 
2202         p->cyclic_temp_file = 1;
2203         c->sendfile = 0;
2204 
2205     } else {
2206         p->cyclic_temp_file = 0;
2207     }
2208 
2209     p->read_timeout = u->conf->read_timeout;
2210     p->send_timeout = clcf->send_timeout;
2211     p->send_lowat = clcf->send_lowat;
2212 
2213     u->read_event_handler = ngx_http_upstream_process_upstream;
2214     r->write_event_handler = ngx_http_upstream_process_downstream;
2215 
2216     ngx_http_upstream_process_upstream(r, u);
2217 }
2218 
2219 
2220 static void
2221 ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r)
2222 {
2223     ngx_event_t          *wev;
2224     ngx_connection_t     *c;
2225     ngx_http_upstream_t  *u;
2226 
2227     c = r->connection;
2228     u = r->upstream;
2229     wev = c->write;
2230 
2231     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2232                    "http upstream process non buffered downstream");
2233 
2234     c->log->action = "sending to client";
2235 
2236     if (wev->timedout) {
2237         c->timedout = 1;
2238         ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
2239         ngx_http_upstream_finalize_request(r, u, 0);
2240         return;
2241     }
2242 
2243     ngx_http_upstream_process_non_buffered_request(r, 1);
2244 }
2245 
2246 
2247 static void
2248 ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
2249     ngx_http_upstream_t *u)
2250 {
2251     ngx_connection_t  *c;
2252 
2253     c = u->peer.connection;
2254 
2255     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2256                    "http upstream process non buffered upstream");
2257 
2258     c->log->action = "reading upstream";
2259 
2260     if (c->read->timedout) {
2261         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
2262         ngx_http_upstream_finalize_request(r, u, 0);
2263         return;
2264     }
2265 
2266     ngx_http_upstream_process_non_buffered_request(r, 0);
2267 }
2268 
2269 
2270 static void
2271 ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
2272     ngx_uint_t do_write)
2273 {
2274     size_t                     size;
2275     ssize_t                    n;
2276     ngx_buf_t                 *b;
2277     ngx_int_t                  rc;
2278     ngx_connection_t          *downstream, *upstream;
2279     ngx_http_upstream_t       *u;
2280     ngx_http_core_loc_conf_t  *clcf;
2281 
2282     u = r->upstream;
2283     downstream = r->connection;
2284     upstream = u->peer.connection;
2285 
2286     b = &u->buffer;
2287 
2288     do_write = do_write || u->length == 0;
2289 
2290     for ( ;; ) {
2291 
2292         if (do_write) {
2293 
2294             if (u->out_bufs || u->busy_bufs) {
2295                 rc = ngx_http_output_filter(r, u->out_bufs);
2296 
2297                 if (rc == NGX_ERROR) {
2298                     ngx_http_upstream_finalize_request(r, u, 0);
2299                     return;
2300                 }
2301 
2302                 ngx_chain_update_chains(&u->free_bufs, &u->busy_bufs,
2303                                         &u->out_bufs, u->output.tag);
2304             }
2305 
2306             if (u->busy_bufs == NULL) {
2307 
2308                 if (u->length == 0
2309                     || upstream->read->eof
2310                     || upstream->read->error)
2311                 {
2312                     ngx_http_upstream_finalize_request(r, u, 0);
2313                     return;
2314                 }
2315 
2316                 b->pos = b->start;
2317                 b->last = b->start;
2318             }
2319         }
2320 
2321         size = b->end - b->last;
2322 
2323         if (size > u->length) {
2324             size = u->length;
2325         }
2326 
2327         if (size && upstream->read->ready) {
2328 
2329             n = upstream->recv(upstream, b->last, size);
2330 
2331             if (n == NGX_AGAIN) {
2332                 break;
2333             }
2334 
2335             if (n > 0) {
2336                 u->state->response_length += n;
2337 
2338                 if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
2339                     ngx_http_upstream_finalize_request(r, u, 0);
2340                     return;
2341                 }
2342             }
2343 
2344             do_write = 1;
2345 
2346             continue;
2347         }
2348 
2349         break;
2350     }
2351 
2352     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2353 
2354     if (downstream->data == r) {
2355         if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
2356             != NGX_OK)
2357         {
2358             ngx_http_upstream_finalize_request(r, u, 0);
2359             return;
2360         }
2361     }
2362 
2363     if (downstream->write->active && !downstream->write->ready) {
2364         ngx_add_timer(downstream->write, clcf->send_timeout);
2365 
2366     } else if (downstream->write->timer_set) {
2367         ngx_del_timer(downstream->write);
2368     }
2369 
2370     if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
2371         ngx_http_upstream_finalize_request(r, u, 0);
2372         return;
2373     }
2374 
2375     if (upstream->read->active && !upstream->read->ready) {
2376         ngx_add_timer(upstream->read, u->conf->read_timeout);
2377 
2378     } else if (upstream->read->timer_set) {
2379         ngx_del_timer(upstream->read);
2380     }
2381 }
2382 
2383 
2384 static ngx_int_t
2385 ngx_http_upstream_non_buffered_filter_init(void *data)
2386 {
2387     return NGX_OK;
2388 }
2389 
2390 
2391 static ngx_int_t
2392 ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
2393 {
2394     ngx_http_request_t  *r = data;
2395 
2396     ngx_buf_t            *b;
2397     ngx_chain_t          *cl, **ll;
2398     ngx_http_upstream_t  *u;
2399 
2400     u = r->upstream;
2401 
2402     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2403         ll = &cl->next;
2404     }
2405 
2406     cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2407     if (cl == NULL) {
2408         return NGX_ERROR;
2409     }
2410 
2411     *ll = cl;
2412 
2413     cl->buf->flush = 1;
2414     cl->buf->memory = 1;
2415 
2416     b = &u->buffer;
2417 
2418     cl->buf->pos = b->last;
2419     b->last += bytes;
2420     cl->buf->last = b->last;
2421     cl->buf->tag = u->output.tag;
2422 
2423     if (u->length == NGX_MAX_SIZE_T_VALUE) {
2424         return NGX_OK;
2425     }
2426 
2427     u->length -= bytes;
2428 
2429     return NGX_OK;
2430 }
2431 
2432 
2433 static void
2434 ngx_http_upstream_process_downstream(ngx_http_request_t *r)
2435 {
2436     ngx_event_t          *wev;
2437     ngx_connection_t     *c;
2438     ngx_event_pipe_t     *p;
2439     ngx_http_upstream_t  *u;
2440 
2441     c = r->connection;
2442     u = r->upstream;
2443     p = u->pipe;
2444     wev = c->write;
2445 
2446     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2447                    "http upstream process downstream");
2448 
2449     c->log->action = "sending to client";
2450 
2451     if (wev->timedout) {
2452 
2453         if (wev->delayed) {
2454 
2455             wev->timedout = 0;
2456             wev->delayed = 0;
2457 
2458             if (!wev->ready) {
2459                 ngx_add_timer(wev, p->send_timeout);
2460 
2461                 if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
2462                     ngx_http_upstream_finalize_request(r, u, 0);
2463                 }
2464 
2465                 return;
2466             }
2467 
2468             if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
2469                 ngx_http_upstream_finalize_request(r, u, 0);
2470                 return;
2471             }
2472 
2473         } else {
2474             p->downstream_error = 1;
2475             c->timedout = 1;
2476             ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
2477         }
2478 
2479     } else {
2480 
2481         if (wev->delayed) {
2482 
2483             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2484                            "http downstream delayed");
2485 
2486             if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
2487                 ngx_http_upstream_finalize_request(r, u, 0);
2488             }
2489 
2490             return;
2491         }
2492 
2493         if (ngx_event_pipe(p, 1) == NGX_ABORT) {
2494             ngx_http_upstream_finalize_request(r, u, 0);
2495             return;
2496         }
2497     }
2498 
2499     ngx_http_upstream_process_request(r);
2500 }
2501 
2502 
2503 static void
2504 ngx_http_upstream_process_upstream(ngx_http_request_t *r,
2505     ngx_http_upstream_t *u)
2506 {
2507     ngx_connection_t  *c;
2508 
2509     c = u->peer.connection;
2510 
2511     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2512                    "http upstream process upstream");
2513 
2514     c->log->action = "reading upstream";
2515 
2516     if (c->read->timedout) {
2517         u->pipe->upstream_error = 1;
2518         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
2519 
2520     } else {
2521         if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
2522             ngx_http_upstream_finalize_request(r, u, 0);
2523             return;
2524         }
2525     }
2526 
2527     ngx_http_upstream_process_request(r);
2528 }
2529 
2530 
2531 static void
2532 ngx_http_upstream_process_request(ngx_http_request_t *r)
2533 {
2534     ngx_uint_t            del;
2535     ngx_temp_file_t      *tf;
2536     ngx_event_pipe_t     *p;
2537     ngx_http_upstream_t  *u;
2538 
2539     u = r->upstream;
2540     p = u->pipe;
2541 
2542     if (u->peer.connection) {
2543 
2544         if (u->store) {
2545 
2546             del = p->upstream_error;
2547 
2548             tf = u->pipe->temp_file;
2549 
2550             if (p->upstream_eof || p->upstream_done) {
2551 
2552                 if (u->headers_in.status_n == NGX_HTTP_OK
2553                     && (u->headers_in.content_length_n == -1
2554                         || (u->headers_in.content_length_n == tf->offset)))
2555                 {
2556                     ngx_http_upstream_store(r, u);
2557 
2558                 } else {
2559                     del = 1;
2560                 }
2561             }
2562 
2563             if (del && tf->file.fd != NGX_INVALID_FILE) {
2564 
2565                 if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
2566 
2567                     ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
2568                                   ngx_delete_file_n " \"%s\" failed",
2569                                   u->pipe->temp_file->file.name.data);
2570                 }
2571             }
2572         }
2573 
2574 #if (NGX_HTTP_CACHE)
2575 
2576         if (u->cacheable) {
2577 
2578             if (p->upstream_done) {
2579                 ngx_http_file_cache_update(r, u->pipe->temp_file);
2580 
2581             } else if (p->upstream_eof) {
2582 
2583                 /* TODO: check length & update cache */
2584 
2585                 ngx_http_file_cache_update(r, u->pipe->temp_file);
2586 
2587             } else if (p->upstream_error) {
2588                 ngx_http_file_cache_free(r, u->pipe->temp_file);
2589             }
2590         }
2591 
2592 #endif
2593 
2594         if (p->upstream_done || p->upstream_eof || p->upstream_error) {
2595             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2596                            "http upstream exit: %p", p->out);
2597 #if 0
2598             ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2599 #endif
2600             ngx_http_upstream_finalize_request(r, u, 0);
2601             return;
2602         }
2603     }
2604 
2605     if (p->downstream_error) {
2606         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2607                        "http upstream downstream error");
2608 
2609         if (!u->cacheable && !u->store && u->peer.connection) {
2610             ngx_http_upstream_finalize_request(r, u, 0);
2611         }
2612     }
2613 }
2614 
2615 
2616 static void
2617 ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
2618 {
2619     size_t                  root;
2620     time_t                  lm;
2621     ngx_str_t               path;
2622     ngx_temp_file_t        *tf;
2623     ngx_ext_rename_file_t   ext;
2624 
2625     tf = u->pipe->temp_file;
2626 
2627     if (tf->file.fd == NGX_INVALID_FILE) {
2628 
2629         /* create file for empty 200 response */
2630 
2631         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
2632         if (tf == NULL) {
2633             return;
2634         }
2635 
2636         tf->file.fd = NGX_INVALID_FILE;
2637         tf->file.log = r->connection->log;
2638         tf->path = u->conf->temp_path;
2639         tf->pool = r->pool;
2640         tf->persistent = 1;
2641 
2642         if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
2643                                  tf->persistent, tf->clean, tf->access)
2644             != NGX_OK)
2645         {
2646             return;
2647         }
2648 
2649         u->pipe->temp_file = tf;
2650     }
2651 
2652     ext.access = u->conf->store_access;
2653     ext.path_access = u->conf->store_access;
2654     ext.time = -1;
2655     ext.create_path = 1;
2656     ext.delete_file = 1;
2657     ext.log = r->connection->log;
2658 
2659     if (u->headers_in.last_modified) {
2660 
2661         lm = ngx_http_parse_time(u->headers_in.last_modified->value.data,
2662                                  u->headers_in.last_modified->value.len);
2663 
2664         if (lm != NGX_ERROR) {
2665             ext.time = lm;
2666             ext.fd = tf->file.fd;
2667         }
2668     }
2669 
2670     if (u->conf->store_lengths == NULL) {
2671 
2672         ngx_http_map_uri_to_path(r, &path, &root, 0);
2673 
2674     } else {
2675         if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0,
2676                                 u->conf->store_values->elts)
2677             == NULL)
2678         {
2679             return;
2680         }
2681     }
2682 
2683     path.len--;
2684 
2685     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2686                    "upstream stores \"%s\" to \"%s\"",
2687                    tf->file.name.data, path.data);
2688 
2689     (void) ngx_ext_rename_file(&tf->file.name, &path, &ext);
2690 }
2691 
2692 
2693 static void
2694 ngx_http_upstream_dummy_handler(ngx_http_request_t *r, ngx_http_upstream_t *u)
2695 {
2696     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2697                    "http upstream dummy handler");
2698 }
2699 
2700 
2701 static void
2702 ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
2703     ngx_uint_t ft_type)
2704 {
2705     ngx_uint_t  status, state;
2706 
2707     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2708                    "http next upstream, %xi", ft_type);
2709 
2710 #if 0
2711     ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2712 #endif
2713 
2714     if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {
2715         state = NGX_PEER_NEXT;
2716     } else {
2717         state = NGX_PEER_FAILED;
2718     }
2719 
2720     if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) {
2721         u->peer.free(&u->peer, u->peer.data, state);
2722     }
2723 
2724     if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
2725         ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
2726                       "upstream timed out");
2727     }
2728 
2729     if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
2730         status = 0;
2731 
2732     } else {
2733         switch(ft_type) {
2734 
2735         case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
2736             status = NGX_HTTP_GATEWAY_TIME_OUT;
2737             break;
2738 
2739         case NGX_HTTP_UPSTREAM_FT_HTTP_500:
2740             status = NGX_HTTP_INTERNAL_SERVER_ERROR;
2741             break;
2742 
2743         case NGX_HTTP_UPSTREAM_FT_HTTP_404:
2744             status = NGX_HTTP_NOT_FOUND;
2745             break;
2746 
2747         /*
2748          * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
2749          * never reach here
2750          */
2751 
2752         default:
2753             status = NGX_HTTP_BAD_GATEWAY;
2754         }
2755     }
2756 
2757     if (r->connection->error) {
2758         ngx_http_upstream_finalize_request(r, u,
2759                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
2760         return;
2761     }
2762 
2763     if (status) {
2764         u->state->status = status;
2765 
2766         if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) {
2767 
2768 #if (NGX_HTTP_CACHE)
2769 
2770             if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
2771                 && (u->conf->cache_use_stale & ft_type))
2772             {
2773                 ngx_int_t  rc;
2774 
2775                 rc = u->reinit_request(r);
2776 
2777                 if (rc == NGX_OK) {
2778                     u->cache_status = NGX_HTTP_CACHE_STALE;
2779                     rc = ngx_http_upstream_cache_send(r, u);
2780                 }
2781 
2782                 ngx_http_upstream_finalize_request(r, u, rc);
2783                 return;
2784             }
2785 #endif
2786 
2787             ngx_http_upstream_finalize_request(r, u, status);
2788             return;
2789         }
2790     }
2791 
2792     if (u->peer.connection) {
2793         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2794                        "close http upstream connection: %d",
2795                        u->peer.connection->fd);
2796 #if (NGX_HTTP_SSL)
2797 
2798         if (u->peer.connection->ssl) {
2799             u->peer.connection->ssl->no_wait_shutdown = 1;
2800             u->peer.connection->ssl->no_send_shutdown = 1;
2801 
2802             (void) ngx_ssl_shutdown(u->peer.connection);
2803         }
2804 #endif
2805 
2806         ngx_close_connection(u->peer.connection);
2807     }
2808 
2809 #if 0
2810     if (u->conf->busy_lock && !u->busy_locked) {
2811         ngx_http_upstream_busy_lock(p);
2812         return;
2813     }
2814 #endif
2815 
2816     ngx_http_upstream_connect(r, u);
2817 }
2818 
2819 
2820 static void
2821 ngx_http_upstream_cleanup(void *data)
2822 {
2823     ngx_http_request_t *r = data;
2824 
2825     ngx_http_upstream_t  *u;
2826 
2827     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2828                    "cleanup http upstream request: \"%V\"", &r->uri);
2829 
2830     u = r->upstream;
2831 
2832     if (u->resolved && u->resolved->ctx) {
2833         ngx_resolve_name_done(u->resolved->ctx);
2834         u->resolved->ctx = NULL;
2835     }
2836 
2837     ngx_http_upstream_finalize_request(r, u, NGX_DONE);
2838 }
2839 
2840 
2841 static void
2842 ngx_http_upstream_finalize_request(ngx_http_request_t *r,
2843     ngx_http_upstream_t *u, ngx_int_t rc)
2844 {
2845     ngx_time_t  *tp;
2846 
2847     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2848                    "finalize http upstream request: %i", rc);
2849 
2850     if (u->cleanup) {
2851         *u->cleanup = NULL;
2852     }
2853 
2854     if (u->resolved && u->resolved->ctx) {
2855         ngx_resolve_name_done(u->resolved->ctx);
2856         u->resolved->ctx = NULL;
2857     }
2858 
2859     if (u->state && u->state->response_sec) {
2860         tp = ngx_timeofday();
2861         u->state->response_sec = tp->sec - u->state->response_sec;
2862         u->state->response_msec = tp->msec - u->state->response_msec;
2863 
2864         if (u->pipe) {
2865             u->state->response_length = u->pipe->read_length;
2866         }
2867     }
2868 
2869     u->finalize_request(r, rc);
2870 
2871     if (u->peer.free) {
2872         u->peer.free(&u->peer, u->peer.data, 0);
2873     }
2874 
2875     if (u->peer.connection) {
2876 
2877 #if (NGX_HTTP_SSL)
2878 
2879         /* TODO: do not shutdown persistent connection */
2880 
2881         if (u->peer.connection->ssl) {
2882 
2883             /*
2884              * We send the "close notify" shutdown alert to the upstream only
2885              * and do not wait its "close notify" shutdown alert.
2886              * It is acceptable according to the TLS standard.
2887              */
2888 
2889             u->peer.connection->ssl->no_wait_shutdown = 1;
2890 
2891             (void) ngx_ssl_shutdown(u->peer.connection);
2892         }
2893 #endif
2894 
2895         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2896                        "close http upstream connection: %d",
2897                        u->peer.connection->fd);
2898 
2899         ngx_close_connection(u->peer.connection);
2900     }
2901 
2902     u->peer.connection = NULL;
2903 
2904     if (u->pipe && u->pipe->temp_file) {
2905         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2906                        "http upstream temp fd: %d",
2907                        u->pipe->temp_file->file.fd);
2908     }
2909 
2910 #if (NGX_HTTP_CACHE)
2911 
2912     if (u->cacheable && r->cache) {
2913         time_t  valid;
2914 
2915         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2916                        "http upstream cache fd: %d",
2917                        r->cache->file.fd);
2918 
2919         if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) {
2920 
2921             valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc);
2922 
2923             if (valid) {
2924                 r->cache->valid_sec = ngx_time() + valid;
2925                 r->cache->error = rc;
2926             }
2927         }
2928 
2929         ngx_http_file_cache_free(r, u->pipe->temp_file);
2930     }
2931 
2932 #endif
2933 
2934     if (u->header_sent
2935         && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
2936     {
2937         rc = 0;
2938     }
2939 
2940     if (rc == NGX_DECLINED) {
2941         return;
2942     }
2943 
2944     r->connection->log->action = "sending to client";
2945 
2946     if (rc == 0) {
2947         rc = ngx_http_send_special(r, NGX_HTTP_LAST);
2948     }
2949 
2950     ngx_http_finalize_request(r, rc);
2951 }
2952 
2953 
2954 static ngx_int_t
2955 ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
2956     ngx_uint_t offset)
2957 {
2958     ngx_table_elt_t  **ph;
2959 
2960     ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
2961 
2962     if (*ph == NULL) {
2963         *ph = h;
2964     }
2965 
2966     return NGX_OK;
2967 }
2968 
2969 
2970 static ngx_int_t
2971 ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
2972     ngx_uint_t offset)
2973 {
2974     return NGX_OK;
2975 }
2976 
2977 
2978 static ngx_int_t
2979 ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
2980     ngx_table_elt_t *h, ngx_uint_t offset)
2981 {
2982     ngx_array_t          *pa;
2983     ngx_table_elt_t     **ph;
2984     ngx_http_upstream_t  *u;
2985 
2986     u = r->upstream;
2987     pa = &u->headers_in.cache_control;
2988 
2989     if (pa->elts == NULL) {
2990        if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
2991        {
2992            return NGX_ERROR;
2993        }
2994     }
2995 
2996     ph = ngx_array_push(pa);
2997     if (ph == NULL) {
2998         return NGX_ERROR;
2999     }
3000 
3001     *ph = h;
3002 
3003 #if (NGX_HTTP_CACHE)
3004     {
3005     u_char     *p, *last;
3006     ngx_int_t   n;
3007 
3008     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) {
3009         return NGX_OK;
3010     }
3011 
3012     if (r->cache == NULL) {
3013         return NGX_OK;
3014     }
3015 
3016     if (r->cache->valid_sec != 0) {
3017         return NGX_OK;
3018     }
3019 
3020     last = h->value.data + h->value.len;
3021 
3022     if (ngx_strlcasestrn(h->value.data, last, (u_char *) "no-cache", 8 - 1)
3023         != NULL)
3024     {
3025         u->cacheable = 0;
3026         return NGX_OK;
3027     }
3028 
3029     p = ngx_strlcasestrn(h->value.data, last, (u_char *) "max-age=", 8 - 1);
3030 
3031     if (p == NULL) {
3032         return NGX_OK;
3033     }
3034 
3035     n = 0;
3036 
3037     for (p += 8; p < last; p++) {
3038         if (*p == ',' || *p == ';' || *p == ' ') {
3039             break;
3040         }
3041 
3042         if (*p >= '' && *p <= '9') {
3043             n = n * 10 + *p - '';
3044             continue;
3045         }
3046 
3047         u->cacheable = 0;
3048         return NGX_OK;
3049     }
3050 
3051     if (n == 0) {
3052         u->cacheable = 0;
3053         return NGX_OK;
3054     }
3055 
3056     r->cache->valid_sec = ngx_time() + n;
3057     }
3058 #endif
3059 
3060     return NGX_OK;
3061 }
3062 
3063 
3064 static ngx_int_t
3065 ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
3066     ngx_uint_t offset)
3067 {
3068     ngx_http_upstream_t  *u;
3069 
3070     u = r->upstream;
3071     u->headers_in.expires = h;
3072 
3073 #if (NGX_HTTP_CACHE)
3074     {
3075     time_t  expires;
3076 
3077     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_EXPIRES) {
3078         return NGX_OK;
3079     }
3080 
3081     if (r->cache == NULL) {
3082         return NGX_OK;
3083     }
3084 
3085     if (r->cache->valid_sec != 0) {
3086         return NGX_OK;
3087     }
3088 
3089     expires = ngx_http_parse_time(h->value.data, h->value.len);
3090 
3091     if (expires == NGX_ERROR || expires < ngx_time()) {
3092         u->cacheable = 0;
3093         return NGX_OK;
3094     }
3095 
3096     r->cache->valid_sec = expires;
3097     }
3098 #endif
3099 
3100     return NGX_OK;
3101 }
3102 
3103 
3104 static ngx_int_t
3105 ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
3106     ngx_table_elt_t *h, ngx_uint_t offset)
3107 {
3108     ngx_http_upstream_t  *u;
3109 
3110     u = r->upstream;
3111     u->headers_in.x_accel_expires = h;
3112 
3113 #if (NGX_HTTP_CACHE)
3114     {
3115     u_char     *p;
3116     size_t      len;
3117     ngx_int_t   n;
3118 
3119     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES) {
3120         return NGX_OK;
3121     }
3122 
3123     if (r->cache == NULL) {
3124         return NGX_OK;
3125     }
3126 
3127     len = h->value.len;
3128     p = h->value.data;
3129 
3130     if (p[0] != '@') {
3131         n = ngx_atoi(p, len);
3132 
3133         switch (n) {
3134         case 0:
3135             u->cacheable = 0;
3136         case NGX_ERROR:
3137             return NGX_OK;
3138 
3139         default:
3140             r->cache->valid_sec = ngx_time() + n;
3141             return NGX_OK;
3142         }
3143     }
3144 
3145     p++;
3146     len--;
3147 
3148     n = ngx_atoi(p, len);
3149 
3150     if (n != NGX_ERROR) {
3151         r->cache->valid_sec = n;
3152     }
3153     }
3154 #endif
3155 
3156     return NGX_OK;
3157 }
3158 
3159 
3160 static ngx_int_t
3161 ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
3162     ngx_uint_t offset)
3163 {
3164     ngx_int_t  n;
3165 
3166     r->upstream->headers_in.x_accel_limit_rate = h;
3167 
3168     n = ngx_atoi(h->value.data, h->value.len);
3169 
3170     if (n != NGX_ERROR) {
3171         r->limit_rate = (size_t) n;
3172     }
3173 
3174     return NGX_OK;
3175 }
3176 
3177 
3178 static ngx_int_t
3179 ngx_http_upstream_process_buffering(ngx_http_request_t *r, ngx_table_elt_t *h,
3180     ngx_uint_t offset)
3181 {
3182     u_char  c0, c1, c2;
3183 
3184     if (r->upstream->conf->change_buffering) {
3185 
3186         if (h->value.len == 2) {
3187             c0 = ngx_tolower(h->value.data[0]);
3188             c1 = ngx_tolower(h->value.data[1]);
3189 
3190             if (c0 == 'n' && c1 == 'o') {
3191                 r->upstream->buffering = 0;
3192             }
3193 
3194         } else if (h->value.len == 3) {
3195             c0 = ngx_tolower(h->value.data[0]);
3196             c1 = ngx_tolower(h->value.data[1]);
3197             c2 = ngx_tolower(h->value.data[2]);
3198 
3199             if (c0 == 'y' && c1 == 'e' && c2 == 's') {
3200                 r->upstream->buffering = 1;
3201             }
3202         }
3203     }
3204 
3205     return NGX_OK;
3206 }
3207 
3208 
3209 static ngx_int_t
3210 ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
3211     ngx_uint_t offset)
3212 {
3213     r->headers_out.override_charset = &h->value;
3214 
3215     return NGX_OK;
3216 }
3217 
3218 
3219 static ngx_int_t
3220 ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
3221     ngx_uint_t offset)
3222 {
3223     ngx_table_elt_t  *ho, **ph;
3224 
3225     ho = ngx_list_push(&r->headers_out.headers);
3226     if (ho == NULL) {
3227         return NGX_ERROR;
3228     }
3229 
3230     *ho = *h;
3231 
3232     if (offset) {
3233         ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
3234         *ph = ho;
3235     }
3236 
3237     return NGX_OK;
3238 }
3239 
3240 
3241 static ngx_int_t
3242 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
3243     ngx_table_elt_t *h, ngx_uint_t offset)
3244 {
3245     ngx_array_t      *pa;
3246     ngx_table_elt_t  *ho, **ph;
3247 
3248     pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
3249 
3250     if (pa->elts == NULL) {
3251         if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
3252         {
3253             return NGX_ERROR;
3254         }
3255     }
3256 
3257     ph = ngx_array_push(pa);
3258     if (ph == NULL) {
3259         return NGX_ERROR;
3260     }
3261 
3262     ho = ngx_list_push(&r->headers_out.headers);
3263     if (ho == NULL) {
3264         return NGX_ERROR;
3265     }
3266 
3267     *ho = *h;
3268     *ph = ho;
3269 
3270     return NGX_OK;
3271 }
3272 
3273 
3274 static ngx_int_t
3275 ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
3276     ngx_uint_t offset)
3277 {
3278     u_char  *p, *last;
3279 
3280     r->headers_out.content_type_len = h->value.len;
3281     r->headers_out.content_type = h->value;
3282     r->headers_out.content_type_lowcase = NULL;
3283 
3284     for (p = h->value.data; *p; p++) {
3285 
3286         if (*p != ';') {
3287             continue;
3288         }
3289 
3290         last = p;
3291 
3292         while (*++p == ' ') { /* void */ }
3293 
3294         if (*p == '\0') {
3295             return NGX_OK;
3296         }
3297 
3298         if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) {
3299             continue;
3300         }
3301 
3302         p += 8;
3303 
3304         r->headers_out.content_type_len = last - h->value.data;
3305 
3306         if (*p == '"') {
3307             p++;
3308         }
3309 
3310         last = h->value.data + h->value.len;
3311 
3312         if (*(last - 1) == '"') {
3313             last--;
3314         }
3315 
3316         r->headers_out.charset.len = last - p;
3317         r->headers_out.charset.data = p;
3318 
3319         return NGX_OK;
3320     }
3321 
3322     return NGX_OK;
3323 }
3324 
3325 
3326 static ngx_int_t
3327 ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h,
3328     ngx_uint_t offset)
3329 {
3330     ngx_table_elt_t  *ho;
3331 
3332     ho = ngx_list_push(&r->headers_out.headers);
3333     if (ho == NULL) {
3334         return NGX_ERROR;
3335     }
3336 
3337     *ho = *h;
3338 
3339     r->headers_out.content_length = ho;
3340     r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len);
3341 
3342     return NGX_OK;
3343 }
3344 
3345 
3346 static ngx_int_t
3347 ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h,
3348     ngx_uint_t offset)
3349 {
3350     ngx_table_elt_t  *ho;
3351 
3352     ho = ngx_list_push(&r->headers_out.headers);
3353     if (ho == NULL) {
3354         return NGX_ERROR;
3355     }
3356 
3357     *ho = *h;
3358 
3359     r->headers_out.last_modified = ho;
3360 
3361 #if (NGX_HTTP_CACHE)
3362 
3363     if (r->upstream->cacheable) {
3364         r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data,
3365                                                                 h->value.len);
3366     }
3367 
3368 #endif
3369 
3370     return NGX_OK;
3371 }
3372 
3373 
3374 static ngx_int_t
3375 ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
3376     ngx_uint_t offset)
3377 {
3378     ngx_int_t         rc;
3379     ngx_table_elt_t  *ho;
3380 
3381     ho = ngx_list_push(&r->headers_out.headers);
3382     if (ho == NULL) {
3383         return NGX_ERROR;
3384     }
3385 
3386     *ho = *h;
3387 
3388     if (r->upstream->rewrite_redirect) {
3389         rc = r->upstream->rewrite_redirect(r, ho, 0);
3390 
3391         if (rc == NGX_DECLINED) {
3392             return NGX_OK;
3393         }
3394 
3395         if (rc == NGX_OK) {
3396             r->headers_out.location = ho;
3397 
3398             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3399                            "rewritten location: \"%V\"", &ho->value);
3400         }
3401 
3402         return rc;
3403     }
3404 
3405     if (ho->value.data[0] != '/') {
3406         r->headers_out.location = ho;
3407     }
3408 
3409     /*
3410      * we do not set r->headers_out.location here to avoid the handling
3411      * the local redirects without a host name by ngx_http_header_filter()
3412      */
3413 
3414     return NGX_OK;
3415 }
3416 
3417 
3418 static ngx_int_t
3419 ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
3420     ngx_uint_t offset)
3421 {
3422     u_char           *p;
3423     ngx_int_t         rc;
3424     ngx_table_elt_t  *ho;
3425 
3426     ho = ngx_list_push(&r->headers_out.headers);
3427     if (ho == NULL) {
3428         return NGX_ERROR;
3429     }
3430 
3431     *ho = *h;
3432 
3433     if (r->upstream->rewrite_redirect) {
3434 
3435         p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);
3436 
3437         if (p) {
3438             rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);
3439 
3440         } else {
3441             return NGX_OK;
3442         }
3443 
3444         if (rc == NGX_DECLINED) {
3445             return NGX_OK;
3446         }
3447 
3448         if (rc == NGX_OK) {
3449             r->headers_out.refresh = ho;
3450 
3451             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3452                            "rewritten refresh: \"%V\"", &ho->value);
3453         }
3454 
3455         return rc;
3456     }
3457 
3458     r->headers_out.refresh = ho;
3459 
3460     return NGX_OK;
3461 }
3462 
3463 
3464 static ngx_int_t
3465 ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
3466     ngx_table_elt_t *h, ngx_uint_t offset)
3467 {
3468     ngx_table_elt_t  *ho;
3469 
3470 #if (NGX_HTTP_CACHE)
3471 
3472     if (r->cached) {
3473         r->allow_ranges = 1;
3474         return NGX_OK;
3475 
3476     }
3477 
3478 #endif
3479 
3480     ho = ngx_list_push(&r->headers_out.headers);
3481     if (ho == NULL) {
3482         return NGX_ERROR;
3483     }
3484 
3485     *ho = *h;
3486 
3487     r->headers_out.accept_ranges = ho;
3488 
3489     return NGX_OK;
3490 }
3491 
3492 
3493 #if (NGX_HTTP_GZIP)
3494 
3495 static ngx_int_t
3496 ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
3497     ngx_table_elt_t *h, ngx_uint_t offset)
3498 {
3499     ngx_table_elt_t  *ho;
3500 
3501     ho = ngx_list_push(&r->headers_out.headers);
3502     if (ho == NULL) {
3503         return NGX_ERROR;
3504     }
3505 
3506     *ho = *h;
3507 
3508     r->headers_out.content_encoding = ho;
3509 
3510     return NGX_OK;
3511 }
3512 
3513 #endif
3514 
3515 
3516 static ngx_int_t
3517 ngx_http_upstream_add_variables(ngx_conf_t *cf)
3518 {
3519     ngx_http_variable_t  *var, *v;
3520 
3521     for (v = ngx_http_upstream_vars; v->name.len; v++) {
3522         var = ngx_http_add_variable(cf, &v->name, v->flags);
3523         if (var == NULL) {
3524             return NGX_ERROR;
3525         }
3526 
3527         var->get_handler = v->get_handler;
3528         var->data = v->data;
3529     }
3530 
3531     return NGX_OK;
3532 }
3533 
3534 
3535 static ngx_int_t
3536 ngx_http_upstream_addr_variable(ngx_http_request_t *r,
3537     ngx_http_variable_value_t *v, uintptr_t data)
3538 {
3539     u_char                     *p;
3540     size_t                      len;
3541     ngx_uint_t                  i;
3542     ngx_http_upstream_state_t  *state;
3543 
3544     v->valid = 1;
3545     v->no_cacheable = 0;
3546     v->not_found = 0;
3547 
3548     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
3549         v->not_found = 1;
3550         return NGX_OK;
3551     }
3552 
3553     len = 0;
3554     state = r->upstream_states->elts;
3555 
3556     for (i = 0; i < r->upstream_states->nelts; i++) {
3557         if (state[i].peer) {
3558             len += state[i].peer->len + 2;
3559 
3560         } else {
3561             len += 3;
3562         }
3563     }
3564 
3565     p = ngx_pnalloc(r->pool, len);
3566     if (p == NULL) {
3567         return NGX_ERROR;
3568     }
3569 
3570     v->data = p;
3571 
3572     i = 0;
3573 
3574     for ( ;; ) {
3575         if (state[i].peer) {
3576             p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len);
3577         }
3578 
3579         if (++i == r->upstream_states->nelts) {
3580             break;
3581         }
3582 
3583         if (state[i].peer) {
3584             *p++ = ',';
3585             *p++ = ' ';
3586 
3587         } else {
3588             *p++ = ' ';
3589             *p++ = ':';
3590             *p++ = ' ';
3591 
3592             if (++i == r->upstream_states->nelts) {
3593                 break;
3594             }
3595 
3596             continue;
3597         }
3598     }
3599 
3600     v->len = p - v->data;
3601 
3602     return NGX_OK;
3603 }
3604 
3605 
3606 static ngx_int_t
3607 ngx_http_upstream_status_variable(ngx_http_request_t *r,
3608     ngx_http_variable_value_t *v, uintptr_t data)
3609 {
3610     u_char                     *p;
3611     size_t                      len;
3612     ngx_uint_t                  i;
3613     ngx_http_upstream_state_t  *state;
3614 
3615     v->valid = 1;
3616     v->no_cacheable = 0;
3617     v->not_found = 0;
3618 
3619     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
3620         v->not_found = 1;
3621         return NGX_OK;
3622     }
3623 
3624     len = r->upstream_states->nelts * (3 + 2);
3625 
3626     p = ngx_pnalloc(r->pool, len);
3627     if (p == NULL) {
3628         return NGX_ERROR;
3629     }
3630 
3631     v->data = p;
3632 
3633     i = 0;
3634     state = r->upstream_states->elts;
3635 
3636     for ( ;; ) {
3637         if (state[i].status) {
3638             p = ngx_sprintf(p, "%ui", state[i].status);
3639 
3640         } else {
3641             *p++ = '-';
3642         }
3643 
3644         if (++i == r->upstream_states->nelts) {
3645             break;
3646         }
3647 
3648         if (state[i].peer) {
3649             *p++ = ',';
3650             *p++ = ' ';
3651 
3652         } else {
3653             *p++ = ' ';
3654             *p++ = ':';
3655             *p++ = ' ';
3656 
3657             if (++i == r->upstream_states->nelts) {
3658                 break;
3659             }
3660 
3661             continue;
3662         }
3663     }
3664 
3665     v->len = p - v->data;
3666 
3667     return NGX_OK;
3668 }
3669 
3670 
3671 static ngx_int_t
3672 ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
3673     ngx_http_variable_value_t *v, uintptr_t data)
3674 {
3675     u_char                     *p;
3676     size_t                      len;
3677     ngx_uint_t                  i;
3678     ngx_msec_int_t              ms;
3679     ngx_http_upstream_state_t  *state;
3680 
3681     v->valid = 1;
3682     v->no_cacheable = 0;
3683     v->not_found = 0;
3684 
3685     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
3686         v->not_found = 1;
3687         return NGX_OK;
3688     }
3689 
3690     len = r->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2);
3691 
3692     p = ngx_pnalloc(r->pool, len);
3693     if (p == NULL) {
3694         return NGX_ERROR;
3695     }
3696 
3697     v->data = p;
3698 
3699     i = 0;
3700     state = r->upstream_states->elts;
3701 
3702     for ( ;; ) {
3703         if (state[i].status) {
3704             ms = (ngx_msec_int_t)
3705                      (state[i].response_sec * 1000 + state[i].response_msec);
3706             ms = (ms >= 0) ? ms : 0;
3707             p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000);
3708 
3709         } else {
3710             *p++ = '-';
3711         }
3712 
3713         if (++i == r->upstream_states->nelts) {
3714             break;
3715         }
3716 
3717         if (state[i].peer) {
3718             *p++ = ',';
3719             *p++ = ' ';
3720 
3721         } else {
3722             *p++ = ' ';
3723             *p++ = ':';
3724             *p++ = ' ';
3725 
3726             if (++i == r->upstream_states->nelts) {
3727                 break;
3728             }
3729 
3730             continue;
3731         }
3732     }
3733 
3734     v->len = p - v->data;
3735 
3736     return NGX_OK;
3737 }
3738 
3739 
3740 static ngx_int_t
3741 ngx_http_upstream_response_length_variable(ngx_http_request_t *r,
3742     ngx_http_variable_value_t *v, uintptr_t data)
3743 {
3744     u_char                     *p;
3745     size_t                      len;
3746     ngx_uint_t                  i;
3747     ngx_http_upstream_state_t  *state;
3748 
3749     v->valid = 1;
3750     v->no_cacheable = 0;
3751     v->not_found = 0;
3752 
3753     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
3754         v->not_found = 1;
3755         return NGX_OK;
3756     }
3757 
3758     len = r->upstream_states->nelts * (NGX_OFF_T_LEN + 2);
3759 
3760     p = ngx_pnalloc(r->pool, len);
3761     if (p == NULL) {
3762         return NGX_ERROR;
3763     }
3764 
3765     v->data = p;
3766 
3767     i = 0;
3768     state = r->upstream_states->elts;
3769 
3770     for ( ;; ) {
3771         p = ngx_sprintf(p, "%O", state[i].response_length);
3772 
3773         if (++i == r->upstream_states->nelts) {
3774             break;
3775         }
3776 
3777         if (state[i].peer) {
3778             *p++ = ',';
3779             *p++ = ' ';
3780 
3781         } else {
3782             *p++ = ' ';
3783             *p++ = ':';
3784             *p++ = ' ';
3785 
3786             if (++i == r->upstream_states->nelts) {
3787                 break;
3788             }
3789 
3790             continue;
3791         }
3792     }
3793 
3794     v->len = p - v->data;
3795 
3796     return NGX_OK;
3797 }
3798 
3799 
3800 ngx_int_t
3801 ngx_http_upstream_header_variable(ngx_http_request_t *r,
3802     ngx_http_variable_value_t *v, uintptr_t data)
3803 {
3804     if (r->upstream == NULL) {
3805         v->not_found = 1;
3806         return NGX_OK;
3807     }
3808 
3809     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
3810                                          &r->upstream->headers_in.headers.part,
3811                                          sizeof("upstream_http_") - 1);
3812 }
3813 
3814 
3815 #if (NGX_HTTP_CACHE)
3816 
3817 ngx_int_t
3818 ngx_http_upstream_cache_status(ngx_http_request_t *r,
3819     ngx_http_variable_value_t *v, uintptr_t data)
3820 {
3821     ngx_uint_t  n;
3822 
3823     if (r->upstream == NULL || r->upstream->cache_status == 0) {
3824         v->not_found = 1;
3825         return NGX_OK;
3826     }
3827 
3828     n = r->upstream->cache_status - 1;
3829 
3830     v->valid = 1;
3831     v->no_cacheable = 0;
3832     v->not_found = 0;
3833     v->len = ngx_http_cache_status[n].len;
3834     v->data = ngx_http_cache_status[n].data;
3835 
3836     return NGX_OK;
3837 }
3838 
3839 #endif
3840 
3841 
3842 static char *
3843 ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
3844 {
3845     char                          *rv;
3846     void                          *mconf;
3847     ngx_str_t                     *value;
3848     ngx_url_t                      u;
3849     ngx_uint_t                     m;
3850     ngx_conf_t                     pcf;
3851     ngx_http_module_t             *module;
3852     ngx_http_conf_ctx_t           *ctx, *http_ctx;
3853     ngx_http_upstream_srv_conf_t  *uscf;
3854 
3855     ngx_memzero(&u, sizeof(ngx_url_t));
3856 
3857     value = cf->args->elts;
3858     u.host = value[1];
3859     u.no_resolve = 1;
3860 
3861     uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
3862                                          |NGX_HTTP_UPSTREAM_WEIGHT
3863                                          |NGX_HTTP_UPSTREAM_MAX_FAILS
3864                                          |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
3865                                          |NGX_HTTP_UPSTREAM_DOWN
3866                                          |NGX_HTTP_UPSTREAM_BACKUP);
3867     if (uscf == NULL) {
3868         return NGX_CONF_ERROR;
3869     }
3870 
3871 
3872     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
3873     if (ctx == NULL) {
3874         return NGX_CONF_ERROR;
3875     }
3876 
3877     http_ctx = cf->ctx;
3878     ctx->main_conf = http_ctx->main_conf;
3879 
3880     /* the upstream{}'s srv_conf */
3881 
3882     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
3883     if (ctx->srv_conf == NULL) {
3884         return NGX_CONF_ERROR;
3885     }
3886 
3887     ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
3888 
3889     uscf->srv_conf = ctx->srv_conf;
3890 
3891 
3892     /* the upstream{}'s loc_conf */
3893 
3894     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
3895     if (ctx->loc_conf == NULL) {
3896         return NGX_CONF_ERROR;
3897     }
3898 
3899     for (m = 0; ngx_modules[m]; m++) {
3900         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
3901             continue;
3902         }
3903 
3904         module = ngx_modules[m]->ctx;
3905 
3906         if (module->create_srv_conf) {
3907             mconf = module->create_srv_conf(cf);
3908             if (mconf == NULL) {
3909                 return NGX_CONF_ERROR;
3910             }
3911 
3912             ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
3913         }
3914 
3915         if (module->create_loc_conf) {
3916             mconf = module->create_loc_conf(cf);
3917             if (mconf == NULL) {
3918                 return NGX_CONF_ERROR;
3919             }
3920 
3921             ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf;
3922         }
3923     }
3924 
3925 
3926     /* parse inside upstream{} */
3927 
3928     pcf = *cf;
3929     cf->ctx = ctx;
3930     cf->cmd_type = NGX_HTTP_UPS_CONF;
3931 
3932     rv = ngx_conf_parse(cf, NULL);
3933 
3934     *cf = pcf;
3935 
3936     if (rv != NGX_CONF_OK) {
3937         return rv;
3938     }
3939 
3940     if (uscf->servers == NULL) {
3941         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3942                            "no servers are inside upstream");
3943         return NGX_CONF_ERROR;
3944     }
3945 
3946     return rv;
3947 }
3948 
3949 
3950 static char *
3951 ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3952 {
3953     ngx_http_upstream_srv_conf_t  *uscf = conf;
3954 
3955     time_t                       fail_timeout;
3956     ngx_str_t                   *value, s;
3957     ngx_url_t                    u;
3958     ngx_int_t                    weight, max_fails;
3959     ngx_uint_t                   i;
3960     ngx_http_upstream_server_t  *us;
3961 
3962     if (uscf->servers == NULL) {
3963         uscf->servers = ngx_array_create(cf->pool, 4,
3964                                          sizeof(ngx_http_upstream_server_t));
3965         if (uscf->servers == NULL) {
3966             return NGX_CONF_ERROR;
3967         }
3968     }
3969 
3970     us = ngx_array_push(uscf->servers);
3971     if (us == NULL) {
3972         return NGX_CONF_ERROR;
3973     }
3974 
3975     ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
3976 
3977     value = cf->args->elts;
3978 
3979     ngx_memzero(&u, sizeof(ngx_url_t));
3980 
3981     u.url = value[1];
3982     u.default_port = 80;
3983 
3984     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
3985         if (u.err) {
3986             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3987                                "%s in upstream \"%V\"", u.err, &u.url);
3988         }
3989 
3990         return NGX_CONF_ERROR;
3991     }
3992 
3993     weight = 1;
3994     max_fails = 1;
3995     fail_timeout = 10;
3996 
3997     for (i = 2; i < cf->args->nelts; i++) {
3998 
3999         if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
4000 
4001             if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
4002                 goto invalid;
4003             }
4004 
4005             weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
4006 
4007             if (weight == NGX_ERROR || weight == 0) {
4008                 goto invalid;
4009             }
4010 
4011             continue;
4012         }
4013 
4014         if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
4015 
4016             if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
4017                 goto invalid;
4018             }
4019 
4020             max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
4021 
4022             if (max_fails == NGX_ERROR) {
4023                 goto invalid;
4024             }
4025 
4026             continue;
4027         }
4028 
4029         if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
4030 
4031             if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
4032                 goto invalid;
4033             }
4034 
4035             s.len = value[i].len - 13;
4036             s.data = &value[i].data[13];
4037 
4038             fail_timeout = ngx_parse_time(&s, 1);
4039 
4040             if (fail_timeout == NGX_ERROR) {
4041                 goto invalid;
4042             }
4043 
4044             continue;
4045         }
4046 
4047         if (ngx_strncmp(value[i].data, "backup", 6) == 0) {
4048 
4049             if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
4050                 goto invalid;
4051             }
4052 
4053             us->backup = 1;
4054 
4055             continue;
4056         }
4057 
4058         if (ngx_strncmp(value[i].data, "down", 4) == 0) {
4059 
4060             if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
4061                 goto invalid;
4062             }
4063 
4064             us->down = 1;
4065 
4066             continue;
4067         }
4068 
4069         goto invalid;
4070     }
4071 
4072     us->addrs = u.addrs;
4073     us->naddrs = u.naddrs;
4074     us->weight = weight;
4075     us->max_fails = max_fails;
4076     us->fail_timeout = fail_timeout;
4077 
4078     return NGX_CONF_OK;
4079 
4080 invalid:
4081 
4082     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4083                        "invalid parameter \"%V\"", &value[i]);
4084 
4085     return NGX_CONF_ERROR;
4086 }
4087 
4088 
4089 ngx_http_upstream_srv_conf_t *
4090 ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
4091 {
4092     ngx_uint_t                      i;
4093     ngx_http_upstream_server_t     *us;
4094     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
4095     ngx_http_upstream_main_conf_t  *umcf;
4096 
4097     if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {
4098 
4099         if (ngx_parse_url(cf->pool, u) != NGX_OK) {
4100             if (u->err) {
4101                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4102                                    "%s in upstream \"%V\"", u->err, &u->url);
4103             }
4104 
4105             return NULL;
4106         }
4107     }
4108 
4109     umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
4110 
4111     uscfp = umcf->upstreams.elts;
4112 
4113     for (i = 0; i < umcf->upstreams.nelts; i++) {
4114 
4115         if (uscfp[i]->host.len != u->host.len
4116             || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
4117                != 0)
4118         {
4119             continue;
4120         }
4121 
4122         if ((flags & NGX_HTTP_UPSTREAM_CREATE)
4123              && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
4124         {
4125             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4126                                "duplicate upstream \"%V\"", &u->host);
4127             return NULL;
4128         }
4129 
4130         if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && u->port) {
4131             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
4132                                "upstream \"%V\" may not have port %d",
4133                                &u->host, u->port);
4134             return NULL;
4135         }
4136 
4137         if ((flags & NGX_HTTP_UPSTREAM_CREATE) && uscfp[i]->port) {
4138             ngx_log_error(NGX_LOG_WARN, cf->log, 0,
4139                           "upstream \"%V\" may not have port %d in %s:%ui",
4140                           &u->host, uscfp[i]->port,
4141                           uscfp[i]->file_name, uscfp[i]->line);
4142             return NULL;
4143         }
4144 
4145         if (uscfp[i]->port != u->port) {
4146             continue;
4147         }
4148 
4149         if (uscfp[i]->default_port && u->default_port
4150             && uscfp[i]->default_port != u->default_port)
4151         {
4152             continue;
4153         }
4154 
4155         return uscfp[i];
4156     }
4157 
4158     uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
4159     if (uscf == NULL) {
4160         return NULL;
4161     }
4162 
4163     uscf->flags = flags;
4164     uscf->host = u->host;
4165     uscf->file_name = cf->conf_file->file.name.data;
4166     uscf->line = cf->conf_file->line;
4167     uscf->port = u->port;
4168     uscf->default_port = u->default_port;
4169 
4170     if (u->naddrs == 1) {
4171         uscf->servers = ngx_array_create(cf->pool, 1,
4172                                          sizeof(ngx_http_upstream_server_t));
4173         if (uscf->servers == NULL) {
4174             return NGX_CONF_ERROR;
4175         }
4176 
4177         us = ngx_array_push(uscf->servers);
4178         if (us == NULL) {
4179             return NGX_CONF_ERROR;
4180         }
4181 
4182         ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
4183 
4184         us->addrs = u->addrs;
4185         us->naddrs = u->naddrs;
4186     }
4187 
4188     uscfp = ngx_array_push(&umcf->upstreams);
4189     if (uscfp == NULL) {
4190         return NULL;
4191     }
4192 
4193     *uscfp = uscf;
4194 
4195     return uscf;
4196 }
4197 
4198 
4199 ngx_int_t
4200 ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
4201     ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
4202     ngx_str_t *default_hide_headers, ngx_hash_init_t *hash)
4203 {
4204     ngx_str_t       *h;
4205     ngx_uint_t       i, j;
4206     ngx_array_t      hide_headers;
4207     ngx_hash_key_t  *hk;
4208 
4209     if (conf->hide_headers == NGX_CONF_UNSET_PTR
4210         && conf->pass_headers == NGX_CONF_UNSET_PTR)
4211     {
4212         conf->hide_headers_hash = prev->hide_headers_hash;
4213 
4214         if (conf->hide_headers_hash.buckets
4215 #if (NGX_HTTP_CACHE)
4216             && ((conf->cache == NULL) == (prev->cache == NULL))
4217 #endif
4218            )
4219         {
4220             return NGX_OK;
4221         }
4222 
4223         conf->hide_headers = prev->hide_headers;
4224         conf->pass_headers = prev->pass_headers;
4225 
4226     } else {
4227         if (conf->hide_headers == NGX_CONF_UNSET_PTR) {
4228             conf->hide_headers = prev->hide_headers;
4229         }
4230 
4231         if (conf->pass_headers == NGX_CONF_UNSET_PTR) {
4232             conf->pass_headers = prev->pass_headers;
4233         }
4234     }
4235 
4236     if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
4237         != NGX_OK)
4238     {
4239         return NGX_ERROR;
4240     }
4241 
4242     for (h = default_hide_headers; h->len; h++) {
4243         hk = ngx_array_push(&hide_headers);
4244         if (hk == NULL) {
4245             return NGX_ERROR;
4246         }
4247 
4248         hk->key = *h;
4249         hk->key_hash = ngx_hash_key_lc(h->data, h->len);
4250         hk->value = (void *) 1;
4251     }
4252 
4253     if (conf->hide_headers != NGX_CONF_UNSET_PTR) {
4254 
4255         h = conf->hide_headers->elts;
4256 
4257         for (i = 0; i < conf->hide_headers->nelts; i++) {
4258 
4259             hk = hide_headers.elts;
4260 
4261             for (j = 0; j < hide_headers.nelts; j++) {
4262                 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
4263                     goto exist;
4264                 }
4265             }
4266 
4267             hk = ngx_array_push(&hide_headers);
4268             if (hk == NULL) {
4269                 return NGX_ERROR;
4270             }
4271 
4272             hk->key = h[i];
4273             hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len);
4274             hk->value = (void *) 1;
4275 
4276         exist:
4277 
4278             continue;
4279         }
4280     }
4281 
4282     if (conf->pass_headers != NGX_CONF_UNSET_PTR) {
4283 
4284         h = conf->pass_headers->elts;
4285         hk = hide_headers.elts;
4286 
4287         for (i = 0; i < conf->pass_headers->nelts; i++) {
4288             for (j = 0; j < hide_headers.nelts; j++) {
4289 
4290                 if (hk[j].key.data == NULL) {
4291                     continue;
4292                 }
4293 
4294                 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
4295                     hk[j].key.data = NULL;
4296                     break;
4297                 }
4298             }
4299         }
4300     }
4301 
4302     hash->hash = &conf->hide_headers_hash;
4303     hash->key = ngx_hash_key_lc;
4304     hash->pool = cf->pool;
4305     hash->temp_pool = NULL;
4306 
4307     return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts);
4308 }
4309 
4310 
4311 static void *
4312 ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
4313 {
4314     ngx_http_upstream_main_conf_t  *umcf;
4315 
4316     umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t));
4317     if (umcf == NULL) {
4318         return NULL;
4319     }
4320 
4321     if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
4322                        sizeof(ngx_http_upstream_srv_conf_t *))
4323         != NGX_OK)
4324     {
4325         return NULL;
4326     }
4327 
4328     return umcf;
4329 }
4330 
4331 
4332 static char *
4333 ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
4334 {
4335     ngx_http_upstream_main_conf_t  *umcf = conf;
4336 
4337     ngx_uint_t                      i;
4338     ngx_array_t                     headers_in;
4339     ngx_hash_key_t                 *hk;
4340     ngx_hash_init_t                 hash;
4341     ngx_http_upstream_init_pt       init;
4342     ngx_http_upstream_header_t     *header;
4343     ngx_http_upstream_srv_conf_t  **uscfp;
4344 
4345     uscfp = umcf->upstreams.elts;
4346 
4347     for (i = 0; i < umcf->upstreams.nelts; i++) {
4348 
4349         init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
4350                                             ngx_http_upstream_init_round_robin;
4351 
4352         if (init(cf, uscfp[i]) != NGX_OK) {
4353             return NGX_CONF_ERROR;
4354         }
4355     }
4356 
4357 
4358     /* upstream_headers_in_hash */
4359 
4360     if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
4361         != NGX_OK)
4362     {
4363         return NGX_CONF_ERROR;
4364     }
4365 
4366     for (header = ngx_http_upstream_headers_in; header->name.len; header++) {
4367         hk = ngx_array_push(&headers_in);
4368         if (hk == NULL) {
4369             return NGX_CONF_ERROR;
4370         }
4371 
4372         hk->key = header->name;
4373         hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
4374         hk->value = header;
4375     }
4376 
4377     hash.hash = &umcf->headers_in_hash;
4378     hash.key = ngx_hash_key_lc;
4379     hash.max_size = 512;
4380     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
4381     hash.name = "upstream_headers_in_hash";
4382     hash.pool = cf->pool;
4383     hash.temp_pool = NULL;
4384 
4385     if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
4386         return NGX_CONF_ERROR;
4387     }
4388 
4389     return NGX_CONF_OK;
4390 }
4391 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.