src/http/ngx_http_upstream.c - nginx-1.7.10

Global variables defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. #if (NGX_HTTP_CACHE)
  9. static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
  10.     ngx_http_upstream_t *u);
  11. static ngx_int_t ngx_http_upstream_cache_get(ngx_http_request_t *r,
  12.     ngx_http_upstream_t *u, ngx_http_file_cache_t **cache);
  13. static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
  14.     ngx_http_upstream_t *u);
  15. static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
  16.     ngx_http_variable_value_t *v, uintptr_t data);
  17. static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
  18.     ngx_http_variable_value_t *v, uintptr_t data);
  19. static ngx_int_t ngx_http_upstream_cache_etag(ngx_http_request_t *r,
  20.     ngx_http_variable_value_t *v, uintptr_t data);
  21. #endif

  22. static void ngx_http_upstream_init_request(ngx_http_request_t *r);
  23. static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
  24. static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
  25. static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
  26. static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
  27.     ngx_event_t *ev);
  28. static void ngx_http_upstream_connect(ngx_http_request_t *r,
  29.     ngx_http_upstream_t *u);
  30. static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r,
  31.     ngx_http_upstream_t *u);
  32. static void ngx_http_upstream_send_request(ngx_http_request_t *r,
  33.     ngx_http_upstream_t *u);
  34. static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
  35.     ngx_http_upstream_t *u);
  36. static void ngx_http_upstream_process_header(ngx_http_request_t *r,
  37.     ngx_http_upstream_t *u);
  38. static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
  39.     ngx_http_upstream_t *u);
  40. static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
  41.     ngx_http_upstream_t *u);
  42. static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
  43. static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r,
  44.     ngx_http_upstream_t *u);
  45. static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
  46.     ngx_http_upstream_t *u);
  47. static void ngx_http_upstream_send_response(ngx_http_request_t *r,
  48.     ngx_http_upstream_t *u);
  49. static void ngx_http_upstream_upgrade(ngx_http_request_t *r,
  50.     ngx_http_upstream_t *u);
  51. static void ngx_http_upstream_upgraded_read_downstream(ngx_http_request_t *r);
  52. static void ngx_http_upstream_upgraded_write_downstream(ngx_http_request_t *r);
  53. static void ngx_http_upstream_upgraded_read_upstream(ngx_http_request_t *r,
  54.     ngx_http_upstream_t *u);
  55. static void ngx_http_upstream_upgraded_write_upstream(ngx_http_request_t *r,
  56.     ngx_http_upstream_t *u);
  57. static void ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
  58.     ngx_uint_t from_upstream, ngx_uint_t do_write);
  59. static void
  60.     ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r);
  61. static void
  62.     ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
  63.     ngx_http_upstream_t *u);
  64. static void
  65.     ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
  66.     ngx_uint_t do_write);
  67. static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
  68. static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
  69.     ssize_t bytes);
  70. static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
  71. static void ngx_http_upstream_process_upstream(ngx_http_request_t *r,
  72.     ngx_http_upstream_t *u);
  73. static void ngx_http_upstream_process_request(ngx_http_request_t *r);
  74. static void ngx_http_upstream_store(ngx_http_request_t *r,
  75.     ngx_http_upstream_t *u);
  76. static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r,
  77.     ngx_http_upstream_t *u);
  78. static void ngx_http_upstream_next(ngx_http_request_t *r,
  79.     ngx_http_upstream_t *u, ngx_uint_t ft_type);
  80. static void ngx_http_upstream_cleanup(void *data);
  81. static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
  82.     ngx_http_upstream_t *u, ngx_int_t rc);

  83. static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
  84.     ngx_table_elt_t *h, ngx_uint_t offset);
  85. static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r,
  86.     ngx_table_elt_t *h, ngx_uint_t offset);
  87. static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r,
  88.     ngx_table_elt_t *h, ngx_uint_t offset);
  89. static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r,
  90.     ngx_table_elt_t *h, ngx_uint_t offset);
  91. static ngx_int_t
  92.     ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
  93.     ngx_table_elt_t *h, ngx_uint_t offset);
  94. static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
  95.     ngx_table_elt_t *h, ngx_uint_t offset);
  96. static ngx_int_t ngx_http_upstream_process_expires(ngx_http_request_t *r,
  97.     ngx_table_elt_t *h, ngx_uint_t offset);
  98. static ngx_int_t ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
  99.     ngx_table_elt_t *h, ngx_uint_t offset);
  100. static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
  101.     ngx_table_elt_t *h, ngx_uint_t offset);
  102. static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
  103.     ngx_table_elt_t *h, ngx_uint_t offset);
  104. static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
  105.     ngx_table_elt_t *h, ngx_uint_t offset);
  106. static ngx_int_t ngx_http_upstream_process_connection(ngx_http_request_t *r,
  107.     ngx_table_elt_t *h, ngx_uint_t offset);
  108. static ngx_int_t
  109.     ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
  110.     ngx_table_elt_t *h, ngx_uint_t offset);
  111. static ngx_int_t ngx_http_upstream_process_vary(ngx_http_request_t *r,
  112.     ngx_table_elt_t *h, ngx_uint_t offset);
  113. static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
  114.     ngx_table_elt_t *h, ngx_uint_t offset);
  115. static ngx_int_t
  116.     ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
  117.     ngx_table_elt_t *h, ngx_uint_t offset);
  118. static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
  119.     ngx_table_elt_t *h, ngx_uint_t offset);
  120. static ngx_int_t ngx_http_upstream_copy_last_modified(ngx_http_request_t *r,
  121.     ngx_table_elt_t *h, ngx_uint_t offset);
  122. static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
  123.     ngx_table_elt_t *h, ngx_uint_t offset);
  124. static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
  125.     ngx_table_elt_t *h, ngx_uint_t offset);
  126. static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r,
  127.     ngx_table_elt_t *h, ngx_uint_t offset);
  128. static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
  129.     ngx_table_elt_t *h, ngx_uint_t offset);

  130. #if (NGX_HTTP_GZIP)
  131. static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
  132.     ngx_table_elt_t *h, ngx_uint_t offset);
  133. #endif

  134. static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
  135. static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
  136.     ngx_http_variable_value_t *v, uintptr_t data);
  137. static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
  138.     ngx_http_variable_value_t *v, uintptr_t data);
  139. static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
  140.     ngx_http_variable_value_t *v, uintptr_t data);
  141. static ngx_int_t ngx_http_upstream_response_length_variable(
  142.     ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);

  143. static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
  144. static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
  145.     void *conf);

  146. static ngx_addr_t *ngx_http_upstream_get_local(ngx_http_request_t *r,
  147.     ngx_http_upstream_local_t *local);

  148. static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
  149. static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);

  150. #if (NGX_HTTP_SSL)
  151. static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
  152.     ngx_http_upstream_t *u, ngx_connection_t *c);
  153. static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
  154. static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r,
  155.     ngx_http_upstream_t *u, ngx_connection_t *c);
  156. #endif


  157. ngx_http_upstream_header_t  ngx_http_upstream_headers_in[] = {

  158.     { ngx_string("Status"),
  159.                  ngx_http_upstream_process_header_line,
  160.                  offsetof(ngx_http_upstream_headers_in_t, status),
  161.                  ngx_http_upstream_copy_header_line, 0, 0 },

  162.     { ngx_string("Content-Type"),
  163.                  ngx_http_upstream_process_header_line,
  164.                  offsetof(ngx_http_upstream_headers_in_t, content_type),
  165.                  ngx_http_upstream_copy_content_type, 0, 1 },

  166.     { ngx_string("Content-Length"),
  167.                  ngx_http_upstream_process_content_length, 0,
  168.                  ngx_http_upstream_ignore_header_line, 0, 0 },

  169.     { ngx_string("Date"),
  170.                  ngx_http_upstream_process_header_line,
  171.                  offsetof(ngx_http_upstream_headers_in_t, date),
  172.                  ngx_http_upstream_copy_header_line,
  173.                  offsetof(ngx_http_headers_out_t, date), 0 },

  174.     { ngx_string("Last-Modified"),
  175.                  ngx_http_upstream_process_last_modified, 0,
  176.                  ngx_http_upstream_copy_last_modified, 0, 0 },

  177.     { ngx_string("ETag"),
  178.                  ngx_http_upstream_process_header_line,
  179.                  offsetof(ngx_http_upstream_headers_in_t, etag),
  180.                  ngx_http_upstream_copy_header_line,
  181.                  offsetof(ngx_http_headers_out_t, etag), 0 },

  182.     { ngx_string("Server"),
  183.                  ngx_http_upstream_process_header_line,
  184.                  offsetof(ngx_http_upstream_headers_in_t, server),
  185.                  ngx_http_upstream_copy_header_line,
  186.                  offsetof(ngx_http_headers_out_t, server), 0 },

  187.     { ngx_string("WWW-Authenticate"),
  188.                  ngx_http_upstream_process_header_line,
  189.                  offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
  190.                  ngx_http_upstream_copy_header_line, 0, 0 },

  191.     { ngx_string("Location"),
  192.                  ngx_http_upstream_process_header_line,
  193.                  offsetof(ngx_http_upstream_headers_in_t, location),
  194.                  ngx_http_upstream_rewrite_location, 0, 0 },

  195.     { ngx_string("Refresh"),
  196.                  ngx_http_upstream_ignore_header_line, 0,
  197.                  ngx_http_upstream_rewrite_refresh, 0, 0 },

  198.     { ngx_string("Set-Cookie"),
  199.                  ngx_http_upstream_process_set_cookie,
  200.                  offsetof(ngx_http_upstream_headers_in_t, cookies),
  201.                  ngx_http_upstream_rewrite_set_cookie, 0, 1 },

  202.     { ngx_string("Content-Disposition"),
  203.                  ngx_http_upstream_ignore_header_line, 0,
  204.                  ngx_http_upstream_copy_header_line, 0, 1 },

  205.     { ngx_string("Cache-Control"),
  206.                  ngx_http_upstream_process_cache_control, 0,
  207.                  ngx_http_upstream_copy_multi_header_lines,
  208.                  offsetof(ngx_http_headers_out_t, cache_control), 1 },

  209.     { ngx_string("Expires"),
  210.                  ngx_http_upstream_process_expires, 0,
  211.                  ngx_http_upstream_copy_header_line,
  212.                  offsetof(ngx_http_headers_out_t, expires), 1 },

  213.     { ngx_string("Accept-Ranges"),
  214.                  ngx_http_upstream_process_header_line,
  215.                  offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
  216.                  ngx_http_upstream_copy_allow_ranges,
  217.                  offsetof(ngx_http_headers_out_t, accept_ranges), 1 },

  218.     { ngx_string("Connection"),
  219.                  ngx_http_upstream_process_connection, 0,
  220.                  ngx_http_upstream_ignore_header_line, 0, 0 },

  221.     { ngx_string("Keep-Alive"),
  222.                  ngx_http_upstream_ignore_header_line, 0,
  223.                  ngx_http_upstream_ignore_header_line, 0, 0 },

  224.     { ngx_string("Vary"),
  225.                  ngx_http_upstream_process_vary, 0,
  226.                  ngx_http_upstream_copy_header_line, 0, 0 },

  227.     { ngx_string("X-Powered-By"),
  228.                  ngx_http_upstream_ignore_header_line, 0,
  229.                  ngx_http_upstream_copy_header_line, 0, 0 },

  230.     { ngx_string("X-Accel-Expires"),
  231.                  ngx_http_upstream_process_accel_expires, 0,
  232.                  ngx_http_upstream_copy_header_line, 0, 0 },

  233.     { ngx_string("X-Accel-Redirect"),
  234.                  ngx_http_upstream_process_header_line,
  235.                  offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
  236.                  ngx_http_upstream_copy_header_line, 0, 0 },

  237.     { ngx_string("X-Accel-Limit-Rate"),
  238.                  ngx_http_upstream_process_limit_rate, 0,
  239.                  ngx_http_upstream_copy_header_line, 0, 0 },

  240.     { ngx_string("X-Accel-Buffering"),
  241.                  ngx_http_upstream_process_buffering, 0,
  242.                  ngx_http_upstream_copy_header_line, 0, 0 },

  243.     { ngx_string("X-Accel-Charset"),
  244.                  ngx_http_upstream_process_charset, 0,
  245.                  ngx_http_upstream_copy_header_line, 0, 0 },

  246.     { ngx_string("Transfer-Encoding"),
  247.                  ngx_http_upstream_process_transfer_encoding, 0,
  248.                  ngx_http_upstream_ignore_header_line, 0, 0 },

  249. #if (NGX_HTTP_GZIP)
  250.     { ngx_string("Content-Encoding"),
  251.                  ngx_http_upstream_process_header_line,
  252.                  offsetof(ngx_http_upstream_headers_in_t, content_encoding),
  253.                  ngx_http_upstream_copy_content_encoding, 0, 0 },
  254. #endif

  255.     { ngx_null_string, NULL, 0, NULL, 0, 0 }
  256. };


  257. static ngx_command_t  ngx_http_upstream_commands[] = {

  258.     { ngx_string("upstream"),
  259.       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
  260.       ngx_http_upstream,
  261.       0,
  262.       0,
  263.       NULL },

  264.     { ngx_string("server"),
  265.       NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
  266.       ngx_http_upstream_server,
  267.       NGX_HTTP_SRV_CONF_OFFSET,
  268.       0,
  269.       NULL },

  270.       ngx_null_command
  271. };


  272. static ngx_http_module_t  ngx_http_upstream_module_ctx = {
  273.     ngx_http_upstream_add_variables,       /* preconfiguration */
  274.     NULL,                                  /* postconfiguration */

  275.     ngx_http_upstream_create_main_conf,    /* create main configuration */
  276.     ngx_http_upstream_init_main_conf,      /* init main configuration */

  277.     NULL,                                  /* create server configuration */
  278.     NULL,                                  /* merge server configuration */

  279.     NULL,                                  /* create location configuration */
  280.     NULL                                   /* merge location configuration */
  281. };


  282. ngx_module_t  ngx_http_upstream_module = {
  283.     NGX_MODULE_V1,
  284.     &ngx_http_upstream_module_ctx,         /* module context */
  285.     ngx_http_upstream_commands,            /* module directives */
  286.     NGX_HTTP_MODULE,                       /* module type */
  287.     NULL,                                  /* init master */
  288.     NULL,                                  /* init module */
  289.     NULL,                                  /* init process */
  290.     NULL,                                  /* init thread */
  291.     NULL,                                  /* exit thread */
  292.     NULL,                                  /* exit process */
  293.     NULL,                                  /* exit master */
  294.     NGX_MODULE_V1_PADDING
  295. };


  296. static ngx_http_variable_t  ngx_http_upstream_vars[] = {

  297.     { ngx_string("upstream_addr"), NULL,
  298.       ngx_http_upstream_addr_variable, 0,
  299.       NGX_HTTP_VAR_NOCACHEABLE, 0 },

  300.     { ngx_string("upstream_status"), NULL,
  301.       ngx_http_upstream_status_variable, 0,
  302.       NGX_HTTP_VAR_NOCACHEABLE, 0 },

  303.     { ngx_string("upstream_header_time"), NULL,
  304.       ngx_http_upstream_response_time_variable, 1,
  305.       NGX_HTTP_VAR_NOCACHEABLE, 0 },

  306.     { ngx_string("upstream_response_time"), NULL,
  307.       ngx_http_upstream_response_time_variable, 0,
  308.       NGX_HTTP_VAR_NOCACHEABLE, 0 },

  309.     { ngx_string("upstream_response_length"), NULL,
  310.       ngx_http_upstream_response_length_variable, 0,
  311.       NGX_HTTP_VAR_NOCACHEABLE, 0 },

  312. #if (NGX_HTTP_CACHE)

  313.     { ngx_string("upstream_cache_status"), NULL,
  314.       ngx_http_upstream_cache_status, 0,
  315.       NGX_HTTP_VAR_NOCACHEABLE, 0 },

  316.     { ngx_string("upstream_cache_last_modified"), NULL,
  317.       ngx_http_upstream_cache_last_modified, 0,
  318.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  319.     { ngx_string("upstream_cache_etag"), NULL,
  320.       ngx_http_upstream_cache_etag, 0,
  321.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  322. #endif

  323.     { ngx_null_string, NULL, NULL, 0, 0, 0 }
  324. };


  325. static ngx_http_upstream_next_t  ngx_http_upstream_next_errors[] = {
  326.     { 500, NGX_HTTP_UPSTREAM_FT_HTTP_500 },
  327.     { 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 },
  328.     { 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 },
  329.     { 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 },
  330.     { 403, NGX_HTTP_UPSTREAM_FT_HTTP_403 },
  331.     { 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 },
  332.     { 0, 0 }
  333. };


  334. ngx_conf_bitmask_t  ngx_http_upstream_cache_method_mask[] = {
  335.    { ngx_string("GET"),  NGX_HTTP_GET},
  336.    { ngx_string("HEAD"), NGX_HTTP_HEAD },
  337.    { ngx_string("POST"), NGX_HTTP_POST },
  338.    { ngx_null_string, 0 }
  339. };


  340. ngx_conf_bitmask_t  ngx_http_upstream_ignore_headers_masks[] = {
  341.     { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT },
  342.     { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES },
  343.     { ngx_string("X-Accel-Limit-Rate"), NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE },
  344.     { ngx_string("X-Accel-Buffering"), NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING },
  345.     { ngx_string("X-Accel-Charset"), NGX_HTTP_UPSTREAM_IGN_XA_CHARSET },
  346.     { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES },
  347.     { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL },
  348.     { ngx_string("Set-Cookie"), NGX_HTTP_UPSTREAM_IGN_SET_COOKIE },
  349.     { ngx_string("Vary"), NGX_HTTP_UPSTREAM_IGN_VARY },
  350.     { ngx_null_string, 0 }
  351. };


  352. ngx_int_t
  353. ngx_http_upstream_create(ngx_http_request_t *r)
  354. {
  355.     ngx_http_upstream_t  *u;

  356.     u = r->upstream;

  357.     if (u && u->cleanup) {
  358.         r->main->count++;
  359.         ngx_http_upstream_cleanup(r);
  360.     }

  361.     u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
  362.     if (u == NULL) {
  363.         return NGX_ERROR;
  364.     }

  365.     r->upstream = u;

  366.     u->peer.log = r->connection->log;
  367.     u->peer.log_error = NGX_ERROR_ERR;
  368. #if (NGX_THREADS)
  369.     u->peer.lock = &r->connection->lock;
  370. #endif

  371. #if (NGX_HTTP_CACHE)
  372.     r->cache = NULL;
  373. #endif

  374.     u->headers_in.content_length_n = -1;
  375.     u->headers_in.last_modified_time = -1;

  376.     return NGX_OK;
  377. }


  378. void
  379. ngx_http_upstream_init(ngx_http_request_t *r)
  380. {
  381.     ngx_connection_t     *c;

  382.     c = r->connection;

  383.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  384.                    "http init upstream, client timer: %d", c->read->timer_set);

  385. #if (NGX_HTTP_SPDY)
  386.     if (r->spdy_stream) {
  387.         ngx_http_upstream_init_request(r);
  388.         return;
  389.     }
  390. #endif

  391.     if (c->read->timer_set) {
  392.         ngx_del_timer(c->read);
  393.     }

  394.     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {

  395.         if (!c->write->active) {
  396.             if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
  397.                 == NGX_ERROR)
  398.             {
  399.                 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
  400.                 return;
  401.             }
  402.         }
  403.     }

  404.     ngx_http_upstream_init_request(r);
  405. }


  406. static void
  407. ngx_http_upstream_init_request(ngx_http_request_t *r)
  408. {
  409.     ngx_str_t                      *host;
  410.     ngx_uint_t                      i;
  411.     ngx_resolver_ctx_t             *ctx, temp;
  412.     ngx_http_cleanup_t             *cln;
  413.     ngx_http_upstream_t            *u;
  414.     ngx_http_core_loc_conf_t       *clcf;
  415.     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
  416.     ngx_http_upstream_main_conf_t  *umcf;

  417.     if (r->aio) {
  418.         return;
  419.     }

  420.     u = r->upstream;

  421. #if (NGX_HTTP_CACHE)

  422.     if (u->conf->cache) {
  423.         ngx_int_t  rc;

  424.         rc = ngx_http_upstream_cache(r, u);

  425.         if (rc == NGX_BUSY) {
  426.             r->write_event_handler = ngx_http_upstream_init_request;
  427.             return;
  428.         }

  429.         r->write_event_handler = ngx_http_request_empty_handler;

  430.         if (rc == NGX_DONE) {
  431.             return;
  432.         }

  433.         if (rc == NGX_ERROR) {
  434.             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
  435.             return;
  436.         }

  437.         if (rc != NGX_DECLINED) {
  438.             ngx_http_finalize_request(r, rc);
  439.             return;
  440.         }
  441.     }

  442. #endif

  443.     u->store = u->conf->store;

  444.     if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
  445.         r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
  446.         r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
  447.     }

  448.     if (r->request_body) {
  449.         u->request_bufs = r->request_body->bufs;
  450.     }

  451.     if (u->create_request(r) != NGX_OK) {
  452.         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
  453.         return;
  454.     }

  455.     u->peer.local = ngx_http_upstream_get_local(r, u->conf->local);

  456.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  457.     u->output.alignment = clcf->directio_alignment;
  458.     u->output.pool = r->pool;
  459.     u->output.bufs.num = 1;
  460.     u->output.bufs.size = clcf->client_body_buffer_size;
  461.     u->output.output_filter = ngx_chain_writer;
  462.     u->output.filter_ctx = &u->writer;

  463.     u->writer.pool = r->pool;

  464.     if (r->upstream_states == NULL) {

  465.         r->upstream_states = ngx_array_create(r->pool, 1,
  466.                                             sizeof(ngx_http_upstream_state_t));
  467.         if (r->upstream_states == NULL) {
  468.             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
  469.             return;
  470.         }

  471.     } else {

  472.         u->state = ngx_array_push(r->upstream_states);
  473.         if (u->state == NULL) {
  474.             ngx_http_upstream_finalize_request(r, u,
  475.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  476.             return;
  477.         }

  478.         ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
  479.     }

  480.     cln = ngx_http_cleanup_add(r, 0);
  481.     if (cln == NULL) {
  482.         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
  483.         return;
  484.     }

  485.     cln->handler = ngx_http_upstream_cleanup;
  486.     cln->data = r;
  487.     u->cleanup = &cln->handler;

  488.     if (u->resolved == NULL) {

  489.         uscf = u->conf->upstream;

  490.     } else {

  491. #if (NGX_HTTP_SSL)
  492.         u->ssl_name = u->resolved->host;
  493. #endif

  494.         if (u->resolved->sockaddr) {

  495.             if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
  496.                 != NGX_OK)
  497.             {
  498.                 ngx_http_upstream_finalize_request(r, u,
  499.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  500.                 return;
  501.             }

  502.             ngx_http_upstream_connect(r, u);

  503.             return;
  504.         }

  505.         host = &u->resolved->host;

  506.         umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  507.         uscfp = umcf->upstreams.elts;

  508.         for (i = 0; i < umcf->upstreams.nelts; i++) {

  509.             uscf = uscfp[i];

  510.             if (uscf->host.len == host->len
  511.                 && ((uscf->port == 0 && u->resolved->no_port)
  512.                      || uscf->port == u->resolved->port)
  513.                 && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
  514.             {
  515.                 goto found;
  516.             }
  517.         }

  518.         if (u->resolved->port == 0) {
  519.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  520.                           "no port in upstream \"%V\"", host);
  521.             ngx_http_upstream_finalize_request(r, u,
  522.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  523.             return;
  524.         }

  525.         temp.name = *host;

  526.         ctx = ngx_resolve_start(clcf->resolver, &temp);
  527.         if (ctx == NULL) {
  528.             ngx_http_upstream_finalize_request(r, u,
  529.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  530.             return;
  531.         }

  532.         if (ctx == NGX_NO_RESOLVER) {
  533.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  534.                           "no resolver defined to resolve %V", host);

  535.             ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
  536.             return;
  537.         }

  538.         ctx->name = *host;
  539.         ctx->handler = ngx_http_upstream_resolve_handler;
  540.         ctx->data = r;
  541.         ctx->timeout = clcf->resolver_timeout;

  542.         u->resolved->ctx = ctx;

  543.         if (ngx_resolve_name(ctx) != NGX_OK) {
  544.             u->resolved->ctx = NULL;
  545.             ngx_http_upstream_finalize_request(r, u,
  546.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  547.             return;
  548.         }

  549.         return;
  550.     }

  551. found:

  552.     if (uscf == NULL) {
  553.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  554.                       "no upstream configuration");
  555.         ngx_http_upstream_finalize_request(r, u,
  556.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  557.         return;
  558.     }

  559. #if (NGX_HTTP_SSL)
  560.     u->ssl_name = uscf->host;
  561. #endif

  562.     if (uscf->peer.init(r, uscf) != NGX_OK) {
  563.         ngx_http_upstream_finalize_request(r, u,
  564.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  565.         return;
  566.     }

  567.     u->peer.start_time = ngx_current_msec;

  568.     if (u->conf->next_upstream_tries
  569.         && u->peer.tries > u->conf->next_upstream_tries)
  570.     {
  571.         u->peer.tries = u->conf->next_upstream_tries;
  572.     }

  573.     ngx_http_upstream_connect(r, u);
  574. }


  575. #if (NGX_HTTP_CACHE)

  576. static ngx_int_t
  577. ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
  578. {
  579.     ngx_int_t               rc;
  580.     ngx_http_cache_t       *c;
  581.     ngx_http_file_cache_t  *cache;

  582.     c = r->cache;

  583.     if (c == NULL) {

  584.         if (!(r->method & u->conf->cache_methods)) {
  585.             return NGX_DECLINED;
  586.         }

  587.         rc = ngx_http_upstream_cache_get(r, u, &cache);

  588.         if (rc != NGX_OK) {
  589.             return rc;
  590.         }

  591.         if (r->method & NGX_HTTP_HEAD) {
  592.             u->method = ngx_http_core_get_method;
  593.         }

  594.         if (ngx_http_file_cache_new(r) != NGX_OK) {
  595.             return NGX_ERROR;
  596.         }

  597.         if (u->create_key(r) != NGX_OK) {
  598.             return NGX_ERROR;
  599.         }

  600.         /* TODO: add keys */

  601.         ngx_http_file_cache_create_key(r);

  602.         if (r->cache->header_start + 256 >= u->conf->buffer_size) {
  603.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  604.                           "%V_buffer_size %uz is not enough for cache key, "
  605.                           "it should be increased to at least %uz",
  606.                           &u->conf->module, u->conf->buffer_size,
  607.                           ngx_align(r->cache->header_start + 256, 1024));

  608.             r->cache = NULL;
  609.             return NGX_DECLINED;
  610.         }

  611.         u->cacheable = 1;

  612.         c = r->cache;

  613.         c->body_start = u->conf->buffer_size;
  614.         c->min_uses = u->conf->cache_min_uses;
  615.         c->file_cache = cache;

  616.         switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) {

  617.         case NGX_ERROR:
  618.             return NGX_ERROR;

  619.         case NGX_DECLINED:
  620.             u->cache_status = NGX_HTTP_CACHE_BYPASS;
  621.             return NGX_DECLINED;

  622.         default: /* NGX_OK */
  623.             break;
  624.         }

  625.         c->lock = u->conf->cache_lock;
  626.         c->lock_timeout = u->conf->cache_lock_timeout;
  627.         c->lock_age = u->conf->cache_lock_age;

  628.         u->cache_status = NGX_HTTP_CACHE_MISS;
  629.     }

  630.     rc = ngx_http_file_cache_open(r);

  631.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  632.                    "http upstream cache: %i", rc);

  633.     switch (rc) {

  634.     case NGX_HTTP_CACHE_UPDATING:

  635.         if (u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) {
  636.             u->cache_status = rc;
  637.             rc = NGX_OK;

  638.         } else {
  639.             rc = NGX_HTTP_CACHE_STALE;
  640.         }

  641.         break;

  642.     case NGX_OK:
  643.         u->cache_status = NGX_HTTP_CACHE_HIT;
  644.     }

  645.     switch (rc) {

  646.     case NGX_OK:

  647.         rc = ngx_http_upstream_cache_send(r, u);

  648.         if (rc != NGX_HTTP_UPSTREAM_INVALID_HEADER) {
  649.             return rc;
  650.         }

  651.         break;

  652.     case NGX_HTTP_CACHE_STALE:

  653.         c->valid_sec = 0;
  654.         u->buffer.start = NULL;
  655.         u->cache_status = NGX_HTTP_CACHE_EXPIRED;

  656.         break;

  657.     case NGX_DECLINED:

  658.         if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {
  659.             u->buffer.start = NULL;

  660.         } else {
  661.             u->buffer.pos = u->buffer.start + c->header_start;
  662.             u->buffer.last = u->buffer.pos;
  663.         }

  664.         break;

  665.     case NGX_HTTP_CACHE_SCARCE:

  666.         u->cacheable = 0;

  667.         break;

  668.     case NGX_AGAIN:

  669.         return NGX_BUSY;

  670.     case NGX_ERROR:

  671.         return NGX_ERROR;

  672.     default:

  673.         /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */

  674.         u->cache_status = NGX_HTTP_CACHE_HIT;

  675.         return rc;
  676.     }

  677.     r->cached = 0;

  678.     return NGX_DECLINED;
  679. }


  680. static ngx_int_t
  681. ngx_http_upstream_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u,
  682.     ngx_http_file_cache_t **cache)
  683. {
  684.     ngx_str_t               *name, val;
  685.     ngx_uint_t               i;
  686.     ngx_http_file_cache_t  **caches;

  687.     if (u->conf->cache_zone) {
  688.         *cache = u->conf->cache_zone->data;
  689.         return NGX_OK;
  690.     }

  691.     if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) {
  692.         return NGX_ERROR;
  693.     }

  694.     if (val.len == 0
  695.         || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0))
  696.     {
  697.         return NGX_DECLINED;
  698.     }

  699.     caches = u->caches->elts;

  700.     for (i = 0; i < u->caches->nelts; i++) {
  701.         name = &caches[i]->shm_zone->shm.name;

  702.         if (name->len == val.len
  703.             && ngx_strncmp(name->data, val.data, val.len) == 0)
  704.         {
  705.             *cache = caches[i];
  706.             return NGX_OK;
  707.         }
  708.     }

  709.     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  710.                   "cache \"%V\" not found", &val);

  711.     return NGX_ERROR;
  712. }


  713. static ngx_int_t
  714. ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
  715. {
  716.     ngx_int_t          rc;
  717.     ngx_http_cache_t  *c;

  718.     r->cached = 1;
  719.     c = r->cache;

  720.     if (c->header_start == c->body_start) {
  721.         r->http_version = NGX_HTTP_VERSION_9;
  722.         return ngx_http_cache_send(r);
  723.     }

  724.     /* TODO: cache stack */

  725.     u->buffer = *c->buf;
  726.     u->buffer.pos += c->header_start;

  727.     ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
  728.     u->headers_in.content_length_n = -1;
  729.     u->headers_in.last_modified_time = -1;

  730.     if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
  731.                       sizeof(ngx_table_elt_t))
  732.         != NGX_OK)
  733.     {
  734.         return NGX_ERROR;
  735.     }

  736.     rc = u->process_header(r);

  737.     if (rc == NGX_OK) {

  738.         if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
  739.             return NGX_DONE;
  740.         }

  741.         return ngx_http_cache_send(r);
  742.     }

  743.     if (rc == NGX_ERROR) {
  744.         return NGX_ERROR;
  745.     }

  746.     /* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */

  747.     /* TODO: delete file */

  748.     return rc;
  749. }

  750. #endif


  751. static void
  752. ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
  753. {
  754.     ngx_connection_t              *c;
  755.     ngx_http_request_t            *r;
  756.     ngx_http_upstream_t           *u;
  757.     ngx_http_upstream_resolved_t  *ur;

  758.     r = ctx->data;
  759.     c = r->connection;

  760.     u = r->upstream;
  761.     ur = u->resolved;

  762.     ngx_http_set_log_request(c->log, r);

  763.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
  764.                    "http upstream resolve: \"%V?%V\"", &r->uri, &r->args);

  765.     if (ctx->state) {
  766.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  767.                       "%V could not be resolved (%i: %s)",
  768.                       &ctx->name, ctx->state,
  769.                       ngx_resolver_strerror(ctx->state));

  770.         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
  771.         goto failed;
  772.     }

  773.     ur->naddrs = ctx->naddrs;
  774.     ur->addrs = ctx->addrs;

  775. #if (NGX_DEBUG)
  776.     {
  777.     u_char      text[NGX_SOCKADDR_STRLEN];
  778.     ngx_str_t   addr;
  779.     ngx_uint_t  i;

  780.     addr.data = text;

  781.     for (i = 0; i < ctx->naddrs; i++) {
  782.         addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen,
  783.                                  text, NGX_SOCKADDR_STRLEN, 0);

  784.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  785.                        "name was resolved to %V", &addr);
  786.     }
  787.     }
  788. #endif

  789.     if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
  790.         ngx_http_upstream_finalize_request(r, u,
  791.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  792.         goto failed;
  793.     }

  794.     ngx_resolve_name_done(ctx);
  795.     ur->ctx = NULL;

  796.     u->peer.start_time = ngx_current_msec;

  797.     if (u->conf->next_upstream_tries
  798.         && u->peer.tries > u->conf->next_upstream_tries)
  799.     {
  800.         u->peer.tries = u->conf->next_upstream_tries;
  801.     }

  802.     ngx_http_upstream_connect(r, u);

  803. failed:

  804.     ngx_http_run_posted_requests(c);
  805. }


  806. static void
  807. ngx_http_upstream_handler(ngx_event_t *ev)
  808. {
  809.     ngx_connection_t     *c;
  810.     ngx_http_request_t   *r;
  811.     ngx_http_upstream_t  *u;

  812.     c = ev->data;
  813.     r = c->data;

  814.     u = r->upstream;
  815.     c = r->connection;

  816.     ngx_http_set_log_request(c->log, r);

  817.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
  818.                    "http upstream request: \"%V?%V\"", &r->uri, &r->args);

  819.     if (ev->write) {
  820.         u->write_event_handler(r, u);

  821.     } else {
  822.         u->read_event_handler(r, u);
  823.     }

  824.     ngx_http_run_posted_requests(c);
  825. }


  826. static void
  827. ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
  828. {
  829.     ngx_http_upstream_check_broken_connection(r, r->connection->read);
  830. }


  831. static void
  832. ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
  833. {
  834.     ngx_http_upstream_check_broken_connection(r, r->connection->write);
  835. }


  836. static void
  837. ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
  838.     ngx_event_t *ev)
  839. {
  840.     int                  n;
  841.     char                 buf[1];
  842.     ngx_err_t            err;
  843.     ngx_int_t            event;
  844.     ngx_connection_t     *c;
  845.     ngx_http_upstream_t  *u;

  846.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
  847.                    "http upstream check client, write event:%d, \"%V\"",
  848.                    ev->write, &r->uri);

  849.     c = r->connection;
  850.     u = r->upstream;

  851.     if (c->error) {
  852.         if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {

  853.             event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;

  854.             if (ngx_del_event(ev, event, 0) != NGX_OK) {
  855.                 ngx_http_upstream_finalize_request(r, u,
  856.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  857.                 return;
  858.             }
  859.         }

  860.         if (!u->cacheable) {
  861.             ngx_http_upstream_finalize_request(r, u,
  862.                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
  863.         }

  864.         return;
  865.     }

  866. #if (NGX_HTTP_SPDY)
  867.     if (r->spdy_stream) {
  868.         return;
  869.     }
  870. #endif

  871. #if (NGX_HAVE_KQUEUE)

  872.     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {

  873.         if (!ev->pending_eof) {
  874.             return;
  875.         }

  876.         ev->eof = 1;
  877.         c->error = 1;

  878.         if (ev->kq_errno) {
  879.             ev->error = 1;
  880.         }

  881.         if (!u->cacheable && u->peer.connection) {
  882.             ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
  883.                           "kevent() reported that client prematurely closed "
  884.                           "connection, so upstream connection is closed too");
  885.             ngx_http_upstream_finalize_request(r, u,
  886.                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
  887.             return;
  888.         }

  889.         ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
  890.                       "kevent() reported that client prematurely closed "
  891.                       "connection");

  892.         if (u->peer.connection == NULL) {
  893.             ngx_http_upstream_finalize_request(r, u,
  894.                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
  895.         }

  896.         return;
  897.     }

  898. #endif

  899. #if (NGX_HAVE_EPOLLRDHUP)

  900.     if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ev->pending_eof) {
  901.         socklen_t  len;

  902.         ev->eof = 1;
  903.         c->error = 1;

  904.         err = 0;
  905.         len = sizeof(ngx_err_t);

  906.         /*
  907.          * BSDs and Linux return 0 and set a pending error in err
  908.          * Solaris returns -1 and sets errno
  909.          */

  910.         if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
  911.             == -1)
  912.         {
  913.             err = ngx_socket_errno;
  914.         }

  915.         if (err) {
  916.             ev->error = 1;
  917.         }

  918.         if (!u->cacheable && u->peer.connection) {
  919.             ngx_log_error(NGX_LOG_INFO, ev->log, err,
  920.                         "epoll_wait() reported that client prematurely closed "
  921.                         "connection, so upstream connection is closed too");
  922.             ngx_http_upstream_finalize_request(r, u,
  923.                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
  924.             return;
  925.         }

  926.         ngx_log_error(NGX_LOG_INFO, ev->log, err,
  927.                       "epoll_wait() reported that client prematurely closed "
  928.                       "connection");

  929.         if (u->peer.connection == NULL) {
  930.             ngx_http_upstream_finalize_request(r, u,
  931.                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
  932.         }

  933.         return;
  934.     }

  935. #endif

  936.     n = recv(c->fd, buf, 1, MSG_PEEK);

  937.     err = ngx_socket_errno;

  938.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
  939.                    "http upstream recv(): %d", n);

  940.     if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
  941.         return;
  942.     }

  943.     if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {

  944.         event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;

  945.         if (ngx_del_event(ev, event, 0) != NGX_OK) {
  946.             ngx_http_upstream_finalize_request(r, u,
  947.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  948.             return;
  949.         }
  950.     }

  951.     if (n > 0) {
  952.         return;
  953.     }

  954.     if (n == -1) {
  955.         if (err == NGX_EAGAIN) {
  956.             return;
  957.         }

  958.         ev->error = 1;

  959.     } else { /* n == 0 */
  960.         err = 0;
  961.     }

  962.     ev->eof = 1;
  963.     c->error = 1;

  964.     if (!u->cacheable && u->peer.connection) {
  965.         ngx_log_error(NGX_LOG_INFO, ev->log, err,
  966.                       "client prematurely closed connection, "
  967.                       "so upstream connection is closed too");
  968.         ngx_http_upstream_finalize_request(r, u,
  969.                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
  970.         return;
  971.     }

  972.     ngx_log_error(NGX_LOG_INFO, ev->log, err,
  973.                   "client prematurely closed connection");

  974.     if (u->peer.connection == NULL) {
  975.         ngx_http_upstream_finalize_request(r, u,
  976.                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
  977.     }
  978. }


  979. static void
  980. ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
  981. {
  982.     ngx_int_t          rc;
  983.     ngx_time_t        *tp;
  984.     ngx_connection_t  *c;

  985.     r->connection->log->action = "connecting to upstream";

  986.     if (u->state && u->state->response_sec) {
  987.         tp = ngx_timeofday();
  988.         u->state->response_sec = tp->sec - u->state->response_sec;
  989.         u->state->response_msec = tp->msec - u->state->response_msec;
  990.     }

  991.     u->state = ngx_array_push(r->upstream_states);
  992.     if (u->state == NULL) {
  993.         ngx_http_upstream_finalize_request(r, u,
  994.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  995.         return;
  996.     }

  997.     ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));

  998.     tp = ngx_timeofday();
  999.     u->state->response_sec = tp->sec;
  1000.     u->state->response_msec = tp->msec;
  1001.     u->state->header_sec = (time_t) NGX_ERROR;

  1002.     rc = ngx_event_connect_peer(&u->peer);

  1003.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1004.                    "http upstream connect: %i", rc);

  1005.     if (rc == NGX_ERROR) {
  1006.         ngx_http_upstream_finalize_request(r, u,
  1007.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  1008.         return;
  1009.     }

  1010.     u->state->peer = u->peer.name;

  1011.     if (rc == NGX_BUSY) {
  1012.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
  1013.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
  1014.         return;
  1015.     }

  1016.     if (rc == NGX_DECLINED) {
  1017.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
  1018.         return;
  1019.     }

  1020.     /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */

  1021.     c = u->peer.connection;

  1022.     c->data = r;

  1023.     c->write->handler = ngx_http_upstream_handler;
  1024.     c->read->handler = ngx_http_upstream_handler;

  1025.     u->write_event_handler = ngx_http_upstream_send_request_handler;
  1026.     u->read_event_handler = ngx_http_upstream_process_header;

  1027.     c->sendfile &= r->connection->sendfile;
  1028.     u->output.sendfile = c->sendfile;

  1029.     if (c->pool == NULL) {

  1030.         /* we need separate pool here to be able to cache SSL connections */

  1031.         c->pool = ngx_create_pool(128, r->connection->log);
  1032.         if (c->pool == NULL) {
  1033.             ngx_http_upstream_finalize_request(r, u,
  1034.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1035.             return;
  1036.         }
  1037.     }

  1038.     c->log = r->connection->log;
  1039.     c->pool->log = c->log;
  1040.     c->read->log = c->log;
  1041.     c->write->log = c->log;

  1042.     /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */

  1043.     u->writer.out = NULL;
  1044.     u->writer.last = &u->writer.out;
  1045.     u->writer.connection = c;
  1046.     u->writer.limit = 0;

  1047.     if (u->request_sent) {
  1048.         if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
  1049.             ngx_http_upstream_finalize_request(r, u,
  1050.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1051.             return;
  1052.         }
  1053.     }

  1054.     if (r->request_body
  1055.         && r->request_body->buf
  1056.         && r->request_body->temp_file
  1057.         && r == r->main)
  1058.     {
  1059.         /*
  1060.          * the r->request_body->buf can be reused for one request only,
  1061.          * the subrequests should allocate their own temporary bufs
  1062.          */

  1063.         u->output.free = ngx_alloc_chain_link(r->pool);
  1064.         if (u->output.free == NULL) {
  1065.             ngx_http_upstream_finalize_request(r, u,
  1066.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1067.             return;
  1068.         }

  1069.         u->output.free->buf = r->request_body->buf;
  1070.         u->output.free->next = NULL;
  1071.         u->output.allocated = 1;

  1072.         r->request_body->buf->pos = r->request_body->buf->start;
  1073.         r->request_body->buf->last = r->request_body->buf->start;
  1074.         r->request_body->buf->tag = u->output.tag;
  1075.     }

  1076.     u->request_sent = 0;

  1077.     if (rc == NGX_AGAIN) {
  1078.         ngx_add_timer(c->write, u->conf->connect_timeout);
  1079.         return;
  1080.     }

  1081. #if (NGX_HTTP_SSL)

  1082.     if (u->ssl && c->ssl == NULL) {
  1083.         ngx_http_upstream_ssl_init_connection(r, u, c);
  1084.         return;
  1085.     }

  1086. #endif

  1087.     ngx_http_upstream_send_request(r, u);
  1088. }


  1089. #if (NGX_HTTP_SSL)

  1090. static void
  1091. ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
  1092.     ngx_http_upstream_t *u, ngx_connection_t *c)
  1093. {
  1094.     ngx_int_t   rc;

  1095.     if (ngx_http_upstream_test_connect(c) != NGX_OK) {
  1096.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
  1097.         return;
  1098.     }

  1099.     if (ngx_ssl_create_connection(u->conf->ssl, c,
  1100.                                   NGX_SSL_BUFFER|NGX_SSL_CLIENT)
  1101.         != NGX_OK)
  1102.     {
  1103.         ngx_http_upstream_finalize_request(r, u,
  1104.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  1105.         return;
  1106.     }

  1107.     c->sendfile = 0;
  1108.     u->output.sendfile = 0;

  1109.     if (u->conf->ssl_server_name || u->conf->ssl_verify) {
  1110.         if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) {
  1111.             ngx_http_upstream_finalize_request(r, u,
  1112.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1113.             return;
  1114.         }
  1115.     }

  1116.     if (u->conf->ssl_session_reuse) {
  1117.         if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
  1118.             ngx_http_upstream_finalize_request(r, u,
  1119.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1120.             return;
  1121.         }
  1122.     }

  1123.     r->connection->log->action = "SSL handshaking to upstream";

  1124.     rc = ngx_ssl_handshake(c);

  1125.     if (rc == NGX_AGAIN) {

  1126.         if (!c->write->timer_set) {
  1127.             ngx_add_timer(c->write, u->conf->connect_timeout);
  1128.         }

  1129.         c->ssl->handler = ngx_http_upstream_ssl_handshake;
  1130.         return;
  1131.     }

  1132.     ngx_http_upstream_ssl_handshake(c);
  1133. }


  1134. static void
  1135. ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
  1136. {
  1137.     long                  rc;
  1138.     ngx_http_request_t   *r;
  1139.     ngx_http_upstream_t  *u;

  1140.     r = c->data;
  1141.     u = r->upstream;

  1142.     ngx_http_set_log_request(c->log, r);

  1143.     if (c->ssl->handshaked) {

  1144.         if (u->conf->ssl_verify) {
  1145.             rc = SSL_get_verify_result(c->ssl->connection);

  1146.             if (rc != X509_V_OK) {
  1147.                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
  1148.                               "upstream SSL certificate verify error: (%l:%s)",
  1149.                               rc, X509_verify_cert_error_string(rc));
  1150.                 goto failed;
  1151.             }

  1152.             if (ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) {
  1153.                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
  1154.                               "upstream SSL certificate does not match \"%V\"",
  1155.                               &u->ssl_name);
  1156.                 goto failed;
  1157.             }
  1158.         }

  1159.         if (u->conf->ssl_session_reuse) {
  1160.             u->peer.save_session(&u->peer, u->peer.data);
  1161.         }

  1162.         c->write->handler = ngx_http_upstream_handler;
  1163.         c->read->handler = ngx_http_upstream_handler;

  1164.         c = r->connection;

  1165.         ngx_http_upstream_send_request(r, u);

  1166.         ngx_http_run_posted_requests(c);
  1167.         return;
  1168.     }

  1169. failed:

  1170.     c = r->connection;

  1171.     ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);

  1172.     ngx_http_run_posted_requests(c);
  1173. }


  1174. static ngx_int_t
  1175. ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u,
  1176.     ngx_connection_t *c)
  1177. {
  1178.     u_char     *p, *last;
  1179.     ngx_str_t   name;

  1180.     if (u->conf->ssl_name) {
  1181.         if (ngx_http_complex_value(r, u->conf->ssl_name, &name) != NGX_OK) {
  1182.             return NGX_ERROR;
  1183.         }

  1184.     } else {
  1185.         name = u->ssl_name;
  1186.     }

  1187.     if (name.len == 0) {
  1188.         goto done;
  1189.     }

  1190.     /*
  1191.      * ssl name here may contain port, notably if derived from $proxy_host
  1192.      * or $http_host; we have to strip it
  1193.      */

  1194.     p = name.data;
  1195.     last = name.data + name.len;

  1196.     if (*p == '[') {
  1197.         p = ngx_strlchr(p, last, ']');

  1198.         if (p == NULL) {
  1199.             p = name.data;
  1200.         }
  1201.     }

  1202.     p = ngx_strlchr(p, last, ':');

  1203.     if (p != NULL) {
  1204.         name.len = p - name.data;
  1205.     }

  1206.     if (!u->conf->ssl_server_name) {
  1207.         goto done;
  1208.     }

  1209. #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME

  1210.     /* as per RFC 6066, literal IPv4 and IPv6 addresses are not permitted */

  1211.     if (name.len == 0 || *name.data == '[') {
  1212.         goto done;
  1213.     }

  1214.     if (ngx_inet_addr(name.data, name.len) != INADDR_NONE) {
  1215.         goto done;
  1216.     }

  1217.     /*
  1218.      * SSL_set_tlsext_host_name() needs a null-terminated string,
  1219.      * hence we explicitly null-terminate name here
  1220.      */

  1221.     p = ngx_pnalloc(r->pool, name.len + 1);
  1222.     if (p == NULL) {
  1223.         return NGX_ERROR;
  1224.     }

  1225.     (void) ngx_cpystrn(p, name.data, name.len + 1);

  1226.     name.data = p;

  1227.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1228.                    "upstream SSL server name: \"%s\"", name.data);

  1229.     if (SSL_set_tlsext_host_name(c->ssl->connection, name.data) == 0) {
  1230.         ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0,
  1231.                       "SSL_set_tlsext_host_name(\"%s\") failed", name.data);
  1232.         return NGX_ERROR;
  1233.     }

  1234. #endif

  1235. done:

  1236.     u->ssl_name = name;

  1237.     return NGX_OK;
  1238. }

  1239. #endif


  1240. static ngx_int_t
  1241. ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
  1242. {
  1243.     off_t         file_pos;
  1244.     ngx_chain_t  *cl;

  1245.     if (u->reinit_request(r) != NGX_OK) {
  1246.         return NGX_ERROR;
  1247.     }

  1248.     u->keepalive = 0;
  1249.     u->upgrade = 0;

  1250.     ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
  1251.     u->headers_in.content_length_n = -1;
  1252.     u->headers_in.last_modified_time = -1;

  1253.     if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
  1254.                       sizeof(ngx_table_elt_t))
  1255.         != NGX_OK)
  1256.     {
  1257.         return NGX_ERROR;
  1258.     }

  1259.     /* reinit the request chain */

  1260.     file_pos = 0;

  1261.     for (cl = u->request_bufs; cl; cl = cl->next) {
  1262.         cl->buf->pos = cl->buf->start;

  1263.         /* there is at most one file */

  1264.         if (cl->buf->in_file) {
  1265.             cl->buf->file_pos = file_pos;
  1266.             file_pos = cl->buf->file_last;
  1267.         }
  1268.     }

  1269.     /* reinit the subrequest's ngx_output_chain() context */

  1270.     if (r->request_body && r->request_body->temp_file
  1271.         && r != r->main && u->output.buf)
  1272.     {
  1273.         u->output.free = ngx_alloc_chain_link(r->pool);
  1274.         if (u->output.free == NULL) {
  1275.             return NGX_ERROR;
  1276.         }

  1277.         u->output.free->buf = u->output.buf;
  1278.         u->output.free->next = NULL;

  1279.         u->output.buf->pos = u->output.buf->start;
  1280.         u->output.buf->last = u->output.buf->start;
  1281.     }

  1282.     u->output.buf = NULL;
  1283.     u->output.in = NULL;
  1284.     u->output.busy = NULL;

  1285.     /* reinit u->buffer */

  1286.     u->buffer.pos = u->buffer.start;

  1287. #if (NGX_HTTP_CACHE)

  1288.     if (r->cache) {
  1289.         u->buffer.pos += r->cache->header_start;
  1290.     }

  1291. #endif

  1292.     u->buffer.last = u->buffer.pos;

  1293.     return NGX_OK;
  1294. }


  1295. static void
  1296. ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
  1297. {
  1298.     ngx_int_t          rc;
  1299.     ngx_connection_t  *c;

  1300.     c = u->peer.connection;

  1301.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  1302.                    "http upstream send request");

  1303.     if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
  1304.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
  1305.         return;
  1306.     }

  1307.     c->log->action = "sending request to upstream";

  1308.     rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);

  1309.     u->request_sent = 1;

  1310.     if (rc == NGX_ERROR) {
  1311.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
  1312.         return;
  1313.     }

  1314.     if (c->write->timer_set) {
  1315.         ngx_del_timer(c->write);
  1316.     }

  1317.     if (rc == NGX_AGAIN) {
  1318.         ngx_add_timer(c->write, u->conf->send_timeout);

  1319.         if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) {
  1320.             ngx_http_upstream_finalize_request(r, u,
  1321.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1322.             return;
  1323.         }

  1324.         return;
  1325.     }

  1326.     /* rc == NGX_OK */

  1327.     if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
  1328.         if (ngx_tcp_push(c->fd) == NGX_ERROR) {
  1329.             ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
  1330.                           ngx_tcp_push_n " failed");
  1331.             ngx_http_upstream_finalize_request(r, u,
  1332.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1333.             return;
  1334.         }

  1335.         c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
  1336.     }

  1337.     u->write_event_handler = ngx_http_upstream_dummy_handler;

  1338.     if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
  1339.         ngx_http_upstream_finalize_request(r, u,
  1340.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  1341.         return;
  1342.     }

  1343.     ngx_add_timer(c->read, u->conf->read_timeout);

  1344.     if (c->read->ready) {
  1345.         ngx_http_upstream_process_header(r, u);
  1346.         return;
  1347.     }
  1348. }


  1349. static void
  1350. ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
  1351.     ngx_http_upstream_t *u)
  1352. {
  1353.     ngx_connection_t  *c;

  1354.     c = u->peer.connection;

  1355.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1356.                    "http upstream send request handler");

  1357.     if (c->write->timedout) {
  1358.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
  1359.         return;
  1360.     }

  1361. #if (NGX_HTTP_SSL)

  1362.     if (u->ssl && c->ssl == NULL) {
  1363.         ngx_http_upstream_ssl_init_connection(r, u, c);
  1364.         return;
  1365.     }

  1366. #endif

  1367.     if (u->header_sent) {
  1368.         u->write_event_handler = ngx_http_upstream_dummy_handler;

  1369.         (void) ngx_handle_write_event(c->write, 0);

  1370.         return;
  1371.     }

  1372.     ngx_http_upstream_send_request(r, u);
  1373. }


  1374. static void
  1375. ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
  1376. {
  1377.     ssize_t            n;
  1378.     ngx_int_t          rc;
  1379.     ngx_time_t        *tp;
  1380.     ngx_connection_t  *c;

  1381.     c = u->peer.connection;

  1382.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  1383.                    "http upstream process header");

  1384.     c->log->action = "reading response header from upstream";

  1385.     if (c->read->timedout) {
  1386.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
  1387.         return;
  1388.     }

  1389.     if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
  1390.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
  1391.         return;
  1392.     }

  1393.     if (u->buffer.start == NULL) {
  1394.         u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size);
  1395.         if (u->buffer.start == NULL) {
  1396.             ngx_http_upstream_finalize_request(r, u,
  1397.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1398.             return;
  1399.         }

  1400.         u->buffer.pos = u->buffer.start;
  1401.         u->buffer.last = u->buffer.start;
  1402.         u->buffer.end = u->buffer.start + u->conf->buffer_size;
  1403.         u->buffer.temporary = 1;

  1404.         u->buffer.tag = u->output.tag;

  1405.         if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
  1406.                           sizeof(ngx_table_elt_t))
  1407.             != NGX_OK)
  1408.         {
  1409.             ngx_http_upstream_finalize_request(r, u,
  1410.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1411.             return;
  1412.         }

  1413. #if (NGX_HTTP_CACHE)

  1414.         if (r->cache) {
  1415.             u->buffer.pos += r->cache->header_start;
  1416.             u->buffer.last = u->buffer.pos;
  1417.         }
  1418. #endif
  1419.     }

  1420.     for ( ;; ) {

  1421.         n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);

  1422.         if (n == NGX_AGAIN) {
  1423. #if 0
  1424.             ngx_add_timer(rev, u->read_timeout);
  1425. #endif

  1426.             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  1427.                 ngx_http_upstream_finalize_request(r, u,
  1428.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1429.                 return;
  1430.             }

  1431.             return;
  1432.         }

  1433.         if (n == 0) {
  1434.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  1435.                           "upstream prematurely closed connection");
  1436.         }

  1437.         if (n == NGX_ERROR || n == 0) {
  1438.             ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
  1439.             return;
  1440.         }

  1441.         u->buffer.last += n;

  1442. #if 0
  1443.         u->valid_header_in = 0;

  1444.         u->peer.cached = 0;
  1445. #endif

  1446.         rc = u->process_header(r);

  1447.         if (rc == NGX_AGAIN) {

  1448.             if (u->buffer.last == u->buffer.end) {
  1449.                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
  1450.                               "upstream sent too big header");

  1451.                 ngx_http_upstream_next(r, u,
  1452.                                        NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
  1453.                 return;
  1454.             }

  1455.             continue;
  1456.         }

  1457.         break;
  1458.     }

  1459.     if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
  1460.         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
  1461.         return;
  1462.     }

  1463.     if (rc == NGX_ERROR) {
  1464.         ngx_http_upstream_finalize_request(r, u,
  1465.                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
  1466.         return;
  1467.     }

  1468.     /* rc == NGX_OK */

  1469.     tp = ngx_timeofday();
  1470.     u->state->header_sec = tp->sec - u->state->response_sec;
  1471.     u->state->header_msec = tp->msec - u->state->response_msec;

  1472.     if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) {

  1473.         if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
  1474.             return;
  1475.         }

  1476.         if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) {
  1477.             return;
  1478.         }
  1479.     }

  1480.     if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
  1481.         return;
  1482.     }

  1483.     if (!r->subrequest_in_memory) {
  1484.         ngx_http_upstream_send_response(r, u);
  1485.         return;
  1486.     }

  1487.     /* subrequest content in memory */

  1488.     if (u->input_filter == NULL) {
  1489.         u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
  1490.         u->input_filter = ngx_http_upstream_non_buffered_filter;
  1491.         u->input_filter_ctx = r;
  1492.     }

  1493.     if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
  1494.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1495.         return;
  1496.     }

  1497.     n = u->buffer.last - u->buffer.pos;

  1498.     if (n) {
  1499.         u->buffer.last = u->buffer.pos;

  1500.         u->state->response_length += n;

  1501.         if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
  1502.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1503.             return;
  1504.         }
  1505.     }

  1506.     if (u->length == 0) {
  1507.         ngx_http_upstream_finalize_request(r, u, 0);
  1508.         return;
  1509.     }

  1510.     u->read_event_handler = ngx_http_upstream_process_body_in_memory;

  1511.     ngx_http_upstream_process_body_in_memory(r, u);
  1512. }


  1513. static ngx_int_t
  1514. ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
  1515. {
  1516.     ngx_uint_t                 status;
  1517.     ngx_http_upstream_next_t  *un;

  1518.     status = u->headers_in.status_n;

  1519.     for (un = ngx_http_upstream_next_errors; un->status; un++) {

  1520.         if (status != un->status) {
  1521.             continue;
  1522.         }

  1523.         if (u->peer.tries > 1 && (u->conf->next_upstream & un->mask)) {
  1524.             ngx_http_upstream_next(r, u, un->mask);
  1525.             return NGX_OK;
  1526.         }

  1527. #if (NGX_HTTP_CACHE)

  1528.         if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
  1529.             && (u->conf->cache_use_stale & un->mask))
  1530.         {
  1531.             ngx_int_t  rc;

  1532.             rc = u->reinit_request(r);

  1533.             if (rc == NGX_OK) {
  1534.                 u->cache_status = NGX_HTTP_CACHE_STALE;
  1535.                 rc = ngx_http_upstream_cache_send(r, u);
  1536.             }

  1537.             ngx_http_upstream_finalize_request(r, u, rc);
  1538.             return NGX_OK;
  1539.         }

  1540. #endif
  1541.     }

  1542. #if (NGX_HTTP_CACHE)

  1543.     if (status == NGX_HTTP_NOT_MODIFIED
  1544.         && u->cache_status == NGX_HTTP_CACHE_EXPIRED
  1545.         && u->conf->cache_revalidate)
  1546.     {
  1547.         time_t     now, valid;
  1548.         ngx_int_t  rc;

  1549.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1550.                        "http upstream not modified");

  1551.         now = ngx_time();
  1552.         valid = r->cache->valid_sec;

  1553.         rc = u->reinit_request(r);

  1554.         if (rc != NGX_OK) {
  1555.             ngx_http_upstream_finalize_request(r, u, rc);
  1556.             return NGX_OK;
  1557.         }

  1558.         u->cache_status = NGX_HTTP_CACHE_REVALIDATED;
  1559.         rc = ngx_http_upstream_cache_send(r, u);

  1560.         if (valid == 0) {
  1561.             valid = r->cache->valid_sec;
  1562.         }

  1563.         if (valid == 0) {
  1564.             valid = ngx_http_file_cache_valid(u->conf->cache_valid,
  1565.                                               u->headers_in.status_n);
  1566.             if (valid) {
  1567.                 valid = now + valid;
  1568.             }
  1569.         }

  1570.         if (valid) {
  1571.             r->cache->valid_sec = valid;
  1572.             r->cache->date = now;

  1573.             ngx_http_file_cache_update_header(r);
  1574.         }

  1575.         ngx_http_upstream_finalize_request(r, u, rc);
  1576.         return NGX_OK;
  1577.     }

  1578. #endif

  1579.     return NGX_DECLINED;
  1580. }


  1581. static ngx_int_t
  1582. ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
  1583.     ngx_http_upstream_t *u)
  1584. {
  1585.     ngx_int_t                  status;
  1586.     ngx_uint_t                 i;
  1587.     ngx_table_elt_t           *h;
  1588.     ngx_http_err_page_t       *err_page;
  1589.     ngx_http_core_loc_conf_t  *clcf;

  1590.     status = u->headers_in.status_n;

  1591.     if (status == NGX_HTTP_NOT_FOUND && u->conf->intercept_404) {
  1592.         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
  1593.         return NGX_OK;
  1594.     }

  1595.     if (!u->conf->intercept_errors) {
  1596.         return NGX_DECLINED;
  1597.     }

  1598.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  1599.     if (clcf->error_pages == NULL) {
  1600.         return NGX_DECLINED;
  1601.     }

  1602.     err_page = clcf->error_pages->elts;
  1603.     for (i = 0; i < clcf->error_pages->nelts; i++) {

  1604.         if (err_page[i].status == status) {

  1605.             if (status == NGX_HTTP_UNAUTHORIZED
  1606.                 && u->headers_in.www_authenticate)
  1607.             {
  1608.                 h = ngx_list_push(&r->headers_out.headers);

  1609.                 if (h == NULL) {
  1610.                     ngx_http_upstream_finalize_request(r, u,
  1611.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1612.                     return NGX_OK;
  1613.                 }

  1614.                 *h = *u->headers_in.www_authenticate;

  1615.                 r->headers_out.www_authenticate = h;
  1616.             }

  1617. #if (NGX_HTTP_CACHE)

  1618.             if (r->cache) {
  1619.                 time_t  valid;

  1620.                 valid = ngx_http_file_cache_valid(u->conf->cache_valid, status);

  1621.                 if (valid) {
  1622.                     r->cache->valid_sec = ngx_time() + valid;
  1623.                     r->cache->error = status;
  1624.                 }

  1625.                 ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
  1626.             }
  1627. #endif
  1628.             ngx_http_upstream_finalize_request(r, u, status);

  1629.             return NGX_OK;
  1630.         }
  1631.     }

  1632.     return NGX_DECLINED;
  1633. }


  1634. static ngx_int_t
  1635. ngx_http_upstream_test_connect(ngx_connection_t *c)
  1636. {
  1637.     int        err;
  1638.     socklen_t  len;

  1639. #if (NGX_HAVE_KQUEUE)

  1640.     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT)  {
  1641.         if (c->write->pending_eof || c->read->pending_eof) {
  1642.             if (c->write->pending_eof) {
  1643.                 err = c->write->kq_errno;

  1644.             } else {
  1645.                 err = c->read->kq_errno;
  1646.             }

  1647.             c->log->action = "connecting to upstream";
  1648.             (void) ngx_connection_error(c, err,
  1649.                                     "kevent() reported that connect() failed");
  1650.             return NGX_ERROR;
  1651.         }

  1652.     } else
  1653. #endif
  1654.     {
  1655.         err = 0;
  1656.         len = sizeof(int);

  1657.         /*
  1658.          * BSDs and Linux return 0 and set a pending error in err
  1659.          * Solaris returns -1 and sets errno
  1660.          */

  1661.         if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
  1662.             == -1)
  1663.         {
  1664.             err = ngx_socket_errno;
  1665.         }

  1666.         if (err) {
  1667.             c->log->action = "connecting to upstream";
  1668.             (void) ngx_connection_error(c, err, "connect() failed");
  1669.             return NGX_ERROR;
  1670.         }
  1671.     }

  1672.     return NGX_OK;
  1673. }


  1674. static ngx_int_t
  1675. ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
  1676. {
  1677.     ngx_str_t                       uri, args;
  1678.     ngx_uint_t                      i, flags;
  1679.     ngx_list_part_t                *part;
  1680.     ngx_table_elt_t                *h;
  1681.     ngx_http_upstream_header_t     *hh;
  1682.     ngx_http_upstream_main_conf_t  *umcf;

  1683.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1684.     if (u->headers_in.x_accel_redirect
  1685.         && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
  1686.     {
  1687.         ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);

  1688.         part = &u->headers_in.headers.part;
  1689.         h = part->elts;

  1690.         for (i = 0; /* void */; i++) {

  1691.             if (i >= part->nelts) {
  1692.                 if (part->next == NULL) {
  1693.                     break;
  1694.                 }

  1695.                 part = part->next;
  1696.                 h = part->elts;
  1697.                 i = 0;
  1698.             }

  1699.             hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
  1700.                                h[i].lowcase_key, h[i].key.len);

  1701.             if (hh && hh->redirect) {
  1702.                 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
  1703.                     ngx_http_finalize_request(r,
  1704.                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
  1705.                     return NGX_DONE;
  1706.                 }
  1707.             }
  1708.         }

  1709.         uri = u->headers_in.x_accel_redirect->value;

  1710.         if (uri.data[0] == '@') {
  1711.             ngx_http_named_location(r, &uri);

  1712.         } else {
  1713.             ngx_str_null(&args);
  1714.             flags = NGX_HTTP_LOG_UNSAFE;

  1715.             if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
  1716.                 ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
  1717.                 return NGX_DONE;
  1718.             }

  1719.             if (r->method != NGX_HTTP_HEAD) {
  1720.                 r->method = NGX_HTTP_GET;
  1721.             }

  1722.             ngx_http_internal_redirect(r, &uri, &args);
  1723.         }

  1724.         ngx_http_finalize_request(r, NGX_DONE);
  1725.         return NGX_DONE;
  1726.     }

  1727.     part = &u->headers_in.headers.part;
  1728.     h = part->elts;

  1729.     for (i = 0; /* void */; i++) {

  1730.         if (i >= part->nelts) {
  1731.             if (part->next == NULL) {
  1732.                 break;
  1733.             }

  1734.             part = part->next;
  1735.             h = part->elts;
  1736.             i = 0;
  1737.         }

  1738.         if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
  1739.                           h[i].lowcase_key, h[i].key.len))
  1740.         {
  1741.             continue;
  1742.         }

  1743.         hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
  1744.                            h[i].lowcase_key, h[i].key.len);

  1745.         if (hh) {
  1746.             if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
  1747.                 ngx_http_upstream_finalize_request(r, u,
  1748.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1749.                 return NGX_DONE;
  1750.             }

  1751.             continue;
  1752.         }

  1753.         if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
  1754.             ngx_http_upstream_finalize_request(r, u,
  1755.                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
  1756.             return NGX_DONE;
  1757.         }
  1758.     }

  1759.     if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
  1760.         r->headers_out.server->hash = 0;
  1761.     }

  1762.     if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
  1763.         r->headers_out.date->hash = 0;
  1764.     }

  1765.     r->headers_out.status = u->headers_in.status_n;
  1766.     r->headers_out.status_line = u->headers_in.status_line;

  1767.     r->headers_out.content_length_n = u->headers_in.content_length_n;

  1768.     r->disable_not_modified = !u->cacheable;

  1769.     if (u->conf->force_ranges) {
  1770.         r->allow_ranges = 1;
  1771.         r->single_range = 1;

  1772. #if (NGX_HTTP_CACHE)
  1773.         if (r->cached) {
  1774.             r->single_range = 0;
  1775.         }
  1776. #endif
  1777.     }

  1778.     u->length = -1;

  1779.     return NGX_OK;
  1780. }


  1781. static void
  1782. ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
  1783.     ngx_http_upstream_t *u)
  1784. {
  1785.     size_t             size;
  1786.     ssize_t            n;
  1787.     ngx_buf_t         *b;
  1788.     ngx_event_t       *rev;
  1789.     ngx_connection_t  *c;

  1790.     c = u->peer.connection;
  1791.     rev = c->read;

  1792.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  1793.                    "http upstream process body on memory");

  1794.     if (rev->timedout) {
  1795.         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
  1796.         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
  1797.         return;
  1798.     }

  1799.     b = &u->buffer;

  1800.     for ( ;; ) {

  1801.         size = b->end - b->last;

  1802.         if (size == 0) {
  1803.             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  1804.                           "upstream buffer is too small to read response");
  1805.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1806.             return;
  1807.         }

  1808.         n = c->recv(c, b->last, size);

  1809.         if (n == NGX_AGAIN) {
  1810.             break;
  1811.         }

  1812.         if (n == 0 || n == NGX_ERROR) {
  1813.             ngx_http_upstream_finalize_request(r, u, n);
  1814.             return;
  1815.         }

  1816.         u->state->response_length += n;

  1817.         if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
  1818.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1819.             return;
  1820.         }

  1821.         if (!rev->ready) {
  1822.             break;
  1823.         }
  1824.     }

  1825.     if (u->length == 0) {
  1826.         ngx_http_upstream_finalize_request(r, u, 0);
  1827.         return;
  1828.     }

  1829.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  1830.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1831.         return;
  1832.     }

  1833.     if (rev->active) {
  1834.         ngx_add_timer(rev, u->conf->read_timeout);

  1835.     } else if (rev->timer_set) {
  1836.         ngx_del_timer(rev);
  1837.     }
  1838. }


  1839. static void
  1840. ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
  1841. {
  1842.     int                        tcp_nodelay;
  1843.     ssize_t                    n;
  1844.     ngx_int_t                  rc;
  1845.     ngx_event_pipe_t          *p;
  1846.     ngx_connection_t          *c;
  1847.     ngx_http_core_loc_conf_t  *clcf;

  1848.     rc = ngx_http_send_header(r);

  1849.     if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
  1850.         ngx_http_upstream_finalize_request(r, u, rc);
  1851.         return;
  1852.     }

  1853.     u->header_sent = 1;

  1854.     if (u->upgrade) {
  1855.         ngx_http_upstream_upgrade(r, u);
  1856.         return;
  1857.     }

  1858.     c = r->connection;

  1859.     if (r->header_only) {

  1860.         if (!u->buffering) {
  1861.             ngx_http_upstream_finalize_request(r, u, rc);
  1862.             return;
  1863.         }

  1864.         if (!u->cacheable && !u->store) {
  1865.             ngx_http_upstream_finalize_request(r, u, rc);
  1866.             return;
  1867.         }

  1868.         u->pipe->downstream_error = 1;
  1869.     }

  1870.     if (r->request_body && r->request_body->temp_file) {
  1871.         ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd);
  1872.         r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
  1873.     }

  1874.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  1875.     if (!u->buffering) {

  1876.         if (u->input_filter == NULL) {
  1877.             u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
  1878.             u->input_filter = ngx_http_upstream_non_buffered_filter;
  1879.             u->input_filter_ctx = r;
  1880.         }

  1881.         u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;
  1882.         r->write_event_handler =
  1883.                              ngx_http_upstream_process_non_buffered_downstream;

  1884.         r->limit_rate = 0;

  1885.         if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
  1886.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1887.             return;
  1888.         }

  1889.         if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
  1890.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");

  1891.             tcp_nodelay = 1;

  1892.             if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
  1893.                                (const void *) &tcp_nodelay, sizeof(int)) == -1)
  1894.             {
  1895.                 ngx_connection_error(c, ngx_socket_errno,
  1896.                                      "setsockopt(TCP_NODELAY) failed");
  1897.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1898.                 return;
  1899.             }

  1900.             c->tcp_nodelay = NGX_TCP_NODELAY_SET;
  1901.         }

  1902.         n = u->buffer.last - u->buffer.pos;

  1903.         if (n) {
  1904.             u->buffer.last = u->buffer.pos;

  1905.             u->state->response_length += n;

  1906.             if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
  1907.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1908.                 return;
  1909.             }

  1910.             ngx_http_upstream_process_non_buffered_downstream(r);

  1911.         } else {
  1912.             u->buffer.pos = u->buffer.start;
  1913.             u->buffer.last = u->buffer.start;

  1914.             if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
  1915.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1916.                 return;
  1917.             }

  1918.             if (u->peer.connection->read->ready || u->length == 0) {
  1919.                 ngx_http_upstream_process_non_buffered_upstream(r, u);
  1920.             }
  1921.         }

  1922.         return;
  1923.     }

  1924.     /* TODO: preallocate event_pipe bufs, look "Content-Length" */

  1925. #if (NGX_HTTP_CACHE)

  1926.     if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) {
  1927.         ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd);
  1928.         r->cache->file.fd = NGX_INVALID_FILE;
  1929.     }

  1930.     switch (ngx_http_test_predicates(r, u->conf->no_cache)) {

  1931.     case NGX_ERROR:
  1932.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1933.         return;

  1934.     case NGX_DECLINED:
  1935.         u->cacheable = 0;
  1936.         break;

  1937.     default: /* NGX_OK */

  1938.         if (u->cache_status == NGX_HTTP_CACHE_BYPASS) {

  1939.             /* create cache if previously bypassed */

  1940.             if (ngx_http_file_cache_create(r) != NGX_OK) {
  1941.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1942.                 return;
  1943.             }
  1944.         }

  1945.         break;
  1946.     }

  1947.     if (u->cacheable) {
  1948.         time_t  now, valid;

  1949.         now = ngx_time();

  1950.         valid = r->cache->valid_sec;

  1951.         if (valid == 0) {
  1952.             valid = ngx_http_file_cache_valid(u->conf->cache_valid,
  1953.                                               u->headers_in.status_n);
  1954.             if (valid) {
  1955.                 r->cache->valid_sec = now + valid;
  1956.             }
  1957.         }

  1958.         if (valid) {
  1959.             r->cache->date = now;
  1960.             r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);

  1961.             if (u->headers_in.status_n == NGX_HTTP_OK
  1962.                 || u->headers_in.status_n == NGX_HTTP_PARTIAL_CONTENT)
  1963.             {
  1964.                 r->cache->last_modified = u->headers_in.last_modified_time;

  1965.                 if (u->headers_in.etag) {
  1966.                     r->cache->etag = u->headers_in.etag->value;
  1967.                 }
  1968.             }

  1969.             if (ngx_http_file_cache_set_header(r, u->buffer.start) != NGX_OK) {
  1970.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1971.                 return;
  1972.             }

  1973.         } else {
  1974.             u->cacheable = 0;
  1975.         }
  1976.     }

  1977.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  1978.                    "http cacheable: %d", u->cacheable);

  1979.     if (u->cacheable == 0 && r->cache) {
  1980.         ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
  1981.     }

  1982. #endif

  1983.     p = u->pipe;

  1984.     p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter;
  1985.     p->output_ctx = r;
  1986.     p->tag = u->output.tag;
  1987.     p->bufs = u->conf->bufs;
  1988.     p->busy_size = u->conf->busy_buffers_size;
  1989.     p->upstream = u->peer.connection;
  1990.     p->downstream = c;
  1991.     p->pool = r->pool;
  1992.     p->log = c->log;
  1993.     p->limit_rate = u->conf->limit_rate;
  1994.     p->start_sec = ngx_time();

  1995.     p->cacheable = u->cacheable || u->store;

  1996.     p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
  1997.     if (p->temp_file == NULL) {
  1998.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  1999.         return;
  2000.     }

  2001.     p->temp_file->file.fd = NGX_INVALID_FILE;
  2002.     p->temp_file->file.log = c->log;
  2003.     p->temp_file->path = u->conf->temp_path;
  2004.     p->temp_file->pool = r->pool;

  2005.     if (p->cacheable) {
  2006.         p->temp_file->persistent = 1;

  2007. #if (NGX_HTTP_CACHE)
  2008.         if (r->cache && r->cache->file_cache->temp_path) {
  2009.             p->temp_file->path = r->cache->file_cache->temp_path;
  2010.         }
  2011. #endif

  2012.     } else {
  2013.         p->temp_file->log_level = NGX_LOG_WARN;
  2014.         p->temp_file->warn = "an upstream response is buffered "
  2015.                              "to a temporary file";
  2016.     }

  2017.     p->max_temp_file_size = u->conf->max_temp_file_size;
  2018.     p->temp_file_write_size = u->conf->temp_file_write_size;

  2019.     p->preread_bufs = ngx_alloc_chain_link(r->pool);
  2020.     if (p->preread_bufs == NULL) {
  2021.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2022.         return;
  2023.     }

  2024.     p->preread_bufs->buf = &u->buffer;
  2025.     p->preread_bufs->next = NULL;
  2026.     u->buffer.recycled = 1;

  2027.     p->preread_size = u->buffer.last - u->buffer.pos;

  2028.     if (u->cacheable) {

  2029.         p->buf_to_file = ngx_calloc_buf(r->pool);
  2030.         if (p->buf_to_file == NULL) {
  2031.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2032.             return;
  2033.         }

  2034.         p->buf_to_file->start = u->buffer.start;
  2035.         p->buf_to_file->pos = u->buffer.start;
  2036.         p->buf_to_file->last = u->buffer.pos;
  2037.         p->buf_to_file->temporary = 1;
  2038.     }

  2039.     if (ngx_event_flags & NGX_USE_AIO_EVENT) {
  2040.         /* the posted aio operation may corrupt a shadow buffer */
  2041.         p->single_buf = 1;
  2042.     }

  2043.     /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
  2044.     p->free_bufs = 1;

  2045.     /*
  2046.      * event_pipe would do u->buffer.last += p->preread_size
  2047.      * as though these bytes were read
  2048.      */
  2049.     u->buffer.last = u->buffer.pos;

  2050.     if (u->conf->cyclic_temp_file) {

  2051.         /*
  2052.          * we need to disable the use of sendfile() if we use cyclic temp file
  2053.          * because the writing a new data may interfere with sendfile()
  2054.          * that uses the same kernel file pages (at least on FreeBSD)
  2055.          */

  2056.         p->cyclic_temp_file = 1;
  2057.         c->sendfile = 0;

  2058.     } else {
  2059.         p->cyclic_temp_file = 0;
  2060.     }

  2061.     p->read_timeout = u->conf->read_timeout;
  2062.     p->send_timeout = clcf->send_timeout;
  2063.     p->send_lowat = clcf->send_lowat;

  2064.     p->length = -1;

  2065.     if (u->input_filter_init
  2066.         && u->input_filter_init(p->input_ctx) != NGX_OK)
  2067.     {
  2068.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2069.         return;
  2070.     }

  2071.     u->read_event_handler = ngx_http_upstream_process_upstream;
  2072.     r->write_event_handler = ngx_http_upstream_process_downstream;

  2073.     ngx_http_upstream_process_upstream(r, u);
  2074. }


  2075. static void
  2076. ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u)
  2077. {
  2078.     int                        tcp_nodelay;
  2079.     ngx_connection_t          *c;
  2080.     ngx_http_core_loc_conf_t  *clcf;

  2081.     c = r->connection;
  2082.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  2083.     /* TODO: prevent upgrade if not requested or not possible */

  2084.     r->keepalive = 0;
  2085.     c->log->action = "proxying upgraded connection";

  2086.     u->read_event_handler = ngx_http_upstream_upgraded_read_upstream;
  2087.     u->write_event_handler = ngx_http_upstream_upgraded_write_upstream;
  2088.     r->read_event_handler = ngx_http_upstream_upgraded_read_downstream;
  2089.     r->write_event_handler = ngx_http_upstream_upgraded_write_downstream;

  2090.     if (clcf->tcp_nodelay) {
  2091.         tcp_nodelay = 1;

  2092.         if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
  2093.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");

  2094.             if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
  2095.                            (const void *) &tcp_nodelay, sizeof(int)) == -1)
  2096.             {
  2097.                 ngx_connection_error(c, ngx_socket_errno,
  2098.                                      "setsockopt(TCP_NODELAY) failed");
  2099.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2100.                 return;
  2101.             }

  2102.             c->tcp_nodelay = NGX_TCP_NODELAY_SET;
  2103.         }

  2104.         if (u->peer.connection->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
  2105.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->peer.connection->log, 0,
  2106.                            "tcp_nodelay");

  2107.             if (setsockopt(u->peer.connection->fd, IPPROTO_TCP, TCP_NODELAY,
  2108.                            (const void *) &tcp_nodelay, sizeof(int)) == -1)
  2109.             {
  2110.                 ngx_connection_error(u->peer.connection, ngx_socket_errno,
  2111.                                      "setsockopt(TCP_NODELAY) failed");
  2112.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2113.                 return;
  2114.             }

  2115.             u->peer.connection->tcp_nodelay = NGX_TCP_NODELAY_SET;
  2116.         }
  2117.     }

  2118.     if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
  2119.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2120.         return;
  2121.     }

  2122.     if (u->peer.connection->read->ready
  2123.         || u->buffer.pos != u->buffer.last)
  2124.     {
  2125.         ngx_post_event(c->read, &ngx_posted_events);
  2126.         ngx_http_upstream_process_upgraded(r, 1, 1);
  2127.         return;
  2128.     }

  2129.     ngx_http_upstream_process_upgraded(r, 0, 1);
  2130. }


  2131. static void
  2132. ngx_http_upstream_upgraded_read_downstream(ngx_http_request_t *r)
  2133. {
  2134.     ngx_http_upstream_process_upgraded(r, 0, 0);
  2135. }


  2136. static void
  2137. ngx_http_upstream_upgraded_write_downstream(ngx_http_request_t *r)
  2138. {
  2139.     ngx_http_upstream_process_upgraded(r, 1, 1);
  2140. }


  2141. static void
  2142. ngx_http_upstream_upgraded_read_upstream(ngx_http_request_t *r,
  2143.     ngx_http_upstream_t *u)
  2144. {
  2145.     ngx_http_upstream_process_upgraded(r, 1, 0);
  2146. }


  2147. static void
  2148. ngx_http_upstream_upgraded_write_upstream(ngx_http_request_t *r,
  2149.     ngx_http_upstream_t *u)
  2150. {
  2151.     ngx_http_upstream_process_upgraded(r, 0, 1);
  2152. }


  2153. static void
  2154. ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
  2155.     ngx_uint_t from_upstream, ngx_uint_t do_write)
  2156. {
  2157.     size_t                     size;
  2158.     ssize_t                    n;
  2159.     ngx_buf_t                 *b;
  2160.     ngx_connection_t          *c, *downstream, *upstream, *dst, *src;
  2161.     ngx_http_upstream_t       *u;
  2162.     ngx_http_core_loc_conf_t  *clcf;

  2163.     c = r->connection;
  2164.     u = r->upstream;

  2165.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  2166.                    "http upstream process upgraded, fu:%ui", from_upstream);

  2167.     downstream = c;
  2168.     upstream = u->peer.connection;

  2169.     if (downstream->write->timedout) {
  2170.         c->timedout = 1;
  2171.         ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
  2172.         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT);
  2173.         return;
  2174.     }

  2175.     if (upstream->read->timedout || upstream->write->timedout) {
  2176.         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
  2177.         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
  2178.         return;
  2179.     }

  2180.     if (from_upstream) {
  2181.         src = upstream;
  2182.         dst = downstream;
  2183.         b = &u->buffer;

  2184.     } else {
  2185.         src = downstream;
  2186.         dst = upstream;
  2187.         b = &u->from_client;

  2188.         if (r->header_in->last > r->header_in->pos) {
  2189.             b = r->header_in;
  2190.             b->end = b->last;
  2191.             do_write = 1;
  2192.         }

  2193.         if (b->start == NULL) {
  2194.             b->start = ngx_palloc(r->pool, u->conf->buffer_size);
  2195.             if (b->start == NULL) {
  2196.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2197.                 return;
  2198.             }

  2199.             b->pos = b->start;
  2200.             b->last = b->start;
  2201.             b->end = b->start + u->conf->buffer_size;
  2202.             b->temporary = 1;
  2203.             b->tag = u->output.tag;
  2204.         }
  2205.     }

  2206.     for ( ;; ) {

  2207.         if (do_write) {

  2208.             size = b->last - b->pos;

  2209.             if (size && dst->write->ready) {

  2210.                 n = dst->send(dst, b->pos, size);

  2211.                 if (n == NGX_ERROR) {
  2212.                     ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2213.                     return;
  2214.                 }

  2215.                 if (n > 0) {
  2216.                     b->pos += n;

  2217.                     if (b->pos == b->last) {
  2218.                         b->pos = b->start;
  2219.                         b->last = b->start;
  2220.                     }
  2221.                 }
  2222.             }
  2223.         }

  2224.         size = b->end - b->last;

  2225.         if (size && src->read->ready) {

  2226.             n = src->recv(src, b->last, size);

  2227.             if (n == NGX_AGAIN || n == 0) {
  2228.                 break;
  2229.             }

  2230.             if (n > 0) {
  2231.                 do_write = 1;
  2232.                 b->last += n;

  2233.                 continue;
  2234.             }

  2235.             if (n == NGX_ERROR) {
  2236.                 src->read->eof = 1;
  2237.             }
  2238.         }

  2239.         break;
  2240.     }

  2241.     if ((upstream->read->eof && u->buffer.pos == u->buffer.last)
  2242.         || (downstream->read->eof && u->from_client.pos == u->from_client.last)
  2243.         || (downstream->read->eof && upstream->read->eof))
  2244.     {
  2245.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  2246.                        "http upstream upgraded done");
  2247.         ngx_http_upstream_finalize_request(r, u, 0);
  2248.         return;
  2249.     }

  2250.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  2251.     if (ngx_handle_write_event(upstream->write, u->conf->send_lowat)
  2252.         != NGX_OK)
  2253.     {
  2254.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2255.         return;
  2256.     }

  2257.     if (upstream->write->active && !upstream->write->ready) {
  2258.         ngx_add_timer(upstream->write, u->conf->send_timeout);

  2259.     } else if (upstream->write->timer_set) {
  2260.         ngx_del_timer(upstream->write);
  2261.     }

  2262.     if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
  2263.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2264.         return;
  2265.     }

  2266.     if (upstream->read->active && !upstream->read->ready) {
  2267.         ngx_add_timer(upstream->read, u->conf->read_timeout);

  2268.     } else if (upstream->read->timer_set) {
  2269.         ngx_del_timer(upstream->read);
  2270.     }

  2271.     if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
  2272.         != NGX_OK)
  2273.     {
  2274.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2275.         return;
  2276.     }

  2277.     if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) {
  2278.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2279.         return;
  2280.     }

  2281.     if (downstream->write->active && !downstream->write->ready) {
  2282.         ngx_add_timer(downstream->write, clcf->send_timeout);

  2283.     } else if (downstream->write->timer_set) {
  2284.         ngx_del_timer(downstream->write);
  2285.     }
  2286. }


  2287. static void
  2288. ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r)
  2289. {
  2290.     ngx_event_t          *wev;
  2291.     ngx_connection_t     *c;
  2292.     ngx_http_upstream_t  *u;

  2293.     c = r->connection;
  2294.     u = r->upstream;
  2295.     wev = c->write;

  2296.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  2297.                    "http upstream process non buffered downstream");

  2298.     c->log->action = "sending to client";

  2299.     if (wev->timedout) {
  2300.         c->timedout = 1;
  2301.         ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
  2302.         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT);
  2303.         return;
  2304.     }

  2305.     ngx_http_upstream_process_non_buffered_request(r, 1);
  2306. }


  2307. static void
  2308. ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
  2309.     ngx_http_upstream_t *u)
  2310. {
  2311.     ngx_connection_t  *c;

  2312.     c = u->peer.connection;

  2313.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  2314.                    "http upstream process non buffered upstream");

  2315.     c->log->action = "reading upstream";

  2316.     if (c->read->timedout) {
  2317.         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
  2318.         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
  2319.         return;
  2320.     }

  2321.     ngx_http_upstream_process_non_buffered_request(r, 0);
  2322. }


  2323. static void
  2324. ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
  2325.     ngx_uint_t do_write)
  2326. {
  2327.     size_t                     size;
  2328.     ssize_t                    n;
  2329.     ngx_buf_t                 *b;
  2330.     ngx_int_t                  rc;
  2331.     ngx_connection_t          *downstream, *upstream;
  2332.     ngx_http_upstream_t       *u;
  2333.     ngx_http_core_loc_conf_t  *clcf;

  2334.     u = r->upstream;
  2335.     downstream = r->connection;
  2336.     upstream = u->peer.connection;

  2337.     b = &u->buffer;

  2338.     do_write = do_write || u->length == 0;

  2339.     for ( ;; ) {

  2340.         if (do_write) {

  2341.             if (u->out_bufs || u->busy_bufs) {
  2342.                 rc = ngx_http_output_filter(r, u->out_bufs);

  2343.                 if (rc == NGX_ERROR) {
  2344.                     ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2345.                     return;
  2346.                 }

  2347.                 ngx_chain_update_chains(r->pool, &u->free_bufs, &u->busy_bufs,
  2348.                                         &u->out_bufs, u->output.tag);
  2349.             }

  2350.             if (u->busy_bufs == NULL) {

  2351.                 if (u->length == 0
  2352.                     || (upstream->read->eof && u->length == -1))
  2353.                 {
  2354.                     ngx_http_upstream_finalize_request(r, u, 0);
  2355.                     return;
  2356.                 }

  2357.                 if (upstream->read->eof) {
  2358.                     ngx_log_error(NGX_LOG_ERR, upstream->log, 0,
  2359.                                   "upstream prematurely closed connection");

  2360.                     ngx_http_upstream_finalize_request(r, u,
  2361.                                                        NGX_HTTP_BAD_GATEWAY);
  2362.                     return;
  2363.                 }

  2364.                 if (upstream->read->error) {
  2365.                     ngx_http_upstream_finalize_request(r, u,
  2366.                                                        NGX_HTTP_BAD_GATEWAY);
  2367.                     return;
  2368.                 }

  2369.                 b->pos = b->start;
  2370.                 b->last = b->start;
  2371.             }
  2372.         }

  2373.         size = b->end - b->last;

  2374.         if (size && upstream->read->ready) {

  2375.             n = upstream->recv(upstream, b->last, size);

  2376.             if (n == NGX_AGAIN) {
  2377.                 break;
  2378.             }

  2379.             if (n > 0) {
  2380.                 u->state->response_length += n;

  2381.                 if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
  2382.                     ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2383.                     return;
  2384.                 }
  2385.             }

  2386.             do_write = 1;

  2387.             continue;
  2388.         }

  2389.         break;
  2390.     }

  2391.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  2392.     if (downstream->data == r) {
  2393.         if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
  2394.             != NGX_OK)
  2395.         {
  2396.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2397.             return;
  2398.         }
  2399.     }

  2400.     if (downstream->write->active && !downstream->write->ready) {
  2401.         ngx_add_timer(downstream->write, clcf->send_timeout);

  2402.     } else if (downstream->write->timer_set) {
  2403.         ngx_del_timer(downstream->write);
  2404.     }

  2405.     if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
  2406.         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2407.         return;
  2408.     }

  2409.     if (upstream->read->active && !upstream->read->ready) {
  2410.         ngx_add_timer(upstream->read, u->conf->read_timeout);

  2411.     } else if (upstream->read->timer_set) {
  2412.         ngx_del_timer(upstream->read);
  2413.     }
  2414. }


  2415. static ngx_int_t
  2416. ngx_http_upstream_non_buffered_filter_init(void *data)
  2417. {
  2418.     return NGX_OK;
  2419. }


  2420. static ngx_int_t
  2421. ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
  2422. {
  2423.     ngx_http_request_t  *r = data;

  2424.     ngx_buf_t            *b;
  2425.     ngx_chain_t          *cl, **ll;
  2426.     ngx_http_upstream_t  *u;

  2427.     u = r->upstream;

  2428.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  2429.         ll = &cl->next;
  2430.     }

  2431.     cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  2432.     if (cl == NULL) {
  2433.         return NGX_ERROR;
  2434.     }

  2435.     *ll = cl;

  2436.     cl->buf->flush = 1;
  2437.     cl->buf->memory = 1;

  2438.     b = &u->buffer;

  2439.     cl->buf->pos = b->last;
  2440.     b->last += bytes;
  2441.     cl->buf->last = b->last;
  2442.     cl->buf->tag = u->output.tag;

  2443.     if (u->length == -1) {
  2444.         return NGX_OK;
  2445.     }

  2446.     u->length -= bytes;

  2447.     return NGX_OK;
  2448. }


  2449. static void
  2450. ngx_http_upstream_process_downstream(ngx_http_request_t *r)
  2451. {
  2452.     ngx_event_t          *wev;
  2453.     ngx_connection_t     *c;
  2454.     ngx_event_pipe_t     *p;
  2455.     ngx_http_upstream_t  *u;

  2456.     c = r->connection;
  2457.     u = r->upstream;
  2458.     p = u->pipe;
  2459.     wev = c->write;

  2460.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  2461.                    "http upstream process downstream");

  2462.     c->log->action = "sending to client";

  2463.     if (wev->timedout) {

  2464.         if (wev->delayed) {

  2465.             wev->timedout = 0;
  2466.             wev->delayed = 0;

  2467.             if (!wev->ready) {
  2468.                 ngx_add_timer(wev, p->send_timeout);

  2469.                 if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
  2470.                     ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2471.                 }

  2472.                 return;
  2473.             }

  2474.             if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
  2475.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2476.                 return;
  2477.             }

  2478.         } else {
  2479.             p->downstream_error = 1;
  2480.             c->timedout = 1;
  2481.             ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
  2482.         }

  2483.     } else {

  2484.         if (wev->delayed) {

  2485.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  2486.                            "http downstream delayed");

  2487.             if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
  2488.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2489.             }

  2490.             return;
  2491.         }

  2492.         if (ngx_event_pipe(p, 1) == NGX_ABORT) {
  2493.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2494.             return;
  2495.         }
  2496.     }

  2497.     ngx_http_upstream_process_request(r);
  2498. }


  2499. static void
  2500. ngx_http_upstream_process_upstream(ngx_http_request_t *r,
  2501.     ngx_http_upstream_t *u)
  2502. {
  2503.     ngx_event_t       *rev;
  2504.     ngx_event_pipe_t  *p;
  2505.     ngx_connection_t  *c;

  2506.     c = u->peer.connection;
  2507.     p = u->pipe;
  2508.     rev = c->read;

  2509.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  2510.                    "http upstream process upstream");

  2511.     c->log->action = "reading upstream";

  2512.     if (rev->timedout) {

  2513.         if (rev->delayed) {

  2514.             rev->timedout = 0;
  2515.             rev->delayed = 0;

  2516.             if (!rev->ready) {
  2517.                 ngx_add_timer(rev, p->read_timeout);

  2518.                 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  2519.                     ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2520.                 }

  2521.                 return;
  2522.             }

  2523.             if (ngx_event_pipe(p, 0) == NGX_ABORT) {
  2524.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2525.                 return;
  2526.             }

  2527.         } else {
  2528.             p->upstream_error = 1;
  2529.             ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
  2530.         }

  2531.     } else {

  2532.         if (rev->delayed) {

  2533.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  2534.                            "http upstream delayed");

  2535.             if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  2536.                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2537.             }

  2538.             return;
  2539.         }

  2540.         if (ngx_event_pipe(p, 0) == NGX_ABORT) {
  2541.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2542.             return;
  2543.         }
  2544.     }

  2545.     ngx_http_upstream_process_request(r);
  2546. }


  2547. static void
  2548. ngx_http_upstream_process_request(ngx_http_request_t *r)
  2549. {
  2550.     ngx_temp_file_t      *tf;
  2551.     ngx_event_pipe_t     *p;
  2552.     ngx_http_upstream_t  *u;

  2553.     u = r->upstream;
  2554.     p = u->pipe;

  2555.     if (u->peer.connection) {

  2556.         if (u->store) {

  2557.             if (p->upstream_eof || p->upstream_done) {

  2558.                 tf = p->temp_file;

  2559.                 if (u->headers_in.status_n == NGX_HTTP_OK
  2560.                     && (p->upstream_done || p->length == -1)
  2561.                     && (u->headers_in.content_length_n == -1
  2562.                         || u->headers_in.content_length_n == tf->offset))
  2563.                 {
  2564.                     ngx_http_upstream_store(r, u);
  2565.                 }
  2566.             }
  2567.         }

  2568. #if (NGX_HTTP_CACHE)

  2569.         if (u->cacheable) {

  2570.             if (p->upstream_done) {
  2571.                 ngx_http_file_cache_update(r, p->temp_file);

  2572.             } else if (p->upstream_eof) {

  2573.                 tf = p->temp_file;

  2574.                 if (p->length == -1
  2575.                     && (u->headers_in.content_length_n == -1
  2576.                         || u->headers_in.content_length_n
  2577.                            == tf->offset - (off_t) r->cache->body_start))
  2578.                 {
  2579.                     ngx_http_file_cache_update(r, tf);

  2580.                 } else {
  2581.                     ngx_http_file_cache_free(r->cache, tf);
  2582.                 }

  2583.             } else if (p->upstream_error) {
  2584.                 ngx_http_file_cache_free(r->cache, p->temp_file);
  2585.             }
  2586.         }

  2587. #endif

  2588.         if (p->upstream_done || p->upstream_eof || p->upstream_error) {
  2589.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2590.                            "http upstream exit: %p", p->out);

  2591.             if (p->upstream_done
  2592.                 || (p->upstream_eof && p->length == -1))
  2593.             {
  2594.                 ngx_http_upstream_finalize_request(r, u, 0);
  2595.                 return;
  2596.             }

  2597.             if (p->upstream_eof) {
  2598.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2599.                               "upstream prematurely closed connection");
  2600.             }

  2601.             ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
  2602.             return;
  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.         if (!u->cacheable && !u->store && u->peer.connection) {
  2609.             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
  2610.         }
  2611.     }
  2612. }


  2613. static void
  2614. ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
  2615. {
  2616.     size_t                  root;
  2617.     time_t                  lm;
  2618.     ngx_str_t               path;
  2619.     ngx_temp_file_t        *tf;
  2620.     ngx_ext_rename_file_t   ext;

  2621.     tf = u->pipe->temp_file;

  2622.     if (tf->file.fd == NGX_INVALID_FILE) {

  2623.         /* create file for empty 200 response */

  2624.         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
  2625.         if (tf == NULL) {
  2626.             return;
  2627.         }

  2628.         tf->file.fd = NGX_INVALID_FILE;
  2629.         tf->file.log = r->connection->log;
  2630.         tf->path = u->conf->temp_path;
  2631.         tf->pool = r->pool;
  2632.         tf->persistent = 1;

  2633.         if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
  2634.                                  tf->persistent, tf->clean, tf->access)
  2635.             != NGX_OK)
  2636.         {
  2637.             return;
  2638.         }

  2639.         u->pipe->temp_file = tf;
  2640.     }

  2641.     ext.access = u->conf->store_access;
  2642.     ext.path_access = u->conf->store_access;
  2643.     ext.time = -1;
  2644.     ext.create_path = 1;
  2645.     ext.delete_file = 1;
  2646.     ext.log = r->connection->log;

  2647.     if (u->headers_in.last_modified) {

  2648.         lm = ngx_http_parse_time(u->headers_in.last_modified->value.data,
  2649.                                  u->headers_in.last_modified->value.len);

  2650.         if (lm != NGX_ERROR) {
  2651.             ext.time = lm;
  2652.             ext.fd = tf->file.fd;
  2653.         }
  2654.     }

  2655.     if (u->conf->store_lengths == NULL) {

  2656.         if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
  2657.             return;
  2658.         }

  2659.     } else {
  2660.         if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0,
  2661.                                 u->conf->store_values->elts)
  2662.             == NULL)
  2663.         {
  2664.             return;
  2665.         }
  2666.     }

  2667.     path.len--;

  2668.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2669.                    "upstream stores \"%s\" to \"%s\"",
  2670.                    tf->file.name.data, path.data);

  2671.     (void) ngx_ext_rename_file(&tf->file.name, &path, &ext);

  2672.     u->store = 0;
  2673. }


  2674. static void
  2675. ngx_http_upstream_dummy_handler(ngx_http_request_t *r, ngx_http_upstream_t *u)
  2676. {
  2677.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2678.                    "http upstream dummy handler");
  2679. }


  2680. static void
  2681. ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
  2682.     ngx_uint_t ft_type)
  2683. {
  2684.     ngx_msec_t  timeout;
  2685.     ngx_uint_t  status, state;

  2686.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2687.                    "http next upstream, %xi", ft_type);

  2688.     if (u->peer.sockaddr) {

  2689.         if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403
  2690.             || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404)
  2691.         {
  2692.             state = NGX_PEER_NEXT;

  2693.         } else {
  2694.             state = NGX_PEER_FAILED;
  2695.         }

  2696.         u->peer.free(&u->peer, u->peer.data, state);
  2697.         u->peer.sockaddr = NULL;
  2698.     }

  2699.     if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
  2700.         ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
  2701.                       "upstream timed out");
  2702.     }

  2703.     if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
  2704.         status = 0;

  2705.         /* TODO: inform balancer instead */

  2706.         u->peer.tries++;

  2707.     } else {
  2708.         switch (ft_type) {

  2709.         case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
  2710.             status = NGX_HTTP_GATEWAY_TIME_OUT;
  2711.             break;

  2712.         case NGX_HTTP_UPSTREAM_FT_HTTP_500:
  2713.             status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  2714.             break;

  2715.         case NGX_HTTP_UPSTREAM_FT_HTTP_403:
  2716.             status = NGX_HTTP_FORBIDDEN;
  2717.             break;

  2718.         case NGX_HTTP_UPSTREAM_FT_HTTP_404:
  2719.             status = NGX_HTTP_NOT_FOUND;
  2720.             break;

  2721.         /*
  2722.          * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
  2723.          * never reach here
  2724.          */

  2725.         default:
  2726.             status = NGX_HTTP_BAD_GATEWAY;
  2727.         }
  2728.     }

  2729.     if (r->connection->error) {
  2730.         ngx_http_upstream_finalize_request(r, u,
  2731.                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
  2732.         return;
  2733.     }

  2734.     if (status) {
  2735.         u->state->status = status;
  2736.         timeout = u->conf->next_upstream_timeout;

  2737.         if (u->peer.tries == 0
  2738.             || !(u->conf->next_upstream & ft_type)
  2739.             || (timeout && ngx_current_msec - u->peer.start_time >= timeout))
  2740.         {
  2741. #if (NGX_HTTP_CACHE)

  2742.             if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
  2743.                 && (u->conf->cache_use_stale & ft_type))
  2744.             {
  2745.                 ngx_int_t  rc;

  2746.                 rc = u->reinit_request(r);

  2747.                 if (rc == NGX_OK) {
  2748.                     u->cache_status = NGX_HTTP_CACHE_STALE;
  2749.                     rc = ngx_http_upstream_cache_send(r, u);
  2750.                 }

  2751.                 ngx_http_upstream_finalize_request(r, u, rc);
  2752.                 return;
  2753.             }
  2754. #endif

  2755.             ngx_http_upstream_finalize_request(r, u, status);
  2756.             return;
  2757.         }
  2758.     }

  2759.     if (u->peer.connection) {
  2760.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2761.                        "close http upstream connection: %d",
  2762.                        u->peer.connection->fd);
  2763. #if (NGX_HTTP_SSL)

  2764.         if (u->peer.connection->ssl) {
  2765.             u->peer.connection->ssl->no_wait_shutdown = 1;
  2766.             u->peer.connection->ssl->no_send_shutdown = 1;

  2767.             (void) ngx_ssl_shutdown(u->peer.connection);
  2768.         }
  2769. #endif

  2770.         if (u->peer.connection->pool) {
  2771.             ngx_destroy_pool(u->peer.connection->pool);
  2772.         }

  2773.         ngx_close_connection(u->peer.connection);
  2774.         u->peer.connection = NULL;
  2775.     }

  2776.     ngx_http_upstream_connect(r, u);
  2777. }


  2778. static void
  2779. ngx_http_upstream_cleanup(void *data)
  2780. {
  2781.     ngx_http_request_t *r = data;

  2782.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2783.                    "cleanup http upstream request: \"%V\"", &r->uri);

  2784.     ngx_http_upstream_finalize_request(r, r->upstream, NGX_DONE);
  2785. }


  2786. static void
  2787. ngx_http_upstream_finalize_request(ngx_http_request_t *r,
  2788.     ngx_http_upstream_t *u, ngx_int_t rc)
  2789. {
  2790.     ngx_uint_t   flush;
  2791.     ngx_time_t  *tp;

  2792.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2793.                    "finalize http upstream request: %i", rc);

  2794.     if (u->cleanup) {
  2795.         *u->cleanup = NULL;
  2796.         u->cleanup = NULL;
  2797.     }

  2798.     if (u->resolved && u->resolved->ctx) {
  2799.         ngx_resolve_name_done(u->resolved->ctx);
  2800.         u->resolved->ctx = NULL;
  2801.     }

  2802.     if (u->state && u->state->response_sec) {
  2803.         tp = ngx_timeofday();
  2804.         u->state->response_sec = tp->sec - u->state->response_sec;
  2805.         u->state->response_msec = tp->msec - u->state->response_msec;

  2806.         if (u->pipe && u->pipe->read_length) {
  2807.             u->state->response_length = u->pipe->read_length;
  2808.         }
  2809.     }

  2810.     u->finalize_request(r, rc);

  2811.     if (u->peer.free && u->peer.sockaddr) {
  2812.         u->peer.free(&u->peer, u->peer.data, 0);
  2813.         u->peer.sockaddr = NULL;
  2814.     }

  2815.     if (u->peer.connection) {

  2816. #if (NGX_HTTP_SSL)

  2817.         /* TODO: do not shutdown persistent connection */

  2818.         if (u->peer.connection->ssl) {

  2819.             /*
  2820.              * We send the "close notify" shutdown alert to the upstream only
  2821.              * and do not wait its "close notify" shutdown alert.
  2822.              * It is acceptable according to the TLS standard.
  2823.              */

  2824.             u->peer.connection->ssl->no_wait_shutdown = 1;

  2825.             (void) ngx_ssl_shutdown(u->peer.connection);
  2826.         }
  2827. #endif

  2828.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2829.                        "close http upstream connection: %d",
  2830.                        u->peer.connection->fd);

  2831.         if (u->peer.connection->pool) {
  2832.             ngx_destroy_pool(u->peer.connection->pool);
  2833.         }

  2834.         ngx_close_connection(u->peer.connection);
  2835.     }

  2836.     u->peer.connection = NULL;

  2837.     if (u->pipe && u->pipe->temp_file) {
  2838.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2839.                        "http upstream temp fd: %d",
  2840.                        u->pipe->temp_file->file.fd);
  2841.     }

  2842.     if (u->store && u->pipe && u->pipe->temp_file
  2843.         && u->pipe->temp_file->file.fd != NGX_INVALID_FILE)
  2844.     {
  2845.         if (ngx_delete_file(u->pipe->temp_file->file.name.data)
  2846.             == NGX_FILE_ERROR)
  2847.         {
  2848.             ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
  2849.                           ngx_delete_file_n " \"%s\" failed",
  2850.                           u->pipe->temp_file->file.name.data);
  2851.         }
  2852.     }

  2853. #if (NGX_HTTP_CACHE)

  2854.     if (r->cache) {

  2855.         if (u->cacheable) {

  2856.             if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) {
  2857.                 time_t  valid;

  2858.                 valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc);

  2859.                 if (valid) {
  2860.                     r->cache->valid_sec = ngx_time() + valid;
  2861.                     r->cache->error = rc;
  2862.                 }
  2863.             }
  2864.         }

  2865.         ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
  2866.     }

  2867. #endif

  2868.     if (r->subrequest_in_memory
  2869.         && u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE)
  2870.     {
  2871.         u->buffer.last = u->buffer.pos;
  2872.     }

  2873.     if (rc == NGX_DECLINED) {
  2874.         return;
  2875.     }

  2876.     r->connection->log->action = "sending to client";

  2877.     if (!u->header_sent
  2878.         || rc == NGX_HTTP_REQUEST_TIME_OUT
  2879.         || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST)
  2880.     {
  2881.         ngx_http_finalize_request(r, rc);
  2882.         return;
  2883.     }

  2884.     flush = 0;

  2885.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  2886.         rc = NGX_ERROR;
  2887.         flush = 1;
  2888.     }

  2889.     if (r->header_only) {
  2890.         ngx_http_finalize_request(r, rc);
  2891.         return;
  2892.     }

  2893.     if (rc == 0) {
  2894.         rc = ngx_http_send_special(r, NGX_HTTP_LAST);

  2895.     } else if (flush) {
  2896.         r->keepalive = 0;
  2897.         rc = ngx_http_send_special(r, NGX_HTTP_FLUSH);
  2898.     }

  2899.     ngx_http_finalize_request(r, rc);
  2900. }


  2901. static ngx_int_t
  2902. ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
  2903.     ngx_uint_t offset)
  2904. {
  2905.     ngx_table_elt_t  **ph;

  2906.     ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);

  2907.     if (*ph == NULL) {
  2908.         *ph = h;
  2909.     }

  2910.     return NGX_OK;
  2911. }


  2912. static ngx_int_t
  2913. ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
  2914.     ngx_uint_t offset)
  2915. {
  2916.     return NGX_OK;
  2917. }


  2918. static ngx_int_t
  2919. ngx_http_upstream_process_content_length(ngx_http_request_t *r,
  2920.     ngx_table_elt_t *h, ngx_uint_t offset)
  2921. {
  2922.     ngx_http_upstream_t  *u;

  2923.     u = r->upstream;

  2924.     u->headers_in.content_length = h;
  2925.     u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len);

  2926.     return NGX_OK;
  2927. }


  2928. static ngx_int_t
  2929. ngx_http_upstream_process_last_modified(ngx_http_request_t *r,
  2930.     ngx_table_elt_t *h, ngx_uint_t offset)
  2931. {
  2932.     ngx_http_upstream_t  *u;

  2933.     u = r->upstream;

  2934.     u->headers_in.last_modified = h;

  2935. #if (NGX_HTTP_CACHE)

  2936.     if (u->cacheable) {
  2937.         u->headers_in.last_modified_time = ngx_http_parse_time(h->value.data,
  2938.                                                                h->value.len);
  2939.     }

  2940. #endif

  2941.     return NGX_OK;
  2942. }


  2943. static ngx_int_t
  2944. ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
  2945.     ngx_uint_t offset)
  2946. {
  2947.     ngx_array_t           *pa;
  2948.     ngx_table_elt_t      **ph;
  2949.     ngx_http_upstream_t   *u;

  2950.     u = r->upstream;
  2951.     pa = &u->headers_in.cookies;

  2952.     if (pa->elts == NULL) {
  2953.         if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK)
  2954.         {
  2955.             return NGX_ERROR;
  2956.         }
  2957.     }

  2958.     ph = ngx_array_push(pa);
  2959.     if (ph == NULL) {
  2960.         return NGX_ERROR;
  2961.     }

  2962.     *ph = h;

  2963. #if (NGX_HTTP_CACHE)
  2964.     if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
  2965.         u->cacheable = 0;
  2966.     }
  2967. #endif

  2968.     return NGX_OK;
  2969. }


  2970. static ngx_int_t
  2971. ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
  2972.     ngx_table_elt_t *h, ngx_uint_t offset)
  2973. {
  2974.     ngx_array_t          *pa;
  2975.     ngx_table_elt_t     **ph;
  2976.     ngx_http_upstream_t  *u;

  2977.     u = r->upstream;
  2978.     pa = &u->headers_in.cache_control;

  2979.     if (pa->elts == NULL) {
  2980.        if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
  2981.        {
  2982.            return NGX_ERROR;
  2983.        }
  2984.     }

  2985.     ph = ngx_array_push(pa);
  2986.     if (ph == NULL) {
  2987.         return NGX_ERROR;
  2988.     }

  2989.     *ph = h;

  2990. #if (NGX_HTTP_CACHE)
  2991.     {
  2992.     u_char     *p, *start, *last;
  2993.     ngx_int_t   n;

  2994.     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) {
  2995.         return NGX_OK;
  2996.     }

  2997.     if (r->cache == NULL) {
  2998.         return NGX_OK;
  2999.     }

  3000.     if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
  3001.         return NGX_OK;
  3002.     }

  3003.     start = h->value.data;
  3004.     last = start + h->value.len;

  3005.     if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL
  3006.         || ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL
  3007.         || ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL)
  3008.     {
  3009.         u->cacheable = 0;
  3010.         return NGX_OK;
  3011.     }

  3012.     p = ngx_strlcasestrn(start, last, (u_char *) "s-maxage=", 9 - 1);
  3013.     offset = 9;

  3014.     if (p == NULL) {
  3015.         p = ngx_strlcasestrn(start, last, (u_char *) "max-age=", 8 - 1);
  3016.         offset = 8;
  3017.     }

  3018.     if (p == NULL) {
  3019.         return NGX_OK;
  3020.     }

  3021.     n = 0;

  3022.     for (p += offset; p < last; p++) {
  3023.         if (*p == ',' || *p == ';' || *p == ' ') {
  3024.             break;
  3025.         }

  3026.         if (*p >= '0' && *p <= '9') {
  3027.             n = n * 10 + *p - '0';
  3028.             continue;
  3029.         }

  3030.         u->cacheable = 0;
  3031.         return NGX_OK;
  3032.     }

  3033.     if (n == 0) {
  3034.         u->cacheable = 0;
  3035.         return NGX_OK;
  3036.     }

  3037.     r->cache->valid_sec = ngx_time() + n;
  3038.     }
  3039. #endif

  3040.     return NGX_OK;
  3041. }


  3042. static ngx_int_t
  3043. ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
  3044.     ngx_uint_t offset)
  3045. {
  3046.     ngx_http_upstream_t  *u;

  3047.     u = r->upstream;
  3048.     u->headers_in.expires = h;

  3049. #if (NGX_HTTP_CACHE)
  3050.     {
  3051.     time_t  expires;

  3052.     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_EXPIRES) {
  3053.         return NGX_OK;
  3054.     }

  3055.     if (r->cache == NULL) {
  3056.         return NGX_OK;
  3057.     }

  3058.     if (r->cache->valid_sec != 0) {
  3059.         return NGX_OK;
  3060.     }

  3061.     expires = ngx_http_parse_time(h->value.data, h->value.len);

  3062.     if (expires == NGX_ERROR || expires < ngx_time()) {
  3063.         u->cacheable = 0;
  3064.         return NGX_OK;
  3065.     }

  3066.     r->cache->valid_sec = expires;
  3067.     }
  3068. #endif

  3069.     return NGX_OK;
  3070. }


  3071. static ngx_int_t
  3072. ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
  3073.     ngx_table_elt_t *h, ngx_uint_t offset)
  3074. {
  3075.     ngx_http_upstream_t  *u;

  3076.     u = r->upstream;
  3077.     u->headers_in.x_accel_expires = h;

  3078. #if (NGX_HTTP_CACHE)
  3079.     {
  3080.     u_char     *p;
  3081.     size_t      len;
  3082.     ngx_int_t   n;

  3083.     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES) {
  3084.         return NGX_OK;
  3085.     }

  3086.     if (r->cache == NULL) {
  3087.         return NGX_OK;
  3088.     }

  3089.     len = h->value.len;
  3090.     p = h->value.data;

  3091.     if (p[0] != '@') {
  3092.         n = ngx_atoi(p, len);

  3093.         switch (n) {
  3094.         case 0:
  3095.             u->cacheable = 0;
  3096.             /* fall through */

  3097.         case NGX_ERROR:
  3098.             return NGX_OK;

  3099.         default:
  3100.             r->cache->valid_sec = ngx_time() + n;
  3101.             return NGX_OK;
  3102.         }
  3103.     }

  3104.     p++;
  3105.     len--;

  3106.     n = ngx_atoi(p, len);

  3107.     if (n != NGX_ERROR) {
  3108.         r->cache->valid_sec = n;
  3109.     }
  3110.     }
  3111. #endif

  3112.     return NGX_OK;
  3113. }


  3114. static ngx_int_t
  3115. ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
  3116.     ngx_uint_t offset)
  3117. {
  3118.     ngx_int_t             n;
  3119.     ngx_http_upstream_t  *u;

  3120.     u = r->upstream;
  3121.     u->headers_in.x_accel_limit_rate = h;

  3122.     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) {
  3123.         return NGX_OK;
  3124.     }

  3125.     n = ngx_atoi(h->value.data, h->value.len);

  3126.     if (n != NGX_ERROR) {
  3127.         r->limit_rate = (size_t) n;
  3128.     }

  3129.     return NGX_OK;
  3130. }


  3131. static ngx_int_t
  3132. ngx_http_upstream_process_buffering(ngx_http_request_t *r, ngx_table_elt_t *h,
  3133.     ngx_uint_t offset)
  3134. {
  3135.     u_char                c0, c1, c2;
  3136.     ngx_http_upstream_t  *u;

  3137.     u = r->upstream;

  3138.     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING) {
  3139.         return NGX_OK;
  3140.     }

  3141.     if (u->conf->change_buffering) {

  3142.         if (h->value.len == 2) {
  3143.             c0 = ngx_tolower(h->value.data[0]);
  3144.             c1 = ngx_tolower(h->value.data[1]);

  3145.             if (c0 == 'n' && c1 == 'o') {
  3146.                 u->buffering = 0;
  3147.             }

  3148.         } else if (h->value.len == 3) {
  3149.             c0 = ngx_tolower(h->value.data[0]);
  3150.             c1 = ngx_tolower(h->value.data[1]);
  3151.             c2 = ngx_tolower(h->value.data[2]);

  3152.             if (c0 == 'y' && c1 == 'e' && c2 == 's') {
  3153.                 u->buffering = 1;
  3154.             }
  3155.         }
  3156.     }

  3157.     return NGX_OK;
  3158. }


  3159. static ngx_int_t
  3160. ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
  3161.     ngx_uint_t offset)
  3162. {
  3163.     if (r->upstream->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) {
  3164.         return NGX_OK;
  3165.     }

  3166.     r->headers_out.override_charset = &h->value;

  3167.     return NGX_OK;
  3168. }


  3169. static ngx_int_t
  3170. ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
  3171.     ngx_uint_t offset)
  3172. {
  3173.     r->upstream->headers_in.connection = h;

  3174.     if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
  3175.                          (u_char *) "close", 5 - 1)
  3176.         != NULL)
  3177.     {
  3178.         r->upstream->headers_in.connection_close = 1;
  3179.     }

  3180.     return NGX_OK;
  3181. }


  3182. static ngx_int_t
  3183. ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
  3184.     ngx_table_elt_t *h, ngx_uint_t offset)
  3185. {
  3186.     r->upstream->headers_in.transfer_encoding = h;

  3187.     if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
  3188.                          (u_char *) "chunked", 7 - 1)
  3189.         != NULL)
  3190.     {
  3191.         r->upstream->headers_in.chunked = 1;
  3192.     }

  3193.     return NGX_OK;
  3194. }


  3195. static ngx_int_t
  3196. ngx_http_upstream_process_vary(ngx_http_request_t *r,
  3197.     ngx_table_elt_t *h, ngx_uint_t offset)
  3198. {
  3199.     ngx_http_upstream_t  *u;

  3200.     u = r->upstream;
  3201.     u->headers_in.vary = h;

  3202. #if (NGX_HTTP_CACHE)

  3203.     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) {
  3204.         return NGX_OK;
  3205.     }

  3206.     if (r->cache == NULL) {
  3207.         return NGX_OK;
  3208.     }

  3209.     if (h->value.len > NGX_HTTP_CACHE_VARY_LEN
  3210.         || (h->value.len == 1 && h->value.data[0] == '*'))
  3211.     {
  3212.         u->cacheable = 0;
  3213.     }

  3214.     r->cache->vary = h->value;

  3215. #endif

  3216.     return NGX_OK;
  3217. }


  3218. static ngx_int_t
  3219. ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
  3220.     ngx_uint_t offset)
  3221. {
  3222.     ngx_table_elt_t  *ho, **ph;

  3223.     ho = ngx_list_push(&r->headers_out.headers);
  3224.     if (ho == NULL) {
  3225.         return NGX_ERROR;
  3226.     }

  3227.     *ho = *h;

  3228.     if (offset) {
  3229.         ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
  3230.         *ph = ho;
  3231.     }

  3232.     return NGX_OK;
  3233. }


  3234. static ngx_int_t
  3235. ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
  3236.     ngx_table_elt_t *h, ngx_uint_t offset)
  3237. {
  3238.     ngx_array_t      *pa;
  3239.     ngx_table_elt_t  *ho, **ph;

  3240.     pa = (ngx_array_t *) ((char *) &r->headers_out + offset);

  3241.     if (pa->elts == NULL) {
  3242.         if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
  3243.         {
  3244.             return NGX_ERROR;
  3245.         }
  3246.     }

  3247.     ph = ngx_array_push(pa);
  3248.     if (ph == NULL) {
  3249.         return NGX_ERROR;
  3250.     }

  3251.     ho = ngx_list_push(&r->headers_out.headers);
  3252.     if (ho == NULL) {
  3253.         return NGX_ERROR;
  3254.     }

  3255.     *ho = *h;
  3256.     *ph = ho;

  3257.     return NGX_OK;
  3258. }


  3259. static ngx_int_t
  3260. ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
  3261.     ngx_uint_t offset)
  3262. {
  3263.     u_char  *p, *last;

  3264.     r->headers_out.content_type_len = h->value.len;
  3265.     r->headers_out.content_type = h->value;
  3266.     r->headers_out.content_type_lowcase = NULL;

  3267.     for (p = h->value.data; *p; p++) {

  3268.         if (*p != ';') {
  3269.             continue;
  3270.         }

  3271.         last = p;

  3272.         while (*++p == ' ') { /* void */ }

  3273.         if (*p == '\0') {
  3274.             return NGX_OK;
  3275.         }

  3276.         if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) {
  3277.             continue;
  3278.         }

  3279.         p += 8;

  3280.         r->headers_out.content_type_len = last - h->value.data;

  3281.         if (*p == '"') {
  3282.             p++;
  3283.         }

  3284.         last = h->value.data + h->value.len;

  3285.         if (*(last - 1) == '"') {
  3286.             last--;
  3287.         }

  3288.         r->headers_out.charset.len = last - p;
  3289.         r->headers_out.charset.data = p;

  3290.         return NGX_OK;
  3291.     }

  3292.     return NGX_OK;
  3293. }


  3294. static ngx_int_t
  3295. ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h,
  3296.     ngx_uint_t offset)
  3297. {
  3298.     ngx_table_elt_t  *ho;

  3299.     ho = ngx_list_push(&r->headers_out.headers);
  3300.     if (ho == NULL) {
  3301.         return NGX_ERROR;
  3302.     }

  3303.     *ho = *h;

  3304.     r->headers_out.last_modified = ho;

  3305. #if (NGX_HTTP_CACHE)

  3306.     if (r->upstream->cacheable) {
  3307.         r->headers_out.last_modified_time =
  3308.                                     r->upstream->headers_in.last_modified_time;
  3309.     }

  3310. #endif

  3311.     return NGX_OK;
  3312. }


  3313. static ngx_int_t
  3314. ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
  3315.     ngx_uint_t offset)
  3316. {
  3317.     ngx_int_t         rc;
  3318.     ngx_table_elt_t  *ho;

  3319.     ho = ngx_list_push(&r->headers_out.headers);
  3320.     if (ho == NULL) {
  3321.         return NGX_ERROR;
  3322.     }

  3323.     *ho = *h;

  3324.     if (r->upstream->rewrite_redirect) {
  3325.         rc = r->upstream->rewrite_redirect(r, ho, 0);

  3326.         if (rc == NGX_DECLINED) {
  3327.             return NGX_OK;
  3328.         }

  3329.         if (rc == NGX_OK) {
  3330.             r->headers_out.location = ho;

  3331.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3332.                            "rewritten location: \"%V\"", &ho->value);
  3333.         }

  3334.         return rc;
  3335.     }

  3336.     if (ho->value.data[0] != '/') {
  3337.         r->headers_out.location = ho;
  3338.     }

  3339.     /*
  3340.      * we do not set r->headers_out.location here to avoid the handling
  3341.      * the local redirects without a host name by ngx_http_header_filter()
  3342.      */

  3343.     return NGX_OK;
  3344. }


  3345. static ngx_int_t
  3346. ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
  3347.     ngx_uint_t offset)
  3348. {
  3349.     u_char           *p;
  3350.     ngx_int_t         rc;
  3351.     ngx_table_elt_t  *ho;

  3352.     ho = ngx_list_push(&r->headers_out.headers);
  3353.     if (ho == NULL) {
  3354.         return NGX_ERROR;
  3355.     }

  3356.     *ho = *h;

  3357.     if (r->upstream->rewrite_redirect) {

  3358.         p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);

  3359.         if (p) {
  3360.             rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);

  3361.         } else {
  3362.             return NGX_OK;
  3363.         }

  3364.         if (rc == NGX_DECLINED) {
  3365.             return NGX_OK;
  3366.         }

  3367.         if (rc == NGX_OK) {
  3368.             r->headers_out.refresh = ho;

  3369.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3370.                            "rewritten refresh: \"%V\"", &ho->value);
  3371.         }

  3372.         return rc;
  3373.     }

  3374.     r->headers_out.refresh = ho;

  3375.     return NGX_OK;
  3376. }


  3377. static ngx_int_t
  3378. ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
  3379.     ngx_uint_t offset)
  3380. {
  3381.     ngx_int_t         rc;
  3382.     ngx_table_elt_t  *ho;

  3383.     ho = ngx_list_push(&r->headers_out.headers);
  3384.     if (ho == NULL) {
  3385.         return NGX_ERROR;
  3386.     }

  3387.     *ho = *h;

  3388.     if (r->upstream->rewrite_cookie) {
  3389.         rc = r->upstream->rewrite_cookie(r, ho);

  3390.         if (rc == NGX_DECLINED) {
  3391.             return NGX_OK;
  3392.         }

  3393. #if (NGX_DEBUG)
  3394.         if (rc == NGX_OK) {
  3395.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3396.                            "rewritten cookie: \"%V\"", &ho->value);
  3397.         }
  3398. #endif

  3399.         return rc;
  3400.     }

  3401.     return NGX_OK;
  3402. }


  3403. static ngx_int_t
  3404. ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
  3405.     ngx_table_elt_t *h, ngx_uint_t offset)
  3406. {
  3407.     ngx_table_elt_t  *ho;

  3408.     if (r->upstream->conf->force_ranges) {
  3409.         return NGX_OK;
  3410.     }

  3411. #if (NGX_HTTP_CACHE)

  3412.     if (r->cached) {
  3413.         r->allow_ranges = 1;
  3414.         return NGX_OK;
  3415.     }

  3416.     if (r->upstream->cacheable) {
  3417.         r->allow_ranges = 1;
  3418.         r->single_range = 1;
  3419.         return NGX_OK;
  3420.     }

  3421. #endif

  3422.     ho = ngx_list_push(&r->headers_out.headers);
  3423.     if (ho == NULL) {
  3424.         return NGX_ERROR;
  3425.     }

  3426.     *ho = *h;

  3427.     r->headers_out.accept_ranges = ho;

  3428.     return NGX_OK;
  3429. }


  3430. #if (NGX_HTTP_GZIP)

  3431. static ngx_int_t
  3432. ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
  3433.     ngx_table_elt_t *h, ngx_uint_t offset)
  3434. {
  3435.     ngx_table_elt_t  *ho;

  3436.     ho = ngx_list_push(&r->headers_out.headers);
  3437.     if (ho == NULL) {
  3438.         return NGX_ERROR;
  3439.     }

  3440.     *ho = *h;

  3441.     r->headers_out.content_encoding = ho;

  3442.     return NGX_OK;
  3443. }

  3444. #endif


  3445. static ngx_int_t
  3446. ngx_http_upstream_add_variables(ngx_conf_t *cf)
  3447. {
  3448.     ngx_http_variable_t  *var, *v;

  3449.     for (v = ngx_http_upstream_vars; v->name.len; v++) {
  3450.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  3451.         if (var == NULL) {
  3452.             return NGX_ERROR;
  3453.         }

  3454.         var->get_handler = v->get_handler;
  3455.         var->data = v->data;
  3456.     }

  3457.     return NGX_OK;
  3458. }


  3459. static ngx_int_t
  3460. ngx_http_upstream_addr_variable(ngx_http_request_t *r,
  3461.     ngx_http_variable_value_t *v, uintptr_t data)
  3462. {
  3463.     u_char                     *p;
  3464.     size_t                      len;
  3465.     ngx_uint_t                  i;
  3466.     ngx_http_upstream_state_t  *state;

  3467.     v->valid = 1;
  3468.     v->no_cacheable = 0;
  3469.     v->not_found = 0;

  3470.     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
  3471.         v->not_found = 1;
  3472.         return NGX_OK;
  3473.     }

  3474.     len = 0;
  3475.     state = r->upstream_states->elts;

  3476.     for (i = 0; i < r->upstream_states->nelts; i++) {
  3477.         if (state[i].peer) {
  3478.             len += state[i].peer->len + 2;

  3479.         } else {
  3480.             len += 3;
  3481.         }
  3482.     }

  3483.     p = ngx_pnalloc(r->pool, len);
  3484.     if (p == NULL) {
  3485.         return NGX_ERROR;
  3486.     }

  3487.     v->data = p;

  3488.     i = 0;

  3489.     for ( ;; ) {
  3490.         if (state[i].peer) {
  3491.             p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len);
  3492.         }

  3493.         if (++i == r->upstream_states->nelts) {
  3494.             break;
  3495.         }

  3496.         if (state[i].peer) {
  3497.             *p++ = ',';
  3498.             *p++ = ' ';

  3499.         } else {
  3500.             *p++ = ' ';
  3501.             *p++ = ':';
  3502.             *p++ = ' ';

  3503.             if (++i == r->upstream_states->nelts) {
  3504.                 break;
  3505.             }

  3506.             continue;
  3507.         }
  3508.     }

  3509.     v->len = p - v->data;

  3510.     return NGX_OK;
  3511. }


  3512. static ngx_int_t
  3513. ngx_http_upstream_status_variable(ngx_http_request_t *r,
  3514.     ngx_http_variable_value_t *v, uintptr_t data)
  3515. {
  3516.     u_char                     *p;
  3517.     size_t                      len;
  3518.     ngx_uint_t                  i;
  3519.     ngx_http_upstream_state_t  *state;

  3520.     v->valid = 1;
  3521.     v->no_cacheable = 0;
  3522.     v->not_found = 0;

  3523.     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
  3524.         v->not_found = 1;
  3525.         return NGX_OK;
  3526.     }

  3527.     len = r->upstream_states->nelts * (3 + 2);

  3528.     p = ngx_pnalloc(r->pool, len);
  3529.     if (p == NULL) {
  3530.         return NGX_ERROR;
  3531.     }

  3532.     v->data = p;

  3533.     i = 0;
  3534.     state = r->upstream_states->elts;

  3535.     for ( ;; ) {
  3536.         if (state[i].status) {
  3537.             p = ngx_sprintf(p, "%ui", state[i].status);

  3538.         } else {
  3539.             *p++ = '-';
  3540.         }

  3541.         if (++i == r->upstream_states->nelts) {
  3542.             break;
  3543.         }

  3544.         if (state[i].peer) {
  3545.             *p++ = ',';
  3546.             *p++ = ' ';

  3547.         } else {
  3548.             *p++ = ' ';
  3549.             *p++ = ':';
  3550.             *p++ = ' ';

  3551.             if (++i == r->upstream_states->nelts) {
  3552.                 break;
  3553.             }

  3554.             continue;
  3555.         }
  3556.     }

  3557.     v->len = p - v->data;

  3558.     return NGX_OK;
  3559. }


  3560. static ngx_int_t
  3561. ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
  3562.     ngx_http_variable_value_t *v, uintptr_t data)
  3563. {
  3564.     u_char                     *p;
  3565.     size_t                      len;
  3566.     ngx_uint_t                  i;
  3567.     ngx_msec_int_t              ms;
  3568.     ngx_http_upstream_state_t  *state;

  3569.     v->valid = 1;
  3570.     v->no_cacheable = 0;
  3571.     v->not_found = 0;

  3572.     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
  3573.         v->not_found = 1;
  3574.         return NGX_OK;
  3575.     }

  3576.     len = r->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2);

  3577.     p = ngx_pnalloc(r->pool, len);
  3578.     if (p == NULL) {
  3579.         return NGX_ERROR;
  3580.     }

  3581.     v->data = p;

  3582.     i = 0;
  3583.     state = r->upstream_states->elts;

  3584.     for ( ;; ) {
  3585.         if (state[i].status) {

  3586.             if (data
  3587.                 && state[i].header_sec != (time_t) NGX_ERROR)
  3588.             {
  3589.                 ms = (ngx_msec_int_t)
  3590.                       (state[i].header_sec * 1000 + state[i].header_msec);

  3591.             } else {
  3592.                 ms = (ngx_msec_int_t)
  3593.                       (state[i].response_sec * 1000 + state[i].response_msec);
  3594.             }

  3595.             ms = ngx_max(ms, 0);
  3596.             p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000);

  3597.         } else {
  3598.             *p++ = '-';
  3599.         }

  3600.         if (++i == r->upstream_states->nelts) {
  3601.             break;
  3602.         }

  3603.         if (state[i].peer) {
  3604.             *p++ = ',';
  3605.             *p++ = ' ';

  3606.         } else {
  3607.             *p++ = ' ';
  3608.             *p++ = ':';
  3609.             *p++ = ' ';

  3610.             if (++i == r->upstream_states->nelts) {
  3611.                 break;
  3612.             }

  3613.             continue;
  3614.         }
  3615.     }

  3616.     v->len = p - v->data;

  3617.     return NGX_OK;
  3618. }


  3619. static ngx_int_t
  3620. ngx_http_upstream_response_length_variable(ngx_http_request_t *r,
  3621.     ngx_http_variable_value_t *v, uintptr_t data)
  3622. {
  3623.     u_char                     *p;
  3624.     size_t                      len;
  3625.     ngx_uint_t                  i;
  3626.     ngx_http_upstream_state_t  *state;

  3627.     v->valid = 1;
  3628.     v->no_cacheable = 0;
  3629.     v->not_found = 0;

  3630.     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
  3631.         v->not_found = 1;
  3632.         return NGX_OK;
  3633.     }

  3634.     len = r->upstream_states->nelts * (NGX_OFF_T_LEN + 2);

  3635.     p = ngx_pnalloc(r->pool, len);
  3636.     if (p == NULL) {
  3637.         return NGX_ERROR;
  3638.     }

  3639.     v->data = p;

  3640.     i = 0;
  3641.     state = r->upstream_states->elts;

  3642.     for ( ;; ) {
  3643.         p = ngx_sprintf(p, "%O", state[i].response_length);

  3644.         if (++i == r->upstream_states->nelts) {
  3645.             break;
  3646.         }

  3647.         if (state[i].peer) {
  3648.             *p++ = ',';
  3649.             *p++ = ' ';

  3650.         } else {
  3651.             *p++ = ' ';
  3652.             *p++ = ':';
  3653.             *p++ = ' ';

  3654.             if (++i == r->upstream_states->nelts) {
  3655.                 break;
  3656.             }

  3657.             continue;
  3658.         }
  3659.     }

  3660.     v->len = p - v->data;

  3661.     return NGX_OK;
  3662. }


  3663. ngx_int_t
  3664. ngx_http_upstream_header_variable(ngx_http_request_t *r,
  3665.     ngx_http_variable_value_t *v, uintptr_t data)
  3666. {
  3667.     if (r->upstream == NULL) {
  3668.         v->not_found = 1;
  3669.         return NGX_OK;
  3670.     }

  3671.     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
  3672.                                          &r->upstream->headers_in.headers.part,
  3673.                                          sizeof("upstream_http_") - 1);
  3674. }


  3675. ngx_int_t
  3676. ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
  3677.     ngx_http_variable_value_t *v, uintptr_t data)
  3678. {
  3679.     ngx_str_t  *name = (ngx_str_t *) data;

  3680.     ngx_str_t   cookie, s;

  3681.     if (r->upstream == NULL) {
  3682.         v->not_found = 1;
  3683.         return NGX_OK;
  3684.     }

  3685.     s.len = name->len - (sizeof("upstream_cookie_") - 1);
  3686.     s.data = name->data + sizeof("upstream_cookie_") - 1;

  3687.     if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies,
  3688.                                         &s, &cookie)
  3689.         == NGX_DECLINED)
  3690.     {
  3691.         v->not_found = 1;
  3692.         return NGX_OK;
  3693.     }

  3694.     v->len = cookie.len;
  3695.     v->valid = 1;
  3696.     v->no_cacheable = 0;
  3697.     v->not_found = 0;
  3698.     v->data = cookie.data;

  3699.     return NGX_OK;
  3700. }


  3701. #if (NGX_HTTP_CACHE)

  3702. ngx_int_t
  3703. ngx_http_upstream_cache_status(ngx_http_request_t *r,
  3704.     ngx_http_variable_value_t *v, uintptr_t data)
  3705. {
  3706.     ngx_uint_t  n;

  3707.     if (r->upstream == NULL || r->upstream->cache_status == 0) {
  3708.         v->not_found = 1;
  3709.         return NGX_OK;
  3710.     }

  3711.     n = r->upstream->cache_status - 1;

  3712.     v->valid = 1;
  3713.     v->no_cacheable = 0;
  3714.     v->not_found = 0;
  3715.     v->len = ngx_http_cache_status[n].len;
  3716.     v->data = ngx_http_cache_status[n].data;

  3717.     return NGX_OK;
  3718. }


  3719. static ngx_int_t
  3720. ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
  3721.     ngx_http_variable_value_t *v, uintptr_t data)
  3722. {
  3723.     u_char  *p;

  3724.     if (r->upstream == NULL
  3725.         || !r->upstream->conf->cache_revalidate
  3726.         || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED
  3727.         || r->cache->last_modified == -1)
  3728.     {
  3729.         v->not_found = 1;
  3730.         return NGX_OK;
  3731.     }

  3732.     p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
  3733.     if (p == NULL) {
  3734.         return NGX_ERROR;
  3735.     }

  3736.     v->len = ngx_http_time(p, r->cache->last_modified) - p;
  3737.     v->valid = 1;
  3738.     v->no_cacheable = 0;
  3739.     v->not_found = 0;
  3740.     v->data = p;

  3741.     return NGX_OK;
  3742. }


  3743. static ngx_int_t
  3744. ngx_http_upstream_cache_etag(ngx_http_request_t *r,
  3745.     ngx_http_variable_value_t *v, uintptr_t data)
  3746. {
  3747.     if (r->upstream == NULL
  3748.         || !r->upstream->conf->cache_revalidate
  3749.         || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED
  3750.         || r->cache->etag.len == 0)
  3751.     {
  3752.         v->not_found = 1;
  3753.         return NGX_OK;
  3754.     }

  3755.     v->valid = 1;
  3756.     v->no_cacheable = 0;
  3757.     v->not_found = 0;
  3758.     v->len = r->cache->etag.len;
  3759.     v->data = r->cache->etag.data;

  3760.     return NGX_OK;
  3761. }

  3762. #endif


  3763. static char *
  3764. ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
  3765. {
  3766.     char                          *rv;
  3767.     void                          *mconf;
  3768.     ngx_str_t                     *value;
  3769.     ngx_url_t                      u;
  3770.     ngx_uint_t                     m;
  3771.     ngx_conf_t                     pcf;
  3772.     ngx_http_module_t             *module;
  3773.     ngx_http_conf_ctx_t           *ctx, *http_ctx;
  3774.     ngx_http_upstream_srv_conf_t  *uscf;

  3775.     ngx_memzero(&u, sizeof(ngx_url_t));

  3776.     value = cf->args->elts;
  3777.     u.host = value[1];
  3778.     u.no_resolve = 1;
  3779.     u.no_port = 1;

  3780.     uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
  3781.                                          |NGX_HTTP_UPSTREAM_WEIGHT
  3782.                                          |NGX_HTTP_UPSTREAM_MAX_FAILS
  3783.                                          |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
  3784.                                          |NGX_HTTP_UPSTREAM_DOWN
  3785.                                          |NGX_HTTP_UPSTREAM_BACKUP);
  3786.     if (uscf == NULL) {
  3787.         return NGX_CONF_ERROR;
  3788.     }


  3789.     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
  3790.     if (ctx == NULL) {
  3791.         return NGX_CONF_ERROR;
  3792.     }

  3793.     http_ctx = cf->ctx;
  3794.     ctx->main_conf = http_ctx->main_conf;

  3795.     /* the upstream{}'s srv_conf */

  3796.     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  3797.     if (ctx->srv_conf == NULL) {
  3798.         return NGX_CONF_ERROR;
  3799.     }

  3800.     ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;

  3801.     uscf->srv_conf = ctx->srv_conf;


  3802.     /* the upstream{}'s loc_conf */

  3803.     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  3804.     if (ctx->loc_conf == NULL) {
  3805.         return NGX_CONF_ERROR;
  3806.     }

  3807.     for (m = 0; ngx_modules[m]; m++) {
  3808.         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
  3809.             continue;
  3810.         }

  3811.         module = ngx_modules[m]->ctx;

  3812.         if (module->create_srv_conf) {
  3813.             mconf = module->create_srv_conf(cf);
  3814.             if (mconf == NULL) {
  3815.                 return NGX_CONF_ERROR;
  3816.             }

  3817.             ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
  3818.         }

  3819.         if (module->create_loc_conf) {
  3820.             mconf = module->create_loc_conf(cf);
  3821.             if (mconf == NULL) {
  3822.                 return NGX_CONF_ERROR;
  3823.             }

  3824.             ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf;
  3825.         }
  3826.     }

  3827.     uscf->servers = ngx_array_create(cf->pool, 4,
  3828.                                      sizeof(ngx_http_upstream_server_t));
  3829.     if (uscf->servers == NULL) {
  3830.         return NGX_CONF_ERROR;
  3831.     }


  3832.     /* parse inside upstream{} */

  3833.     pcf = *cf;
  3834.     cf->ctx = ctx;
  3835.     cf->cmd_type = NGX_HTTP_UPS_CONF;

  3836.     rv = ngx_conf_parse(cf, NULL);

  3837.     *cf = pcf;

  3838.     if (rv != NGX_CONF_OK) {
  3839.         return rv;
  3840.     }

  3841.     if (uscf->servers->nelts == 0) {
  3842.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3843.                            "no servers are inside upstream");
  3844.         return NGX_CONF_ERROR;
  3845.     }

  3846.     return rv;
  3847. }


  3848. static char *
  3849. ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3850. {
  3851.     ngx_http_upstream_srv_conf_t  *uscf = conf;

  3852.     time_t                       fail_timeout;
  3853.     ngx_str_t                   *value, s;
  3854.     ngx_url_t                    u;
  3855.     ngx_int_t                    weight, max_fails;
  3856.     ngx_uint_t                   i;
  3857.     ngx_http_upstream_server_t  *us;

  3858.     us = ngx_array_push(uscf->servers);
  3859.     if (us == NULL) {
  3860.         return NGX_CONF_ERROR;
  3861.     }

  3862.     ngx_memzero(us, sizeof(ngx_http_upstream_server_t));

  3863.     value = cf->args->elts;

  3864.     weight = 1;
  3865.     max_fails = 1;
  3866.     fail_timeout = 10;

  3867.     for (i = 2; i < cf->args->nelts; i++) {

  3868.         if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {

  3869.             if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
  3870.                 goto not_supported;
  3871.             }

  3872.             weight = ngx_atoi(&value[i].data[7], value[i].len - 7);

  3873.             if (weight == NGX_ERROR || weight == 0) {
  3874.                 goto invalid;
  3875.             }

  3876.             continue;
  3877.         }

  3878.         if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {

  3879.             if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
  3880.                 goto not_supported;
  3881.             }

  3882.             max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);

  3883.             if (max_fails == NGX_ERROR) {
  3884.                 goto invalid;
  3885.             }

  3886.             continue;
  3887.         }

  3888.         if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {

  3889.             if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
  3890.                 goto not_supported;
  3891.             }

  3892.             s.len = value[i].len - 13;
  3893.             s.data = &value[i].data[13];

  3894.             fail_timeout = ngx_parse_time(&s, 1);

  3895.             if (fail_timeout == (time_t) NGX_ERROR) {
  3896.                 goto invalid;
  3897.             }

  3898.             continue;
  3899.         }

  3900.         if (ngx_strcmp(value[i].data, "backup") == 0) {

  3901.             if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
  3902.                 goto not_supported;
  3903.             }

  3904.             us->backup = 1;

  3905.             continue;
  3906.         }

  3907.         if (ngx_strcmp(value[i].data, "down") == 0) {

  3908.             if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
  3909.                 goto not_supported;
  3910.             }

  3911.             us->down = 1;

  3912.             continue;
  3913.         }

  3914.         goto invalid;
  3915.     }

  3916.     ngx_memzero(&u, sizeof(ngx_url_t));

  3917.     u.url = value[1];
  3918.     u.default_port = 80;

  3919.     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
  3920.         if (u.err) {
  3921.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3922.                                "%s in upstream \"%V\"", u.err, &u.url);
  3923.         }

  3924.         return NGX_CONF_ERROR;
  3925.     }

  3926.     us->name = u.url;
  3927.     us->addrs = u.addrs;
  3928.     us->naddrs = u.naddrs;
  3929.     us->weight = weight;
  3930.     us->max_fails = max_fails;
  3931.     us->fail_timeout = fail_timeout;

  3932.     return NGX_CONF_OK;

  3933. invalid:

  3934.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3935.                        "invalid parameter \"%V\"", &value[i]);

  3936.     return NGX_CONF_ERROR;

  3937. not_supported:

  3938.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3939.                        "balancing method does not support parameter \"%V\"",
  3940.                        &value[i]);

  3941.     return NGX_CONF_ERROR;
  3942. }


  3943. ngx_http_upstream_srv_conf_t *
  3944. ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
  3945. {
  3946.     ngx_uint_t                      i;
  3947.     ngx_http_upstream_server_t     *us;
  3948.     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
  3949.     ngx_http_upstream_main_conf_t  *umcf;

  3950.     if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {

  3951.         if (ngx_parse_url(cf->pool, u) != NGX_OK) {
  3952.             if (u->err) {
  3953.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3954.                                    "%s in upstream \"%V\"", u->err, &u->url);
  3955.             }

  3956.             return NULL;
  3957.         }
  3958.     }

  3959.     umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);

  3960.     uscfp = umcf->upstreams.elts;

  3961.     for (i = 0; i < umcf->upstreams.nelts; i++) {

  3962.         if (uscfp[i]->host.len != u->host.len
  3963.             || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
  3964.                != 0)
  3965.         {
  3966.             continue;
  3967.         }

  3968.         if ((flags & NGX_HTTP_UPSTREAM_CREATE)
  3969.              && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
  3970.         {
  3971.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3972.                                "duplicate upstream \"%V\"", &u->host);
  3973.             return NULL;
  3974.         }

  3975.         if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && !u->no_port) {
  3976.             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  3977.                                "upstream \"%V\" may not have port %d",
  3978.                                &u->host, u->port);
  3979.             return NULL;
  3980.         }

  3981.         if ((flags & NGX_HTTP_UPSTREAM_CREATE) && !uscfp[i]->no_port) {
  3982.             ngx_log_error(NGX_LOG_WARN, cf->log, 0,
  3983.                           "upstream \"%V\" may not have port %d in %s:%ui",
  3984.                           &u->host, uscfp[i]->port,
  3985.                           uscfp[i]->file_name, uscfp[i]->line);
  3986.             return NULL;
  3987.         }

  3988.         if (uscfp[i]->port && u->port
  3989.             && uscfp[i]->port != u->port)
  3990.         {
  3991.             continue;
  3992.         }

  3993.         if (uscfp[i]->default_port && u->default_port
  3994.             && uscfp[i]->default_port != u->default_port)
  3995.         {
  3996.             continue;
  3997.         }

  3998.         if (flags & NGX_HTTP_UPSTREAM_CREATE) {
  3999.             uscfp[i]->flags = flags;
  4000.         }

  4001.         return uscfp[i];
  4002.     }

  4003.     uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
  4004.     if (uscf == NULL) {
  4005.         return NULL;
  4006.     }

  4007.     uscf->flags = flags;
  4008.     uscf->host = u->host;
  4009.     uscf->file_name = cf->conf_file->file.name.data;
  4010.     uscf->line = cf->conf_file->line;
  4011.     uscf->port = u->port;
  4012.     uscf->default_port = u->default_port;
  4013.     uscf->no_port = u->no_port;

  4014.     if (u->naddrs == 1) {
  4015.         uscf->servers = ngx_array_create(cf->pool, 1,
  4016.                                          sizeof(ngx_http_upstream_server_t));
  4017.         if (uscf->servers == NULL) {
  4018.             return NULL;
  4019.         }

  4020.         us = ngx_array_push(uscf->servers);
  4021.         if (us == NULL) {
  4022.             return NULL;
  4023.         }

  4024.         ngx_memzero(us, sizeof(ngx_http_upstream_server_t));

  4025.         us->addrs = u->addrs;
  4026.         us->naddrs = 1;
  4027.     }

  4028.     uscfp = ngx_array_push(&umcf->upstreams);
  4029.     if (uscfp == NULL) {
  4030.         return NULL;
  4031.     }

  4032.     *uscfp = uscf;

  4033.     return uscf;
  4034. }


  4035. char *
  4036. ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
  4037.     void *conf)
  4038. {
  4039.     char  *p = conf;

  4040.     ngx_int_t                           rc;
  4041.     ngx_str_t                          *value;
  4042.     ngx_http_complex_value_t            cv;
  4043.     ngx_http_upstream_local_t         **plocal, *local;
  4044.     ngx_http_compile_complex_value_t    ccv;

  4045.     plocal = (ngx_http_upstream_local_t **) (p + cmd->offset);

  4046.     if (*plocal != NGX_CONF_UNSET_PTR) {
  4047.         return "is duplicate";
  4048.     }

  4049.     value = cf->args->elts;

  4050.     if (ngx_strcmp(value[1].data, "off") == 0) {
  4051.         *plocal = NULL;
  4052.         return NGX_CONF_OK;
  4053.     }

  4054.     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  4055.     ccv.cf = cf;
  4056.     ccv.value = &value[1];
  4057.     ccv.complex_value = &cv;

  4058.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  4059.         return NGX_CONF_ERROR;
  4060.     }

  4061.     local = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_local_t));
  4062.     if (local == NULL) {
  4063.         return NGX_CONF_ERROR;
  4064.     }

  4065.     *plocal = local;

  4066.     if (cv.lengths) {
  4067.         local->value = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
  4068.         if (local->value == NULL) {
  4069.             return NGX_CONF_ERROR;
  4070.         }

  4071.         *local->value = cv;

  4072.         return NGX_CONF_OK;
  4073.     }

  4074.     local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t));
  4075.     if (local->addr == NULL) {
  4076.         return NGX_CONF_ERROR;
  4077.     }

  4078.     rc = ngx_parse_addr(cf->pool, local->addr, value[1].data, value[1].len);

  4079.     switch (rc) {
  4080.     case NGX_OK:
  4081.         local->addr->name = value[1];
  4082.         return NGX_CONF_OK;

  4083.     case NGX_DECLINED:
  4084.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  4085.                            "invalid address \"%V\"", &value[1]);
  4086.         /* fall through */

  4087.     default:
  4088.         return NGX_CONF_ERROR;
  4089.     }
  4090. }


  4091. static ngx_addr_t *
  4092. ngx_http_upstream_get_local(ngx_http_request_t *r,
  4093.     ngx_http_upstream_local_t *local)
  4094. {
  4095.     ngx_int_t    rc;
  4096.     ngx_str_t    val;
  4097.     ngx_addr_t  *addr;

  4098.     if (local == NULL) {
  4099.         return NULL;
  4100.     }

  4101.     if (local->value == NULL) {
  4102.         return local->addr;
  4103.     }

  4104.     if (ngx_http_complex_value(r, local->value, &val) != NGX_OK) {
  4105.         return NULL;
  4106.     }

  4107.     if (val.len == 0) {
  4108.         return NULL;
  4109.     }

  4110.     addr = ngx_palloc(r->pool, sizeof(ngx_addr_t));
  4111.     if (addr == NULL) {
  4112.         return NULL;
  4113.     }

  4114.     rc = ngx_parse_addr(r->pool, addr, val.data, val.len);

  4115.     switch (rc) {
  4116.     case NGX_OK:
  4117.         addr->name = val;
  4118.         return addr;

  4119.     case NGX_DECLINED:
  4120.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  4121.                       "invalid local address \"%V\"", &val);
  4122.         /* fall through */

  4123.     default:
  4124.         return NULL;
  4125.     }
  4126. }


  4127. char *
  4128. ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
  4129.     void *conf)
  4130. {
  4131.     char  *p = conf;

  4132.     ngx_str_t                   *value;
  4133.     ngx_array_t                **a;
  4134.     ngx_http_upstream_param_t   *param;

  4135.     a = (ngx_array_t **) (p + cmd->offset);

  4136.     if (*a == NULL) {
  4137.         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_http_upstream_param_t));
  4138.         if (*a == NULL) {
  4139.             return NGX_CONF_ERROR;
  4140.         }
  4141.     }

  4142.     param = ngx_array_push(*a);
  4143.     if (param == NULL) {
  4144.         return NGX_CONF_ERROR;
  4145.     }

  4146.     value = cf->args->elts;

  4147.     param->key = value[1];
  4148.     param->value = value[2];
  4149.     param->skip_empty = 0;

  4150.     if (cf->args->nelts == 4) {
  4151.         if (ngx_strcmp(value[3].data, "if_not_empty") != 0) {
  4152.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  4153.                                "invalid parameter \"%V\"", &value[3]);
  4154.             return NGX_CONF_ERROR;
  4155.         }

  4156.         param->skip_empty = 1;
  4157.     }

  4158.     return NGX_CONF_OK;
  4159. }


  4160. ngx_int_t
  4161. ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
  4162.     ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
  4163.     ngx_str_t *default_hide_headers, ngx_hash_init_t *hash)
  4164. {
  4165.     ngx_str_t       *h;
  4166.     ngx_uint_t       i, j;
  4167.     ngx_array_t      hide_headers;
  4168.     ngx_hash_key_t  *hk;

  4169.     if (conf->hide_headers == NGX_CONF_UNSET_PTR
  4170.         && conf->pass_headers == NGX_CONF_UNSET_PTR)
  4171.     {
  4172.         conf->hide_headers = prev->hide_headers;
  4173.         conf->pass_headers = prev->pass_headers;

  4174.         conf->hide_headers_hash = prev->hide_headers_hash;

  4175.         if (conf->hide_headers_hash.buckets
  4176. #if (NGX_HTTP_CACHE)
  4177.             && ((conf->cache == 0) == (prev->cache == 0))
  4178. #endif
  4179.            )
  4180.         {
  4181.             return NGX_OK;
  4182.         }

  4183.     } else {
  4184.         if (conf->hide_headers == NGX_CONF_UNSET_PTR) {
  4185.             conf->hide_headers = prev->hide_headers;
  4186.         }

  4187.         if (conf->pass_headers == NGX_CONF_UNSET_PTR) {
  4188.             conf->pass_headers = prev->pass_headers;
  4189.         }
  4190.     }

  4191.     if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  4192.         != NGX_OK)
  4193.     {
  4194.         return NGX_ERROR;
  4195.     }

  4196.     for (h = default_hide_headers; h->len; h++) {
  4197.         hk = ngx_array_push(&hide_headers);
  4198.         if (hk == NULL) {
  4199.             return NGX_ERROR;
  4200.         }

  4201.         hk->key = *h;
  4202.         hk->key_hash = ngx_hash_key_lc(h->data, h->len);
  4203.         hk->value = (void *) 1;
  4204.     }

  4205.     if (conf->hide_headers != NGX_CONF_UNSET_PTR) {

  4206.         h = conf->hide_headers->elts;

  4207.         for (i = 0; i < conf->hide_headers->nelts; i++) {

  4208.             hk = hide_headers.elts;

  4209.             for (j = 0; j < hide_headers.nelts; j++) {
  4210.                 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
  4211.                     goto exist;
  4212.                 }
  4213.             }

  4214.             hk = ngx_array_push(&hide_headers);
  4215.             if (hk == NULL) {
  4216.                 return NGX_ERROR;
  4217.             }

  4218.             hk->key = h[i];
  4219.             hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len);
  4220.             hk->value = (void *) 1;

  4221.         exist:

  4222.             continue;
  4223.         }
  4224.     }

  4225.     if (conf->pass_headers != NGX_CONF_UNSET_PTR) {

  4226.         h = conf->pass_headers->elts;
  4227.         hk = hide_headers.elts;

  4228.         for (i = 0; i < conf->pass_headers->nelts; i++) {
  4229.             for (j = 0; j < hide_headers.nelts; j++) {

  4230.                 if (hk[j].key.data == NULL) {
  4231.                     continue;
  4232.                 }

  4233.                 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
  4234.                     hk[j].key.data = NULL;
  4235.                     break;
  4236.                 }
  4237.             }
  4238.         }
  4239.     }

  4240.     hash->hash = &conf->hide_headers_hash;
  4241.     hash->key = ngx_hash_key_lc;
  4242.     hash->pool = cf->pool;
  4243.     hash->temp_pool = NULL;

  4244.     return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts);
  4245. }


  4246. static void *
  4247. ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
  4248. {
  4249.     ngx_http_upstream_main_conf_t  *umcf;

  4250.     umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t));
  4251.     if (umcf == NULL) {
  4252.         return NULL;
  4253.     }

  4254.     if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
  4255.                        sizeof(ngx_http_upstream_srv_conf_t *))
  4256.         != NGX_OK)
  4257.     {
  4258.         return NULL;
  4259.     }

  4260.     return umcf;
  4261. }


  4262. static char *
  4263. ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
  4264. {
  4265.     ngx_http_upstream_main_conf_t  *umcf = conf;

  4266.     ngx_uint_t                      i;
  4267.     ngx_array_t                     headers_in;
  4268.     ngx_hash_key_t                 *hk;
  4269.     ngx_hash_init_t                 hash;
  4270.     ngx_http_upstream_init_pt       init;
  4271.     ngx_http_upstream_header_t     *header;
  4272.     ngx_http_upstream_srv_conf_t  **uscfp;

  4273.     uscfp = umcf->upstreams.elts;

  4274.     for (i = 0; i < umcf->upstreams.nelts; i++) {

  4275.         init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
  4276.                                             ngx_http_upstream_init_round_robin;

  4277.         if (init(cf, uscfp[i]) != NGX_OK) {
  4278.             return NGX_CONF_ERROR;
  4279.         }
  4280.     }


  4281.     /* upstream_headers_in_hash */

  4282.     if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
  4283.         != NGX_OK)
  4284.     {
  4285.         return NGX_CONF_ERROR;
  4286.     }

  4287.     for (header = ngx_http_upstream_headers_in; header->name.len; header++) {
  4288.         hk = ngx_array_push(&headers_in);
  4289.         if (hk == NULL) {
  4290.             return NGX_CONF_ERROR;
  4291.         }

  4292.         hk->key = header->name;
  4293.         hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
  4294.         hk->value = header;
  4295.     }

  4296.     hash.hash = &umcf->headers_in_hash;
  4297.     hash.key = ngx_hash_key_lc;
  4298.     hash.max_size = 512;
  4299.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  4300.     hash.name = "upstream_headers_in_hash";
  4301.     hash.pool = cf->pool;
  4302.     hash.temp_pool = NULL;

  4303.     if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
  4304.         return NGX_CONF_ERROR;
  4305.     }

  4306.     return NGX_CONF_OK;
  4307. }