src/http/modules/ngx_http_proxy_module.c - nginx-1.7.10

Global variables defined

Data types 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. typedef struct {
  9.     ngx_array_t                    caches;  /* ngx_http_file_cache_t * */
  10. } ngx_http_proxy_main_conf_t;


  11. typedef struct ngx_http_proxy_rewrite_s  ngx_http_proxy_rewrite_t;

  12. typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
  13.     ngx_table_elt_t *h, size_t prefix, size_t len,
  14.     ngx_http_proxy_rewrite_t *pr);

  15. struct ngx_http_proxy_rewrite_s {
  16.     ngx_http_proxy_rewrite_pt      handler;

  17.     union {
  18.         ngx_http_complex_value_t   complex;
  19. #if (NGX_PCRE)
  20.         ngx_http_regex_t          *regex;
  21. #endif
  22.     } pattern;

  23.     ngx_http_complex_value_t       replacement;
  24. };


  25. typedef struct {
  26.     ngx_str_t                      key_start;
  27.     ngx_str_t                      schema;
  28.     ngx_str_t                      host_header;
  29.     ngx_str_t                      port;
  30.     ngx_str_t                      uri;
  31. } ngx_http_proxy_vars_t;


  32. typedef struct {
  33.     ngx_array_t                   *flushes;
  34.     ngx_array_t                   *lengths;
  35.     ngx_array_t                   *values;
  36.     ngx_hash_t                     hash;
  37. } ngx_http_proxy_headers_t;


  38. typedef struct {
  39.     ngx_http_upstream_conf_t       upstream;

  40.     ngx_array_t                   *body_flushes;
  41.     ngx_array_t                   *body_lengths;
  42.     ngx_array_t                   *body_values;
  43.     ngx_str_t                      body_source;

  44.     ngx_http_proxy_headers_t       headers;
  45. #if (NGX_HTTP_CACHE)
  46.     ngx_http_proxy_headers_t       headers_cache;
  47. #endif
  48.     ngx_array_t                   *headers_source;

  49.     ngx_array_t                   *proxy_lengths;
  50.     ngx_array_t                   *proxy_values;

  51.     ngx_array_t                   *redirects;
  52.     ngx_array_t                   *cookie_domains;
  53.     ngx_array_t                   *cookie_paths;

  54.     ngx_str_t                      method;
  55.     ngx_str_t                      location;
  56.     ngx_str_t                      url;

  57. #if (NGX_HTTP_CACHE)
  58.     ngx_http_complex_value_t       cache_key;
  59. #endif

  60.     ngx_http_proxy_vars_t          vars;

  61.     ngx_flag_t                     redirect;

  62.     ngx_uint_t                     http_version;

  63.     ngx_uint_t                     headers_hash_max_size;
  64.     ngx_uint_t                     headers_hash_bucket_size;

  65. #if (NGX_HTTP_SSL)
  66.     ngx_uint_t                     ssl;
  67.     ngx_uint_t                     ssl_protocols;
  68.     ngx_str_t                      ssl_ciphers;
  69.     ngx_uint_t                     ssl_verify_depth;
  70.     ngx_str_t                      ssl_trusted_certificate;
  71.     ngx_str_t                      ssl_crl;
  72.     ngx_str_t                      ssl_certificate;
  73.     ngx_str_t                      ssl_certificate_key;
  74.     ngx_array_t                   *ssl_passwords;
  75. #endif
  76. } ngx_http_proxy_loc_conf_t;


  77. typedef struct {
  78.     ngx_http_status_t              status;
  79.     ngx_http_chunked_t             chunked;
  80.     ngx_http_proxy_vars_t          vars;
  81.     off_t                          internal_body_length;

  82.     ngx_uint_t                     head;  /* unsigned  head:1 */
  83. } ngx_http_proxy_ctx_t;


  84. static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
  85.     ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
  86. #if (NGX_HTTP_CACHE)
  87. static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
  88. #endif
  89. static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
  90. static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
  91. static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
  92. static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
  93. static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
  94. static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
  95.     ngx_buf_t *buf);
  96. static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
  97.     ngx_buf_t *buf);
  98. static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
  99.     ssize_t bytes);
  100. static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
  101.     ssize_t bytes);
  102. static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
  103. static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
  104.     ngx_int_t rc);

  105. static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
  106.     ngx_http_variable_value_t *v, uintptr_t data);
  107. static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
  108.     ngx_http_variable_value_t *v, uintptr_t data);
  109. static ngx_int_t
  110.     ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
  111.     ngx_http_variable_value_t *v, uintptr_t data);
  112. static ngx_int_t
  113.     ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
  114.     ngx_http_variable_value_t *v, uintptr_t data);
  115. static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
  116.     ngx_table_elt_t *h, size_t prefix);
  117. static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
  118.     ngx_table_elt_t *h);
  119. static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
  120.     ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
  121. static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
  122.     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);

  123. static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
  124. static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf);
  125. static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
  126. static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
  127.     void *parent, void *child);
  128. static ngx_int_t ngx_http_proxy_init_headers(ngx_conf_t *cf,
  129.     ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_headers_t *headers,
  130.     ngx_keyval_t *default_headers);

  131. static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
  132.     void *conf);
  133. static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
  134.     void *conf);
  135. static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
  136.     void *conf);
  137. static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
  138.     void *conf);
  139. static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
  140.     void *conf);
  141. #if (NGX_HTTP_CACHE)
  142. static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  143.     void *conf);
  144. static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
  145.     void *conf);
  146. #endif
  147. #if (NGX_HTTP_SSL)
  148. static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf,
  149.     ngx_command_t *cmd, void *conf);
  150. #endif

  151. static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);

  152. static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
  153.     ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);

  154. #if (NGX_HTTP_SSL)
  155. static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
  156.     ngx_http_proxy_loc_conf_t *plcf);
  157. #endif
  158. static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);


  159. static ngx_conf_post_t  ngx_http_proxy_lowat_post =
  160.     { ngx_http_proxy_lowat_check };


  161. static ngx_conf_bitmask_t  ngx_http_proxy_next_upstream_masks[] = {
  162.     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
  163.     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
  164.     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
  165.     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
  166.     { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
  167.     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
  168.     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
  169.     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
  170.     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
  171.     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
  172.     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
  173.     { ngx_null_string, 0 }
  174. };


  175. #if (NGX_HTTP_SSL)

  176. static ngx_conf_bitmask_t  ngx_http_proxy_ssl_protocols[] = {
  177.     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
  178.     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
  179.     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
  180.     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
  181.     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
  182.     { ngx_null_string, 0 }
  183. };

  184. #endif


  185. static ngx_conf_enum_t  ngx_http_proxy_http_version[] = {
  186.     { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
  187.     { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
  188.     { ngx_null_string, 0 }
  189. };


  190. ngx_module_t  ngx_http_proxy_module;


  191. static ngx_command_t  ngx_http_proxy_commands[] = {

  192.     { ngx_string("proxy_pass"),
  193.       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
  194.       ngx_http_proxy_pass,
  195.       NGX_HTTP_LOC_CONF_OFFSET,
  196.       0,
  197.       NULL },

  198.     { ngx_string("proxy_redirect"),
  199.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  200.       ngx_http_proxy_redirect,
  201.       NGX_HTTP_LOC_CONF_OFFSET,
  202.       0,
  203.       NULL },

  204.     { ngx_string("proxy_cookie_domain"),
  205.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  206.       ngx_http_proxy_cookie_domain,
  207.       NGX_HTTP_LOC_CONF_OFFSET,
  208.       0,
  209.       NULL },

  210.     { ngx_string("proxy_cookie_path"),
  211.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  212.       ngx_http_proxy_cookie_path,
  213.       NGX_HTTP_LOC_CONF_OFFSET,
  214.       0,
  215.       NULL },

  216.     { ngx_string("proxy_store"),
  217.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  218.       ngx_http_proxy_store,
  219.       NGX_HTTP_LOC_CONF_OFFSET,
  220.       0,
  221.       NULL },

  222.     { ngx_string("proxy_store_access"),
  223.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
  224.       ngx_conf_set_access_slot,
  225.       NGX_HTTP_LOC_CONF_OFFSET,
  226.       offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
  227.       NULL },

  228.     { ngx_string("proxy_buffering"),
  229.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  230.       ngx_conf_set_flag_slot,
  231.       NGX_HTTP_LOC_CONF_OFFSET,
  232.       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
  233.       NULL },

  234.     { ngx_string("proxy_ignore_client_abort"),
  235.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  236.       ngx_conf_set_flag_slot,
  237.       NGX_HTTP_LOC_CONF_OFFSET,
  238.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
  239.       NULL },

  240.     { ngx_string("proxy_bind"),
  241.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  242.       ngx_http_upstream_bind_set_slot,
  243.       NGX_HTTP_LOC_CONF_OFFSET,
  244.       offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
  245.       NULL },

  246.     { ngx_string("proxy_connect_timeout"),
  247.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  248.       ngx_conf_set_msec_slot,
  249.       NGX_HTTP_LOC_CONF_OFFSET,
  250.       offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
  251.       NULL },

  252.     { ngx_string("proxy_send_timeout"),
  253.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  254.       ngx_conf_set_msec_slot,
  255.       NGX_HTTP_LOC_CONF_OFFSET,
  256.       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
  257.       NULL },

  258.     { ngx_string("proxy_send_lowat"),
  259.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  260.       ngx_conf_set_size_slot,
  261.       NGX_HTTP_LOC_CONF_OFFSET,
  262.       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
  263.       &ngx_http_proxy_lowat_post },

  264.     { ngx_string("proxy_intercept_errors"),
  265.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  266.       ngx_conf_set_flag_slot,
  267.       NGX_HTTP_LOC_CONF_OFFSET,
  268.       offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
  269.       NULL },

  270.     { ngx_string("proxy_set_header"),
  271.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  272.       ngx_conf_set_keyval_slot,
  273.       NGX_HTTP_LOC_CONF_OFFSET,
  274.       offsetof(ngx_http_proxy_loc_conf_t, headers_source),
  275.       NULL },

  276.     { ngx_string("proxy_headers_hash_max_size"),
  277.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  278.       ngx_conf_set_num_slot,
  279.       NGX_HTTP_LOC_CONF_OFFSET,
  280.       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
  281.       NULL },

  282.     { ngx_string("proxy_headers_hash_bucket_size"),
  283.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  284.       ngx_conf_set_num_slot,
  285.       NGX_HTTP_LOC_CONF_OFFSET,
  286.       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
  287.       NULL },

  288.     { ngx_string("proxy_set_body"),
  289.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  290.       ngx_conf_set_str_slot,
  291.       NGX_HTTP_LOC_CONF_OFFSET,
  292.       offsetof(ngx_http_proxy_loc_conf_t, body_source),
  293.       NULL },

  294.     { ngx_string("proxy_method"),
  295.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  296.       ngx_conf_set_str_slot,
  297.       NGX_HTTP_LOC_CONF_OFFSET,
  298.       offsetof(ngx_http_proxy_loc_conf_t, method),
  299.       NULL },

  300.     { ngx_string("proxy_pass_request_headers"),
  301.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  302.       ngx_conf_set_flag_slot,
  303.       NGX_HTTP_LOC_CONF_OFFSET,
  304.       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
  305.       NULL },

  306.     { ngx_string("proxy_pass_request_body"),
  307.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  308.       ngx_conf_set_flag_slot,
  309.       NGX_HTTP_LOC_CONF_OFFSET,
  310.       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
  311.       NULL },

  312.     { ngx_string("proxy_buffer_size"),
  313.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  314.       ngx_conf_set_size_slot,
  315.       NGX_HTTP_LOC_CONF_OFFSET,
  316.       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
  317.       NULL },

  318.     { ngx_string("proxy_read_timeout"),
  319.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  320.       ngx_conf_set_msec_slot,
  321.       NGX_HTTP_LOC_CONF_OFFSET,
  322.       offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
  323.       NULL },

  324.     { ngx_string("proxy_buffers"),
  325.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  326.       ngx_conf_set_bufs_slot,
  327.       NGX_HTTP_LOC_CONF_OFFSET,
  328.       offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
  329.       NULL },

  330.     { ngx_string("proxy_busy_buffers_size"),
  331.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  332.       ngx_conf_set_size_slot,
  333.       NGX_HTTP_LOC_CONF_OFFSET,
  334.       offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
  335.       NULL },

  336.     { ngx_string("proxy_force_ranges"),
  337.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  338.       ngx_conf_set_flag_slot,
  339.       NGX_HTTP_LOC_CONF_OFFSET,
  340.       offsetof(ngx_http_proxy_loc_conf_t, upstream.force_ranges),
  341.       NULL },

  342.     { ngx_string("proxy_limit_rate"),
  343.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  344.       ngx_conf_set_size_slot,
  345.       NGX_HTTP_LOC_CONF_OFFSET,
  346.       offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate),
  347.       NULL },

  348. #if (NGX_HTTP_CACHE)

  349.     { ngx_string("proxy_cache"),
  350.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  351.       ngx_http_proxy_cache,
  352.       NGX_HTTP_LOC_CONF_OFFSET,
  353.       0,
  354.       NULL },

  355.     { ngx_string("proxy_cache_key"),
  356.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  357.       ngx_http_proxy_cache_key,
  358.       NGX_HTTP_LOC_CONF_OFFSET,
  359.       0,
  360.       NULL },

  361.     { ngx_string("proxy_cache_path"),
  362.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  363.       ngx_http_file_cache_set_slot,
  364.       NGX_HTTP_MAIN_CONF_OFFSET,
  365.       offsetof(ngx_http_proxy_main_conf_t, caches),
  366.       &ngx_http_proxy_module },

  367.     { ngx_string("proxy_cache_bypass"),
  368.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  369.       ngx_http_set_predicate_slot,
  370.       NGX_HTTP_LOC_CONF_OFFSET,
  371.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
  372.       NULL },

  373.     { ngx_string("proxy_no_cache"),
  374.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  375.       ngx_http_set_predicate_slot,
  376.       NGX_HTTP_LOC_CONF_OFFSET,
  377.       offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
  378.       NULL },

  379.     { ngx_string("proxy_cache_valid"),
  380.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  381.       ngx_http_file_cache_valid_set_slot,
  382.       NGX_HTTP_LOC_CONF_OFFSET,
  383.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
  384.       NULL },

  385.     { ngx_string("proxy_cache_min_uses"),
  386.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  387.       ngx_conf_set_num_slot,
  388.       NGX_HTTP_LOC_CONF_OFFSET,
  389.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
  390.       NULL },

  391.     { ngx_string("proxy_cache_use_stale"),
  392.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  393.       ngx_conf_set_bitmask_slot,
  394.       NGX_HTTP_LOC_CONF_OFFSET,
  395.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
  396.       &ngx_http_proxy_next_upstream_masks },

  397.     { ngx_string("proxy_cache_methods"),
  398.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  399.       ngx_conf_set_bitmask_slot,
  400.       NGX_HTTP_LOC_CONF_OFFSET,
  401.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
  402.       &ngx_http_upstream_cache_method_mask },

  403.     { ngx_string("proxy_cache_lock"),
  404.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  405.       ngx_conf_set_flag_slot,
  406.       NGX_HTTP_LOC_CONF_OFFSET,
  407.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
  408.       NULL },

  409.     { ngx_string("proxy_cache_lock_timeout"),
  410.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  411.       ngx_conf_set_msec_slot,
  412.       NGX_HTTP_LOC_CONF_OFFSET,
  413.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
  414.       NULL },

  415.     { ngx_string("proxy_cache_lock_age"),
  416.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  417.       ngx_conf_set_msec_slot,
  418.       NGX_HTTP_LOC_CONF_OFFSET,
  419.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_age),
  420.       NULL },

  421.     { ngx_string("proxy_cache_revalidate"),
  422.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  423.       ngx_conf_set_flag_slot,
  424.       NGX_HTTP_LOC_CONF_OFFSET,
  425.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate),
  426.       NULL },

  427. #endif

  428.     { ngx_string("proxy_temp_path"),
  429.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  430.       ngx_conf_set_path_slot,
  431.       NGX_HTTP_LOC_CONF_OFFSET,
  432.       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
  433.       NULL },

  434.     { ngx_string("proxy_max_temp_file_size"),
  435.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  436.       ngx_conf_set_size_slot,
  437.       NGX_HTTP_LOC_CONF_OFFSET,
  438.       offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
  439.       NULL },

  440.     { ngx_string("proxy_temp_file_write_size"),
  441.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  442.       ngx_conf_set_size_slot,
  443.       NGX_HTTP_LOC_CONF_OFFSET,
  444.       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
  445.       NULL },

  446.     { ngx_string("proxy_next_upstream"),
  447.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  448.       ngx_conf_set_bitmask_slot,
  449.       NGX_HTTP_LOC_CONF_OFFSET,
  450.       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
  451.       &ngx_http_proxy_next_upstream_masks },

  452.     { ngx_string("proxy_next_upstream_tries"),
  453.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  454.       ngx_conf_set_num_slot,
  455.       NGX_HTTP_LOC_CONF_OFFSET,
  456.       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_tries),
  457.       NULL },

  458.     { ngx_string("proxy_next_upstream_timeout"),
  459.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  460.       ngx_conf_set_msec_slot,
  461.       NGX_HTTP_LOC_CONF_OFFSET,
  462.       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_timeout),
  463.       NULL },

  464.     { ngx_string("proxy_pass_header"),
  465.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  466.       ngx_conf_set_str_array_slot,
  467.       NGX_HTTP_LOC_CONF_OFFSET,
  468.       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
  469.       NULL },

  470.     { ngx_string("proxy_hide_header"),
  471.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  472.       ngx_conf_set_str_array_slot,
  473.       NGX_HTTP_LOC_CONF_OFFSET,
  474.       offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
  475.       NULL },

  476.     { ngx_string("proxy_ignore_headers"),
  477.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  478.       ngx_conf_set_bitmask_slot,
  479.       NGX_HTTP_LOC_CONF_OFFSET,
  480.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
  481.       &ngx_http_upstream_ignore_headers_masks },

  482.     { ngx_string("proxy_http_version"),
  483.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  484.       ngx_conf_set_enum_slot,
  485.       NGX_HTTP_LOC_CONF_OFFSET,
  486.       offsetof(ngx_http_proxy_loc_conf_t, http_version),
  487.       &ngx_http_proxy_http_version },

  488. #if (NGX_HTTP_SSL)

  489.     { ngx_string("proxy_ssl_session_reuse"),
  490.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  491.       ngx_conf_set_flag_slot,
  492.       NGX_HTTP_LOC_CONF_OFFSET,
  493.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
  494.       NULL },

  495.     { ngx_string("proxy_ssl_protocols"),
  496.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  497.       ngx_conf_set_bitmask_slot,
  498.       NGX_HTTP_LOC_CONF_OFFSET,
  499.       offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols),
  500.       &ngx_http_proxy_ssl_protocols },

  501.     { ngx_string("proxy_ssl_ciphers"),
  502.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  503.       ngx_conf_set_str_slot,
  504.       NGX_HTTP_LOC_CONF_OFFSET,
  505.       offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers),
  506.       NULL },

  507.     { ngx_string("proxy_ssl_name"),
  508.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  509.       ngx_http_set_complex_value_slot,
  510.       NGX_HTTP_LOC_CONF_OFFSET,
  511.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_name),
  512.       NULL },

  513.     { ngx_string("proxy_ssl_server_name"),
  514.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  515.       ngx_conf_set_flag_slot,
  516.       NGX_HTTP_LOC_CONF_OFFSET,
  517.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_server_name),
  518.       NULL },

  519.     { ngx_string("proxy_ssl_verify"),
  520.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  521.       ngx_conf_set_flag_slot,
  522.       NGX_HTTP_LOC_CONF_OFFSET,
  523.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify),
  524.       NULL },

  525.     { ngx_string("proxy_ssl_verify_depth"),
  526.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  527.       ngx_conf_set_num_slot,
  528.       NGX_HTTP_LOC_CONF_OFFSET,
  529.       offsetof(ngx_http_proxy_loc_conf_t, ssl_verify_depth),
  530.       NULL },

  531.     { ngx_string("proxy_ssl_trusted_certificate"),
  532.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  533.       ngx_conf_set_str_slot,
  534.       NGX_HTTP_LOC_CONF_OFFSET,
  535.       offsetof(ngx_http_proxy_loc_conf_t, ssl_trusted_certificate),
  536.       NULL },

  537.     { ngx_string("proxy_ssl_crl"),
  538.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  539.       ngx_conf_set_str_slot,
  540.       NGX_HTTP_LOC_CONF_OFFSET,
  541.       offsetof(ngx_http_proxy_loc_conf_t, ssl_crl),
  542.       NULL },

  543.     { ngx_string("proxy_ssl_certificate"),
  544.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  545.       ngx_conf_set_str_slot,
  546.       NGX_HTTP_LOC_CONF_OFFSET,
  547.       offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate),
  548.       NULL },

  549.     { ngx_string("proxy_ssl_certificate_key"),
  550.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  551.       ngx_conf_set_str_slot,
  552.       NGX_HTTP_LOC_CONF_OFFSET,
  553.       offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key),
  554.       NULL },

  555.     { ngx_string("proxy_ssl_password_file"),
  556.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  557.       ngx_http_proxy_ssl_password_file,
  558.       NGX_HTTP_LOC_CONF_OFFSET,
  559.       0,
  560.       NULL },

  561. #endif

  562.       ngx_null_command
  563. };


  564. static ngx_http_module_t  ngx_http_proxy_module_ctx = {
  565.     ngx_http_proxy_add_variables,          /* preconfiguration */
  566.     NULL,                                  /* postconfiguration */

  567.     ngx_http_proxy_create_main_conf,       /* create main configuration */
  568.     NULL,                                  /* init main configuration */

  569.     NULL,                                  /* create server configuration */
  570.     NULL,                                  /* merge server configuration */

  571.     ngx_http_proxy_create_loc_conf,        /* create location configuration */
  572.     ngx_http_proxy_merge_loc_conf          /* merge location configuration */
  573. };


  574. ngx_module_t  ngx_http_proxy_module = {
  575.     NGX_MODULE_V1,
  576.     &ngx_http_proxy_module_ctx,            /* module context */
  577.     ngx_http_proxy_commands,               /* module directives */
  578.     NGX_HTTP_MODULE,                       /* module type */
  579.     NULL,                                  /* init master */
  580.     NULL,                                  /* init module */
  581.     NULL,                                  /* init process */
  582.     NULL,                                  /* init thread */
  583.     NULL,                                  /* exit thread */
  584.     NULL,                                  /* exit process */
  585.     NULL,                                  /* exit master */
  586.     NGX_MODULE_V1_PADDING
  587. };


  588. static char  ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
  589. static char  ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;


  590. static ngx_keyval_t  ngx_http_proxy_headers[] = {
  591.     { ngx_string("Host"), ngx_string("$proxy_host") },
  592.     { ngx_string("Connection"), ngx_string("close") },
  593.     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
  594.     { ngx_string("TE"), ngx_string("") },
  595.     { ngx_string("Transfer-Encoding"), ngx_string("") },
  596.     { ngx_string("Keep-Alive"), ngx_string("") },
  597.     { ngx_string("Expect"), ngx_string("") },
  598.     { ngx_string("Upgrade"), ngx_string("") },
  599.     { ngx_null_string, ngx_null_string }
  600. };


  601. static ngx_str_t  ngx_http_proxy_hide_headers[] = {
  602.     ngx_string("Date"),
  603.     ngx_string("Server"),
  604.     ngx_string("X-Pad"),
  605.     ngx_string("X-Accel-Expires"),
  606.     ngx_string("X-Accel-Redirect"),
  607.     ngx_string("X-Accel-Limit-Rate"),
  608.     ngx_string("X-Accel-Buffering"),
  609.     ngx_string("X-Accel-Charset"),
  610.     ngx_null_string
  611. };


  612. #if (NGX_HTTP_CACHE)

  613. static ngx_keyval_t  ngx_http_proxy_cache_headers[] = {
  614.     { ngx_string("Host"), ngx_string("$proxy_host") },
  615.     { ngx_string("Connection"), ngx_string("close") },
  616.     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
  617.     { ngx_string("TE"), ngx_string("") },
  618.     { ngx_string("Transfer-Encoding"), ngx_string("") },
  619.     { ngx_string("Keep-Alive"), ngx_string("") },
  620.     { ngx_string("Expect"), ngx_string("") },
  621.     { ngx_string("Upgrade"), ngx_string("") },
  622.     { ngx_string("If-Modified-Since"),
  623.       ngx_string("$upstream_cache_last_modified") },
  624.     { ngx_string("If-Unmodified-Since"), ngx_string("") },
  625.     { ngx_string("If-None-Match"), ngx_string("$upstream_cache_etag") },
  626.     { ngx_string("If-Match"), ngx_string("") },
  627.     { ngx_string("Range"), ngx_string("") },
  628.     { ngx_string("If-Range"), ngx_string("") },
  629.     { ngx_null_string, ngx_null_string }
  630. };

  631. #endif


  632. static ngx_http_variable_t  ngx_http_proxy_vars[] = {

  633.     { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
  634.       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  635.     { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
  636.       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  637.     { ngx_string("proxy_add_x_forwarded_for"), NULL,
  638.       ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },

  639. #if 0
  640.     { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
  641. #endif

  642.     { ngx_string("proxy_internal_body_length"), NULL,
  643.       ngx_http_proxy_internal_body_length_variable, 0,
  644.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  645.     { ngx_null_string, NULL, NULL, 0, 0, 0 }
  646. };


  647. static ngx_path_init_t  ngx_http_proxy_temp_path = {
  648.     ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
  649. };


  650. static ngx_int_t
  651. ngx_http_proxy_handler(ngx_http_request_t *r)
  652. {
  653.     ngx_int_t                    rc;
  654.     ngx_http_upstream_t         *u;
  655.     ngx_http_proxy_ctx_t        *ctx;
  656.     ngx_http_proxy_loc_conf_t   *plcf;
  657. #if (NGX_HTTP_CACHE)
  658.     ngx_http_proxy_main_conf_t  *pmcf;
  659. #endif

  660.     if (ngx_http_upstream_create(r) != NGX_OK) {
  661.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  662.     }

  663.     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
  664.     if (ctx == NULL) {
  665.         return NGX_ERROR;
  666.     }

  667.     ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);

  668.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  669.     u = r->upstream;

  670.     if (plcf->proxy_lengths == NULL) {
  671.         ctx->vars = plcf->vars;
  672.         u->schema = plcf->vars.schema;
  673. #if (NGX_HTTP_SSL)
  674.         u->ssl = (plcf->upstream.ssl != NULL);
  675. #endif

  676.     } else {
  677.         if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
  678.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  679.         }
  680.     }

  681.     u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;

  682.     u->conf = &plcf->upstream;

  683. #if (NGX_HTTP_CACHE)
  684.     pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module);

  685.     u->caches = &pmcf->caches;
  686.     u->create_key = ngx_http_proxy_create_key;
  687. #endif

  688.     u->create_request = ngx_http_proxy_create_request;
  689.     u->reinit_request = ngx_http_proxy_reinit_request;
  690.     u->process_header = ngx_http_proxy_process_status_line;
  691.     u->abort_request = ngx_http_proxy_abort_request;
  692.     u->finalize_request = ngx_http_proxy_finalize_request;
  693.     r->state = 0;

  694.     if (plcf->redirects) {
  695.         u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
  696.     }

  697.     if (plcf->cookie_domains || plcf->cookie_paths) {
  698.         u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
  699.     }

  700.     u->buffering = plcf->upstream.buffering;

  701.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  702.     if (u->pipe == NULL) {
  703.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  704.     }

  705.     u->pipe->input_filter = ngx_http_proxy_copy_filter;
  706.     u->pipe->input_ctx = r;

  707.     u->input_filter_init = ngx_http_proxy_input_filter_init;
  708.     u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
  709.     u->input_filter_ctx = r;

  710.     u->accel = 1;

  711.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  712.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  713.         return rc;
  714.     }

  715.     return NGX_DONE;
  716. }


  717. static ngx_int_t
  718. ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
  719.     ngx_http_proxy_loc_conf_t *plcf)
  720. {
  721.     u_char               *p;
  722.     size_t                add;
  723.     u_short               port;
  724.     ngx_str_t             proxy;
  725.     ngx_url_t             url;
  726.     ngx_http_upstream_t  *u;

  727.     if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
  728.                             plcf->proxy_values->elts)
  729.         == NULL)
  730.     {
  731.         return NGX_ERROR;
  732.     }

  733.     if (proxy.len > 7
  734.         && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
  735.     {
  736.         add = 7;
  737.         port = 80;

  738. #if (NGX_HTTP_SSL)

  739.     } else if (proxy.len > 8
  740.                && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
  741.     {
  742.         add = 8;
  743.         port = 443;
  744.         r->upstream->ssl = 1;

  745. #endif

  746.     } else {
  747.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  748.                       "invalid URL prefix in \"%V\"", &proxy);
  749.         return NGX_ERROR;
  750.     }

  751.     u = r->upstream;

  752.     u->schema.len = add;
  753.     u->schema.data = proxy.data;

  754.     ngx_memzero(&url, sizeof(ngx_url_t));

  755.     url.url.len = proxy.len - add;
  756.     url.url.data = proxy.data + add;
  757.     url.default_port = port;
  758.     url.uri_part = 1;
  759.     url.no_resolve = 1;

  760.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  761.         if (url.err) {
  762.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  763.                           "%s in upstream \"%V\"", url.err, &url.url);
  764.         }

  765.         return NGX_ERROR;
  766.     }

  767.     if (url.uri.len) {
  768.         if (url.uri.data[0] == '?') {
  769.             p = ngx_pnalloc(r->pool, url.uri.len + 1);
  770.             if (p == NULL) {
  771.                 return NGX_ERROR;
  772.             }

  773.             *p++ = '/';
  774.             ngx_memcpy(p, url.uri.data, url.uri.len);

  775.             url.uri.len++;
  776.             url.uri.data = p - 1;
  777.         }
  778.     }

  779.     ctx->vars.key_start = u->schema;

  780.     ngx_http_proxy_set_vars(&url, &ctx->vars);

  781.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  782.     if (u->resolved == NULL) {
  783.         return NGX_ERROR;
  784.     }

  785.     if (url.addrs && url.addrs[0].sockaddr) {
  786.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  787.         u->resolved->socklen = url.addrs[0].socklen;
  788.         u->resolved->naddrs = 1;
  789.         u->resolved->host = url.addrs[0].name;

  790.     } else {
  791.         u->resolved->host = url.host;
  792.         u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
  793.         u->resolved->no_port = url.no_port;
  794.     }

  795.     return NGX_OK;
  796. }


  797. #if (NGX_HTTP_CACHE)

  798. static ngx_int_t
  799. ngx_http_proxy_create_key(ngx_http_request_t *r)
  800. {
  801.     size_t                      len, loc_len;
  802.     u_char                     *p;
  803.     uintptr_t                   escape;
  804.     ngx_str_t                  *key;
  805.     ngx_http_upstream_t        *u;
  806.     ngx_http_proxy_ctx_t       *ctx;
  807.     ngx_http_proxy_loc_conf_t  *plcf;

  808.     u = r->upstream;

  809.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  810.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  811.     key = ngx_array_push(&r->cache->keys);
  812.     if (key == NULL) {
  813.         return NGX_ERROR;
  814.     }

  815.     if (plcf->cache_key.value.data) {

  816.         if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
  817.             return NGX_ERROR;
  818.         }

  819.         return NGX_OK;
  820.     }

  821.     *key = ctx->vars.key_start;

  822.     key = ngx_array_push(&r->cache->keys);
  823.     if (key == NULL) {
  824.         return NGX_ERROR;
  825.     }

  826.     if (plcf->proxy_lengths && ctx->vars.uri.len) {

  827.         *key = ctx->vars.uri;
  828.         u->uri = ctx->vars.uri;

  829.         return NGX_OK;

  830.     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
  831.     {
  832.         *key = r->unparsed_uri;
  833.         u->uri = r->unparsed_uri;

  834.         return NGX_OK;
  835.     }

  836.     loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;

  837.     if (r->quoted_uri || r->internal) {
  838.         escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
  839.                                     r->uri.len - loc_len, NGX_ESCAPE_URI);
  840.     } else {
  841.         escape = 0;
  842.     }

  843.     len = ctx->vars.uri.len + r->uri.len - loc_len + escape
  844.           + sizeof("?") - 1 + r->args.len;

  845.     p = ngx_pnalloc(r->pool, len);
  846.     if (p == NULL) {
  847.         return NGX_ERROR;
  848.     }

  849.     key->data = p;

  850.     if (r->valid_location) {
  851.         p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
  852.     }

  853.     if (escape) {
  854.         ngx_escape_uri(p, r->uri.data + loc_len,
  855.                        r->uri.len - loc_len, NGX_ESCAPE_URI);
  856.         p += r->uri.len - loc_len + escape;

  857.     } else {
  858.         p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
  859.     }

  860.     if (r->args.len > 0) {
  861.         *p++ = '?';
  862.         p = ngx_copy(p, r->args.data, r->args.len);
  863.     }

  864.     key->len = p - key->data;
  865.     u->uri = *key;

  866.     return NGX_OK;
  867. }

  868. #endif


  869. static ngx_int_t
  870. ngx_http_proxy_create_request(ngx_http_request_t *r)
  871. {
  872.     size_t                        len, uri_len, loc_len, body_len;
  873.     uintptr_t                     escape;
  874.     ngx_buf_t                    *b;
  875.     ngx_str_t                     method;
  876.     ngx_uint_t                    i, unparsed_uri;
  877.     ngx_chain_t                  *cl, *body;
  878.     ngx_list_part_t              *part;
  879.     ngx_table_elt_t              *header;
  880.     ngx_http_upstream_t          *u;
  881.     ngx_http_proxy_ctx_t         *ctx;
  882.     ngx_http_script_code_pt       code;
  883.     ngx_http_proxy_headers_t     *headers;
  884.     ngx_http_script_engine_t      e, le;
  885.     ngx_http_proxy_loc_conf_t    *plcf;
  886.     ngx_http_script_len_code_pt   lcode;

  887.     u = r->upstream;

  888.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  889. #if (NGX_HTTP_CACHE)
  890.     headers = u->cacheable ? &plcf->headers_cache : &plcf->headers;
  891. #else
  892.     headers = &plcf->headers;
  893. #endif

  894.     if (u->method.len) {
  895.         /* HEAD was changed to GET to cache response */
  896.         method = u->method;
  897.         method.len++;

  898.     } else if (plcf->method.len) {
  899.         method = plcf->method;

  900.     } else {
  901.         method = r->method_name;
  902.         method.len++;
  903.     }

  904.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  905.     if (method.len == 5
  906.         && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
  907.     {
  908.         ctx->head = 1;
  909.     }

  910.     len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;

  911.     escape = 0;
  912.     loc_len = 0;
  913.     unparsed_uri = 0;

  914.     if (plcf->proxy_lengths && ctx->vars.uri.len) {
  915.         uri_len = ctx->vars.uri.len;

  916.     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
  917.     {
  918.         unparsed_uri = 1;
  919.         uri_len = r->unparsed_uri.len;

  920.     } else {
  921.         loc_len = (r->valid_location && ctx->vars.uri.len) ?
  922.                       plcf->location.len : 0;

  923.         if (r->quoted_uri || r->space_in_uri || r->internal) {
  924.             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
  925.                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
  926.         }

  927.         uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
  928.                   + sizeof("?") - 1 + r->args.len;
  929.     }

  930.     if (uri_len == 0) {
  931.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  932.                       "zero length URI to proxy");
  933.         return NGX_ERROR;
  934.     }

  935.     len += uri_len;

  936.     ngx_memzero(&le, sizeof(ngx_http_script_engine_t));

  937.     ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
  938.     ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);

  939.     if (plcf->body_lengths) {
  940.         le.ip = plcf->body_lengths->elts;
  941.         le.request = r;
  942.         le.flushed = 1;
  943.         body_len = 0;

  944.         while (*(uintptr_t *) le.ip) {
  945.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  946.             body_len += lcode(&le);
  947.         }

  948.         ctx->internal_body_length = body_len;
  949.         len += body_len;

  950.     } else {
  951.         ctx->internal_body_length = r->headers_in.content_length_n;
  952.     }

  953.     le.ip = headers->lengths->elts;
  954.     le.request = r;
  955.     le.flushed = 1;

  956.     while (*(uintptr_t *) le.ip) {
  957.         while (*(uintptr_t *) le.ip) {
  958.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  959.             len += lcode(&le);
  960.         }
  961.         le.ip += sizeof(uintptr_t);
  962.     }


  963.     if (plcf->upstream.pass_request_headers) {
  964.         part = &r->headers_in.headers.part;
  965.         header = part->elts;

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

  967.             if (i >= part->nelts) {
  968.                 if (part->next == NULL) {
  969.                     break;
  970.                 }

  971.                 part = part->next;
  972.                 header = part->elts;
  973.                 i = 0;
  974.             }

  975.             if (ngx_hash_find(&headers->hash, header[i].hash,
  976.                               header[i].lowcase_key, header[i].key.len))
  977.             {
  978.                 continue;
  979.             }

  980.             len += header[i].key.len + sizeof(": ") - 1
  981.                 + header[i].value.len + sizeof(CRLF) - 1;
  982.         }
  983.     }


  984.     b = ngx_create_temp_buf(r->pool, len);
  985.     if (b == NULL) {
  986.         return NGX_ERROR;
  987.     }

  988.     cl = ngx_alloc_chain_link(r->pool);
  989.     if (cl == NULL) {
  990.         return NGX_ERROR;
  991.     }

  992.     cl->buf = b;


  993.     /* the request line */

  994.     b->last = ngx_copy(b->last, method.data, method.len);

  995.     u->uri.data = b->last;

  996.     if (plcf->proxy_lengths && ctx->vars.uri.len) {
  997.         b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);

  998.     } else if (unparsed_uri) {
  999.         b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);

  1000.     } else {
  1001.         if (r->valid_location) {
  1002.             b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
  1003.         }

  1004.         if (escape) {
  1005.             ngx_escape_uri(b->last, r->uri.data + loc_len,
  1006.                            r->uri.len - loc_len, NGX_ESCAPE_URI);
  1007.             b->last += r->uri.len - loc_len + escape;

  1008.         } else {
  1009.             b->last = ngx_copy(b->last, r->uri.data + loc_len,
  1010.                                r->uri.len - loc_len);
  1011.         }

  1012.         if (r->args.len > 0) {
  1013.             *b->last++ = '?';
  1014.             b->last = ngx_copy(b->last, r->args.data, r->args.len);
  1015.         }
  1016.     }

  1017.     u->uri.len = b->last - u->uri.data;

  1018.     if (plcf->http_version == NGX_HTTP_VERSION_11) {
  1019.         b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
  1020.                              sizeof(ngx_http_proxy_version_11) - 1);

  1021.     } else {
  1022.         b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
  1023.                              sizeof(ngx_http_proxy_version) - 1);
  1024.     }

  1025.     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));

  1026.     e.ip = headers->values->elts;
  1027.     e.pos = b->last;
  1028.     e.request = r;
  1029.     e.flushed = 1;

  1030.     le.ip = headers->lengths->elts;

  1031.     while (*(uintptr_t *) le.ip) {
  1032.         lcode = *(ngx_http_script_len_code_pt *) le.ip;

  1033.         /* skip the header line name length */
  1034.         (void) lcode(&le);

  1035.         if (*(ngx_http_script_len_code_pt *) le.ip) {

  1036.             for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
  1037.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  1038.             }

  1039.             e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;

  1040.         } else {
  1041.             e.skip = 0;
  1042.         }

  1043.         le.ip += sizeof(uintptr_t);

  1044.         while (*(uintptr_t *) e.ip) {
  1045.             code = *(ngx_http_script_code_pt *) e.ip;
  1046.             code((ngx_http_script_engine_t *) &e);
  1047.         }
  1048.         e.ip += sizeof(uintptr_t);
  1049.     }

  1050.     b->last = e.pos;


  1051.     if (plcf->upstream.pass_request_headers) {
  1052.         part = &r->headers_in.headers.part;
  1053.         header = part->elts;

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

  1055.             if (i >= part->nelts) {
  1056.                 if (part->next == NULL) {
  1057.                     break;
  1058.                 }

  1059.                 part = part->next;
  1060.                 header = part->elts;
  1061.                 i = 0;
  1062.             }

  1063.             if (ngx_hash_find(&headers->hash, header[i].hash,
  1064.                               header[i].lowcase_key, header[i].key.len))
  1065.             {
  1066.                 continue;
  1067.             }

  1068.             b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);

  1069.             *b->last++ = ':'; *b->last++ = ' ';

  1070.             b->last = ngx_copy(b->last, header[i].value.data,
  1071.                                header[i].value.len);

  1072.             *b->last++ = CR; *b->last++ = LF;

  1073.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1074.                            "http proxy header: \"%V: %V\"",
  1075.                            &header[i].key, &header[i].value);
  1076.         }
  1077.     }


  1078.     /* add "\r\n" at the header end */
  1079.     *b->last++ = CR; *b->last++ = LF;

  1080.     if (plcf->body_values) {
  1081.         e.ip = plcf->body_values->elts;
  1082.         e.pos = b->last;

  1083.         while (*(uintptr_t *) e.ip) {
  1084.             code = *(ngx_http_script_code_pt *) e.ip;
  1085.             code((ngx_http_script_engine_t *) &e);
  1086.         }

  1087.         b->last = e.pos;
  1088.     }

  1089.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1090.                    "http proxy header:%N\"%*s\"",
  1091.                    (size_t) (b->last - b->pos), b->pos);

  1092.     if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {

  1093.         body = u->request_bufs;
  1094.         u->request_bufs = cl;

  1095.         while (body) {
  1096.             b = ngx_alloc_buf(r->pool);
  1097.             if (b == NULL) {
  1098.                 return NGX_ERROR;
  1099.             }

  1100.             ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));

  1101.             cl->next = ngx_alloc_chain_link(r->pool);
  1102.             if (cl->next == NULL) {
  1103.                 return NGX_ERROR;
  1104.             }

  1105.             cl = cl->next;
  1106.             cl->buf = b;

  1107.             body = body->next;
  1108.         }

  1109.     } else {
  1110.         u->request_bufs = cl;
  1111.     }

  1112.     b->flush = 1;
  1113.     cl->next = NULL;

  1114.     return NGX_OK;
  1115. }


  1116. static ngx_int_t
  1117. ngx_http_proxy_reinit_request(ngx_http_request_t *r)
  1118. {
  1119.     ngx_http_proxy_ctx_t  *ctx;

  1120.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1121.     if (ctx == NULL) {
  1122.         return NGX_OK;
  1123.     }

  1124.     ctx->status.code = 0;
  1125.     ctx->status.count = 0;
  1126.     ctx->status.start = NULL;
  1127.     ctx->status.end = NULL;
  1128.     ctx->chunked.state = 0;

  1129.     r->upstream->process_header = ngx_http_proxy_process_status_line;
  1130.     r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
  1131.     r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
  1132.     r->state = 0;

  1133.     return NGX_OK;
  1134. }


  1135. static ngx_int_t
  1136. ngx_http_proxy_process_status_line(ngx_http_request_t *r)
  1137. {
  1138.     size_t                 len;
  1139.     ngx_int_t              rc;
  1140.     ngx_http_upstream_t   *u;
  1141.     ngx_http_proxy_ctx_t  *ctx;

  1142.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1143.     if (ctx == NULL) {
  1144.         return NGX_ERROR;
  1145.     }

  1146.     u = r->upstream;

  1147.     rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);

  1148.     if (rc == NGX_AGAIN) {
  1149.         return rc;
  1150.     }

  1151.     if (rc == NGX_ERROR) {

  1152. #if (NGX_HTTP_CACHE)

  1153.         if (r->cache) {
  1154.             r->http_version = NGX_HTTP_VERSION_9;
  1155.             return NGX_OK;
  1156.         }

  1157. #endif

  1158.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1159.                       "upstream sent no valid HTTP/1.0 header");

  1160. #if 0
  1161.         if (u->accel) {
  1162.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1163.         }
  1164. #endif

  1165.         r->http_version = NGX_HTTP_VERSION_9;
  1166.         u->state->status = NGX_HTTP_OK;
  1167.         u->headers_in.connection_close = 1;

  1168.         return NGX_OK;
  1169.     }

  1170.     if (u->state && u->state->status == 0) {
  1171.         u->state->status = ctx->status.code;
  1172.     }

  1173.     u->headers_in.status_n = ctx->status.code;

  1174.     len = ctx->status.end - ctx->status.start;
  1175.     u->headers_in.status_line.len = len;

  1176.     u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
  1177.     if (u->headers_in.status_line.data == NULL) {
  1178.         return NGX_ERROR;
  1179.     }

  1180.     ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);

  1181.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1182.                    "http proxy status %ui \"%V\"",
  1183.                    u->headers_in.status_n, &u->headers_in.status_line);

  1184.     if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
  1185.         u->headers_in.connection_close = 1;
  1186.     }

  1187.     u->process_header = ngx_http_proxy_process_header;

  1188.     return ngx_http_proxy_process_header(r);
  1189. }


  1190. static ngx_int_t
  1191. ngx_http_proxy_process_header(ngx_http_request_t *r)
  1192. {
  1193.     ngx_int_t                       rc;
  1194.     ngx_table_elt_t                *h;
  1195.     ngx_http_upstream_t            *u;
  1196.     ngx_http_proxy_ctx_t           *ctx;
  1197.     ngx_http_upstream_header_t     *hh;
  1198.     ngx_http_upstream_main_conf_t  *umcf;

  1199.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1200.     for ( ;; ) {

  1201.         rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);

  1202.         if (rc == NGX_OK) {

  1203.             /* a header line has been parsed successfully */

  1204.             h = ngx_list_push(&r->upstream->headers_in.headers);
  1205.             if (h == NULL) {
  1206.                 return NGX_ERROR;
  1207.             }

  1208.             h->hash = r->header_hash;

  1209.             h->key.len = r->header_name_end - r->header_name_start;
  1210.             h->value.len = r->header_end - r->header_start;

  1211.             h->key.data = ngx_pnalloc(r->pool,
  1212.                                h->key.len + 1 + h->value.len + 1 + h->key.len);
  1213.             if (h->key.data == NULL) {
  1214.                 return NGX_ERROR;
  1215.             }

  1216.             h->value.data = h->key.data + h->key.len + 1;
  1217.             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;

  1218.             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  1219.             h->key.data[h->key.len] = '\0';
  1220.             ngx_memcpy(h->value.data, r->header_start, h->value.len);
  1221.             h->value.data[h->value.len] = '\0';

  1222.             if (h->key.len == r->lowcase_index) {
  1223.                 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);

  1224.             } else {
  1225.                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  1226.             }

  1227.             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
  1228.                                h->lowcase_key, h->key.len);

  1229.             if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
  1230.                 return NGX_ERROR;
  1231.             }

  1232.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1233.                            "http proxy header: \"%V: %V\"",
  1234.                            &h->key, &h->value);

  1235.             continue;
  1236.         }

  1237.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

  1238.             /* a whole header has been parsed successfully */

  1239.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1240.                            "http proxy header done");

  1241.             /*
  1242.              * if no "Server" and "Date" in header line,
  1243.              * then add the special empty headers
  1244.              */

  1245.             if (r->upstream->headers_in.server == NULL) {
  1246.                 h = ngx_list_push(&r->upstream->headers_in.headers);
  1247.                 if (h == NULL) {
  1248.                     return NGX_ERROR;
  1249.                 }

  1250.                 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
  1251.                                     ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');

  1252.                 ngx_str_set(&h->key, "Server");
  1253.                 ngx_str_null(&h->value);
  1254.                 h->lowcase_key = (u_char *) "server";
  1255.             }

  1256.             if (r->upstream->headers_in.date == NULL) {
  1257.                 h = ngx_list_push(&r->upstream->headers_in.headers);
  1258.                 if (h == NULL) {
  1259.                     return NGX_ERROR;
  1260.                 }

  1261.                 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');

  1262.                 ngx_str_set(&h->key, "Date");
  1263.                 ngx_str_null(&h->value);
  1264.                 h->lowcase_key = (u_char *) "date";
  1265.             }

  1266.             /* clear content length if response is chunked */

  1267.             u = r->upstream;

  1268.             if (u->headers_in.chunked) {
  1269.                 u->headers_in.content_length_n = -1;
  1270.             }

  1271.             /*
  1272.              * set u->keepalive if response has no body; this allows to keep
  1273.              * connections alive in case of r->header_only or X-Accel-Redirect
  1274.              */

  1275.             ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1276.             if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1277.                 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
  1278.                 || ctx->head
  1279.                 || (!u->headers_in.chunked
  1280.                     && u->headers_in.content_length_n == 0))
  1281.             {
  1282.                 u->keepalive = !u->headers_in.connection_close;
  1283.             }

  1284.             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
  1285.                 u->keepalive = 0;

  1286.                 if (r->headers_in.upgrade) {
  1287.                     u->upgrade = 1;
  1288.                 }
  1289.             }

  1290.             return NGX_OK;
  1291.         }

  1292.         if (rc == NGX_AGAIN) {
  1293.             return NGX_AGAIN;
  1294.         }

  1295.         /* there was error while a header line parsing */

  1296.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1297.                       "upstream sent invalid header");

  1298.         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1299.     }
  1300. }


  1301. static ngx_int_t
  1302. ngx_http_proxy_input_filter_init(void *data)
  1303. {
  1304.     ngx_http_request_t    *r = data;
  1305.     ngx_http_upstream_t   *u;
  1306.     ngx_http_proxy_ctx_t  *ctx;

  1307.     u = r->upstream;
  1308.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1309.     if (ctx == NULL) {
  1310.         return NGX_ERROR;
  1311.     }

  1312.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1313.                    "http proxy filter init s:%d h:%d c:%d l:%O",
  1314.                    u->headers_in.status_n, ctx->head, u->headers_in.chunked,
  1315.                    u->headers_in.content_length_n);

  1316.     /* as per RFC2616, 4.4 Message Length */

  1317.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1318.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
  1319.         || ctx->head)
  1320.     {
  1321.         /* 1xx, 204, and 304 and replies to HEAD requests */
  1322.         /* no 1xx since we don't send Expect and Upgrade */

  1323.         u->pipe->length = 0;
  1324.         u->length = 0;
  1325.         u->keepalive = !u->headers_in.connection_close;

  1326.     } else if (u->headers_in.chunked) {
  1327.         /* chunked */

  1328.         u->pipe->input_filter = ngx_http_proxy_chunked_filter;
  1329.         u->pipe->length = 3; /* "0" LF LF */

  1330.         u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
  1331.         u->length = 1;

  1332.     } else if (u->headers_in.content_length_n == 0) {
  1333.         /* empty body: special case as filter won't be called */

  1334.         u->pipe->length = 0;
  1335.         u->length = 0;
  1336.         u->keepalive = !u->headers_in.connection_close;

  1337.     } else {
  1338.         /* content length or connection close */

  1339.         u->pipe->length = u->headers_in.content_length_n;
  1340.         u->length = u->headers_in.content_length_n;
  1341.     }

  1342.     return NGX_OK;
  1343. }


  1344. static ngx_int_t
  1345. ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1346. {
  1347.     ngx_buf_t           *b;
  1348.     ngx_chain_t         *cl;
  1349.     ngx_http_request_t  *r;

  1350.     if (buf->pos == buf->last) {
  1351.         return NGX_OK;
  1352.     }

  1353.     cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1354.     if (cl == NULL) {
  1355.         return NGX_ERROR;
  1356.     }

  1357.     b = cl->buf;

  1358.     ngx_memcpy(b, buf, sizeof(ngx_buf_t));
  1359.     b->shadow = buf;
  1360.     b->tag = p->tag;
  1361.     b->last_shadow = 1;
  1362.     b->recycled = 1;
  1363.     buf->shadow = b;

  1364.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);

  1365.     if (p->in) {
  1366.         *p->last_in = cl;
  1367.     } else {
  1368.         p->in = cl;
  1369.     }
  1370.     p->last_in = &cl->next;

  1371.     if (p->length == -1) {
  1372.         return NGX_OK;
  1373.     }

  1374.     p->length -= b->last - b->pos;

  1375.     if (p->length == 0) {
  1376.         r = p->input_ctx;
  1377.         p->upstream_done = 1;
  1378.         r->upstream->keepalive = !r->upstream->headers_in.connection_close;

  1379.     } else if (p->length < 0) {
  1380.         r = p->input_ctx;
  1381.         p->upstream_done = 1;

  1382.         ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  1383.                       "upstream sent more data than specified in "
  1384.                       "\"Content-Length\" header");
  1385.     }

  1386.     return NGX_OK;
  1387. }


  1388. static ngx_int_t
  1389. ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1390. {
  1391.     ngx_int_t              rc;
  1392.     ngx_buf_t             *b, **prev;
  1393.     ngx_chain_t           *cl;
  1394.     ngx_http_request_t    *r;
  1395.     ngx_http_proxy_ctx_t  *ctx;

  1396.     if (buf->pos == buf->last) {
  1397.         return NGX_OK;
  1398.     }

  1399.     r = p->input_ctx;
  1400.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1401.     if (ctx == NULL) {
  1402.         return NGX_ERROR;
  1403.     }

  1404.     b = NULL;
  1405.     prev = &buf->shadow;

  1406.     for ( ;; ) {

  1407.         rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);

  1408.         if (rc == NGX_OK) {

  1409.             /* a chunk has been parsed successfully */

  1410.             cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1411.             if (cl == NULL) {
  1412.                 return NGX_ERROR;
  1413.             }

  1414.             b = cl->buf;

  1415.             ngx_memzero(b, sizeof(ngx_buf_t));

  1416.             b->pos = buf->pos;
  1417.             b->start = buf->start;
  1418.             b->end = buf->end;
  1419.             b->tag = p->tag;
  1420.             b->temporary = 1;
  1421.             b->recycled = 1;

  1422.             *prev = b;
  1423.             prev = &b->shadow;

  1424.             if (p->in) {
  1425.                 *p->last_in = cl;
  1426.             } else {
  1427.                 p->in = cl;
  1428.             }
  1429.             p->last_in = &cl->next;

  1430.             /* STUB */ b->num = buf->num;

  1431.             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
  1432.                            "input buf #%d %p", b->num, b->pos);

  1433.             if (buf->last - buf->pos >= ctx->chunked.size) {

  1434.                 buf->pos += (size_t) ctx->chunked.size;
  1435.                 b->last = buf->pos;
  1436.                 ctx->chunked.size = 0;

  1437.                 continue;
  1438.             }

  1439.             ctx->chunked.size -= buf->last - buf->pos;
  1440.             buf->pos = buf->last;
  1441.             b->last = buf->last;

  1442.             continue;
  1443.         }

  1444.         if (rc == NGX_DONE) {

  1445.             /* a whole response has been parsed successfully */

  1446.             p->upstream_done = 1;
  1447.             r->upstream->keepalive = !r->upstream->headers_in.connection_close;

  1448.             break;
  1449.         }

  1450.         if (rc == NGX_AGAIN) {

  1451.             /* set p->length, minimal amount of data we want to see */

  1452.             p->length = ctx->chunked.length;

  1453.             break;
  1454.         }

  1455.         /* invalid response */

  1456.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1457.                       "upstream sent invalid chunked response");

  1458.         return NGX_ERROR;
  1459.     }

  1460.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1461.                    "http proxy chunked state %d, length %d",
  1462.                    ctx->chunked.state, p->length);

  1463.     if (b) {
  1464.         b->shadow = buf;
  1465.         b->last_shadow = 1;

  1466.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
  1467.                        "input buf %p %z", b->pos, b->last - b->pos);

  1468.         return NGX_OK;
  1469.     }

  1470.     /* there is no data record in the buf, add it to free chain */

  1471.     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
  1472.         return NGX_ERROR;
  1473.     }

  1474.     return NGX_OK;
  1475. }


  1476. static ngx_int_t
  1477. ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
  1478. {
  1479.     ngx_http_request_t   *r = data;

  1480.     ngx_buf_t            *b;
  1481.     ngx_chain_t          *cl, **ll;
  1482.     ngx_http_upstream_t  *u;

  1483.     u = r->upstream;

  1484.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1485.         ll = &cl->next;
  1486.     }

  1487.     cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1488.     if (cl == NULL) {
  1489.         return NGX_ERROR;
  1490.     }

  1491.     *ll = cl;

  1492.     cl->buf->flush = 1;
  1493.     cl->buf->memory = 1;

  1494.     b = &u->buffer;

  1495.     cl->buf->pos = b->last;
  1496.     b->last += bytes;
  1497.     cl->buf->last = b->last;
  1498.     cl->buf->tag = u->output.tag;

  1499.     if (u->length == -1) {
  1500.         return NGX_OK;
  1501.     }

  1502.     u->length -= bytes;

  1503.     if (u->length == 0) {
  1504.         u->keepalive = !u->headers_in.connection_close;
  1505.     }

  1506.     return NGX_OK;
  1507. }


  1508. static ngx_int_t
  1509. ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
  1510. {
  1511.     ngx_http_request_t   *r = data;

  1512.     ngx_int_t              rc;
  1513.     ngx_buf_t             *b, *buf;
  1514.     ngx_chain_t           *cl, **ll;
  1515.     ngx_http_upstream_t   *u;
  1516.     ngx_http_proxy_ctx_t  *ctx;

  1517.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1518.     if (ctx == NULL) {
  1519.         return NGX_ERROR;
  1520.     }

  1521.     u = r->upstream;
  1522.     buf = &u->buffer;

  1523.     buf->pos = buf->last;
  1524.     buf->last += bytes;

  1525.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1526.         ll = &cl->next;
  1527.     }

  1528.     for ( ;; ) {

  1529.         rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);

  1530.         if (rc == NGX_OK) {

  1531.             /* a chunk has been parsed successfully */

  1532.             cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1533.             if (cl == NULL) {
  1534.                 return NGX_ERROR;
  1535.             }

  1536.             *ll = cl;
  1537.             ll = &cl->next;

  1538.             b = cl->buf;

  1539.             b->flush = 1;
  1540.             b->memory = 1;

  1541.             b->pos = buf->pos;
  1542.             b->tag = u->output.tag;

  1543.             if (buf->last - buf->pos >= ctx->chunked.size) {
  1544.                 buf->pos += (size_t) ctx->chunked.size;
  1545.                 b->last = buf->pos;
  1546.                 ctx->chunked.size = 0;

  1547.             } else {
  1548.                 ctx->chunked.size -= buf->last - buf->pos;
  1549.                 buf->pos = buf->last;
  1550.                 b->last = buf->last;
  1551.             }

  1552.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1553.                            "http proxy out buf %p %z",
  1554.                            b->pos, b->last - b->pos);

  1555.             continue;
  1556.         }

  1557.         if (rc == NGX_DONE) {

  1558.             /* a whole response has been parsed successfully */

  1559.             u->keepalive = !u->headers_in.connection_close;
  1560.             u->length = 0;

  1561.             break;
  1562.         }

  1563.         if (rc == NGX_AGAIN) {
  1564.             break;
  1565.         }

  1566.         /* invalid response */

  1567.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1568.                       "upstream sent invalid chunked response");

  1569.         return NGX_ERROR;
  1570.     }

  1571.     /* provide continuous buffer for subrequests in memory */

  1572.     if (r->subrequest_in_memory) {

  1573.         cl = u->out_bufs;

  1574.         if (cl) {
  1575.             buf->pos = cl->buf->pos;
  1576.         }

  1577.         buf->last = buf->pos;

  1578.         for (cl = u->out_bufs; cl; cl = cl->next) {
  1579.             ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1580.                            "http proxy in memory %p-%p %uz",
  1581.                            cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));

  1582.             if (buf->last == cl->buf->pos) {
  1583.                 buf->last = cl->buf->last;
  1584.                 continue;
  1585.             }

  1586.             buf->last = ngx_movemem(buf->last, cl->buf->pos,
  1587.                                     cl->buf->last - cl->buf->pos);

  1588.             cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
  1589.             cl->buf->last = buf->last;
  1590.         }
  1591.     }

  1592.     return NGX_OK;
  1593. }


  1594. static void
  1595. ngx_http_proxy_abort_request(ngx_http_request_t *r)
  1596. {
  1597.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1598.                    "abort http proxy request");

  1599.     return;
  1600. }


  1601. static void
  1602. ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  1603. {
  1604.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1605.                    "finalize http proxy request");

  1606.     return;
  1607. }


  1608. static ngx_int_t
  1609. ngx_http_proxy_host_variable(ngx_http_request_t *r,
  1610.     ngx_http_variable_value_t *v, uintptr_t data)
  1611. {
  1612.     ngx_http_proxy_ctx_t  *ctx;

  1613.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1614.     if (ctx == NULL) {
  1615.         v->not_found = 1;
  1616.         return NGX_OK;
  1617.     }

  1618.     v->len = ctx->vars.host_header.len;
  1619.     v->valid = 1;
  1620.     v->no_cacheable = 0;
  1621.     v->not_found = 0;
  1622.     v->data = ctx->vars.host_header.data;

  1623.     return NGX_OK;
  1624. }


  1625. static ngx_int_t
  1626. ngx_http_proxy_port_variable(ngx_http_request_t *r,
  1627.     ngx_http_variable_value_t *v, uintptr_t data)
  1628. {
  1629.     ngx_http_proxy_ctx_t  *ctx;

  1630.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1631.     if (ctx == NULL) {
  1632.         v->not_found = 1;
  1633.         return NGX_OK;
  1634.     }

  1635.     v->len = ctx->vars.port.len;
  1636.     v->valid = 1;
  1637.     v->no_cacheable = 0;
  1638.     v->not_found = 0;
  1639.     v->data = ctx->vars.port.data;

  1640.     return NGX_OK;
  1641. }


  1642. static ngx_int_t
  1643. ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
  1644.     ngx_http_variable_value_t *v, uintptr_t data)
  1645. {
  1646.     size_t             len;
  1647.     u_char            *p;
  1648.     ngx_uint_t         i, n;
  1649.     ngx_table_elt_t  **h;

  1650.     v->valid = 1;
  1651.     v->no_cacheable = 0;
  1652.     v->not_found = 0;

  1653.     n = r->headers_in.x_forwarded_for.nelts;
  1654.     h = r->headers_in.x_forwarded_for.elts;

  1655.     len = 0;

  1656.     for (i = 0; i < n; i++) {
  1657.         len += h[i]->value.len + sizeof(", ") - 1;
  1658.     }

  1659.     if (len == 0) {
  1660.         v->len = r->connection->addr_text.len;
  1661.         v->data = r->connection->addr_text.data;
  1662.         return NGX_OK;
  1663.     }

  1664.     len += r->connection->addr_text.len;

  1665.     p = ngx_pnalloc(r->pool, len);
  1666.     if (p == NULL) {
  1667.         return NGX_ERROR;
  1668.     }

  1669.     v->len = len;
  1670.     v->data = p;

  1671.     for (i = 0; i < n; i++) {
  1672.         p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
  1673.         *p++ = ','; *p++ = ' ';
  1674.     }

  1675.     ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);

  1676.     return NGX_OK;
  1677. }


  1678. static ngx_int_t
  1679. ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
  1680.     ngx_http_variable_value_t *v, uintptr_t data)
  1681. {
  1682.     ngx_http_proxy_ctx_t  *ctx;

  1683.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1684.     if (ctx == NULL || ctx->internal_body_length < 0) {
  1685.         v->not_found = 1;
  1686.         return NGX_OK;
  1687.     }

  1688.     v->valid = 1;
  1689.     v->no_cacheable = 0;
  1690.     v->not_found = 0;

  1691.     v->data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);

  1692.     if (v->data == NULL) {
  1693.         return NGX_ERROR;
  1694.     }

  1695.     v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;

  1696.     return NGX_OK;
  1697. }


  1698. static ngx_int_t
  1699. ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
  1700.     size_t prefix)
  1701. {
  1702.     size_t                      len;
  1703.     ngx_int_t                   rc;
  1704.     ngx_uint_t                  i;
  1705.     ngx_http_proxy_rewrite_t   *pr;
  1706.     ngx_http_proxy_loc_conf_t  *plcf;

  1707.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  1708.     pr = plcf->redirects->elts;

  1709.     if (pr == NULL) {
  1710.         return NGX_DECLINED;
  1711.     }

  1712.     len = h->value.len - prefix;

  1713.     for (i = 0; i < plcf->redirects->nelts; i++) {
  1714.         rc = pr[i].handler(r, h, prefix, len, &pr[i]);

  1715.         if (rc != NGX_DECLINED) {
  1716.             return rc;
  1717.         }
  1718.     }

  1719.     return NGX_DECLINED;
  1720. }


  1721. static ngx_int_t
  1722. ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
  1723. {
  1724.     size_t                      prefix;
  1725.     u_char                     *p;
  1726.     ngx_int_t                   rc, rv;
  1727.     ngx_http_proxy_loc_conf_t  *plcf;

  1728.     p = (u_char *) ngx_strchr(h->value.data, ';');
  1729.     if (p == NULL) {
  1730.         return NGX_DECLINED;
  1731.     }

  1732.     prefix = p + 1 - h->value.data;

  1733.     rv = NGX_DECLINED;

  1734.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  1735.     if (plcf->cookie_domains) {
  1736.         p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);

  1737.         if (p) {
  1738.             rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
  1739.                                                      plcf->cookie_domains);
  1740.             if (rc == NGX_ERROR) {
  1741.                 return NGX_ERROR;
  1742.             }

  1743.             if (rc != NGX_DECLINED) {
  1744.                 rv = rc;
  1745.             }
  1746.         }
  1747.     }

  1748.     if (plcf->cookie_paths) {
  1749.         p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);

  1750.         if (p) {
  1751.             rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
  1752.                                                      plcf->cookie_paths);
  1753.             if (rc == NGX_ERROR) {
  1754.                 return NGX_ERROR;
  1755.             }

  1756.             if (rc != NGX_DECLINED) {
  1757.                 rv = rc;
  1758.             }
  1759.         }
  1760.     }

  1761.     return rv;
  1762. }


  1763. static ngx_int_t
  1764. ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
  1765.     u_char *value, ngx_array_t *rewrites)
  1766. {
  1767.     size_t                     len, prefix;
  1768.     u_char                    *p;
  1769.     ngx_int_t                  rc;
  1770.     ngx_uint_t                 i;
  1771.     ngx_http_proxy_rewrite_t  *pr;

  1772.     prefix = value - h->value.data;

  1773.     p = (u_char *) ngx_strchr(value, ';');

  1774.     len = p ? (size_t) (p - value) : (h->value.len - prefix);

  1775.     pr = rewrites->elts;

  1776.     for (i = 0; i < rewrites->nelts; i++) {
  1777.         rc = pr[i].handler(r, h, prefix, len, &pr[i]);

  1778.         if (rc != NGX_DECLINED) {
  1779.             return rc;
  1780.         }
  1781.     }

  1782.     return NGX_DECLINED;
  1783. }


  1784. static ngx_int_t
  1785. ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
  1786.     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
  1787. {
  1788.     ngx_str_t  pattern, replacement;

  1789.     if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
  1790.         return NGX_ERROR;
  1791.     }

  1792.     if (pattern.len > len
  1793.         || ngx_rstrncmp(h->value.data + prefix, pattern.data,
  1794.                         pattern.len) != 0)
  1795.     {
  1796.         return NGX_DECLINED;
  1797.     }

  1798.     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
  1799.         return NGX_ERROR;
  1800.     }

  1801.     return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
  1802. }


  1803. #if (NGX_PCRE)

  1804. static ngx_int_t
  1805. ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
  1806.     size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
  1807. {
  1808.     ngx_str_t  pattern, replacement;

  1809.     pattern.len = len;
  1810.     pattern.data = h->value.data + prefix;

  1811.     if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
  1812.         return NGX_DECLINED;
  1813.     }

  1814.     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
  1815.         return NGX_ERROR;
  1816.     }

  1817.     if (prefix == 0 && h->value.len == len) {
  1818.         h->value = replacement;
  1819.         return NGX_OK;
  1820.     }

  1821.     return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
  1822. }

  1823. #endif


  1824. static ngx_int_t
  1825. ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
  1826.     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
  1827. {
  1828.     u_char     *p;
  1829.     ngx_str_t   pattern, replacement;

  1830.     if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
  1831.         return NGX_ERROR;
  1832.     }

  1833.     p = h->value.data + prefix;

  1834.     if (p[0] == '.') {
  1835.         p++;
  1836.         prefix++;
  1837.         len--;
  1838.     }

  1839.     if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
  1840.         return NGX_DECLINED;
  1841.     }

  1842.     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
  1843.         return NGX_ERROR;
  1844.     }

  1845.     return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
  1846. }


  1847. static ngx_int_t
  1848. ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
  1849.     size_t len, ngx_str_t *replacement)
  1850. {
  1851.     u_char  *p, *data;
  1852.     size_t   new_len;

  1853.     new_len = replacement->len + h->value.len - len;

  1854.     if (replacement->len > len) {

  1855.         data = ngx_pnalloc(r->pool, new_len + 1);
  1856.         if (data == NULL) {
  1857.             return NGX_ERROR;
  1858.         }

  1859.         p = ngx_copy(data, h->value.data, prefix);
  1860.         p = ngx_copy(p, replacement->data, replacement->len);

  1861.         ngx_memcpy(p, h->value.data + prefix + len,
  1862.                    h->value.len - len - prefix + 1);

  1863.         h->value.data = data;

  1864.     } else {
  1865.         p = ngx_copy(h->value.data + prefix, replacement->data,
  1866.                      replacement->len);

  1867.         ngx_memmove(p, h->value.data + prefix + len,
  1868.                     h->value.len - len - prefix + 1);
  1869.     }

  1870.     h->value.len = new_len;

  1871.     return NGX_OK;
  1872. }


  1873. static ngx_int_t
  1874. ngx_http_proxy_add_variables(ngx_conf_t *cf)
  1875. {
  1876.     ngx_http_variable_t  *var, *v;

  1877.     for (v = ngx_http_proxy_vars; v->name.len; v++) {
  1878.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  1879.         if (var == NULL) {
  1880.             return NGX_ERROR;
  1881.         }

  1882.         var->get_handler = v->get_handler;
  1883.         var->data = v->data;
  1884.     }

  1885.     return NGX_OK;
  1886. }


  1887. static void *
  1888. ngx_http_proxy_create_main_conf(ngx_conf_t *cf)
  1889. {
  1890.     ngx_http_proxy_main_conf_t  *conf;

  1891.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_main_conf_t));
  1892.     if (conf == NULL) {
  1893.         return NULL;
  1894.     }

  1895. #if (NGX_HTTP_CACHE)
  1896.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  1897.                        sizeof(ngx_http_file_cache_t *))
  1898.         != NGX_OK)
  1899.     {
  1900.         return NULL;
  1901.     }
  1902. #endif

  1903.     return conf;
  1904. }


  1905. static void *
  1906. ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
  1907. {
  1908.     ngx_http_proxy_loc_conf_t  *conf;

  1909.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
  1910.     if (conf == NULL) {
  1911.         return NULL;
  1912.     }

  1913.     /*
  1914.      * set by ngx_pcalloc():
  1915.      *
  1916.      *     conf->upstream.bufs.num = 0;
  1917.      *     conf->upstream.ignore_headers = 0;
  1918.      *     conf->upstream.next_upstream = 0;
  1919.      *     conf->upstream.cache_zone = NULL;
  1920.      *     conf->upstream.cache_use_stale = 0;
  1921.      *     conf->upstream.cache_methods = 0;
  1922.      *     conf->upstream.temp_path = NULL;
  1923.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  1924.      *     conf->upstream.uri = { 0, NULL };
  1925.      *     conf->upstream.location = NULL;
  1926.      *     conf->upstream.store_lengths = NULL;
  1927.      *     conf->upstream.store_values = NULL;
  1928.      *     conf->upstream.ssl_name = NULL;
  1929.      *
  1930.      *     conf->method = { 0, NULL };
  1931.      *     conf->headers_source = NULL;
  1932.      *     conf->headers.lengths = NULL;
  1933.      *     conf->headers.values = NULL;
  1934.      *     conf->headers.hash = { NULL, 0 };
  1935.      *     conf->headers_cache.lengths = NULL;
  1936.      *     conf->headers_cache.values = NULL;
  1937.      *     conf->headers_cache.hash = { NULL, 0 };
  1938.      *     conf->body_lengths = NULL;
  1939.      *     conf->body_values = NULL;
  1940.      *     conf->body_source = { 0, NULL };
  1941.      *     conf->redirects = NULL;
  1942.      *     conf->ssl = 0;
  1943.      *     conf->ssl_protocols = 0;
  1944.      *     conf->ssl_ciphers = { 0, NULL };
  1945.      *     conf->ssl_trusted_certificate = { 0, NULL };
  1946.      *     conf->ssl_crl = { 0, NULL };
  1947.      *     conf->ssl_certificate = { 0, NULL };
  1948.      *     conf->ssl_certificate_key = { 0, NULL };
  1949.      */

  1950.     conf->upstream.store = NGX_CONF_UNSET;
  1951.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  1952.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  1953.     conf->upstream.buffering = NGX_CONF_UNSET;
  1954.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  1955.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  1956.     conf->upstream.local = NGX_CONF_UNSET_PTR;

  1957.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  1958.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  1959.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  1960.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  1961.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  1962.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  1963.     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;

  1964.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  1965.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  1966.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  1967.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  1968.     conf->upstream.pass_request_body = NGX_CONF_UNSET;

  1969. #if (NGX_HTTP_CACHE)
  1970.     conf->upstream.cache = NGX_CONF_UNSET;
  1971.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  1972.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  1973.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  1974.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  1975.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  1976.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  1977.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  1978.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  1979. #endif

  1980.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  1981.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  1982.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  1983. #if (NGX_HTTP_SSL)
  1984.     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
  1985.     conf->upstream.ssl_server_name = NGX_CONF_UNSET;
  1986.     conf->upstream.ssl_verify = NGX_CONF_UNSET;
  1987.     conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
  1988.     conf->ssl_passwords = NGX_CONF_UNSET_PTR;
  1989. #endif

  1990.     /* "proxy_cyclic_temp_file" is disabled */
  1991.     conf->upstream.cyclic_temp_file = 0;

  1992.     conf->redirect = NGX_CONF_UNSET;
  1993.     conf->upstream.change_buffering = 1;

  1994.     conf->cookie_domains = NGX_CONF_UNSET_PTR;
  1995.     conf->cookie_paths = NGX_CONF_UNSET_PTR;

  1996.     conf->http_version = NGX_CONF_UNSET_UINT;

  1997.     conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
  1998.     conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;

  1999.     ngx_str_set(&conf->upstream.module, "proxy");

  2000.     return conf;
  2001. }


  2002. static char *
  2003. ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  2004. {
  2005.     ngx_http_proxy_loc_conf_t *prev = parent;
  2006.     ngx_http_proxy_loc_conf_t *conf = child;

  2007.     u_char                     *p;
  2008.     size_t                      size;
  2009.     ngx_int_t                   rc;
  2010.     ngx_hash_init_t             hash;
  2011.     ngx_http_core_loc_conf_t   *clcf;
  2012.     ngx_http_proxy_rewrite_t   *pr;
  2013.     ngx_http_script_compile_t   sc;

  2014. #if (NGX_HTTP_CACHE)

  2015.     if (conf->upstream.store > 0) {
  2016.         conf->upstream.cache = 0;
  2017.     }

  2018.     if (conf->upstream.cache > 0) {
  2019.         conf->upstream.store = 0;
  2020.     }

  2021. #endif

  2022.     if (conf->upstream.store == NGX_CONF_UNSET) {
  2023.         ngx_conf_merge_value(conf->upstream.store,
  2024.                               prev->upstream.store, 0);

  2025.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  2026.         conf->upstream.store_values = prev->upstream.store_values;
  2027.     }

  2028.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  2029.                               prev->upstream.store_access, 0600);

  2030.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  2031.                               prev->upstream.next_upstream_tries, 0);

  2032.     ngx_conf_merge_value(conf->upstream.buffering,
  2033.                               prev->upstream.buffering, 1);

  2034.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  2035.                               prev->upstream.ignore_client_abort, 0);

  2036.     ngx_conf_merge_value(conf->upstream.force_ranges,
  2037.                               prev->upstream.force_ranges, 0);

  2038.     ngx_conf_merge_ptr_value(conf->upstream.local,
  2039.                               prev->upstream.local, NULL);

  2040.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  2041.                               prev->upstream.connect_timeout, 60000);

  2042.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  2043.                               prev->upstream.send_timeout, 60000);

  2044.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  2045.                               prev->upstream.read_timeout, 60000);

  2046.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  2047.                               prev->upstream.next_upstream_timeout, 0);

  2048.     ngx_conf_merge_size_value(conf->upstream.send_lowat,
  2049.                               prev->upstream.send_lowat, 0);

  2050.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  2051.                               prev->upstream.buffer_size,
  2052.                               (size_t) ngx_pagesize);

  2053.     ngx_conf_merge_size_value(conf->upstream.limit_rate,
  2054.                               prev->upstream.limit_rate, 0);

  2055.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  2056.                               8, ngx_pagesize);

  2057.     if (conf->upstream.bufs.num < 2) {
  2058.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2059.                            "there must be at least 2 \"proxy_buffers\"");
  2060.         return NGX_CONF_ERROR;
  2061.     }


  2062.     size = conf->upstream.buffer_size;
  2063.     if (size < conf->upstream.bufs.size) {
  2064.         size = conf->upstream.bufs.size;
  2065.     }


  2066.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  2067.                               prev->upstream.busy_buffers_size_conf,
  2068.                               NGX_CONF_UNSET_SIZE);

  2069.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  2070.         conf->upstream.busy_buffers_size = 2 * size;
  2071.     } else {
  2072.         conf->upstream.busy_buffers_size =
  2073.                                          conf->upstream.busy_buffers_size_conf;
  2074.     }

  2075.     if (conf->upstream.busy_buffers_size < size) {
  2076.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2077.              "\"proxy_busy_buffers_size\" must be equal to or greater than "
  2078.              "the maximum of the value of \"proxy_buffer_size\" and "
  2079.              "one of the \"proxy_buffers\"");

  2080.         return NGX_CONF_ERROR;
  2081.     }

  2082.     if (conf->upstream.busy_buffers_size
  2083.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  2084.     {
  2085.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2086.              "\"proxy_busy_buffers_size\" must be less than "
  2087.              "the size of all \"proxy_buffers\" minus one buffer");

  2088.         return NGX_CONF_ERROR;
  2089.     }


  2090.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  2091.                               prev->upstream.temp_file_write_size_conf,
  2092.                               NGX_CONF_UNSET_SIZE);

  2093.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  2094.         conf->upstream.temp_file_write_size = 2 * size;
  2095.     } else {
  2096.         conf->upstream.temp_file_write_size =
  2097.                                       conf->upstream.temp_file_write_size_conf;
  2098.     }

  2099.     if (conf->upstream.temp_file_write_size < size) {
  2100.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2101.              "\"proxy_temp_file_write_size\" must be equal to or greater "
  2102.              "than the maximum of the value of \"proxy_buffer_size\" and "
  2103.              "one of the \"proxy_buffers\"");

  2104.         return NGX_CONF_ERROR;
  2105.     }

  2106.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  2107.                               prev->upstream.max_temp_file_size_conf,
  2108.                               NGX_CONF_UNSET_SIZE);

  2109.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  2110.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  2111.     } else {
  2112.         conf->upstream.max_temp_file_size =
  2113.                                         conf->upstream.max_temp_file_size_conf;
  2114.     }

  2115.     if (conf->upstream.max_temp_file_size != 0
  2116.         && conf->upstream.max_temp_file_size < size)
  2117.     {
  2118.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2119.              "\"proxy_max_temp_file_size\" must be equal to zero to disable "
  2120.              "temporary files usage or must be equal to or greater than "
  2121.              "the maximum of the value of \"proxy_buffer_size\" and "
  2122.              "one of the \"proxy_buffers\"");

  2123.         return NGX_CONF_ERROR;
  2124.     }


  2125.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  2126.                               prev->upstream.ignore_headers,
  2127.                               NGX_CONF_BITMASK_SET);


  2128.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  2129.                               prev->upstream.next_upstream,
  2130.                               (NGX_CONF_BITMASK_SET
  2131.                                |NGX_HTTP_UPSTREAM_FT_ERROR
  2132.                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  2133.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  2134.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  2135.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  2136.     }

  2137.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  2138.                               prev->upstream.temp_path,
  2139.                               &ngx_http_proxy_temp_path)
  2140.         != NGX_OK)
  2141.     {
  2142.         return NGX_CONF_ERROR;
  2143.     }


  2144. #if (NGX_HTTP_CACHE)

  2145.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  2146.         ngx_conf_merge_value(conf->upstream.cache,
  2147.                               prev->upstream.cache, 0);

  2148.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  2149.         conf->upstream.cache_value = prev->upstream.cache_value;
  2150.     }

  2151.     if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
  2152.         ngx_shm_zone_t  *shm_zone;

  2153.         shm_zone = conf->upstream.cache_zone;

  2154.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2155.                            "\"proxy_cache\" zone \"%V\" is unknown",
  2156.                            &shm_zone->shm.name);

  2157.         return NGX_CONF_ERROR;
  2158.     }

  2159.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  2160.                               prev->upstream.cache_min_uses, 1);

  2161.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  2162.                               prev->upstream.cache_use_stale,
  2163.                               (NGX_CONF_BITMASK_SET
  2164.                                |NGX_HTTP_UPSTREAM_FT_OFF));

  2165.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
  2166.         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
  2167.                                          |NGX_HTTP_UPSTREAM_FT_OFF;
  2168.     }

  2169.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  2170.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  2171.     }

  2172.     if (conf->upstream.cache_methods == 0) {
  2173.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  2174.     }

  2175.     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;

  2176.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  2177.                              prev->upstream.cache_bypass, NULL);

  2178.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  2179.                              prev->upstream.no_cache, NULL);

  2180.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  2181.                              prev->upstream.cache_valid, NULL);

  2182.     if (conf->cache_key.value.data == NULL) {
  2183.         conf->cache_key = prev->cache_key;
  2184.     }

  2185.     ngx_conf_merge_value(conf->upstream.cache_lock,
  2186.                               prev->upstream.cache_lock, 0);

  2187.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  2188.                               prev->upstream.cache_lock_timeout, 5000);

  2189.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  2190.                               prev->upstream.cache_lock_age, 5000);

  2191.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  2192.                               prev->upstream.cache_revalidate, 0);

  2193. #endif

  2194.     ngx_conf_merge_str_value(conf->method, prev->method, "");

  2195.     if (conf->method.len
  2196.         && conf->method.data[conf->method.len - 1] != ' ')
  2197.     {
  2198.         conf->method.data[conf->method.len] = ' ';
  2199.         conf->method.len++;
  2200.     }

  2201.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  2202.                               prev->upstream.pass_request_headers, 1);
  2203.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  2204.                               prev->upstream.pass_request_body, 1);

  2205.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  2206.                               prev->upstream.intercept_errors, 0);

  2207. #if (NGX_HTTP_SSL)

  2208.     ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
  2209.                               prev->upstream.ssl_session_reuse, 1);

  2210.     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
  2211.                                  (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3
  2212.                                   |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
  2213.                                   |NGX_SSL_TLSv1_2));

  2214.     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
  2215.                              "DEFAULT");

  2216.     if (conf->upstream.ssl_name == NULL) {
  2217.         conf->upstream.ssl_name = prev->upstream.ssl_name;
  2218.     }

  2219.     ngx_conf_merge_value(conf->upstream.ssl_server_name,
  2220.                               prev->upstream.ssl_server_name, 0);
  2221.     ngx_conf_merge_value(conf->upstream.ssl_verify,
  2222.                               prev->upstream.ssl_verify, 0);
  2223.     ngx_conf_merge_uint_value(conf->ssl_verify_depth,
  2224.                               prev->ssl_verify_depth, 1);
  2225.     ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
  2226.                               prev->ssl_trusted_certificate, "");
  2227.     ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");

  2228.     ngx_conf_merge_str_value(conf->ssl_certificate,
  2229.                               prev->ssl_certificate, "");
  2230.     ngx_conf_merge_str_value(conf->ssl_certificate_key,
  2231.                               prev->ssl_certificate_key, "");
  2232.     ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);

  2233.     if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
  2234.         return NGX_CONF_ERROR;
  2235.     }

  2236. #endif

  2237.     ngx_conf_merge_value(conf->redirect, prev->redirect, 1);

  2238.     if (conf->redirect) {

  2239.         if (conf->redirects == NULL) {
  2240.             conf->redirects = prev->redirects;
  2241.         }

  2242.         if (conf->redirects == NULL && conf->url.data) {

  2243.             conf->redirects = ngx_array_create(cf->pool, 1,
  2244.                                              sizeof(ngx_http_proxy_rewrite_t));
  2245.             if (conf->redirects == NULL) {
  2246.                 return NGX_CONF_ERROR;
  2247.             }

  2248.             pr = ngx_array_push(conf->redirects);
  2249.             if (pr == NULL) {
  2250.                 return NGX_CONF_ERROR;
  2251.             }

  2252.             ngx_memzero(&pr->pattern.complex,
  2253.                         sizeof(ngx_http_complex_value_t));

  2254.             ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));

  2255.             pr->handler = ngx_http_proxy_rewrite_complex_handler;

  2256.             if (conf->vars.uri.len) {
  2257.                 pr->pattern.complex.value = conf->url;
  2258.                 pr->replacement.value = conf->location;

  2259.             } else {
  2260.                 pr->pattern.complex.value.len = conf->url.len
  2261.                                                 + sizeof("/") - 1;

  2262.                 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
  2263.                 if (p == NULL) {
  2264.                     return NGX_CONF_ERROR;
  2265.                 }

  2266.                 pr->pattern.complex.value.data = p;

  2267.                 p = ngx_cpymem(p, conf->url.data, conf->url.len);
  2268.                 *p = '/';

  2269.                 ngx_str_set(&pr->replacement.value, "/");
  2270.             }
  2271.         }
  2272.     }

  2273.     ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);

  2274.     ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);

  2275.     ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
  2276.                               NGX_HTTP_VERSION_10);

  2277.     ngx_conf_merge_uint_value(conf->headers_hash_max_size,
  2278.                               prev->headers_hash_max_size, 512);

  2279.     ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
  2280.                               prev->headers_hash_bucket_size, 64);

  2281.     conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
  2282.                                                ngx_cacheline_size);

  2283.     hash.max_size = conf->headers_hash_max_size;
  2284.     hash.bucket_size = conf->headers_hash_bucket_size;
  2285.     hash.name = "proxy_headers_hash";

  2286.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  2287.             &prev->upstream, ngx_http_proxy_hide_headers, &hash)
  2288.         != NGX_OK)
  2289.     {
  2290.         return NGX_CONF_ERROR;
  2291.     }

  2292.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2293.     if (clcf->noname
  2294.         && conf->upstream.upstream == NULL && conf->proxy_lengths == NULL)
  2295.     {
  2296.         conf->upstream.upstream = prev->upstream.upstream;
  2297.         conf->location = prev->location;
  2298.         conf->vars = prev->vars;

  2299.         conf->proxy_lengths = prev->proxy_lengths;
  2300.         conf->proxy_values = prev->proxy_values;

  2301. #if (NGX_HTTP_SSL)
  2302.         conf->upstream.ssl = prev->upstream.ssl;
  2303. #endif
  2304.     }

  2305.     if (clcf->lmt_excpt && clcf->handler == NULL
  2306.         && (conf->upstream.upstream || conf->proxy_lengths))
  2307.     {
  2308.         clcf->handler = ngx_http_proxy_handler;
  2309.     }

  2310.     if (conf->body_source.data == NULL) {
  2311.         conf->body_flushes = prev->body_flushes;
  2312.         conf->body_source = prev->body_source;
  2313.         conf->body_lengths = prev->body_lengths;
  2314.         conf->body_values = prev->body_values;
  2315.     }

  2316.     if (conf->body_source.data && conf->body_lengths == NULL) {

  2317.         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

  2318.         sc.cf = cf;
  2319.         sc.source = &conf->body_source;
  2320.         sc.flushes = &conf->body_flushes;
  2321.         sc.lengths = &conf->body_lengths;
  2322.         sc.values = &conf->body_values;
  2323.         sc.complete_lengths = 1;
  2324.         sc.complete_values = 1;

  2325.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2326.             return NGX_CONF_ERROR;
  2327.         }
  2328.     }

  2329.     if (conf->headers_source == NULL) {
  2330.         conf->headers = prev->headers;
  2331. #if (NGX_HTTP_CACHE)
  2332.         conf->headers_cache = prev->headers_cache;
  2333. #endif
  2334.         conf->headers_source = prev->headers_source;
  2335.     }

  2336.     rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers,
  2337.                                      ngx_http_proxy_headers);
  2338.     if (rc != NGX_OK) {
  2339.         return NGX_CONF_ERROR;
  2340.     }

  2341. #if (NGX_HTTP_CACHE)

  2342.     if (conf->upstream.cache) {
  2343.         rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers_cache,
  2344.                                          ngx_http_proxy_cache_headers);
  2345.         if (rc != NGX_OK) {
  2346.             return NGX_CONF_ERROR;
  2347.         }
  2348.     }

  2349. #endif

  2350.     return NGX_CONF_OK;
  2351. }


  2352. static ngx_int_t
  2353. ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
  2354.     ngx_http_proxy_headers_t *headers, ngx_keyval_t *default_headers)
  2355. {
  2356.     u_char                       *p;
  2357.     size_t                        size;
  2358.     uintptr_t                    *code;
  2359.     ngx_uint_t                    i;
  2360.     ngx_array_t                   headers_names, headers_merged;
  2361.     ngx_keyval_t                 *src, *s, *h;
  2362.     ngx_hash_key_t               *hk;
  2363.     ngx_hash_init_t               hash;
  2364.     ngx_http_script_compile_t     sc;
  2365.     ngx_http_script_copy_code_t  *copy;

  2366.     if (headers->hash.buckets) {
  2367.         return NGX_OK;
  2368.     }

  2369.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  2370.         != NGX_OK)
  2371.     {
  2372.         return NGX_ERROR;
  2373.     }

  2374.     if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
  2375.         != NGX_OK)
  2376.     {
  2377.         return NGX_ERROR;
  2378.     }

  2379.     if (conf->headers_source == NULL) {
  2380.         conf->headers_source = ngx_array_create(cf->pool, 4,
  2381.                                                 sizeof(ngx_keyval_t));
  2382.         if (conf->headers_source == NULL) {
  2383.             return NGX_ERROR;
  2384.         }
  2385.     }

  2386.     headers->lengths = ngx_array_create(cf->pool, 64, 1);
  2387.     if (headers->lengths == NULL) {
  2388.         return NGX_ERROR;
  2389.     }

  2390.     headers->values = ngx_array_create(cf->pool, 512, 1);
  2391.     if (headers->values == NULL) {
  2392.         return NGX_ERROR;
  2393.     }

  2394.     src = conf->headers_source->elts;
  2395.     for (i = 0; i < conf->headers_source->nelts; i++) {

  2396.         s = ngx_array_push(&headers_merged);
  2397.         if (s == NULL) {
  2398.             return NGX_ERROR;
  2399.         }

  2400.         *s = src[i];
  2401.     }

  2402.     h = default_headers;

  2403.     while (h->key.len) {

  2404.         src = headers_merged.elts;
  2405.         for (i = 0; i < headers_merged.nelts; i++) {
  2406.             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  2407.                 goto next;
  2408.             }
  2409.         }

  2410.         s = ngx_array_push(&headers_merged);
  2411.         if (s == NULL) {
  2412.             return NGX_ERROR;
  2413.         }

  2414.         *s = *h;

  2415.     next:

  2416.         h++;
  2417.     }


  2418.     src = headers_merged.elts;
  2419.     for (i = 0; i < headers_merged.nelts; i++) {

  2420.         hk = ngx_array_push(&headers_names);
  2421.         if (hk == NULL) {
  2422.             return NGX_ERROR;
  2423.         }

  2424.         hk->key = src[i].key;
  2425.         hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
  2426.         hk->value = (void *) 1;

  2427.         if (src[i].value.len == 0) {
  2428.             continue;
  2429.         }

  2430.         if (ngx_http_script_variables_count(&src[i].value) == 0) {
  2431.             copy = ngx_array_push_n(headers->lengths,
  2432.                                     sizeof(ngx_http_script_copy_code_t));
  2433.             if (copy == NULL) {
  2434.                 return NGX_ERROR;
  2435.             }

  2436.             copy->code = (ngx_http_script_code_pt)
  2437.                                                  ngx_http_script_copy_len_code;
  2438.             copy->len = src[i].key.len + sizeof(": ") - 1
  2439.                         + src[i].value.len + sizeof(CRLF) - 1;


  2440.             size = (sizeof(ngx_http_script_copy_code_t)
  2441.                        + src[i].key.len + sizeof(": ") - 1
  2442.                        + src[i].value.len + sizeof(CRLF) - 1
  2443.                        + sizeof(uintptr_t) - 1)
  2444.                     & ~(sizeof(uintptr_t) - 1);

  2445.             copy = ngx_array_push_n(headers->values, size);
  2446.             if (copy == NULL) {
  2447.                 return NGX_ERROR;
  2448.             }

  2449.             copy->code = ngx_http_script_copy_code;
  2450.             copy->len = src[i].key.len + sizeof(": ") - 1
  2451.                         + src[i].value.len + sizeof(CRLF) - 1;

  2452.             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);

  2453.             p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
  2454.             *p++ = ':'; *p++ = ' ';
  2455.             p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
  2456.             *p++ = CR; *p = LF;

  2457.         } else {
  2458.             copy = ngx_array_push_n(headers->lengths,
  2459.                                     sizeof(ngx_http_script_copy_code_t));
  2460.             if (copy == NULL) {
  2461.                 return NGX_ERROR;
  2462.             }

  2463.             copy->code = (ngx_http_script_code_pt)
  2464.                                                  ngx_http_script_copy_len_code;
  2465.             copy->len = src[i].key.len + sizeof(": ") - 1;


  2466.             size = (sizeof(ngx_http_script_copy_code_t)
  2467.                     + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
  2468.                     & ~(sizeof(uintptr_t) - 1);

  2469.             copy = ngx_array_push_n(headers->values, size);
  2470.             if (copy == NULL) {
  2471.                 return NGX_ERROR;
  2472.             }

  2473.             copy->code = ngx_http_script_copy_code;
  2474.             copy->len = src[i].key.len + sizeof(": ") - 1;

  2475.             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
  2476.             p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
  2477.             *p++ = ':'; *p = ' ';


  2478.             ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

  2479.             sc.cf = cf;
  2480.             sc.source = &src[i].value;
  2481.             sc.flushes = &headers->flushes;
  2482.             sc.lengths = &headers->lengths;
  2483.             sc.values = &headers->values;

  2484.             if (ngx_http_script_compile(&sc) != NGX_OK) {
  2485.                 return NGX_ERROR;
  2486.             }


  2487.             copy = ngx_array_push_n(headers->lengths,
  2488.                                     sizeof(ngx_http_script_copy_code_t));
  2489.             if (copy == NULL) {
  2490.                 return NGX_ERROR;
  2491.             }

  2492.             copy->code = (ngx_http_script_code_pt)
  2493.                                                  ngx_http_script_copy_len_code;
  2494.             copy->len = sizeof(CRLF) - 1;


  2495.             size = (sizeof(ngx_http_script_copy_code_t)
  2496.                     + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
  2497.                     & ~(sizeof(uintptr_t) - 1);

  2498.             copy = ngx_array_push_n(headers->values, size);
  2499.             if (copy == NULL) {
  2500.                 return NGX_ERROR;
  2501.             }

  2502.             copy->code = ngx_http_script_copy_code;
  2503.             copy->len = sizeof(CRLF) - 1;

  2504.             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
  2505.             *p++ = CR; *p = LF;
  2506.         }

  2507.         code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
  2508.         if (code == NULL) {
  2509.             return NGX_ERROR;
  2510.         }

  2511.         *code = (uintptr_t) NULL;

  2512.         code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
  2513.         if (code == NULL) {
  2514.             return NGX_ERROR;
  2515.         }

  2516.         *code = (uintptr_t) NULL;
  2517.     }

  2518.     code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
  2519.     if (code == NULL) {
  2520.         return NGX_ERROR;
  2521.     }

  2522.     *code = (uintptr_t) NULL;


  2523.     hash.hash = &headers->hash;
  2524.     hash.key = ngx_hash_key_lc;
  2525.     hash.max_size = conf->headers_hash_max_size;
  2526.     hash.bucket_size = conf->headers_hash_bucket_size;
  2527.     hash.name = "proxy_headers_hash";
  2528.     hash.pool = cf->pool;
  2529.     hash.temp_pool = NULL;

  2530.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  2531. }


  2532. static char *
  2533. ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2534. {
  2535.     ngx_http_proxy_loc_conf_t *plcf = conf;

  2536.     size_t                      add;
  2537.     u_short                     port;
  2538.     ngx_str_t                  *value, *url;
  2539.     ngx_url_t                   u;
  2540.     ngx_uint_t                  n;
  2541.     ngx_http_core_loc_conf_t   *clcf;
  2542.     ngx_http_script_compile_t   sc;

  2543.     if (plcf->upstream.upstream || plcf->proxy_lengths) {
  2544.         return "is duplicate";
  2545.     }

  2546.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2547.     clcf->handler = ngx_http_proxy_handler;

  2548.     if (clcf->name.data[clcf->name.len - 1] == '/') {
  2549.         clcf->auto_redirect = 1;
  2550.     }

  2551.     value = cf->args->elts;

  2552.     url = &value[1];

  2553.     n = ngx_http_script_variables_count(url);

  2554.     if (n) {

  2555.         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

  2556.         sc.cf = cf;
  2557.         sc.source = url;
  2558.         sc.lengths = &plcf->proxy_lengths;
  2559.         sc.values = &plcf->proxy_values;
  2560.         sc.variables = n;
  2561.         sc.complete_lengths = 1;
  2562.         sc.complete_values = 1;

  2563.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2564.             return NGX_CONF_ERROR;
  2565.         }

  2566. #if (NGX_HTTP_SSL)
  2567.         plcf->ssl = 1;
  2568. #endif

  2569.         return NGX_CONF_OK;
  2570.     }

  2571.     if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
  2572.         add = 7;
  2573.         port = 80;

  2574.     } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {

  2575. #if (NGX_HTTP_SSL)
  2576.         plcf->ssl = 1;

  2577.         add = 8;
  2578.         port = 443;
  2579. #else
  2580.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2581.                            "https protocol requires SSL support");
  2582.         return NGX_CONF_ERROR;
  2583. #endif

  2584.     } else {
  2585.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
  2586.         return NGX_CONF_ERROR;
  2587.     }

  2588.     ngx_memzero(&u, sizeof(ngx_url_t));

  2589.     u.url.len = url->len - add;
  2590.     u.url.data = url->data + add;
  2591.     u.default_port = port;
  2592.     u.uri_part = 1;
  2593.     u.no_resolve = 1;

  2594.     plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  2595.     if (plcf->upstream.upstream == NULL) {
  2596.         return NGX_CONF_ERROR;
  2597.     }

  2598.     plcf->vars.schema.len = add;
  2599.     plcf->vars.schema.data = url->data;
  2600.     plcf->vars.key_start = plcf->vars.schema;

  2601.     ngx_http_proxy_set_vars(&u, &plcf->vars);

  2602.     plcf->location = clcf->name;

  2603.     if (clcf->named
  2604. #if (NGX_PCRE)
  2605.         || clcf->regex
  2606. #endif
  2607.         || clcf->noname)
  2608.     {
  2609.         if (plcf->vars.uri.len) {
  2610.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2611.                                "\"proxy_pass\" cannot have URI part in "
  2612.                                "location given by regular expression, "
  2613.                                "or inside named location, "
  2614.                                "or inside \"if\" statement, "
  2615.                                "or inside \"limit_except\" block");
  2616.             return NGX_CONF_ERROR;
  2617.         }

  2618.         plcf->location.len = 0;
  2619.     }

  2620.     plcf->url = *url;

  2621.     return NGX_CONF_OK;
  2622. }


  2623. static char *
  2624. ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2625. {
  2626.     ngx_http_proxy_loc_conf_t *plcf = conf;

  2627.     u_char                            *p;
  2628.     ngx_str_t                         *value;
  2629.     ngx_http_proxy_rewrite_t          *pr;
  2630.     ngx_http_compile_complex_value_t   ccv;

  2631.     if (plcf->redirect == 0) {
  2632.         return NGX_CONF_OK;
  2633.     }

  2634.     plcf->redirect = 1;

  2635.     value = cf->args->elts;

  2636.     if (cf->args->nelts == 2) {
  2637.         if (ngx_strcmp(value[1].data, "off") == 0) {
  2638.             plcf->redirect = 0;
  2639.             plcf->redirects = NULL;
  2640.             return NGX_CONF_OK;
  2641.         }

  2642.         if (ngx_strcmp(value[1].data, "false") == 0) {
  2643.             ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
  2644.                            "invalid parameter \"false\", use \"off\" instead");
  2645.             plcf->redirect = 0;
  2646.             plcf->redirects = NULL;
  2647.             return NGX_CONF_OK;
  2648.         }

  2649.         if (ngx_strcmp(value[1].data, "default") != 0) {
  2650.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2651.                                "invalid parameter \"%V\"", &value[1]);
  2652.             return NGX_CONF_ERROR;
  2653.         }
  2654.     }

  2655.     if (plcf->redirects == NULL) {
  2656.         plcf->redirects = ngx_array_create(cf->pool, 1,
  2657.                                            sizeof(ngx_http_proxy_rewrite_t));
  2658.         if (plcf->redirects == NULL) {
  2659.             return NGX_CONF_ERROR;
  2660.         }
  2661.     }

  2662.     pr = ngx_array_push(plcf->redirects);
  2663.     if (pr == NULL) {
  2664.         return NGX_CONF_ERROR;
  2665.     }

  2666.     if (ngx_strcmp(value[1].data, "default") == 0) {
  2667.         if (plcf->proxy_lengths) {
  2668.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2669.                                "\"proxy_redirect default\" cannot be used "
  2670.                                "with \"proxy_pass\" directive with variables");
  2671.             return NGX_CONF_ERROR;
  2672.         }

  2673.         if (plcf->url.data == NULL) {
  2674.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2675.                                "\"proxy_redirect default\" should be placed "
  2676.                                "after the \"proxy_pass\" directive");
  2677.             return NGX_CONF_ERROR;
  2678.         }

  2679.         pr->handler = ngx_http_proxy_rewrite_complex_handler;

  2680.         ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));

  2681.         ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));

  2682.         if (plcf->vars.uri.len) {
  2683.             pr->pattern.complex.value = plcf->url;
  2684.             pr->replacement.value = plcf->location;

  2685.         } else {
  2686.             pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;

  2687.             p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
  2688.             if (p == NULL) {
  2689.                 return NGX_CONF_ERROR;
  2690.             }

  2691.             pr->pattern.complex.value.data = p;

  2692.             p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
  2693.             *p = '/';

  2694.             ngx_str_set(&pr->replacement.value, "/");
  2695.         }

  2696.         return NGX_CONF_OK;
  2697.     }


  2698.     if (value[1].data[0] == '~') {
  2699.         value[1].len--;
  2700.         value[1].data++;

  2701.         if (value[1].data[0] == '*') {
  2702.             value[1].len--;
  2703.             value[1].data++;

  2704.             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
  2705.                 return NGX_CONF_ERROR;
  2706.             }

  2707.         } else {
  2708.             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
  2709.                 return NGX_CONF_ERROR;
  2710.             }
  2711.         }

  2712.     } else {

  2713.         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  2714.         ccv.cf = cf;
  2715.         ccv.value = &value[1];
  2716.         ccv.complex_value = &pr->pattern.complex;

  2717.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2718.             return NGX_CONF_ERROR;
  2719.         }

  2720.         pr->handler = ngx_http_proxy_rewrite_complex_handler;
  2721.     }


  2722.     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  2723.     ccv.cf = cf;
  2724.     ccv.value = &value[2];
  2725.     ccv.complex_value = &pr->replacement;

  2726.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2727.         return NGX_CONF_ERROR;
  2728.     }

  2729.     return NGX_CONF_OK;
  2730. }


  2731. static char *
  2732. ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2733. {
  2734.     ngx_http_proxy_loc_conf_t *plcf = conf;

  2735.     ngx_str_t                         *value;
  2736.     ngx_http_proxy_rewrite_t          *pr;
  2737.     ngx_http_compile_complex_value_t   ccv;

  2738.     if (plcf->cookie_domains == NULL) {
  2739.         return NGX_CONF_OK;
  2740.     }

  2741.     value = cf->args->elts;

  2742.     if (cf->args->nelts == 2) {

  2743.         if (ngx_strcmp(value[1].data, "off") == 0) {
  2744.             plcf->cookie_domains = NULL;
  2745.             return NGX_CONF_OK;
  2746.         }

  2747.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2748.                            "invalid parameter \"%V\"", &value[1]);
  2749.         return NGX_CONF_ERROR;
  2750.     }

  2751.     if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
  2752.         plcf->cookie_domains = ngx_array_create(cf->pool, 1,
  2753.                                      sizeof(ngx_http_proxy_rewrite_t));
  2754.         if (plcf->cookie_domains == NULL) {
  2755.             return NGX_CONF_ERROR;
  2756.         }
  2757.     }

  2758.     pr = ngx_array_push(plcf->cookie_domains);
  2759.     if (pr == NULL) {
  2760.         return NGX_CONF_ERROR;
  2761.     }

  2762.     if (value[1].data[0] == '~') {
  2763.         value[1].len--;
  2764.         value[1].data++;

  2765.         if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
  2766.             return NGX_CONF_ERROR;
  2767.         }

  2768.     } else {

  2769.         if (value[1].data[0] == '.') {
  2770.             value[1].len--;
  2771.             value[1].data++;
  2772.         }

  2773.         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  2774.         ccv.cf = cf;
  2775.         ccv.value = &value[1];
  2776.         ccv.complex_value = &pr->pattern.complex;

  2777.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2778.             return NGX_CONF_ERROR;
  2779.         }

  2780.         pr->handler = ngx_http_proxy_rewrite_domain_handler;

  2781.         if (value[2].data[0] == '.') {
  2782.             value[2].len--;
  2783.             value[2].data++;
  2784.         }
  2785.     }

  2786.     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  2787.     ccv.cf = cf;
  2788.     ccv.value = &value[2];
  2789.     ccv.complex_value = &pr->replacement;

  2790.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2791.         return NGX_CONF_ERROR;
  2792.     }

  2793.     return NGX_CONF_OK;
  2794. }


  2795. static char *
  2796. ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2797. {
  2798.     ngx_http_proxy_loc_conf_t *plcf = conf;

  2799.     ngx_str_t                         *value;
  2800.     ngx_http_proxy_rewrite_t          *pr;
  2801.     ngx_http_compile_complex_value_t   ccv;

  2802.     if (plcf->cookie_paths == NULL) {
  2803.         return NGX_CONF_OK;
  2804.     }

  2805.     value = cf->args->elts;

  2806.     if (cf->args->nelts == 2) {

  2807.         if (ngx_strcmp(value[1].data, "off") == 0) {
  2808.             plcf->cookie_paths = NULL;
  2809.             return NGX_CONF_OK;
  2810.         }

  2811.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2812.                            "invalid parameter \"%V\"", &value[1]);
  2813.         return NGX_CONF_ERROR;
  2814.     }

  2815.     if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
  2816.         plcf->cookie_paths = ngx_array_create(cf->pool, 1,
  2817.                                      sizeof(ngx_http_proxy_rewrite_t));
  2818.         if (plcf->cookie_paths == NULL) {
  2819.             return NGX_CONF_ERROR;
  2820.         }
  2821.     }

  2822.     pr = ngx_array_push(plcf->cookie_paths);
  2823.     if (pr == NULL) {
  2824.         return NGX_CONF_ERROR;
  2825.     }

  2826.     if (value[1].data[0] == '~') {
  2827.         value[1].len--;
  2828.         value[1].data++;

  2829.         if (value[1].data[0] == '*') {
  2830.             value[1].len--;
  2831.             value[1].data++;

  2832.             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
  2833.                 return NGX_CONF_ERROR;
  2834.             }

  2835.         } else {
  2836.             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
  2837.                 return NGX_CONF_ERROR;
  2838.             }
  2839.         }

  2840.     } else {

  2841.         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  2842.         ccv.cf = cf;
  2843.         ccv.value = &value[1];
  2844.         ccv.complex_value = &pr->pattern.complex;

  2845.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2846.             return NGX_CONF_ERROR;
  2847.         }

  2848.         pr->handler = ngx_http_proxy_rewrite_complex_handler;
  2849.     }

  2850.     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  2851.     ccv.cf = cf;
  2852.     ccv.value = &value[2];
  2853.     ccv.complex_value = &pr->replacement;

  2854.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2855.         return NGX_CONF_ERROR;
  2856.     }

  2857.     return NGX_CONF_OK;
  2858. }


  2859. static ngx_int_t
  2860. ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
  2861.     ngx_str_t *regex, ngx_uint_t caseless)
  2862. {
  2863. #if (NGX_PCRE)
  2864.     u_char               errstr[NGX_MAX_CONF_ERRSTR];
  2865.     ngx_regex_compile_t  rc;

  2866.     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

  2867.     rc.pattern = *regex;
  2868.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  2869.     rc.err.data = errstr;

  2870.     if (caseless) {
  2871.         rc.options = NGX_REGEX_CASELESS;
  2872.     }

  2873.     pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
  2874.     if (pr->pattern.regex == NULL) {
  2875.         return NGX_ERROR;
  2876.     }

  2877.     pr->handler = ngx_http_proxy_rewrite_regex_handler;

  2878.     return NGX_OK;

  2879. #else

  2880.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2881.                        "using regex \"%V\" requires PCRE library", regex);
  2882.     return NGX_ERROR;

  2883. #endif
  2884. }


  2885. static char *
  2886. ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2887. {
  2888.     ngx_http_proxy_loc_conf_t *plcf = conf;

  2889.     ngx_str_t                  *value;
  2890.     ngx_http_script_compile_t   sc;

  2891.     if (plcf->upstream.store != NGX_CONF_UNSET) {
  2892.         return "is duplicate";
  2893.     }

  2894.     value = cf->args->elts;

  2895.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2896.         plcf->upstream.store = 0;
  2897.         return NGX_CONF_OK;
  2898.     }

  2899. #if (NGX_HTTP_CACHE)
  2900.     if (plcf->upstream.cache > 0) {
  2901.         return "is incompatible with \"proxy_cache\"";
  2902.     }
  2903. #endif

  2904.     plcf->upstream.store = 1;

  2905.     if (ngx_strcmp(value[1].data, "on") == 0) {
  2906.         return NGX_CONF_OK;
  2907.     }

  2908.     /* include the terminating '\0' into script */
  2909.     value[1].len++;

  2910.     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

  2911.     sc.cf = cf;
  2912.     sc.source = &value[1];
  2913.     sc.lengths = &plcf->upstream.store_lengths;
  2914.     sc.values = &plcf->upstream.store_values;
  2915.     sc.variables = ngx_http_script_variables_count(&value[1]);
  2916.     sc.complete_lengths = 1;
  2917.     sc.complete_values = 1;

  2918.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  2919.         return NGX_CONF_ERROR;
  2920.     }

  2921.     return NGX_CONF_OK;
  2922. }


  2923. #if (NGX_HTTP_CACHE)

  2924. static char *
  2925. ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2926. {
  2927.     ngx_http_proxy_loc_conf_t *plcf = conf;

  2928.     ngx_str_t                         *value;
  2929.     ngx_http_complex_value_t           cv;
  2930.     ngx_http_compile_complex_value_t   ccv;

  2931.     value = cf->args->elts;

  2932.     if (plcf->upstream.cache != NGX_CONF_UNSET) {
  2933.         return "is duplicate";
  2934.     }

  2935.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2936.         plcf->upstream.cache = 0;
  2937.         return NGX_CONF_OK;
  2938.     }

  2939.     if (plcf->upstream.store > 0) {
  2940.         return "is incompatible with \"proxy_store\"";
  2941.     }

  2942.     plcf->upstream.cache = 1;

  2943.     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  2944.     ccv.cf = cf;
  2945.     ccv.value = &value[1];
  2946.     ccv.complex_value = &cv;

  2947.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2948.         return NGX_CONF_ERROR;
  2949.     }

  2950.     if (cv.lengths != NULL) {

  2951.         plcf->upstream.cache_value = ngx_palloc(cf->pool,
  2952.                                              sizeof(ngx_http_complex_value_t));
  2953.         if (plcf->upstream.cache_value == NULL) {
  2954.             return NGX_CONF_ERROR;
  2955.         }

  2956.         *plcf->upstream.cache_value = cv;

  2957.         return NGX_CONF_OK;
  2958.     }

  2959.     plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  2960.                                                       &ngx_http_proxy_module);
  2961.     if (plcf->upstream.cache_zone == NULL) {
  2962.         return NGX_CONF_ERROR;
  2963.     }

  2964.     return NGX_CONF_OK;
  2965. }


  2966. static char *
  2967. ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2968. {
  2969.     ngx_http_proxy_loc_conf_t *plcf = conf;

  2970.     ngx_str_t                         *value;
  2971.     ngx_http_compile_complex_value_t   ccv;

  2972.     value = cf->args->elts;

  2973.     if (plcf->cache_key.value.data) {
  2974.         return "is duplicate";
  2975.     }

  2976.     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  2977.     ccv.cf = cf;
  2978.     ccv.value = &value[1];
  2979.     ccv.complex_value = &plcf->cache_key;

  2980.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2981.         return NGX_CONF_ERROR;
  2982.     }

  2983.     return NGX_CONF_OK;
  2984. }

  2985. #endif


  2986. #if (NGX_HTTP_SSL)

  2987. static char *
  2988. ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2989. {
  2990.     ngx_http_proxy_loc_conf_t *plcf = conf;

  2991.     ngx_str_t  *value;

  2992.     if (plcf->ssl_passwords != NGX_CONF_UNSET_PTR) {
  2993.         return "is duplicate";
  2994.     }

  2995.     value = cf->args->elts;

  2996.     plcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);

  2997.     if (plcf->ssl_passwords == NULL) {
  2998.         return NGX_CONF_ERROR;
  2999.     }

  3000.     return NGX_CONF_OK;
  3001. }

  3002. #endif


  3003. static char *
  3004. ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
  3005. {
  3006. #if (NGX_FREEBSD)
  3007.     ssize_t *np = data;

  3008.     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
  3009.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3010.                            "\"proxy_send_lowat\" must be less than %d "
  3011.                            "(sysctl net.inet.tcp.sendspace)",
  3012.                            ngx_freebsd_net_inet_tcp_sendspace);

  3013.         return NGX_CONF_ERROR;
  3014.     }

  3015. #elif !(NGX_HAVE_SO_SNDLOWAT)
  3016.     ssize_t *np = data;

  3017.     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  3018.                        "\"proxy_send_lowat\" is not supported, ignored");

  3019.     *np = 0;

  3020. #endif

  3021.     return NGX_CONF_OK;
  3022. }


  3023. #if (NGX_HTTP_SSL)

  3024. static ngx_int_t
  3025. ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
  3026. {
  3027.     ngx_pool_cleanup_t  *cln;

  3028.     plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
  3029.     if (plcf->upstream.ssl == NULL) {
  3030.         return NGX_ERROR;
  3031.     }

  3032.     plcf->upstream.ssl->log = cf->log;

  3033.     if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL)
  3034.         != NGX_OK)
  3035.     {
  3036.         return NGX_ERROR;
  3037.     }

  3038.     cln = ngx_pool_cleanup_add(cf->pool, 0);
  3039.     if (cln == NULL) {
  3040.         return NGX_ERROR;
  3041.     }

  3042.     cln->handler = ngx_ssl_cleanup_ctx;
  3043.     cln->data = plcf->upstream.ssl;

  3044.     if (plcf->ssl_certificate.len) {

  3045.         if (plcf->ssl_certificate_key.len == 0) {
  3046.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  3047.                           "no \"proxy_ssl_certificate_key\" is defined "
  3048.                           "for certificate \"%V\"", &plcf->ssl_certificate);
  3049.             return NGX_ERROR;
  3050.         }

  3051.         if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate,
  3052.                                 &plcf->ssl_certificate_key, plcf->ssl_passwords)
  3053.             != NGX_OK)
  3054.         {
  3055.             return NGX_ERROR;
  3056.         }
  3057.     }

  3058.     if (SSL_CTX_set_cipher_list(plcf->upstream.ssl->ctx,
  3059.                                 (const char *) plcf->ssl_ciphers.data)
  3060.         == 0)
  3061.     {
  3062.         ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
  3063.                       "SSL_CTX_set_cipher_list(\"%V\") failed",
  3064.                       &plcf->ssl_ciphers);
  3065.         return NGX_ERROR;
  3066.     }

  3067.     if (plcf->upstream.ssl_verify) {
  3068.         if (plcf->ssl_trusted_certificate.len == 0) {
  3069.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  3070.                       "no proxy_ssl_trusted_certificate for proxy_ssl_verify");
  3071.             return NGX_ERROR;
  3072.         }

  3073.         if (ngx_ssl_trusted_certificate(cf, plcf->upstream.ssl,
  3074.                                         &plcf->ssl_trusted_certificate,
  3075.                                         plcf->ssl_verify_depth)
  3076.             != NGX_OK)
  3077.         {
  3078.             return NGX_ERROR;
  3079.         }

  3080.         if (ngx_ssl_crl(cf, plcf->upstream.ssl, &plcf->ssl_crl) != NGX_OK) {
  3081.             return NGX_ERROR;
  3082.         }
  3083.     }

  3084.     return NGX_OK;
  3085. }

  3086. #endif


  3087. static void
  3088. ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
  3089. {
  3090.     if (u->family != AF_UNIX) {

  3091.         if (u->no_port || u->port == u->default_port) {

  3092.             v->host_header = u->host;

  3093.             if (u->default_port == 80) {
  3094.                 ngx_str_set(&v->port, "80");

  3095.             } else {
  3096.                 ngx_str_set(&v->port, "443");
  3097.             }

  3098.         } else {
  3099.             v->host_header.len = u->host.len + 1 + u->port_text.len;
  3100.             v->host_header.data = u->host.data;
  3101.             v->port = u->port_text;
  3102.         }

  3103.         v->key_start.len += v->host_header.len;

  3104.     } else {
  3105.         ngx_str_set(&v->host_header, "localhost");
  3106.         ngx_str_null(&v->port);
  3107.         v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
  3108.     }

  3109.     v->uri = u->uri;
  3110. }