src/http/modules/ngx_http_proxy_module.c - nginx source code

Global variables defined

Data types defined

Functions defined

Macros 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. #define  NGX_HTTP_PROXY_COOKIE_SECURE           0x0001
  9. #define  NGX_HTTP_PROXY_COOKIE_SECURE_ON        0x0002
  10. #define  NGX_HTTP_PROXY_COOKIE_SECURE_OFF       0x0004
  11. #define  NGX_HTTP_PROXY_COOKIE_HTTPONLY         0x0008
  12. #define  NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON      0x0010
  13. #define  NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF     0x0020
  14. #define  NGX_HTTP_PROXY_COOKIE_SAMESITE         0x0040
  15. #define  NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT  0x0080
  16. #define  NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX     0x0100
  17. #define  NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE    0x0200
  18. #define  NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF     0x0400


  19. typedef struct {
  20.     ngx_array_t                    caches;  /* ngx_http_file_cache_t * */
  21. } ngx_http_proxy_main_conf_t;


  22. typedef struct ngx_http_proxy_rewrite_s  ngx_http_proxy_rewrite_t;

  23. typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
  24.     ngx_str_t *value, size_t prefix, size_t len,
  25.     ngx_http_proxy_rewrite_t *pr);

  26. struct ngx_http_proxy_rewrite_s {
  27.     ngx_http_proxy_rewrite_pt      handler;

  28.     union {
  29.         ngx_http_complex_value_t   complex;
  30. #if (NGX_PCRE)
  31.         ngx_http_regex_t          *regex;
  32. #endif
  33.     } pattern;

  34.     ngx_http_complex_value_t       replacement;
  35. };


  36. typedef struct {
  37.     union {
  38.         ngx_http_complex_value_t   complex;
  39. #if (NGX_PCRE)
  40.         ngx_http_regex_t          *regex;
  41. #endif
  42.     } cookie;

  43.     ngx_array_t                    flags_values;
  44.     ngx_uint_t                     regex;
  45. } ngx_http_proxy_cookie_flags_t;


  46. typedef struct {
  47.     ngx_str_t                      key_start;
  48.     ngx_str_t                      schema;
  49.     ngx_str_t                      host_header;
  50.     ngx_str_t                      port;
  51.     ngx_str_t                      uri;
  52. } ngx_http_proxy_vars_t;


  53. typedef struct {
  54.     ngx_array_t                   *flushes;
  55.     ngx_array_t                   *lengths;
  56.     ngx_array_t                   *values;
  57.     ngx_hash_t                     hash;
  58. } ngx_http_proxy_headers_t;


  59. typedef struct {
  60.     ngx_http_upstream_conf_t       upstream;

  61.     ngx_array_t                   *body_flushes;
  62.     ngx_array_t                   *body_lengths;
  63.     ngx_array_t                   *body_values;
  64.     ngx_str_t                      body_source;

  65.     ngx_http_proxy_headers_t       headers;
  66. #if (NGX_HTTP_CACHE)
  67.     ngx_http_proxy_headers_t       headers_cache;
  68. #endif
  69.     ngx_array_t                   *headers_source;

  70.     ngx_array_t                   *proxy_lengths;
  71.     ngx_array_t                   *proxy_values;

  72.     ngx_array_t                   *redirects;
  73.     ngx_array_t                   *cookie_domains;
  74.     ngx_array_t                   *cookie_paths;
  75.     ngx_array_t                   *cookie_flags;

  76.     ngx_http_complex_value_t      *method;
  77.     ngx_str_t                      location;
  78.     ngx_str_t                      url;

  79. #if (NGX_HTTP_CACHE)
  80.     ngx_http_complex_value_t       cache_key;
  81. #endif

  82.     ngx_http_proxy_vars_t          vars;

  83.     ngx_flag_t                     redirect;

  84.     ngx_uint_t                     http_version;

  85.     ngx_uint_t                     headers_hash_max_size;
  86.     ngx_uint_t                     headers_hash_bucket_size;

  87. #if (NGX_HTTP_SSL)
  88.     ngx_uint_t                     ssl;
  89.     ngx_uint_t                     ssl_protocols;
  90.     ngx_str_t                      ssl_ciphers;
  91.     ngx_uint_t                     ssl_verify_depth;
  92.     ngx_str_t                      ssl_trusted_certificate;
  93.     ngx_str_t                      ssl_crl;
  94.     ngx_array_t                   *ssl_conf_commands;
  95. #endif
  96. } ngx_http_proxy_loc_conf_t;


  97. typedef struct {
  98.     ngx_http_status_t              status;
  99.     ngx_http_chunked_t             chunked;
  100.     ngx_http_proxy_vars_t          vars;
  101.     off_t                          internal_body_length;

  102.     ngx_chain_t                   *free;
  103.     ngx_chain_t                   *busy;

  104.     ngx_buf_t                     *trailers;

  105.     unsigned                       head:1;
  106.     unsigned                       internal_chunked:1;
  107.     unsigned                       header_sent:1;
  108. } ngx_http_proxy_ctx_t;


  109. static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
  110.     ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
  111. #if (NGX_HTTP_CACHE)
  112. static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
  113. #endif
  114. static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
  115. static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
  116. static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in);
  117. static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
  118. static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
  119. static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
  120. static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
  121.     ngx_buf_t *buf);
  122. static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
  123.     ngx_buf_t *buf);
  124. static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
  125.     ssize_t bytes);
  126. static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
  127.     ssize_t bytes);
  128. static ngx_int_t ngx_http_proxy_process_trailer(ngx_http_request_t *r,
  129.     ngx_buf_t *buf);
  130. static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
  131. static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
  132.     ngx_int_t rc);

  133. static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
  134.     ngx_http_variable_value_t *v, uintptr_t data);
  135. static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
  136.     ngx_http_variable_value_t *v, uintptr_t data);
  137. static ngx_int_t
  138.     ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
  139.     ngx_http_variable_value_t *v, uintptr_t data);
  140. static ngx_int_t
  141.     ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
  142.     ngx_http_variable_value_t *v, uintptr_t data);
  143. static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
  144.     ngx_http_variable_value_t *v, uintptr_t data);
  145. static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
  146.     ngx_table_elt_t *h, size_t prefix);
  147. static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
  148.     ngx_table_elt_t *h);
  149. static ngx_int_t ngx_http_proxy_parse_cookie(ngx_str_t *value,
  150.     ngx_array_t *attrs);
  151. static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
  152.     ngx_str_t *value, ngx_array_t *rewrites);
  153. static ngx_int_t ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r,
  154.     ngx_array_t *attrs, ngx_array_t *flags);
  155. static ngx_int_t ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r,
  156.     ngx_array_t *attrs, ngx_uint_t flags);
  157. static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
  158.     ngx_str_t *value, size_t prefix, size_t len, ngx_str_t *replacement);

  159. static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
  160. static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf);
  161. static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
  162. static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
  163.     void *parent, void *child);
  164. static ngx_int_t ngx_http_proxy_init_headers(ngx_conf_t *cf,
  165.     ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_headers_t *headers,
  166.     ngx_keyval_t *default_headers);

  167. static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
  168.     void *conf);
  169. static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
  170.     void *conf);
  171. static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
  172.     void *conf);
  173. static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
  174.     void *conf);
  175. static char *ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd,
  176.     void *conf);
  177. static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
  178.     void *conf);
  179. #if (NGX_HTTP_CACHE)
  180. static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  181.     void *conf);
  182. static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
  183.     void *conf);
  184. #endif
  185. #if (NGX_HTTP_SSL)
  186. static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf,
  187.     ngx_command_t *cmd, void *conf);
  188. #endif

  189. static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
  190. #if (NGX_HTTP_SSL)
  191. static char *ngx_http_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post,
  192.     void *data);
  193. #endif

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

  196. #if (NGX_HTTP_SSL)
  197. static ngx_int_t ngx_http_proxy_merge_ssl(ngx_conf_t *cf,
  198.     ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev);
  199. static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
  200.     ngx_http_proxy_loc_conf_t *plcf);
  201. #endif
  202. static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);


  203. static ngx_conf_post_t  ngx_http_proxy_lowat_post =
  204.     { ngx_http_proxy_lowat_check };


  205. static ngx_conf_bitmask_t  ngx_http_proxy_next_upstream_masks[] = {
  206.     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
  207.     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
  208.     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
  209.     { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
  210.     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
  211.     { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
  212.     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
  213.     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
  214.     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
  215.     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
  216.     { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
  217.     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
  218.     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
  219.     { ngx_null_string, 0 }
  220. };


  221. #if (NGX_HTTP_SSL)

  222. static ngx_conf_bitmask_t  ngx_http_proxy_ssl_protocols[] = {
  223.     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
  224.     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
  225.     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
  226.     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
  227.     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
  228.     { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
  229.     { ngx_null_string, 0 }
  230. };

  231. static ngx_conf_post_t  ngx_http_proxy_ssl_conf_command_post =
  232.     { ngx_http_proxy_ssl_conf_command_check };

  233. #endif


  234. static ngx_conf_enum_t  ngx_http_proxy_http_version[] = {
  235.     { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
  236.     { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
  237.     { ngx_null_string, 0 }
  238. };


  239. ngx_module_t  ngx_http_proxy_module;


  240. static ngx_command_t  ngx_http_proxy_commands[] = {

  241.     { ngx_string("proxy_pass"),
  242.       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
  243.       ngx_http_proxy_pass,
  244.       NGX_HTTP_LOC_CONF_OFFSET,
  245.       0,
  246.       NULL },

  247.     { ngx_string("proxy_redirect"),
  248.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  249.       ngx_http_proxy_redirect,
  250.       NGX_HTTP_LOC_CONF_OFFSET,
  251.       0,
  252.       NULL },

  253.     { ngx_string("proxy_cookie_domain"),
  254.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  255.       ngx_http_proxy_cookie_domain,
  256.       NGX_HTTP_LOC_CONF_OFFSET,
  257.       0,
  258.       NULL },

  259.     { ngx_string("proxy_cookie_path"),
  260.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  261.       ngx_http_proxy_cookie_path,
  262.       NGX_HTTP_LOC_CONF_OFFSET,
  263.       0,
  264.       NULL },

  265.     { ngx_string("proxy_cookie_flags"),
  266.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  267.       ngx_http_proxy_cookie_flags,
  268.       NGX_HTTP_LOC_CONF_OFFSET,
  269.       0,
  270.       NULL },

  271.     { ngx_string("proxy_store"),
  272.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  273.       ngx_http_proxy_store,
  274.       NGX_HTTP_LOC_CONF_OFFSET,
  275.       0,
  276.       NULL },

  277.     { ngx_string("proxy_store_access"),
  278.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
  279.       ngx_conf_set_access_slot,
  280.       NGX_HTTP_LOC_CONF_OFFSET,
  281.       offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
  282.       NULL },

  283.     { ngx_string("proxy_buffering"),
  284.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  285.       ngx_conf_set_flag_slot,
  286.       NGX_HTTP_LOC_CONF_OFFSET,
  287.       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
  288.       NULL },

  289.     { ngx_string("proxy_request_buffering"),
  290.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  291.       ngx_conf_set_flag_slot,
  292.       NGX_HTTP_LOC_CONF_OFFSET,
  293.       offsetof(ngx_http_proxy_loc_conf_t, upstream.request_buffering),
  294.       NULL },

  295.     { ngx_string("proxy_ignore_client_abort"),
  296.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  297.       ngx_conf_set_flag_slot,
  298.       NGX_HTTP_LOC_CONF_OFFSET,
  299.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
  300.       NULL },

  301.     { ngx_string("proxy_bind"),
  302.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  303.       ngx_http_upstream_bind_set_slot,
  304.       NGX_HTTP_LOC_CONF_OFFSET,
  305.       offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
  306.       NULL },

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

  313.     { ngx_string("proxy_connect_timeout"),
  314.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  315.       ngx_conf_set_msec_slot,
  316.       NGX_HTTP_LOC_CONF_OFFSET,
  317.       offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
  318.       NULL },

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

  325.     { ngx_string("proxy_send_lowat"),
  326.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  327.       ngx_conf_set_size_slot,
  328.       NGX_HTTP_LOC_CONF_OFFSET,
  329.       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
  330.       &ngx_http_proxy_lowat_post },

  331.     { ngx_string("proxy_intercept_errors"),
  332.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  333.       ngx_conf_set_flag_slot,
  334.       NGX_HTTP_LOC_CONF_OFFSET,
  335.       offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
  336.       NULL },

  337.     { ngx_string("proxy_set_header"),
  338.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  339.       ngx_conf_set_keyval_slot,
  340.       NGX_HTTP_LOC_CONF_OFFSET,
  341.       offsetof(ngx_http_proxy_loc_conf_t, headers_source),
  342.       NULL },

  343.     { ngx_string("proxy_headers_hash_max_size"),
  344.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  345.       ngx_conf_set_num_slot,
  346.       NGX_HTTP_LOC_CONF_OFFSET,
  347.       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
  348.       NULL },

  349.     { ngx_string("proxy_headers_hash_bucket_size"),
  350.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  351.       ngx_conf_set_num_slot,
  352.       NGX_HTTP_LOC_CONF_OFFSET,
  353.       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
  354.       NULL },

  355.     { ngx_string("proxy_set_body"),
  356.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  357.       ngx_conf_set_str_slot,
  358.       NGX_HTTP_LOC_CONF_OFFSET,
  359.       offsetof(ngx_http_proxy_loc_conf_t, body_source),
  360.       NULL },

  361.     { ngx_string("proxy_method"),
  362.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  363.       ngx_http_set_complex_value_slot,
  364.       NGX_HTTP_LOC_CONF_OFFSET,
  365.       offsetof(ngx_http_proxy_loc_conf_t, method),
  366.       NULL },

  367.     { ngx_string("proxy_pass_request_headers"),
  368.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  369.       ngx_conf_set_flag_slot,
  370.       NGX_HTTP_LOC_CONF_OFFSET,
  371.       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
  372.       NULL },

  373.     { ngx_string("proxy_pass_request_body"),
  374.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  375.       ngx_conf_set_flag_slot,
  376.       NGX_HTTP_LOC_CONF_OFFSET,
  377.       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
  378.       NULL },

  379.     { ngx_string("proxy_pass_trailers"),
  380.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  381.       ngx_conf_set_flag_slot,
  382.       NGX_HTTP_LOC_CONF_OFFSET,
  383.       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_trailers),
  384.       NULL },

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

  391.     { ngx_string("proxy_read_timeout"),
  392.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  393.       ngx_conf_set_msec_slot,
  394.       NGX_HTTP_LOC_CONF_OFFSET,
  395.       offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
  396.       NULL },

  397.     { ngx_string("proxy_buffers"),
  398.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  399.       ngx_conf_set_bufs_slot,
  400.       NGX_HTTP_LOC_CONF_OFFSET,
  401.       offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
  402.       NULL },

  403.     { ngx_string("proxy_busy_buffers_size"),
  404.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  405.       ngx_conf_set_size_slot,
  406.       NGX_HTTP_LOC_CONF_OFFSET,
  407.       offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
  408.       NULL },

  409.     { ngx_string("proxy_force_ranges"),
  410.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  411.       ngx_conf_set_flag_slot,
  412.       NGX_HTTP_LOC_CONF_OFFSET,
  413.       offsetof(ngx_http_proxy_loc_conf_t, upstream.force_ranges),
  414.       NULL },

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

  421. #if (NGX_HTTP_CACHE)

  422.     { ngx_string("proxy_cache"),
  423.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  424.       ngx_http_proxy_cache,
  425.       NGX_HTTP_LOC_CONF_OFFSET,
  426.       0,
  427.       NULL },

  428.     { ngx_string("proxy_cache_key"),
  429.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  430.       ngx_http_proxy_cache_key,
  431.       NGX_HTTP_LOC_CONF_OFFSET,
  432.       0,
  433.       NULL },

  434.     { ngx_string("proxy_cache_path"),
  435.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  436.       ngx_http_file_cache_set_slot,
  437.       NGX_HTTP_MAIN_CONF_OFFSET,
  438.       offsetof(ngx_http_proxy_main_conf_t, caches),
  439.       &ngx_http_proxy_module },

  440.     { ngx_string("proxy_cache_bypass"),
  441.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  442.       ngx_http_set_predicate_slot,
  443.       NGX_HTTP_LOC_CONF_OFFSET,
  444.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
  445.       NULL },

  446.     { ngx_string("proxy_no_cache"),
  447.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  448.       ngx_http_set_predicate_slot,
  449.       NGX_HTTP_LOC_CONF_OFFSET,
  450.       offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
  451.       NULL },

  452.     { ngx_string("proxy_cache_valid"),
  453.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  454.       ngx_http_file_cache_valid_set_slot,
  455.       NGX_HTTP_LOC_CONF_OFFSET,
  456.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
  457.       NULL },

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

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

  470.     { ngx_string("proxy_cache_use_stale"),
  471.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  472.       ngx_conf_set_bitmask_slot,
  473.       NGX_HTTP_LOC_CONF_OFFSET,
  474.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
  475.       &ngx_http_proxy_next_upstream_masks },

  476.     { ngx_string("proxy_cache_methods"),
  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.cache_methods),
  481.       &ngx_http_upstream_cache_method_mask },

  482.     { ngx_string("proxy_cache_lock"),
  483.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  484.       ngx_conf_set_flag_slot,
  485.       NGX_HTTP_LOC_CONF_OFFSET,
  486.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
  487.       NULL },

  488.     { ngx_string("proxy_cache_lock_timeout"),
  489.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  490.       ngx_conf_set_msec_slot,
  491.       NGX_HTTP_LOC_CONF_OFFSET,
  492.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
  493.       NULL },

  494.     { ngx_string("proxy_cache_lock_age"),
  495.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  496.       ngx_conf_set_msec_slot,
  497.       NGX_HTTP_LOC_CONF_OFFSET,
  498.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_age),
  499.       NULL },

  500.     { ngx_string("proxy_cache_revalidate"),
  501.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  502.       ngx_conf_set_flag_slot,
  503.       NGX_HTTP_LOC_CONF_OFFSET,
  504.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate),
  505.       NULL },

  506.     { ngx_string("proxy_cache_convert_head"),
  507.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  508.       ngx_conf_set_flag_slot,
  509.       NGX_HTTP_LOC_CONF_OFFSET,
  510.       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_convert_head),
  511.       NULL },

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

  518. #endif

  519.     { ngx_string("proxy_temp_path"),
  520.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  521.       ngx_conf_set_path_slot,
  522.       NGX_HTTP_LOC_CONF_OFFSET,
  523.       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
  524.       NULL },

  525.     { ngx_string("proxy_max_temp_file_size"),
  526.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  527.       ngx_conf_set_size_slot,
  528.       NGX_HTTP_LOC_CONF_OFFSET,
  529.       offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
  530.       NULL },

  531.     { ngx_string("proxy_temp_file_write_size"),
  532.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  533.       ngx_conf_set_size_slot,
  534.       NGX_HTTP_LOC_CONF_OFFSET,
  535.       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
  536.       NULL },

  537.     { ngx_string("proxy_next_upstream"),
  538.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  539.       ngx_conf_set_bitmask_slot,
  540.       NGX_HTTP_LOC_CONF_OFFSET,
  541.       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
  542.       &ngx_http_proxy_next_upstream_masks },

  543.     { ngx_string("proxy_next_upstream_tries"),
  544.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  545.       ngx_conf_set_num_slot,
  546.       NGX_HTTP_LOC_CONF_OFFSET,
  547.       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_tries),
  548.       NULL },

  549.     { ngx_string("proxy_next_upstream_timeout"),
  550.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  551.       ngx_conf_set_msec_slot,
  552.       NGX_HTTP_LOC_CONF_OFFSET,
  553.       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_timeout),
  554.       NULL },

  555.     { ngx_string("proxy_pass_header"),
  556.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  557.       ngx_conf_set_str_array_slot,
  558.       NGX_HTTP_LOC_CONF_OFFSET,
  559.       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
  560.       NULL },

  561.     { ngx_string("proxy_hide_header"),
  562.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  563.       ngx_conf_set_str_array_slot,
  564.       NGX_HTTP_LOC_CONF_OFFSET,
  565.       offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
  566.       NULL },

  567.     { ngx_string("proxy_ignore_headers"),
  568.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  569.       ngx_conf_set_bitmask_slot,
  570.       NGX_HTTP_LOC_CONF_OFFSET,
  571.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
  572.       &ngx_http_upstream_ignore_headers_masks },

  573.     { ngx_string("proxy_http_version"),
  574.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  575.       ngx_conf_set_enum_slot,
  576.       NGX_HTTP_LOC_CONF_OFFSET,
  577.       offsetof(ngx_http_proxy_loc_conf_t, http_version),
  578.       &ngx_http_proxy_http_version },

  579. #if (NGX_HTTP_SSL)

  580.     { ngx_string("proxy_ssl_session_reuse"),
  581.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  582.       ngx_conf_set_flag_slot,
  583.       NGX_HTTP_LOC_CONF_OFFSET,
  584.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
  585.       NULL },

  586.     { ngx_string("proxy_ssl_protocols"),
  587.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  588.       ngx_conf_set_bitmask_slot,
  589.       NGX_HTTP_LOC_CONF_OFFSET,
  590.       offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols),
  591.       &ngx_http_proxy_ssl_protocols },

  592.     { ngx_string("proxy_ssl_ciphers"),
  593.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  594.       ngx_conf_set_str_slot,
  595.       NGX_HTTP_LOC_CONF_OFFSET,
  596.       offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers),
  597.       NULL },

  598.     { ngx_string("proxy_ssl_name"),
  599.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  600.       ngx_http_set_complex_value_slot,
  601.       NGX_HTTP_LOC_CONF_OFFSET,
  602.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_name),
  603.       NULL },

  604.     { ngx_string("proxy_ssl_server_name"),
  605.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  606.       ngx_conf_set_flag_slot,
  607.       NGX_HTTP_LOC_CONF_OFFSET,
  608.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_server_name),
  609.       NULL },

  610.     { ngx_string("proxy_ssl_verify"),
  611.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  612.       ngx_conf_set_flag_slot,
  613.       NGX_HTTP_LOC_CONF_OFFSET,
  614.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify),
  615.       NULL },

  616.     { ngx_string("proxy_ssl_verify_depth"),
  617.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  618.       ngx_conf_set_num_slot,
  619.       NGX_HTTP_LOC_CONF_OFFSET,
  620.       offsetof(ngx_http_proxy_loc_conf_t, ssl_verify_depth),
  621.       NULL },

  622.     { ngx_string("proxy_ssl_trusted_certificate"),
  623.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  624.       ngx_conf_set_str_slot,
  625.       NGX_HTTP_LOC_CONF_OFFSET,
  626.       offsetof(ngx_http_proxy_loc_conf_t, ssl_trusted_certificate),
  627.       NULL },

  628.     { ngx_string("proxy_ssl_crl"),
  629.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  630.       ngx_conf_set_str_slot,
  631.       NGX_HTTP_LOC_CONF_OFFSET,
  632.       offsetof(ngx_http_proxy_loc_conf_t, ssl_crl),
  633.       NULL },

  634.     { ngx_string("proxy_ssl_certificate"),
  635.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  636.       ngx_http_set_complex_value_zero_slot,
  637.       NGX_HTTP_LOC_CONF_OFFSET,
  638.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate),
  639.       NULL },

  640.     { ngx_string("proxy_ssl_certificate_key"),
  641.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  642.       ngx_http_set_complex_value_zero_slot,
  643.       NGX_HTTP_LOC_CONF_OFFSET,
  644.       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate_key),
  645.       NULL },

  646.     { ngx_string("proxy_ssl_password_file"),
  647.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  648.       ngx_http_proxy_ssl_password_file,
  649.       NGX_HTTP_LOC_CONF_OFFSET,
  650.       0,
  651.       NULL },

  652.     { ngx_string("proxy_ssl_conf_command"),
  653.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  654.       ngx_conf_set_keyval_slot,
  655.       NGX_HTTP_LOC_CONF_OFFSET,
  656.       offsetof(ngx_http_proxy_loc_conf_t, ssl_conf_commands),
  657.       &ngx_http_proxy_ssl_conf_command_post },

  658. #endif

  659.       ngx_null_command
  660. };


  661. static ngx_http_module_t  ngx_http_proxy_module_ctx = {
  662.     ngx_http_proxy_add_variables,          /* preconfiguration */
  663.     NULL,                                  /* postconfiguration */

  664.     ngx_http_proxy_create_main_conf,       /* create main configuration */
  665.     NULL,                                  /* init main configuration */

  666.     NULL,                                  /* create server configuration */
  667.     NULL,                                  /* merge server configuration */

  668.     ngx_http_proxy_create_loc_conf,        /* create location configuration */
  669.     ngx_http_proxy_merge_loc_conf          /* merge location configuration */
  670. };


  671. ngx_module_t  ngx_http_proxy_module = {
  672.     NGX_MODULE_V1,
  673.     &ngx_http_proxy_module_ctx,            /* module context */
  674.     ngx_http_proxy_commands,               /* module directives */
  675.     NGX_HTTP_MODULE,                       /* module type */
  676.     NULL,                                  /* init master */
  677.     NULL,                                  /* init module */
  678.     NULL,                                  /* init process */
  679.     NULL,                                  /* init thread */
  680.     NULL,                                  /* exit thread */
  681.     NULL,                                  /* exit process */
  682.     NULL,                                  /* exit master */
  683.     NGX_MODULE_V1_PADDING
  684. };


  685. static char  ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
  686. static char  ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;


  687. static ngx_keyval_t  ngx_http_proxy_headers[] = {
  688.     { ngx_string("Host"), ngx_string("$proxy_host") },
  689.     { ngx_string("Connection"), ngx_string("close") },
  690.     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
  691.     { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
  692.     { ngx_string("TE"), ngx_string("") },
  693.     { ngx_string("Keep-Alive"), ngx_string("") },
  694.     { ngx_string("Expect"), ngx_string("") },
  695.     { ngx_string("Upgrade"), ngx_string("") },
  696.     { ngx_null_string, ngx_null_string }
  697. };


  698. static ngx_str_t  ngx_http_proxy_hide_headers[] = {
  699.     ngx_string("Date"),
  700.     ngx_string("Server"),
  701.     ngx_string("X-Pad"),
  702.     ngx_string("X-Accel-Expires"),
  703.     ngx_string("X-Accel-Redirect"),
  704.     ngx_string("X-Accel-Limit-Rate"),
  705.     ngx_string("X-Accel-Buffering"),
  706.     ngx_string("X-Accel-Charset"),
  707.     ngx_null_string
  708. };


  709. #if (NGX_HTTP_CACHE)

  710. static ngx_keyval_t  ngx_http_proxy_cache_headers[] = {
  711.     { ngx_string("Host"), ngx_string("$proxy_host") },
  712.     { ngx_string("Connection"), ngx_string("close") },
  713.     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
  714.     { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
  715.     { ngx_string("TE"), ngx_string("") },
  716.     { ngx_string("Keep-Alive"), ngx_string("") },
  717.     { ngx_string("Expect"), ngx_string("") },
  718.     { ngx_string("Upgrade"), ngx_string("") },
  719.     { ngx_string("If-Modified-Since"),
  720.       ngx_string("$upstream_cache_last_modified") },
  721.     { ngx_string("If-Unmodified-Since"), ngx_string("") },
  722.     { ngx_string("If-None-Match"), ngx_string("$upstream_cache_etag") },
  723.     { ngx_string("If-Match"), ngx_string("") },
  724.     { ngx_string("Range"), ngx_string("") },
  725.     { ngx_string("If-Range"), ngx_string("") },
  726.     { ngx_null_string, ngx_null_string }
  727. };

  728. #endif


  729. static ngx_http_variable_t  ngx_http_proxy_vars[] = {

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

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

  734.     { ngx_string("proxy_add_x_forwarded_for"), NULL,
  735.       ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },

  736. #if 0
  737.     { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
  738. #endif

  739.     { ngx_string("proxy_internal_body_length"), NULL,
  740.       ngx_http_proxy_internal_body_length_variable, 0,
  741.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  742.     { ngx_string("proxy_internal_chunked"), NULL,
  743.       ngx_http_proxy_internal_chunked_variable, 0,
  744.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  745.       ngx_http_null_variable
  746. };


  747. static ngx_path_init_t  ngx_http_proxy_temp_path = {
  748.     ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
  749. };


  750. static ngx_conf_bitmask_t  ngx_http_proxy_cookie_flags_masks[] = {

  751.     { ngx_string("secure"),
  752.       NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_ON },

  753.     { ngx_string("nosecure"),
  754.       NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_OFF },

  755.     { ngx_string("httponly"),
  756.       NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON },

  757.     { ngx_string("nohttponly"),
  758.       NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF },

  759.     { ngx_string("samesite=strict"),
  760.       NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT },

  761.     { ngx_string("samesite=lax"),
  762.       NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX },

  763.     { ngx_string("samesite=none"),
  764.       NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE },

  765.     { ngx_string("nosamesite"),
  766.       NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF },

  767.     { ngx_null_string, 0 }
  768. };


  769. static ngx_int_t
  770. ngx_http_proxy_handler(ngx_http_request_t *r)
  771. {
  772.     ngx_int_t                    rc;
  773.     ngx_http_upstream_t         *u;
  774.     ngx_http_proxy_ctx_t        *ctx;
  775.     ngx_http_proxy_loc_conf_t   *plcf;
  776. #if (NGX_HTTP_CACHE)
  777.     ngx_http_proxy_main_conf_t  *pmcf;
  778. #endif

  779.     if (ngx_http_upstream_create(r) != NGX_OK) {
  780.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  781.     }

  782.     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
  783.     if (ctx == NULL) {
  784.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  785.     }

  786.     ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);

  787.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  788.     u = r->upstream;

  789.     if (plcf->proxy_lengths == NULL) {
  790.         ctx->vars = plcf->vars;
  791.         u->schema = plcf->vars.schema;
  792. #if (NGX_HTTP_SSL)
  793.         u->ssl = plcf->ssl;
  794. #endif

  795.     } else {
  796.         if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
  797.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  798.         }
  799.     }

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

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

  802. #if (NGX_HTTP_CACHE)
  803.     pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module);

  804.     u->caches = &pmcf->caches;
  805.     u->create_key = ngx_http_proxy_create_key;
  806. #endif

  807.     u->create_request = ngx_http_proxy_create_request;
  808.     u->reinit_request = ngx_http_proxy_reinit_request;
  809.     u->process_header = ngx_http_proxy_process_status_line;
  810.     u->abort_request = ngx_http_proxy_abort_request;
  811.     u->finalize_request = ngx_http_proxy_finalize_request;
  812.     r->state = 0;

  813.     if (plcf->redirects) {
  814.         u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
  815.     }

  816.     if (plcf->cookie_domains || plcf->cookie_paths || plcf->cookie_flags) {
  817.         u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
  818.     }

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

  820.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  821.     if (u->pipe == NULL) {
  822.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  823.     }

  824.     u->pipe->input_filter = ngx_http_proxy_copy_filter;
  825.     u->pipe->input_ctx = r;

  826.     u->input_filter_init = ngx_http_proxy_input_filter_init;
  827.     u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
  828.     u->input_filter_ctx = r;

  829.     u->accel = 1;

  830.     if (!plcf->upstream.request_buffering
  831.         && plcf->body_values == NULL && plcf->upstream.pass_request_body
  832.         && (!r->headers_in.chunked
  833.             || plcf->http_version == NGX_HTTP_VERSION_11))
  834.     {
  835.         r->request_body_no_buffering = 1;
  836.     }

  837.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  838.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  839.         return rc;
  840.     }

  841.     return NGX_DONE;
  842. }


  843. static ngx_int_t
  844. ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
  845.     ngx_http_proxy_loc_conf_t *plcf)
  846. {
  847.     u_char               *p;
  848.     size_t                add;
  849.     u_short               port;
  850.     ngx_str_t             proxy;
  851.     ngx_url_t             url;
  852.     ngx_http_upstream_t  *u;

  853.     if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
  854.                             plcf->proxy_values->elts)
  855.         == NULL)
  856.     {
  857.         return NGX_ERROR;
  858.     }

  859.     if (proxy.len > 7
  860.         && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
  861.     {
  862.         add = 7;
  863.         port = 80;

  864. #if (NGX_HTTP_SSL)

  865.     } else if (proxy.len > 8
  866.                && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
  867.     {
  868.         add = 8;
  869.         port = 443;
  870.         r->upstream->ssl = 1;

  871. #endif

  872.     } else {
  873.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  874.                       "invalid URL prefix in \"%V\"", &proxy);
  875.         return NGX_ERROR;
  876.     }

  877.     u = r->upstream;

  878.     u->schema.len = add;
  879.     u->schema.data = proxy.data;

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

  881.     url.url.len = proxy.len - add;
  882.     url.url.data = proxy.data + add;
  883.     url.default_port = port;
  884.     url.uri_part = 1;
  885.     url.no_resolve = 1;

  886.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  887.         if (url.err) {
  888.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  889.                           "%s in upstream \"%V\"", url.err, &url.url);
  890.         }

  891.         return NGX_ERROR;
  892.     }

  893.     if (url.uri.len) {
  894.         if (url.uri.data[0] == '?') {
  895.             p = ngx_pnalloc(r->pool, url.uri.len + 1);
  896.             if (p == NULL) {
  897.                 return NGX_ERROR;
  898.             }

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

  901.             url.uri.len++;
  902.             url.uri.data = p - 1;
  903.         }
  904.     }

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

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

  907.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  908.     if (u->resolved == NULL) {
  909.         return NGX_ERROR;
  910.     }

  911.     if (url.addrs) {
  912.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  913.         u->resolved->socklen = url.addrs[0].socklen;
  914.         u->resolved->name = url.addrs[0].name;
  915.         u->resolved->naddrs = 1;
  916.     }

  917.     u->resolved->host = url.host;
  918.     u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
  919.     u->resolved->no_port = url.no_port;

  920.     return NGX_OK;
  921. }


  922. #if (NGX_HTTP_CACHE)

  923. static ngx_int_t
  924. ngx_http_proxy_create_key(ngx_http_request_t *r)
  925. {
  926.     size_t                      len, loc_len;
  927.     u_char                     *p;
  928.     uintptr_t                   escape;
  929.     ngx_str_t                  *key;
  930.     ngx_http_upstream_t        *u;
  931.     ngx_http_proxy_ctx_t       *ctx;
  932.     ngx_http_proxy_loc_conf_t  *plcf;

  933.     u = r->upstream;

  934.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  935.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  936.     key = ngx_array_push(&r->cache->keys);
  937.     if (key == NULL) {
  938.         return NGX_ERROR;
  939.     }

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

  941.         if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
  942.             return NGX_ERROR;
  943.         }

  944.         return NGX_OK;
  945.     }

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

  947.     key = ngx_array_push(&r->cache->keys);
  948.     if (key == NULL) {
  949.         return NGX_ERROR;
  950.     }

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

  952.         *key = ctx->vars.uri;
  953.         u->uri = ctx->vars.uri;

  954.         return NGX_OK;

  955.     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri) {
  956.         *key = r->unparsed_uri;
  957.         u->uri = r->unparsed_uri;

  958.         return NGX_OK;
  959.     }

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

  961.     if (r->quoted_uri || r->internal) {
  962.         escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
  963.                                     r->uri.len - loc_len, NGX_ESCAPE_URI);
  964.     } else {
  965.         escape = 0;
  966.     }

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

  969.     p = ngx_pnalloc(r->pool, len);
  970.     if (p == NULL) {
  971.         return NGX_ERROR;
  972.     }

  973.     key->data = p;

  974.     if (r->valid_location) {
  975.         p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
  976.     }

  977.     if (escape) {
  978.         ngx_escape_uri(p, r->uri.data + loc_len,
  979.                        r->uri.len - loc_len, NGX_ESCAPE_URI);
  980.         p += r->uri.len - loc_len + escape;

  981.     } else {
  982.         p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
  983.     }

  984.     if (r->args.len > 0) {
  985.         *p++ = '?';
  986.         p = ngx_copy(p, r->args.data, r->args.len);
  987.     }

  988.     key->len = p - key->data;
  989.     u->uri = *key;

  990.     return NGX_OK;
  991. }

  992. #endif


  993. static ngx_int_t
  994. ngx_http_proxy_create_request(ngx_http_request_t *r)
  995. {
  996.     size_t                        len, uri_len, loc_len, body_len,
  997.                                   key_len, val_len;
  998.     uintptr_t                     escape;
  999.     ngx_buf_t                    *b;
  1000.     ngx_str_t                     method;
  1001.     ngx_uint_t                    i, unparsed_uri;
  1002.     ngx_chain_t                  *cl, *body;
  1003.     ngx_list_part_t              *part;
  1004.     ngx_table_elt_t              *header;
  1005.     ngx_http_upstream_t          *u;
  1006.     ngx_http_proxy_ctx_t         *ctx;
  1007.     ngx_http_script_code_pt       code;
  1008.     ngx_http_proxy_headers_t     *headers;
  1009.     ngx_http_script_engine_t      e, le;
  1010.     ngx_http_proxy_loc_conf_t    *plcf;
  1011.     ngx_http_script_len_code_pt   lcode;

  1012.     u = r->upstream;

  1013.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  1014. #if (NGX_HTTP_CACHE)
  1015.     headers = u->cacheable ? &plcf->headers_cache : &plcf->headers;
  1016. #else
  1017.     headers = &plcf->headers;
  1018. #endif

  1019.     if (u->method.len) {
  1020.         /* HEAD was changed to GET to cache response */
  1021.         method = u->method;

  1022.     } else if (plcf->method) {
  1023.         if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) {
  1024.             return NGX_ERROR;
  1025.         }

  1026.     } else {
  1027.         method = r->method_name;
  1028.     }

  1029.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1030.     if (method.len == 4
  1031.         && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0)
  1032.     {
  1033.         ctx->head = 1;
  1034.     }

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

  1037.     escape = 0;
  1038.     loc_len = 0;
  1039.     unparsed_uri = 0;

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

  1042.     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri) {
  1043.         unparsed_uri = 1;
  1044.         uri_len = r->unparsed_uri.len;

  1045.     } else {
  1046.         loc_len = (r->valid_location && ctx->vars.uri.len) ?
  1047.                       plcf->location.len : 0;

  1048.         if (r->quoted_uri || r->internal) {
  1049.             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
  1050.                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
  1051.         }

  1052.         uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
  1053.                   + sizeof("?") - 1 + r->args.len;
  1054.     }

  1055.     if (uri_len == 0) {
  1056.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1057.                       "zero length URI to proxy");
  1058.         return NGX_ERROR;
  1059.     }

  1060.     len += uri_len;

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

  1062.     ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
  1063.     ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);

  1064.     if (plcf->body_lengths) {
  1065.         le.ip = plcf->body_lengths->elts;
  1066.         le.request = r;
  1067.         le.flushed = 1;
  1068.         body_len = 0;

  1069.         while (*(uintptr_t *) le.ip) {
  1070.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  1071.             body_len += lcode(&le);
  1072.         }

  1073.         ctx->internal_body_length = body_len;
  1074.         len += body_len;

  1075.     } else if (r->headers_in.chunked && r->reading_body) {
  1076.         ctx->internal_body_length = -1;
  1077.         ctx->internal_chunked = 1;

  1078.     } else {
  1079.         ctx->internal_body_length = r->headers_in.content_length_n;
  1080.     }

  1081.     le.ip = headers->lengths->elts;
  1082.     le.request = r;
  1083.     le.flushed = 1;

  1084.     while (*(uintptr_t *) le.ip) {

  1085.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  1086.         key_len = lcode(&le);

  1087.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  1088.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  1089.         }
  1090.         le.ip += sizeof(uintptr_t);

  1091.         if (val_len == 0) {
  1092.             continue;
  1093.         }

  1094.         len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1;
  1095.     }


  1096.     if (plcf->upstream.pass_request_headers) {
  1097.         part = &r->headers_in.headers.part;
  1098.         header = part->elts;

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

  1100.             if (i >= part->nelts) {
  1101.                 if (part->next == NULL) {
  1102.                     break;
  1103.                 }

  1104.                 part = part->next;
  1105.                 header = part->elts;
  1106.                 i = 0;
  1107.             }

  1108.             if (ngx_hash_find(&headers->hash, header[i].hash,
  1109.                               header[i].lowcase_key, header[i].key.len))
  1110.             {
  1111.                 continue;
  1112.             }

  1113.             len += header[i].key.len + sizeof(": ") - 1
  1114.                 + header[i].value.len + sizeof(CRLF) - 1;
  1115.         }
  1116.     }


  1117.     b = ngx_create_temp_buf(r->pool, len);
  1118.     if (b == NULL) {
  1119.         return NGX_ERROR;
  1120.     }

  1121.     cl = ngx_alloc_chain_link(r->pool);
  1122.     if (cl == NULL) {
  1123.         return NGX_ERROR;
  1124.     }

  1125.     cl->buf = b;


  1126.     /* the request line */

  1127.     b->last = ngx_copy(b->last, method.data, method.len);
  1128.     *b->last++ = ' ';

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

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

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

  1134.     } else {
  1135.         if (r->valid_location) {
  1136.             b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
  1137.         }

  1138.         if (escape) {
  1139.             ngx_escape_uri(b->last, r->uri.data + loc_len,
  1140.                            r->uri.len - loc_len, NGX_ESCAPE_URI);
  1141.             b->last += r->uri.len - loc_len + escape;

  1142.         } else {
  1143.             b->last = ngx_copy(b->last, r->uri.data + loc_len,
  1144.                                r->uri.len - loc_len);
  1145.         }

  1146.         if (r->args.len > 0) {
  1147.             *b->last++ = '?';
  1148.             b->last = ngx_copy(b->last, r->args.data, r->args.len);
  1149.         }
  1150.     }

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

  1152.     if (plcf->http_version == NGX_HTTP_VERSION_11) {
  1153.         b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
  1154.                              sizeof(ngx_http_proxy_version_11) - 1);

  1155.     } else {
  1156.         b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
  1157.                              sizeof(ngx_http_proxy_version) - 1);
  1158.     }

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

  1160.     e.ip = headers->values->elts;
  1161.     e.pos = b->last;
  1162.     e.request = r;
  1163.     e.flushed = 1;

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

  1165.     while (*(uintptr_t *) le.ip) {

  1166.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  1167.         (void) lcode(&le);

  1168.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  1169.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  1170.         }
  1171.         le.ip += sizeof(uintptr_t);

  1172.         if (val_len == 0) {
  1173.             e.skip = 1;

  1174.             while (*(uintptr_t *) e.ip) {
  1175.                 code = *(ngx_http_script_code_pt *) e.ip;
  1176.                 code((ngx_http_script_engine_t *) &e);
  1177.             }
  1178.             e.ip += sizeof(uintptr_t);

  1179.             e.skip = 0;

  1180.             continue;
  1181.         }

  1182.         code = *(ngx_http_script_code_pt *) e.ip;
  1183.         code((ngx_http_script_engine_t *) &e);

  1184.         *e.pos++ = ':'; *e.pos++ = ' ';

  1185.         while (*(uintptr_t *) e.ip) {
  1186.             code = *(ngx_http_script_code_pt *) e.ip;
  1187.             code((ngx_http_script_engine_t *) &e);
  1188.         }
  1189.         e.ip += sizeof(uintptr_t);

  1190.         *e.pos++ = CR; *e.pos++ = LF;
  1191.     }

  1192.     b->last = e.pos;


  1193.     if (plcf->upstream.pass_request_headers) {
  1194.         part = &r->headers_in.headers.part;
  1195.         header = part->elts;

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

  1197.             if (i >= part->nelts) {
  1198.                 if (part->next == NULL) {
  1199.                     break;
  1200.                 }

  1201.                 part = part->next;
  1202.                 header = part->elts;
  1203.                 i = 0;
  1204.             }

  1205.             if (ngx_hash_find(&headers->hash, header[i].hash,
  1206.                               header[i].lowcase_key, header[i].key.len))
  1207.             {
  1208.                 continue;
  1209.             }

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

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

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

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

  1215.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1216.                            "http proxy header: \"%V: %V\"",
  1217.                            &header[i].key, &header[i].value);
  1218.         }
  1219.     }


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

  1222.     if (plcf->body_values) {
  1223.         e.ip = plcf->body_values->elts;
  1224.         e.pos = b->last;
  1225.         e.skip = 0;

  1226.         while (*(uintptr_t *) e.ip) {
  1227.             code = *(ngx_http_script_code_pt *) e.ip;
  1228.             code((ngx_http_script_engine_t *) &e);
  1229.         }

  1230.         b->last = e.pos;
  1231.     }

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

  1235.     if (r->request_body_no_buffering) {

  1236.         u->request_bufs = cl;

  1237.         if (ctx->internal_chunked) {
  1238.             u->output.output_filter = ngx_http_proxy_body_output_filter;
  1239.             u->output.filter_ctx = r;
  1240.         }

  1241.     } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {

  1242.         body = u->request_bufs;
  1243.         u->request_bufs = cl;

  1244.         while (body) {
  1245.             b = ngx_alloc_buf(r->pool);
  1246.             if (b == NULL) {
  1247.                 return NGX_ERROR;
  1248.             }

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

  1250.             cl->next = ngx_alloc_chain_link(r->pool);
  1251.             if (cl->next == NULL) {
  1252.                 return NGX_ERROR;
  1253.             }

  1254.             cl = cl->next;
  1255.             cl->buf = b;

  1256.             body = body->next;
  1257.         }

  1258.     } else {
  1259.         u->request_bufs = cl;
  1260.     }

  1261.     b->flush = 1;
  1262.     cl->next = NULL;

  1263.     return NGX_OK;
  1264. }


  1265. static ngx_int_t
  1266. ngx_http_proxy_reinit_request(ngx_http_request_t *r)
  1267. {
  1268.     ngx_http_proxy_ctx_t  *ctx;

  1269.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1270.     if (ctx == NULL) {
  1271.         return NGX_OK;
  1272.     }

  1273.     ctx->status.code = 0;
  1274.     ctx->status.count = 0;
  1275.     ctx->status.start = NULL;
  1276.     ctx->status.end = NULL;
  1277.     ctx->chunked.state = 0;

  1278.     r->upstream->process_header = ngx_http_proxy_process_status_line;
  1279.     r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
  1280.     r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
  1281.     r->state = 0;

  1282.     return NGX_OK;
  1283. }


  1284. static ngx_int_t
  1285. ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in)
  1286. {
  1287.     ngx_http_request_t  *r = data;

  1288.     off_t                  size;
  1289.     u_char                *chunk;
  1290.     ngx_int_t              rc;
  1291.     ngx_buf_t             *b;
  1292.     ngx_chain_t           *out, *cl, *tl, **ll, **fl;
  1293.     ngx_http_proxy_ctx_t  *ctx;

  1294.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1295.                    "proxy output filter");

  1296.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1297.     if (in == NULL) {
  1298.         out = in;
  1299.         goto out;
  1300.     }

  1301.     out = NULL;
  1302.     ll = &out;

  1303.     if (!ctx->header_sent) {
  1304.         /* first buffer contains headers, pass it unmodified */

  1305.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1306.                        "proxy output header");

  1307.         ctx->header_sent = 1;

  1308.         tl = ngx_alloc_chain_link(r->pool);
  1309.         if (tl == NULL) {
  1310.             return NGX_ERROR;
  1311.         }

  1312.         tl->buf = in->buf;
  1313.         *ll = tl;
  1314.         ll = &tl->next;

  1315.         in = in->next;

  1316.         if (in == NULL) {
  1317.             tl->next = NULL;
  1318.             goto out;
  1319.         }
  1320.     }

  1321.     size = 0;
  1322.     cl = in;
  1323.     fl = ll;

  1324.     for ( ;; ) {
  1325.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1326.                        "proxy output chunk: %O", ngx_buf_size(cl->buf));

  1327.         size += ngx_buf_size(cl->buf);

  1328.         if (cl->buf->flush
  1329.             || cl->buf->sync
  1330.             || ngx_buf_in_memory(cl->buf)
  1331.             || cl->buf->in_file)
  1332.         {
  1333.             tl = ngx_alloc_chain_link(r->pool);
  1334.             if (tl == NULL) {
  1335.                 return NGX_ERROR;
  1336.             }

  1337.             tl->buf = cl->buf;
  1338.             *ll = tl;
  1339.             ll = &tl->next;
  1340.         }

  1341.         if (cl->next == NULL) {
  1342.             break;
  1343.         }

  1344.         cl = cl->next;
  1345.     }

  1346.     if (size) {
  1347.         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  1348.         if (tl == NULL) {
  1349.             return NGX_ERROR;
  1350.         }

  1351.         b = tl->buf;
  1352.         chunk = b->start;

  1353.         if (chunk == NULL) {
  1354.             /* the "0000000000000000" is 64-bit hexadecimal string */

  1355.             chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
  1356.             if (chunk == NULL) {
  1357.                 return NGX_ERROR;
  1358.             }

  1359.             b->start = chunk;
  1360.             b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
  1361.         }

  1362.         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
  1363.         b->memory = 0;
  1364.         b->temporary = 1;
  1365.         b->pos = chunk;
  1366.         b->last = ngx_sprintf(chunk, "%xO" CRLF, size);

  1367.         tl->next = *fl;
  1368.         *fl = tl;
  1369.     }

  1370.     if (cl->buf->last_buf) {
  1371.         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  1372.         if (tl == NULL) {
  1373.             return NGX_ERROR;
  1374.         }

  1375.         b = tl->buf;

  1376.         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
  1377.         b->temporary = 0;
  1378.         b->memory = 1;
  1379.         b->last_buf = 1;
  1380.         b->pos = (u_char *) CRLF "0" CRLF CRLF;
  1381.         b->last = b->pos + 7;

  1382.         cl->buf->last_buf = 0;

  1383.         *ll = tl;

  1384.         if (size == 0) {
  1385.             b->pos += 2;
  1386.         }

  1387.     } else if (size > 0) {
  1388.         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  1389.         if (tl == NULL) {
  1390.             return NGX_ERROR;
  1391.         }

  1392.         b = tl->buf;

  1393.         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
  1394.         b->temporary = 0;
  1395.         b->memory = 1;
  1396.         b->pos = (u_char *) CRLF;
  1397.         b->last = b->pos + 2;

  1398.         *ll = tl;

  1399.     } else {
  1400.         *ll = NULL;
  1401.     }

  1402. out:

  1403.     rc = ngx_chain_writer(&r->upstream->writer, out);

  1404.     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
  1405.                             (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter);

  1406.     return rc;
  1407. }


  1408. static ngx_int_t
  1409. ngx_http_proxy_process_status_line(ngx_http_request_t *r)
  1410. {
  1411.     size_t                 len;
  1412.     ngx_int_t              rc;
  1413.     ngx_http_upstream_t   *u;
  1414.     ngx_http_proxy_ctx_t  *ctx;

  1415.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1416.     if (ctx == NULL) {
  1417.         return NGX_ERROR;
  1418.     }

  1419.     u = r->upstream;

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

  1421.     if (rc == NGX_AGAIN) {
  1422.         return rc;
  1423.     }

  1424.     if (rc == NGX_ERROR) {

  1425. #if (NGX_HTTP_CACHE)

  1426.         if (r->cache) {
  1427.             r->http_version = NGX_HTTP_VERSION_9;
  1428.             return NGX_OK;
  1429.         }

  1430. #endif

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

  1433. #if 0
  1434.         if (u->accel) {
  1435.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1436.         }
  1437. #endif

  1438.         r->http_version = NGX_HTTP_VERSION_9;
  1439.         u->state->status = NGX_HTTP_OK;
  1440.         u->headers_in.connection_close = 1;

  1441.         return NGX_OK;
  1442.     }

  1443.     if (u->state && u->state->status == 0) {
  1444.         u->state->status = ctx->status.code;
  1445.     }

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

  1447.     len = ctx->status.end - ctx->status.start;
  1448.     u->headers_in.status_line.len = len;

  1449.     u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
  1450.     if (u->headers_in.status_line.data == NULL) {
  1451.         return NGX_ERROR;
  1452.     }

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

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

  1457.     if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
  1458.         u->headers_in.connection_close = 1;
  1459.     }

  1460.     u->process_header = ngx_http_proxy_process_header;

  1461.     return ngx_http_proxy_process_header(r);
  1462. }


  1463. static ngx_int_t
  1464. ngx_http_proxy_process_header(ngx_http_request_t *r)
  1465. {
  1466.     ngx_int_t                       rc;
  1467.     ngx_table_elt_t                *h;
  1468.     ngx_http_upstream_t            *u;
  1469.     ngx_http_proxy_ctx_t           *ctx;
  1470.     ngx_http_upstream_header_t     *hh;
  1471.     ngx_http_upstream_main_conf_t  *umcf;

  1472.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1473.     for ( ;; ) {

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

  1475.         if (rc == NGX_OK) {

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

  1477.             h = ngx_list_push(&r->upstream->headers_in.headers);
  1478.             if (h == NULL) {
  1479.                 return NGX_ERROR;
  1480.             }

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

  1482.             h->key.len = r->header_name_end - r->header_name_start;
  1483.             h->value.len = r->header_end - r->header_start;

  1484.             h->key.data = ngx_pnalloc(r->pool,
  1485.                                h->key.len + 1 + h->value.len + 1 + h->key.len);
  1486.             if (h->key.data == NULL) {
  1487.                 h->hash = 0;
  1488.                 return NGX_ERROR;
  1489.             }

  1490.             h->value.data = h->key.data + h->key.len + 1;
  1491.             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;

  1492.             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  1493.             h->key.data[h->key.len] = '\0';
  1494.             ngx_memcpy(h->value.data, r->header_start, h->value.len);
  1495.             h->value.data[h->value.len] = '\0';

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

  1498.             } else {
  1499.                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  1500.             }

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

  1503.             if (hh) {
  1504.                 rc = hh->handler(r, h, hh->offset);

  1505.                 if (rc != NGX_OK) {
  1506.                     return rc;
  1507.                 }
  1508.             }

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

  1512.             continue;
  1513.         }

  1514.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1518.             /*
  1519.              * if no "Server" and "Date" in header line,
  1520.              * then add the special empty headers
  1521.              */

  1522.             if (r->upstream->headers_in.server == NULL) {
  1523.                 h = ngx_list_push(&r->upstream->headers_in.headers);
  1524.                 if (h == NULL) {
  1525.                     return NGX_ERROR;
  1526.                 }

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

  1529.                 ngx_str_set(&h->key, "Server");
  1530.                 ngx_str_null(&h->value);
  1531.                 h->lowcase_key = (u_char *) "server";
  1532.                 h->next = NULL;
  1533.             }

  1534.             if (r->upstream->headers_in.date == NULL) {
  1535.                 h = ngx_list_push(&r->upstream->headers_in.headers);
  1536.                 if (h == NULL) {
  1537.                     return NGX_ERROR;
  1538.                 }

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

  1540.                 ngx_str_set(&h->key, "Date");
  1541.                 ngx_str_null(&h->value);
  1542.                 h->lowcase_key = (u_char *) "date";
  1543.                 h->next = NULL;
  1544.             }

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

  1546.             u = r->upstream;

  1547.             if (u->headers_in.chunked) {
  1548.                 u->headers_in.content_length_n = -1;
  1549.             }

  1550.             /*
  1551.              * set u->keepalive if response has no body; this allows to keep
  1552.              * connections alive in case of r->header_only or X-Accel-Redirect
  1553.              */

  1554.             ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1555.             if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1556.                 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
  1557.                 || ctx->head
  1558.                 || (!u->headers_in.chunked
  1559.                     && u->headers_in.content_length_n == 0))
  1560.             {
  1561.                 u->keepalive = !u->headers_in.connection_close;
  1562.             }

  1563.             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
  1564.                 u->keepalive = 0;

  1565.                 if (r->headers_in.upgrade) {
  1566.                     u->upgrade = 1;
  1567.                 }
  1568.             }

  1569.             return NGX_OK;
  1570.         }

  1571.         if (rc == NGX_AGAIN) {
  1572.             return NGX_AGAIN;
  1573.         }

  1574.         /* rc == NGX_HTTP_PARSE_INVALID_HEADER */

  1575.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1576.                       "upstream sent invalid header: \"%*s\\x%02xd...\"",
  1577.                       r->header_end - r->header_name_start,
  1578.                       r->header_name_start, *r->header_end);

  1579.         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1580.     }
  1581. }


  1582. static ngx_int_t
  1583. ngx_http_proxy_input_filter_init(void *data)
  1584. {
  1585.     ngx_http_request_t    *r = data;
  1586.     ngx_http_upstream_t   *u;
  1587.     ngx_http_proxy_ctx_t  *ctx;

  1588.     u = r->upstream;
  1589.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1590.     if (ctx == NULL) {
  1591.         return NGX_ERROR;
  1592.     }

  1593.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1594.                    "http proxy filter init s:%ui h:%d c:%d l:%O",
  1595.                    u->headers_in.status_n, ctx->head, u->headers_in.chunked,
  1596.                    u->headers_in.content_length_n);

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

  1598.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1599.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
  1600.         || ctx->head)
  1601.     {
  1602.         /* 1xx, 204, and 304 and replies to HEAD requests */
  1603.         /* no 1xx since we don't send Expect and Upgrade */

  1604.         u->pipe->length = 0;
  1605.         u->length = 0;
  1606.         u->keepalive = !u->headers_in.connection_close;

  1607.     } else if (u->headers_in.chunked) {
  1608.         /* chunked */

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

  1611.         u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
  1612.         u->length = 1;

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

  1615.         u->pipe->length = 0;
  1616.         u->length = 0;
  1617.         u->keepalive = !u->headers_in.connection_close;

  1618.     } else {
  1619.         /* content length or connection close */

  1620.         u->pipe->length = u->headers_in.content_length_n;
  1621.         u->length = u->headers_in.content_length_n;
  1622.     }

  1623.     return NGX_OK;
  1624. }


  1625. static ngx_int_t
  1626. ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1627. {
  1628.     ngx_buf_t           *b;
  1629.     ngx_chain_t         *cl;
  1630.     ngx_http_request_t  *r;

  1631.     if (buf->pos == buf->last) {
  1632.         return NGX_OK;
  1633.     }

  1634.     if (p->upstream_done) {
  1635.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
  1636.                        "http proxy data after close");
  1637.         return NGX_OK;
  1638.     }

  1639.     if (p->length == 0) {

  1640.         ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1641.                       "upstream sent more data than specified in "
  1642.                       "\"Content-Length\" header");

  1643.         r = p->input_ctx;
  1644.         r->upstream->keepalive = 0;
  1645.         p->upstream_done = 1;

  1646.         return NGX_OK;
  1647.     }

  1648.     cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1649.     if (cl == NULL) {
  1650.         return NGX_ERROR;
  1651.     }

  1652.     b = cl->buf;

  1653.     ngx_memcpy(b, buf, sizeof(ngx_buf_t));
  1654.     b->shadow = buf;
  1655.     b->tag = p->tag;
  1656.     b->last_shadow = 1;
  1657.     b->recycled = 1;
  1658.     buf->shadow = b;

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

  1660.     if (p->in) {
  1661.         *p->last_in = cl;
  1662.     } else {
  1663.         p->in = cl;
  1664.     }
  1665.     p->last_in = &cl->next;

  1666.     if (p->length == -1) {
  1667.         return NGX_OK;
  1668.     }

  1669.     if (b->last - b->pos > p->length) {

  1670.         ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1671.                       "upstream sent more data than specified in "
  1672.                       "\"Content-Length\" header");

  1673.         b->last = b->pos + p->length;
  1674.         p->upstream_done = 1;

  1675.         return NGX_OK;
  1676.     }

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

  1678.     if (p->length == 0) {
  1679.         r = p->input_ctx;
  1680.         r->upstream->keepalive = !r->upstream->headers_in.connection_close;
  1681.     }

  1682.     return NGX_OK;
  1683. }


  1684. static ngx_int_t
  1685. ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1686. {
  1687.     ngx_int_t                   rc;
  1688.     ngx_buf_t                  *b, **prev;
  1689.     ngx_chain_t                *cl;
  1690.     ngx_http_request_t         *r;
  1691.     ngx_http_proxy_ctx_t       *ctx;
  1692.     ngx_http_proxy_loc_conf_t  *plcf;

  1693.     if (buf->pos == buf->last) {
  1694.         return NGX_OK;
  1695.     }

  1696.     r = p->input_ctx;
  1697.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1698.     if (ctx == NULL) {
  1699.         return NGX_ERROR;
  1700.     }

  1701.     if (p->upstream_done) {
  1702.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
  1703.                        "http proxy data after close");
  1704.         return NGX_OK;
  1705.     }

  1706.     if (p->length == 0) {

  1707.         ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1708.                       "upstream sent data after final chunk");

  1709.         r->upstream->keepalive = 0;
  1710.         p->upstream_done = 1;

  1711.         return NGX_OK;
  1712.     }

  1713.     b = NULL;

  1714.     if (ctx->trailers) {
  1715.         rc = ngx_http_proxy_process_trailer(r, buf);

  1716.         if (rc == NGX_ERROR) {
  1717.             return NGX_ERROR;
  1718.         }

  1719.         if (rc == NGX_OK) {

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

  1721.             p->length = 0;
  1722.             r->upstream->keepalive = !r->upstream->headers_in.connection_close;

  1723.             if (buf->pos != buf->last) {
  1724.                 ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1725.                               "upstream sent data after trailers");
  1726.                 r->upstream->keepalive = 0;
  1727.             }
  1728.         }

  1729.         goto free_buf;
  1730.     }

  1731.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  1732.     prev = &buf->shadow;

  1733.     for ( ;; ) {

  1734.         rc = ngx_http_parse_chunked(r, buf, &ctx->chunked,
  1735.                                     plcf->upstream.pass_trailers);

  1736.         if (rc == NGX_OK) {

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

  1738.             cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1739.             if (cl == NULL) {
  1740.                 return NGX_ERROR;
  1741.             }

  1742.             b = cl->buf;

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

  1744.             b->pos = buf->pos;
  1745.             b->start = buf->start;
  1746.             b->end = buf->end;
  1747.             b->tag = p->tag;
  1748.             b->temporary = 1;
  1749.             b->recycled = 1;

  1750.             *prev = b;
  1751.             prev = &b->shadow;

  1752.             if (p->in) {
  1753.                 *p->last_in = cl;
  1754.             } else {
  1755.                 p->in = cl;
  1756.             }
  1757.             p->last_in = &cl->next;

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

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

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

  1762.                 buf->pos += (size_t) ctx->chunked.size;
  1763.                 b->last = buf->pos;
  1764.                 ctx->chunked.size = 0;

  1765.                 continue;
  1766.             }

  1767.             ctx->chunked.size -= buf->last - buf->pos;
  1768.             buf->pos = buf->last;
  1769.             b->last = buf->last;

  1770.             continue;
  1771.         }

  1772.         if (rc == NGX_DONE) {

  1773.             if (plcf->upstream.pass_trailers) {
  1774.                 rc = ngx_http_proxy_process_trailer(r, buf);

  1775.                 if (rc == NGX_ERROR) {
  1776.                     return NGX_ERROR;
  1777.                 }

  1778.                 if (rc == NGX_AGAIN) {
  1779.                     p->length = 1;
  1780.                     break;
  1781.                 }
  1782.             }

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

  1784.             p->length = 0;
  1785.             r->upstream->keepalive = !r->upstream->headers_in.connection_close;

  1786.             if (buf->pos != buf->last) {
  1787.                 ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1788.                               "upstream sent data after final chunk");
  1789.                 r->upstream->keepalive = 0;
  1790.             }

  1791.             break;
  1792.         }

  1793.         if (rc == NGX_AGAIN) {

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

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

  1796.             break;
  1797.         }

  1798.         /* invalid response */

  1799.         ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1800.                       "upstream sent invalid chunked response");

  1801.         return NGX_ERROR;
  1802.     }

  1803. free_buf:

  1804.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0,
  1805.                    "http proxy chunked state %ui, length %O",
  1806.                    ctx->chunked.state, p->length);

  1807.     if (b) {
  1808.         b->shadow = buf;
  1809.         b->last_shadow = 1;

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

  1812.         return NGX_OK;
  1813.     }

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

  1815.     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
  1816.         return NGX_ERROR;
  1817.     }

  1818.     return NGX_OK;
  1819. }


  1820. static ngx_int_t
  1821. ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
  1822. {
  1823.     ngx_http_request_t   *r = data;

  1824.     ngx_buf_t            *b;
  1825.     ngx_chain_t          *cl, **ll;
  1826.     ngx_http_upstream_t  *u;

  1827.     u = r->upstream;

  1828.     if (u->length == 0) {
  1829.         ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  1830.                       "upstream sent more data than specified in "
  1831.                       "\"Content-Length\" header");
  1832.         u->keepalive = 0;
  1833.         return NGX_OK;
  1834.     }

  1835.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1836.         ll = &cl->next;
  1837.     }

  1838.     cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1839.     if (cl == NULL) {
  1840.         return NGX_ERROR;
  1841.     }

  1842.     *ll = cl;

  1843.     cl->buf->flush = 1;
  1844.     cl->buf->memory = 1;

  1845.     b = &u->buffer;

  1846.     cl->buf->pos = b->last;
  1847.     b->last += bytes;
  1848.     cl->buf->last = b->last;
  1849.     cl->buf->tag = u->output.tag;

  1850.     if (u->length == -1) {
  1851.         return NGX_OK;
  1852.     }

  1853.     if (bytes > u->length) {

  1854.         ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  1855.                       "upstream sent more data than specified in "
  1856.                       "\"Content-Length\" header");

  1857.         cl->buf->last = cl->buf->pos + u->length;
  1858.         u->length = 0;

  1859.         return NGX_OK;
  1860.     }

  1861.     u->length -= bytes;

  1862.     if (u->length == 0) {
  1863.         u->keepalive = !u->headers_in.connection_close;
  1864.     }

  1865.     return NGX_OK;
  1866. }


  1867. static ngx_int_t
  1868. ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
  1869. {
  1870.     ngx_http_request_t   *r = data;

  1871.     ngx_int_t                   rc;
  1872.     ngx_buf_t                  *b, *buf;
  1873.     ngx_chain_t                *cl, **ll;
  1874.     ngx_http_upstream_t        *u;
  1875.     ngx_http_proxy_ctx_t       *ctx;
  1876.     ngx_http_proxy_loc_conf_t  *plcf;

  1877.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  1878.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1879.     if (ctx == NULL) {
  1880.         return NGX_ERROR;
  1881.     }

  1882.     u = r->upstream;
  1883.     buf = &u->buffer;

  1884.     buf->pos = buf->last;
  1885.     buf->last += bytes;

  1886.     if (ctx->trailers) {
  1887.         rc = ngx_http_proxy_process_trailer(r, buf);

  1888.         if (rc == NGX_ERROR) {
  1889.             return NGX_ERROR;
  1890.         }

  1891.         if (rc == NGX_OK) {

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

  1893.             r->upstream->keepalive = !u->headers_in.connection_close;
  1894.             u->length = 0;

  1895.             if (buf->pos != buf->last) {
  1896.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  1897.                               "upstream sent data after trailers");
  1898.                 u->keepalive = 0;
  1899.             }
  1900.         }

  1901.         return NGX_OK;
  1902.     }

  1903.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1904.         ll = &cl->next;
  1905.     }

  1906.     for ( ;; ) {

  1907.         rc = ngx_http_parse_chunked(r, buf, &ctx->chunked,
  1908.                                     plcf->upstream.pass_trailers);

  1909.         if (rc == NGX_OK) {

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

  1911.             cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1912.             if (cl == NULL) {
  1913.                 return NGX_ERROR;
  1914.             }

  1915.             *ll = cl;
  1916.             ll = &cl->next;

  1917.             b = cl->buf;

  1918.             b->flush = 1;
  1919.             b->memory = 1;

  1920.             b->pos = buf->pos;
  1921.             b->tag = u->output.tag;

  1922.             if (buf->last - buf->pos >= ctx->chunked.size) {
  1923.                 buf->pos += (size_t) ctx->chunked.size;
  1924.                 b->last = buf->pos;
  1925.                 ctx->chunked.size = 0;

  1926.             } else {
  1927.                 ctx->chunked.size -= buf->last - buf->pos;
  1928.                 buf->pos = buf->last;
  1929.                 b->last = buf->last;
  1930.             }

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

  1934.             continue;
  1935.         }

  1936.         if (rc == NGX_DONE) {

  1937.             if (plcf->upstream.pass_trailers) {
  1938.                 rc = ngx_http_proxy_process_trailer(r, buf);

  1939.                 if (rc == NGX_ERROR) {
  1940.                     return NGX_ERROR;
  1941.                 }

  1942.                 if (rc == NGX_AGAIN) {
  1943.                     u->length = 1;
  1944.                     break;
  1945.                 }
  1946.             }

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

  1948.             u->keepalive = !u->headers_in.connection_close;
  1949.             u->length = 0;

  1950.             if (buf->pos != buf->last) {
  1951.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  1952.                               "upstream sent data after final chunk");
  1953.                 u->keepalive = 0;
  1954.             }

  1955.             break;
  1956.         }

  1957.         if (rc == NGX_AGAIN) {
  1958.             break;
  1959.         }

  1960.         /* invalid response */

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

  1963.         return NGX_ERROR;
  1964.     }

  1965.     return NGX_OK;
  1966. }


  1967. static ngx_int_t
  1968. ngx_http_proxy_process_trailer(ngx_http_request_t *r, ngx_buf_t *buf)
  1969. {
  1970.     size_t                      len;
  1971.     ngx_int_t                   rc;
  1972.     ngx_buf_t                  *b;
  1973.     ngx_table_elt_t            *h;
  1974.     ngx_http_proxy_ctx_t       *ctx;
  1975.     ngx_http_proxy_loc_conf_t  *plcf;

  1976.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  1977.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  1978.     if (ctx->trailers == NULL) {
  1979.         ctx->trailers = ngx_create_temp_buf(r->pool,
  1980.                                             plcf->upstream.buffer_size);
  1981.         if (ctx->trailers == NULL) {
  1982.             return NGX_ERROR;
  1983.         }
  1984.     }

  1985.     b = ctx->trailers;
  1986.     len = ngx_min(buf->last - buf->pos, b->end - b->last);

  1987.     b->last = ngx_cpymem(b->last, buf->pos, len);

  1988.     for ( ;; ) {

  1989.         rc = ngx_http_parse_header_line(r, b, 1);

  1990.         if (rc == NGX_OK) {

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

  1992.             h = ngx_list_push(&r->upstream->headers_in.trailers);
  1993.             if (h == NULL) {
  1994.                 return NGX_ERROR;
  1995.             }

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

  1997.             h->key.len = r->header_name_end - r->header_name_start;
  1998.             h->value.len = r->header_end - r->header_start;

  1999.             h->key.data = ngx_pnalloc(r->pool,
  2000.                                h->key.len + 1 + h->value.len + 1 + h->key.len);
  2001.             if (h->key.data == NULL) {
  2002.                 h->hash = 0;
  2003.                 return NGX_ERROR;
  2004.             }

  2005.             h->value.data = h->key.data + h->key.len + 1;
  2006.             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;

  2007.             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  2008.             h->key.data[h->key.len] = '\0';
  2009.             ngx_memcpy(h->value.data, r->header_start, h->value.len);
  2010.             h->value.data[h->value.len] = '\0';

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

  2013.             } else {
  2014.                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  2015.             }

  2016.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2017.                            "http proxy trailer: \"%V: %V\"",
  2018.                            &h->key, &h->value);
  2019.             continue;
  2020.         }

  2021.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

  2023.             buf->pos += len - (b->last - b->pos);

  2024.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2025.                            "http proxy trailer done");

  2026.             return NGX_OK;
  2027.         }

  2028.         if (rc == NGX_AGAIN) {
  2029.             buf->pos += len;

  2030.             if (b->last == b->end) {
  2031.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2032.                               "upstream sent too big trailers");
  2033.                 return NGX_ERROR;
  2034.             }

  2035.             return NGX_AGAIN;
  2036.         }

  2037.         /* rc == NGX_HTTP_PARSE_INVALID_HEADER */

  2038.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2039.                       "upstream sent invalid trailer: \"%*s\\x%02xd...\"",
  2040.                       r->header_end - r->header_name_start,
  2041.                       r->header_name_start, *r->header_end);

  2042.         return NGX_ERROR;
  2043.     }
  2044. }


  2045. static void
  2046. ngx_http_proxy_abort_request(ngx_http_request_t *r)
  2047. {
  2048.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2049.                    "abort http proxy request");

  2050.     return;
  2051. }


  2052. static void
  2053. ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  2054. {
  2055.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2056.                    "finalize http proxy request");

  2057.     return;
  2058. }


  2059. static ngx_int_t
  2060. ngx_http_proxy_host_variable(ngx_http_request_t *r,
  2061.     ngx_http_variable_value_t *v, uintptr_t data)
  2062. {
  2063.     ngx_http_proxy_ctx_t  *ctx;

  2064.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  2065.     if (ctx == NULL) {
  2066.         v->not_found = 1;
  2067.         return NGX_OK;
  2068.     }

  2069.     v->len = ctx->vars.host_header.len;
  2070.     v->valid = 1;
  2071.     v->no_cacheable = 0;
  2072.     v->not_found = 0;
  2073.     v->data = ctx->vars.host_header.data;

  2074.     return NGX_OK;
  2075. }


  2076. static ngx_int_t
  2077. ngx_http_proxy_port_variable(ngx_http_request_t *r,
  2078.     ngx_http_variable_value_t *v, uintptr_t data)
  2079. {
  2080.     ngx_http_proxy_ctx_t  *ctx;

  2081.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  2082.     if (ctx == NULL) {
  2083.         v->not_found = 1;
  2084.         return NGX_OK;
  2085.     }

  2086.     v->len = ctx->vars.port.len;
  2087.     v->valid = 1;
  2088.     v->no_cacheable = 0;
  2089.     v->not_found = 0;
  2090.     v->data = ctx->vars.port.data;

  2091.     return NGX_OK;
  2092. }


  2093. static ngx_int_t
  2094. ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
  2095.     ngx_http_variable_value_t *v, uintptr_t data)
  2096. {
  2097.     size_t            len;
  2098.     u_char           *p;
  2099.     ngx_table_elt_t  *h, *xfwd;

  2100.     v->valid = 1;
  2101.     v->no_cacheable = 0;
  2102.     v->not_found = 0;

  2103.     xfwd = r->headers_in.x_forwarded_for;

  2104.     len = 0;

  2105.     for (h = xfwd; h; h = h->next) {
  2106.         len += h->value.len + sizeof(", ") - 1;
  2107.     }

  2108.     if (len == 0) {
  2109.         v->len = r->connection->addr_text.len;
  2110.         v->data = r->connection->addr_text.data;
  2111.         return NGX_OK;
  2112.     }

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

  2114.     p = ngx_pnalloc(r->pool, len);
  2115.     if (p == NULL) {
  2116.         return NGX_ERROR;
  2117.     }

  2118.     v->len = len;
  2119.     v->data = p;

  2120.     for (h = xfwd; h; h = h->next) {
  2121.         p = ngx_copy(p, h->value.data, h->value.len);
  2122.         *p++ = ','; *p++ = ' ';
  2123.     }

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

  2125.     return NGX_OK;
  2126. }


  2127. static ngx_int_t
  2128. ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
  2129.     ngx_http_variable_value_t *v, uintptr_t data)
  2130. {
  2131.     ngx_http_proxy_ctx_t  *ctx;

  2132.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  2133.     if (ctx == NULL || ctx->internal_body_length < 0) {
  2134.         v->not_found = 1;
  2135.         return NGX_OK;
  2136.     }

  2137.     v->valid = 1;
  2138.     v->no_cacheable = 0;
  2139.     v->not_found = 0;

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

  2141.     if (v->data == NULL) {
  2142.         return NGX_ERROR;
  2143.     }

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

  2145.     return NGX_OK;
  2146. }


  2147. static ngx_int_t
  2148. ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
  2149.     ngx_http_variable_value_t *v, uintptr_t data)
  2150. {
  2151.     ngx_http_proxy_ctx_t  *ctx;

  2152.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

  2153.     if (ctx == NULL || !ctx->internal_chunked) {
  2154.         v->not_found = 1;
  2155.         return NGX_OK;
  2156.     }

  2157.     v->valid = 1;
  2158.     v->no_cacheable = 0;
  2159.     v->not_found = 0;

  2160.     v->data = (u_char *) "chunked";
  2161.     v->len = sizeof("chunked") - 1;

  2162.     return NGX_OK;
  2163. }


  2164. static ngx_int_t
  2165. ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
  2166.     size_t prefix)
  2167. {
  2168.     size_t                      len;
  2169.     ngx_int_t                   rc;
  2170.     ngx_uint_t                  i;
  2171.     ngx_http_proxy_rewrite_t   *pr;
  2172.     ngx_http_proxy_loc_conf_t  *plcf;

  2173.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

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

  2175.     if (pr == NULL) {
  2176.         return NGX_DECLINED;
  2177.     }

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

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

  2181.         if (rc != NGX_DECLINED) {
  2182.             return rc;
  2183.         }
  2184.     }

  2185.     return NGX_DECLINED;
  2186. }


  2187. static ngx_int_t
  2188. ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
  2189. {
  2190.     u_char                     *p;
  2191.     size_t                      len;
  2192.     ngx_int_t                   rc, rv;
  2193.     ngx_str_t                  *key, *value;
  2194.     ngx_uint_t                  i;
  2195.     ngx_array_t                 attrs;
  2196.     ngx_keyval_t               *attr;
  2197.     ngx_http_proxy_loc_conf_t  *plcf;

  2198.     if (ngx_array_init(&attrs, r->pool, 2, sizeof(ngx_keyval_t)) != NGX_OK) {
  2199.         return NGX_ERROR;
  2200.     }

  2201.     if (ngx_http_proxy_parse_cookie(&h->value, &attrs) != NGX_OK) {
  2202.         return NGX_ERROR;
  2203.     }

  2204.     attr = attrs.elts;

  2205.     if (attr[0].value.data == NULL) {
  2206.         return NGX_DECLINED;
  2207.     }

  2208.     rv = NGX_DECLINED;

  2209.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  2210.     for (i = 1; i < attrs.nelts; i++) {

  2211.         key = &attr[i].key;
  2212.         value = &attr[i].value;

  2213.         if (plcf->cookie_domains && key->len == 6
  2214.             && ngx_strncasecmp(key->data, (u_char *) "domain", 6) == 0
  2215.             && value->data)
  2216.         {
  2217.             rc = ngx_http_proxy_rewrite_cookie_value(r, value,
  2218.                                                      plcf->cookie_domains);
  2219.             if (rc == NGX_ERROR) {
  2220.                 return NGX_ERROR;
  2221.             }

  2222.             if (rc != NGX_DECLINED) {
  2223.                 rv = rc;
  2224.             }
  2225.         }

  2226.         if (plcf->cookie_paths && key->len == 4
  2227.             && ngx_strncasecmp(key->data, (u_char *) "path", 4) == 0
  2228.             && value->data)
  2229.         {
  2230.             rc = ngx_http_proxy_rewrite_cookie_value(r, value,
  2231.                                                      plcf->cookie_paths);
  2232.             if (rc == NGX_ERROR) {
  2233.                 return NGX_ERROR;
  2234.             }

  2235.             if (rc != NGX_DECLINED) {
  2236.                 rv = rc;
  2237.             }
  2238.         }
  2239.     }

  2240.     if (plcf->cookie_flags) {
  2241.         rc = ngx_http_proxy_rewrite_cookie_flags(r, &attrs,
  2242.                                                  plcf->cookie_flags);
  2243.         if (rc == NGX_ERROR) {
  2244.             return NGX_ERROR;
  2245.         }

  2246.         if (rc != NGX_DECLINED) {
  2247.             rv = rc;
  2248.         }

  2249.         attr = attrs.elts;
  2250.     }

  2251.     if (rv != NGX_OK) {
  2252.         return rv;
  2253.     }

  2254.     len = 0;

  2255.     for (i = 0; i < attrs.nelts; i++) {

  2256.         if (attr[i].key.data == NULL) {
  2257.             continue;
  2258.         }

  2259.         if (i > 0) {
  2260.             len += 2;
  2261.         }

  2262.         len += attr[i].key.len;

  2263.         if (attr[i].value.data) {
  2264.             len += 1 + attr[i].value.len;
  2265.         }
  2266.     }

  2267.     p = ngx_pnalloc(r->pool, len + 1);
  2268.     if (p == NULL) {
  2269.         return NGX_ERROR;
  2270.     }

  2271.     h->value.data = p;
  2272.     h->value.len = len;

  2273.     for (i = 0; i < attrs.nelts; i++) {

  2274.         if (attr[i].key.data == NULL) {
  2275.             continue;
  2276.         }

  2277.         if (i > 0) {
  2278.             *p++ = ';';
  2279.             *p++ = ' ';
  2280.         }

  2281.         p = ngx_cpymem(p, attr[i].key.data, attr[i].key.len);

  2282.         if (attr[i].value.data) {
  2283.             *p++ = '=';
  2284.             p = ngx_cpymem(p, attr[i].value.data, attr[i].value.len);
  2285.         }
  2286.     }

  2287.     *p = '\0';

  2288.     return NGX_OK;
  2289. }


  2290. static ngx_int_t
  2291. ngx_http_proxy_parse_cookie(ngx_str_t *value, ngx_array_t *attrs)
  2292. {
  2293.     u_char        *start, *end, *p, *last;
  2294.     ngx_str_t      name, val;
  2295.     ngx_keyval_t  *attr;

  2296.     start = value->data;
  2297.     end = value->data + value->len;

  2298.     for ( ;; ) {

  2299.         last = (u_char *) ngx_strchr(start, ';');

  2300.         if (last == NULL) {
  2301.             last = end;
  2302.         }

  2303.         while (start < last && *start == ' ') { start++; }

  2304.         for (p = start; p < last && *p != '='; p++) { /* void */ }

  2305.         name.data = start;
  2306.         name.len = p - start;

  2307.         while (name.len && name.data[name.len - 1] == ' ') {
  2308.             name.len--;
  2309.         }

  2310.         if (p < last) {

  2311.             p++;

  2312.             while (p < last && *p == ' ') { p++; }

  2313.             val.data = p;
  2314.             val.len = last - val.data;

  2315.             while (val.len && val.data[val.len - 1] == ' ') {
  2316.                 val.len--;
  2317.             }

  2318.         } else {
  2319.             ngx_str_null(&val);
  2320.         }

  2321.         attr = ngx_array_push(attrs);
  2322.         if (attr == NULL) {
  2323.             return NGX_ERROR;
  2324.         }

  2325.         attr->key = name;
  2326.         attr->value = val;

  2327.         if (last == end) {
  2328.             break;
  2329.         }

  2330.         start = last + 1;
  2331.     }

  2332.     return NGX_OK;
  2333. }


  2334. static ngx_int_t
  2335. ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_str_t *value,
  2336.     ngx_array_t *rewrites)
  2337. {
  2338.     ngx_int_t                  rc;
  2339.     ngx_uint_t                 i;
  2340.     ngx_http_proxy_rewrite_t  *pr;

  2341.     pr = rewrites->elts;

  2342.     for (i = 0; i < rewrites->nelts; i++) {
  2343.         rc = pr[i].handler(r, value, 0, value->len, &pr[i]);

  2344.         if (rc != NGX_DECLINED) {
  2345.             return rc;
  2346.         }
  2347.     }

  2348.     return NGX_DECLINED;
  2349. }


  2350. static ngx_int_t
  2351. ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs,
  2352.     ngx_array_t *flags)
  2353. {
  2354.     ngx_str_t                       pattern, value;
  2355. #if (NGX_PCRE)
  2356.     ngx_int_t                       rc;
  2357. #endif
  2358.     ngx_uint_t                      i, m, f, nelts;
  2359.     ngx_keyval_t                   *attr;
  2360.     ngx_conf_bitmask_t             *mask;
  2361.     ngx_http_complex_value_t       *flags_values;
  2362.     ngx_http_proxy_cookie_flags_t  *pcf;

  2363.     attr = attrs->elts;
  2364.     pcf = flags->elts;

  2365.     for (i = 0; i < flags->nelts; i++) {

  2366. #if (NGX_PCRE)
  2367.         if (pcf[i].regex) {
  2368.             rc = ngx_http_regex_exec(r, pcf[i].cookie.regex, &attr[0].key);

  2369.             if (rc == NGX_ERROR) {
  2370.                 return NGX_ERROR;
  2371.             }

  2372.             if (rc == NGX_OK) {
  2373.                 break;
  2374.             }

  2375.             /* NGX_DECLINED */

  2376.             continue;
  2377.         }
  2378. #endif

  2379.         if (ngx_http_complex_value(r, &pcf[i].cookie.complex, &pattern)
  2380.             != NGX_OK)
  2381.         {
  2382.             return NGX_ERROR;
  2383.         }

  2384.         if (pattern.len == attr[0].key.len
  2385.             && ngx_strncasecmp(attr[0].key.data, pattern.data, pattern.len)
  2386.                == 0)
  2387.         {
  2388.             break;
  2389.         }
  2390.     }

  2391.     if (i == flags->nelts) {
  2392.         return NGX_DECLINED;
  2393.     }

  2394.     nelts = pcf[i].flags_values.nelts;
  2395.     flags_values = pcf[i].flags_values.elts;

  2396.     mask = ngx_http_proxy_cookie_flags_masks;
  2397.     f = 0;

  2398.     for (i = 0; i < nelts; i++) {

  2399.         if (ngx_http_complex_value(r, &flags_values[i], &value) != NGX_OK) {
  2400.             return NGX_ERROR;
  2401.         }

  2402.         if (value.len == 0) {
  2403.             continue;
  2404.         }

  2405.         for (m = 0; mask[m].name.len != 0; m++) {

  2406.             if (mask[m].name.len != value.len
  2407.                 || ngx_strncasecmp(mask[m].name.data, value.data, value.len)
  2408.                    != 0)
  2409.             {
  2410.                 continue;
  2411.             }

  2412.             f |= mask[m].mask;

  2413.             break;
  2414.         }

  2415.         if (mask[m].name.len == 0) {
  2416.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2417.                            "invalid proxy_cookie_flags flag \"%V\"", &value);
  2418.         }
  2419.     }

  2420.     if (f == 0) {
  2421.         return NGX_DECLINED;
  2422.     }

  2423.     return ngx_http_proxy_edit_cookie_flags(r, attrs, f);
  2424. }


  2425. static ngx_int_t
  2426. ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs,
  2427.     ngx_uint_t flags)
  2428. {
  2429.     ngx_str_t     *key, *value;
  2430.     ngx_uint_t     i;
  2431.     ngx_keyval_t  *attr;

  2432.     attr = attrs->elts;

  2433.     for (i = 1; i < attrs->nelts; i++) {
  2434.         key = &attr[i].key;

  2435.         if (key->len == 6
  2436.             && ngx_strncasecmp(key->data, (u_char *) "secure", 6) == 0)
  2437.         {
  2438.             if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) {
  2439.                 flags &= ~NGX_HTTP_PROXY_COOKIE_SECURE_ON;

  2440.             } else if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_OFF) {
  2441.                 key->data = NULL;
  2442.             }

  2443.             continue;
  2444.         }

  2445.         if (key->len == 8
  2446.             && ngx_strncasecmp(key->data, (u_char *) "httponly", 8) == 0)
  2447.         {
  2448.             if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) {
  2449.                 flags &= ~NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON;

  2450.             } else if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF) {
  2451.                 key->data = NULL;
  2452.             }

  2453.             continue;
  2454.         }

  2455.         if (key->len == 8
  2456.             && ngx_strncasecmp(key->data, (u_char *) "samesite", 8) == 0)
  2457.         {
  2458.             value = &attr[i].value;

  2459.             if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) {
  2460.                 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT;

  2461.                 if (value->len != 6
  2462.                     || ngx_strncasecmp(value->data, (u_char *) "strict", 6)
  2463.                        != 0)
  2464.                 {
  2465.                     ngx_str_set(key, "SameSite");
  2466.                     ngx_str_set(value, "Strict");
  2467.                 }

  2468.             } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) {
  2469.                 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX;

  2470.                 if (value->len != 3
  2471.                     || ngx_strncasecmp(value->data, (u_char *) "lax", 3) != 0)
  2472.                 {
  2473.                     ngx_str_set(key, "SameSite");
  2474.                     ngx_str_set(value, "Lax");
  2475.                 }

  2476.             } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE) {
  2477.                 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE;

  2478.                 if (value->len != 4
  2479.                     || ngx_strncasecmp(value->data, (u_char *) "none", 4) != 0)
  2480.                 {
  2481.                     ngx_str_set(key, "SameSite");
  2482.                     ngx_str_set(value, "None");
  2483.                 }

  2484.             } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF) {
  2485.                 key->data = NULL;
  2486.             }

  2487.             continue;
  2488.         }
  2489.     }

  2490.     if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) {
  2491.         attr = ngx_array_push(attrs);
  2492.         if (attr == NULL) {
  2493.             return NGX_ERROR;
  2494.         }

  2495.         ngx_str_set(&attr->key, "Secure");
  2496.         ngx_str_null(&attr->value);
  2497.     }

  2498.     if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) {
  2499.         attr = ngx_array_push(attrs);
  2500.         if (attr == NULL) {
  2501.             return NGX_ERROR;
  2502.         }

  2503.         ngx_str_set(&attr->key, "HttpOnly");
  2504.         ngx_str_null(&attr->value);
  2505.     }

  2506.     if (flags & (NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT
  2507.                  |NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX
  2508.                  |NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE))
  2509.     {
  2510.         attr = ngx_array_push(attrs);
  2511.         if (attr == NULL) {
  2512.             return NGX_ERROR;
  2513.         }

  2514.         ngx_str_set(&attr->key, "SameSite");

  2515.         if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) {
  2516.             ngx_str_set(&attr->value, "Strict");

  2517.         } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) {
  2518.             ngx_str_set(&attr->value, "Lax");

  2519.         } else {
  2520.             ngx_str_set(&attr->value, "None");
  2521.         }
  2522.     }

  2523.     return NGX_OK;
  2524. }


  2525. static ngx_int_t
  2526. ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, ngx_str_t *value,
  2527.     size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
  2528. {
  2529.     ngx_str_t  pattern, replacement;

  2530.     if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
  2531.         return NGX_ERROR;
  2532.     }

  2533.     if (pattern.len > len
  2534.         || ngx_rstrncmp(value->data + prefix, pattern.data, pattern.len) != 0)
  2535.     {
  2536.         return NGX_DECLINED;
  2537.     }

  2538.     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
  2539.         return NGX_ERROR;
  2540.     }

  2541.     return ngx_http_proxy_rewrite(r, value, prefix, pattern.len, &replacement);
  2542. }


  2543. #if (NGX_PCRE)

  2544. static ngx_int_t
  2545. ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_str_t *value,
  2546.     size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
  2547. {
  2548.     ngx_str_t  pattern, replacement;

  2549.     pattern.len = len;
  2550.     pattern.data = value->data + prefix;

  2551.     if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
  2552.         return NGX_DECLINED;
  2553.     }

  2554.     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
  2555.         return NGX_ERROR;
  2556.     }

  2557.     return ngx_http_proxy_rewrite(r, value, prefix, len, &replacement);
  2558. }

  2559. #endif


  2560. static ngx_int_t
  2561. ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, ngx_str_t *value,
  2562.     size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
  2563. {
  2564.     u_char     *p;
  2565.     ngx_str_t   pattern, replacement;

  2566.     if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
  2567.         return NGX_ERROR;
  2568.     }

  2569.     p = value->data + prefix;

  2570.     if (len && p[0] == '.') {
  2571.         p++;
  2572.         prefix++;
  2573.         len--;
  2574.     }

  2575.     if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
  2576.         return NGX_DECLINED;
  2577.     }

  2578.     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
  2579.         return NGX_ERROR;
  2580.     }

  2581.     return ngx_http_proxy_rewrite(r, value, prefix, len, &replacement);
  2582. }


  2583. static ngx_int_t
  2584. ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_str_t *value, size_t prefix,
  2585.     size_t len, ngx_str_t *replacement)
  2586. {
  2587.     u_char  *p, *data;
  2588.     size_t   new_len;

  2589.     if (len == value->len) {
  2590.         *value = *replacement;
  2591.         return NGX_OK;
  2592.     }

  2593.     new_len = replacement->len + value->len - len;

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

  2595.         data = ngx_pnalloc(r->pool, new_len + 1);
  2596.         if (data == NULL) {
  2597.             return NGX_ERROR;
  2598.         }

  2599.         p = ngx_copy(data, value->data, prefix);
  2600.         p = ngx_copy(p, replacement->data, replacement->len);

  2601.         ngx_memcpy(p, value->data + prefix + len,
  2602.                    value->len - len - prefix + 1);

  2603.         value->data = data;

  2604.     } else {
  2605.         p = ngx_copy(value->data + prefix, replacement->data, replacement->len);

  2606.         ngx_memmove(p, value->data + prefix + len,
  2607.                     value->len - len - prefix + 1);
  2608.     }

  2609.     value->len = new_len;

  2610.     return NGX_OK;
  2611. }


  2612. static ngx_int_t
  2613. ngx_http_proxy_add_variables(ngx_conf_t *cf)
  2614. {
  2615.     ngx_http_variable_t  *var, *v;

  2616.     for (v = ngx_http_proxy_vars; v->name.len; v++) {
  2617.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  2618.         if (var == NULL) {
  2619.             return NGX_ERROR;
  2620.         }

  2621.         var->get_handler = v->get_handler;
  2622.         var->data = v->data;
  2623.     }

  2624.     return NGX_OK;
  2625. }


  2626. static void *
  2627. ngx_http_proxy_create_main_conf(ngx_conf_t *cf)
  2628. {
  2629.     ngx_http_proxy_main_conf_t  *conf;

  2630.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_main_conf_t));
  2631.     if (conf == NULL) {
  2632.         return NULL;
  2633.     }

  2634. #if (NGX_HTTP_CACHE)
  2635.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  2636.                        sizeof(ngx_http_file_cache_t *))
  2637.         != NGX_OK)
  2638.     {
  2639.         return NULL;
  2640.     }
  2641. #endif

  2642.     return conf;
  2643. }


  2644. static void *
  2645. ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
  2646. {
  2647.     ngx_http_proxy_loc_conf_t  *conf;

  2648.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
  2649.     if (conf == NULL) {
  2650.         return NULL;
  2651.     }

  2652.     /*
  2653.      * set by ngx_pcalloc():
  2654.      *
  2655.      *     conf->upstream.bufs.num = 0;
  2656.      *     conf->upstream.ignore_headers = 0;
  2657.      *     conf->upstream.next_upstream = 0;
  2658.      *     conf->upstream.cache_zone = NULL;
  2659.      *     conf->upstream.cache_use_stale = 0;
  2660.      *     conf->upstream.cache_methods = 0;
  2661.      *     conf->upstream.temp_path = NULL;
  2662.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  2663.      *     conf->upstream.store_lengths = NULL;
  2664.      *     conf->upstream.store_values = NULL;
  2665.      *
  2666.      *     conf->location = NULL;
  2667.      *     conf->url = { 0, NULL };
  2668.      *     conf->headers.lengths = NULL;
  2669.      *     conf->headers.values = NULL;
  2670.      *     conf->headers.hash = { NULL, 0 };
  2671.      *     conf->headers_cache.lengths = NULL;
  2672.      *     conf->headers_cache.values = NULL;
  2673.      *     conf->headers_cache.hash = { NULL, 0 };
  2674.      *     conf->body_lengths = NULL;
  2675.      *     conf->body_values = NULL;
  2676.      *     conf->body_source = { 0, NULL };
  2677.      *     conf->redirects = NULL;
  2678.      *     conf->ssl = 0;
  2679.      *     conf->ssl_protocols = 0;
  2680.      *     conf->ssl_ciphers = { 0, NULL };
  2681.      *     conf->ssl_trusted_certificate = { 0, NULL };
  2682.      *     conf->ssl_crl = { 0, NULL };
  2683.      */

  2684.     conf->upstream.store = NGX_CONF_UNSET;
  2685.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  2686.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  2687.     conf->upstream.buffering = NGX_CONF_UNSET;
  2688.     conf->upstream.request_buffering = NGX_CONF_UNSET;
  2689.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  2690.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  2691.     conf->upstream.local = NGX_CONF_UNSET_PTR;
  2692.     conf->upstream.socket_keepalive = NGX_CONF_UNSET;

  2693.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  2694.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  2695.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  2696.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  2697.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  2698.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  2699.     conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;

  2700.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  2701.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  2702.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  2703.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  2704.     conf->upstream.pass_request_body = NGX_CONF_UNSET;
  2705.     conf->upstream.pass_trailers = NGX_CONF_UNSET;

  2706. #if (NGX_HTTP_CACHE)
  2707.     conf->upstream.cache = NGX_CONF_UNSET;
  2708.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  2709.     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
  2710.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  2711.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  2712.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  2713.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  2714.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  2715.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  2716.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  2717.     conf->upstream.cache_convert_head = NGX_CONF_UNSET;
  2718.     conf->upstream.cache_background_update = NGX_CONF_UNSET;
  2719. #endif

  2720.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  2721.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  2722.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  2723. #if (NGX_HTTP_SSL)
  2724.     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
  2725.     conf->upstream.ssl_name = NGX_CONF_UNSET_PTR;
  2726.     conf->upstream.ssl_server_name = NGX_CONF_UNSET;
  2727.     conf->upstream.ssl_verify = NGX_CONF_UNSET;
  2728.     conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR;
  2729.     conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR;
  2730.     conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR;
  2731.     conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
  2732.     conf->ssl_conf_commands = NGX_CONF_UNSET_PTR;
  2733. #endif

  2734.     /* "proxy_cyclic_temp_file" is disabled */
  2735.     conf->upstream.cyclic_temp_file = 0;

  2736.     conf->upstream.change_buffering = 1;

  2737.     conf->headers_source = NGX_CONF_UNSET_PTR;

  2738.     conf->method = NGX_CONF_UNSET_PTR;

  2739.     conf->redirect = NGX_CONF_UNSET;

  2740.     conf->cookie_domains = NGX_CONF_UNSET_PTR;
  2741.     conf->cookie_paths = NGX_CONF_UNSET_PTR;
  2742.     conf->cookie_flags = NGX_CONF_UNSET_PTR;

  2743.     conf->http_version = NGX_CONF_UNSET_UINT;

  2744.     conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
  2745.     conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;

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

  2747.     return conf;
  2748. }


  2749. static char *
  2750. ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  2751. {
  2752.     ngx_http_proxy_loc_conf_t *prev = parent;
  2753.     ngx_http_proxy_loc_conf_t *conf = child;

  2754.     u_char                     *p;
  2755.     size_t                      size;
  2756.     ngx_int_t                   rc;
  2757.     ngx_hash_init_t             hash;
  2758.     ngx_http_core_loc_conf_t   *clcf;
  2759.     ngx_http_proxy_rewrite_t   *pr;
  2760.     ngx_http_script_compile_t   sc;

  2761. #if (NGX_HTTP_CACHE)

  2762.     if (conf->upstream.store > 0) {
  2763.         conf->upstream.cache = 0;
  2764.     }

  2765.     if (conf->upstream.cache > 0) {
  2766.         conf->upstream.store = 0;
  2767.     }

  2768. #endif

  2769.     if (conf->upstream.store == NGX_CONF_UNSET) {
  2770.         ngx_conf_merge_value(conf->upstream.store,
  2771.                               prev->upstream.store, 0);

  2772.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  2773.         conf->upstream.store_values = prev->upstream.store_values;
  2774.     }

  2775.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  2776.                               prev->upstream.store_access, 0600);

  2777.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  2778.                               prev->upstream.next_upstream_tries, 0);

  2779.     ngx_conf_merge_value(conf->upstream.buffering,
  2780.                               prev->upstream.buffering, 1);

  2781.     ngx_conf_merge_value(conf->upstream.request_buffering,
  2782.                               prev->upstream.request_buffering, 1);

  2783.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  2784.                               prev->upstream.ignore_client_abort, 0);

  2785.     ngx_conf_merge_value(conf->upstream.force_ranges,
  2786.                               prev->upstream.force_ranges, 0);

  2787.     ngx_conf_merge_ptr_value(conf->upstream.local,
  2788.                               prev->upstream.local, NULL);

  2789.     ngx_conf_merge_value(conf->upstream.socket_keepalive,
  2790.                               prev->upstream.socket_keepalive, 0);

  2791.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  2792.                               prev->upstream.connect_timeout, 60000);

  2793.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  2794.                               prev->upstream.send_timeout, 60000);

  2795.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  2796.                               prev->upstream.read_timeout, 60000);

  2797.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  2798.                               prev->upstream.next_upstream_timeout, 0);

  2799.     ngx_conf_merge_size_value(conf->upstream.send_lowat,
  2800.                               prev->upstream.send_lowat, 0);

  2801.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  2802.                               prev->upstream.buffer_size,
  2803.                               (size_t) ngx_pagesize);

  2804.     ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
  2805.                               prev->upstream.limit_rate, NULL);

  2806.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  2807.                               8, ngx_pagesize);

  2808.     if (conf->upstream.bufs.num < 2) {
  2809.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2810.                            "there must be at least 2 \"proxy_buffers\"");
  2811.         return NGX_CONF_ERROR;
  2812.     }


  2813.     size = conf->upstream.buffer_size;
  2814.     if (size < conf->upstream.bufs.size) {
  2815.         size = conf->upstream.bufs.size;
  2816.     }


  2817.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  2818.                               prev->upstream.busy_buffers_size_conf,
  2819.                               NGX_CONF_UNSET_SIZE);

  2820.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  2821.         conf->upstream.busy_buffers_size = 2 * size;
  2822.     } else {
  2823.         conf->upstream.busy_buffers_size =
  2824.                                          conf->upstream.busy_buffers_size_conf;
  2825.     }

  2826.     if (conf->upstream.busy_buffers_size < size) {
  2827.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2828.              "\"proxy_busy_buffers_size\" must be equal to or greater than "
  2829.              "the maximum of the value of \"proxy_buffer_size\" and "
  2830.              "one of the \"proxy_buffers\"");

  2831.         return NGX_CONF_ERROR;
  2832.     }

  2833.     if (conf->upstream.busy_buffers_size
  2834.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  2835.     {
  2836.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2837.              "\"proxy_busy_buffers_size\" must be less than "
  2838.              "the size of all \"proxy_buffers\" minus one buffer");

  2839.         return NGX_CONF_ERROR;
  2840.     }


  2841.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  2842.                               prev->upstream.temp_file_write_size_conf,
  2843.                               NGX_CONF_UNSET_SIZE);

  2844.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  2845.         conf->upstream.temp_file_write_size = 2 * size;
  2846.     } else {
  2847.         conf->upstream.temp_file_write_size =
  2848.                                       conf->upstream.temp_file_write_size_conf;
  2849.     }

  2850.     if (conf->upstream.temp_file_write_size < size) {
  2851.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2852.              "\"proxy_temp_file_write_size\" must be equal to or greater "
  2853.              "than the maximum of the value of \"proxy_buffer_size\" and "
  2854.              "one of the \"proxy_buffers\"");

  2855.         return NGX_CONF_ERROR;
  2856.     }

  2857.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  2858.                               prev->upstream.max_temp_file_size_conf,
  2859.                               NGX_CONF_UNSET_SIZE);

  2860.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  2861.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  2862.     } else {
  2863.         conf->upstream.max_temp_file_size =
  2864.                                         conf->upstream.max_temp_file_size_conf;
  2865.     }

  2866.     if (conf->upstream.max_temp_file_size != 0
  2867.         && conf->upstream.max_temp_file_size < size)
  2868.     {
  2869.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2870.              "\"proxy_max_temp_file_size\" must be equal to zero to disable "
  2871.              "temporary files usage or must be equal to or greater than "
  2872.              "the maximum of the value of \"proxy_buffer_size\" and "
  2873.              "one of the \"proxy_buffers\"");

  2874.         return NGX_CONF_ERROR;
  2875.     }


  2876.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  2877.                               prev->upstream.ignore_headers,
  2878.                               NGX_CONF_BITMASK_SET);


  2879.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  2880.                               prev->upstream.next_upstream,
  2881.                               (NGX_CONF_BITMASK_SET
  2882.                                |NGX_HTTP_UPSTREAM_FT_ERROR
  2883.                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  2884.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  2885.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  2886.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  2887.     }

  2888.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  2889.                               prev->upstream.temp_path,
  2890.                               &ngx_http_proxy_temp_path)
  2891.         != NGX_OK)
  2892.     {
  2893.         return NGX_CONF_ERROR;
  2894.     }


  2895. #if (NGX_HTTP_CACHE)

  2896.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  2897.         ngx_conf_merge_value(conf->upstream.cache,
  2898.                               prev->upstream.cache, 0);

  2899.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  2900.         conf->upstream.cache_value = prev->upstream.cache_value;
  2901.     }

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

  2904.         shm_zone = conf->upstream.cache_zone;

  2905.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2906.                            "\"proxy_cache\" zone \"%V\" is unknown",
  2907.                            &shm_zone->shm.name);

  2908.         return NGX_CONF_ERROR;
  2909.     }

  2910.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  2911.                               prev->upstream.cache_min_uses, 1);

  2912.     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
  2913.                               prev->upstream.cache_max_range_offset,
  2914.                               NGX_MAX_OFF_T_VALUE);

  2915.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  2916.                               prev->upstream.cache_use_stale,
  2917.                               (NGX_CONF_BITMASK_SET
  2918.                                |NGX_HTTP_UPSTREAM_FT_OFF));

  2919.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
  2920.         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
  2921.                                          |NGX_HTTP_UPSTREAM_FT_OFF;
  2922.     }

  2923.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  2924.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  2925.     }

  2926.     if (conf->upstream.cache_methods == 0) {
  2927.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  2928.     }

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

  2930.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  2931.                              prev->upstream.cache_bypass, NULL);

  2932.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  2933.                              prev->upstream.no_cache, NULL);

  2934.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  2935.                              prev->upstream.cache_valid, NULL);

  2936.     if (conf->cache_key.value.data == NULL) {
  2937.         conf->cache_key = prev->cache_key;
  2938.     }

  2939.     ngx_conf_merge_value(conf->upstream.cache_lock,
  2940.                               prev->upstream.cache_lock, 0);

  2941.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  2942.                               prev->upstream.cache_lock_timeout, 5000);

  2943.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  2944.                               prev->upstream.cache_lock_age, 5000);

  2945.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  2946.                               prev->upstream.cache_revalidate, 0);

  2947.     ngx_conf_merge_value(conf->upstream.cache_convert_head,
  2948.                               prev->upstream.cache_convert_head, 1);

  2949.     ngx_conf_merge_value(conf->upstream.cache_background_update,
  2950.                               prev->upstream.cache_background_update, 0);

  2951. #endif

  2952.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  2953.                               prev->upstream.pass_request_headers, 1);
  2954.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  2955.                               prev->upstream.pass_request_body, 1);

  2956.     ngx_conf_merge_value(conf->upstream.pass_trailers,
  2957.                               prev->upstream.pass_trailers, 0);

  2958.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  2959.                               prev->upstream.intercept_errors, 0);

  2960. #if (NGX_HTTP_SSL)

  2961.     if (ngx_http_proxy_merge_ssl(cf, conf, prev) != NGX_OK) {
  2962.         return NGX_CONF_ERROR;
  2963.     }

  2964.     ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
  2965.                               prev->upstream.ssl_session_reuse, 1);

  2966.     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
  2967.                               (NGX_CONF_BITMASK_SET|NGX_SSL_DEFAULT_PROTOCOLS));

  2968.     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
  2969.                              "DEFAULT");

  2970.     ngx_conf_merge_ptr_value(conf->upstream.ssl_name,
  2971.                               prev->upstream.ssl_name, NULL);
  2972.     ngx_conf_merge_value(conf->upstream.ssl_server_name,
  2973.                               prev->upstream.ssl_server_name, 0);
  2974.     ngx_conf_merge_value(conf->upstream.ssl_verify,
  2975.                               prev->upstream.ssl_verify, 0);
  2976.     ngx_conf_merge_uint_value(conf->ssl_verify_depth,
  2977.                               prev->ssl_verify_depth, 1);
  2978.     ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
  2979.                               prev->ssl_trusted_certificate, "");
  2980.     ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");

  2981.     ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate,
  2982.                               prev->upstream.ssl_certificate, NULL);
  2983.     ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key,
  2984.                               prev->upstream.ssl_certificate_key, NULL);
  2985.     ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords,
  2986.                               prev->upstream.ssl_passwords, NULL);

  2987.     ngx_conf_merge_ptr_value(conf->ssl_conf_commands,
  2988.                               prev->ssl_conf_commands, NULL);

  2989.     if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
  2990.         return NGX_CONF_ERROR;
  2991.     }

  2992. #endif

  2993.     ngx_conf_merge_ptr_value(conf->method, prev->method, NULL);

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

  2995.     if (conf->redirect) {

  2996.         if (conf->redirects == NULL) {
  2997.             conf->redirects = prev->redirects;
  2998.         }

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

  3000.             conf->redirects = ngx_array_create(cf->pool, 1,
  3001.                                              sizeof(ngx_http_proxy_rewrite_t));
  3002.             if (conf->redirects == NULL) {
  3003.                 return NGX_CONF_ERROR;
  3004.             }

  3005.             pr = ngx_array_push(conf->redirects);
  3006.             if (pr == NULL) {
  3007.                 return NGX_CONF_ERROR;
  3008.             }

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

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

  3012.             pr->handler = ngx_http_proxy_rewrite_complex_handler;

  3013.             if (conf->vars.uri.len) {
  3014.                 pr->pattern.complex.value = conf->url;
  3015.                 pr->replacement.value = conf->location;

  3016.             } else {
  3017.                 pr->pattern.complex.value.len = conf->url.len
  3018.                                                 + sizeof("/") - 1;

  3019.                 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
  3020.                 if (p == NULL) {
  3021.                     return NGX_CONF_ERROR;
  3022.                 }

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

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

  3026.                 ngx_str_set(&pr->replacement.value, "/");
  3027.             }
  3028.         }
  3029.     }

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

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

  3032.     ngx_conf_merge_ptr_value(conf->cookie_flags, prev->cookie_flags, NULL);

  3033.     ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
  3034.                               NGX_HTTP_VERSION_10);

  3035.     ngx_conf_merge_uint_value(conf->headers_hash_max_size,
  3036.                               prev->headers_hash_max_size, 512);

  3037.     ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
  3038.                               prev->headers_hash_bucket_size, 64);

  3039.     conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
  3040.                                                ngx_cacheline_size);

  3041.     hash.max_size = conf->headers_hash_max_size;
  3042.     hash.bucket_size = conf->headers_hash_bucket_size;
  3043.     hash.name = "proxy_headers_hash";

  3044.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  3045.             &prev->upstream, ngx_http_proxy_hide_headers, &hash)
  3046.         != NGX_OK)
  3047.     {
  3048.         return NGX_CONF_ERROR;
  3049.     }

  3050.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  3051.     if (clcf->noname
  3052.         && conf->upstream.upstream == NULL && conf->proxy_lengths == NULL)
  3053.     {
  3054.         conf->upstream.upstream = prev->upstream.upstream;
  3055.         conf->location = prev->location;
  3056.         conf->vars = prev->vars;

  3057.         conf->proxy_lengths = prev->proxy_lengths;
  3058.         conf->proxy_values = prev->proxy_values;

  3059. #if (NGX_HTTP_SSL)
  3060.         conf->ssl = prev->ssl;
  3061. #endif
  3062.     }

  3063.     if (clcf->lmt_excpt && clcf->handler == NULL
  3064.         && (conf->upstream.upstream || conf->proxy_lengths))
  3065.     {
  3066.         clcf->handler = ngx_http_proxy_handler;
  3067.     }

  3068.     if (conf->body_source.data == NULL) {
  3069.         conf->body_flushes = prev->body_flushes;
  3070.         conf->body_source = prev->body_source;
  3071.         conf->body_lengths = prev->body_lengths;
  3072.         conf->body_values = prev->body_values;
  3073.     }

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

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

  3076.         sc.cf = cf;
  3077.         sc.source = &conf->body_source;
  3078.         sc.flushes = &conf->body_flushes;
  3079.         sc.lengths = &conf->body_lengths;
  3080.         sc.values = &conf->body_values;
  3081.         sc.complete_lengths = 1;
  3082.         sc.complete_values = 1;

  3083.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  3084.             return NGX_CONF_ERROR;
  3085.         }
  3086.     }

  3087.     ngx_conf_merge_ptr_value(conf->headers_source, prev->headers_source, NULL);

  3088.     if (conf->headers_source == prev->headers_source) {
  3089.         conf->headers = prev->headers;
  3090. #if (NGX_HTTP_CACHE)
  3091.         conf->headers_cache = prev->headers_cache;
  3092. #endif
  3093.     }

  3094.     rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers,
  3095.                                      ngx_http_proxy_headers);
  3096.     if (rc != NGX_OK) {
  3097.         return NGX_CONF_ERROR;
  3098.     }

  3099. #if (NGX_HTTP_CACHE)

  3100.     if (conf->upstream.cache) {
  3101.         rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers_cache,
  3102.                                          ngx_http_proxy_cache_headers);
  3103.         if (rc != NGX_OK) {
  3104.             return NGX_CONF_ERROR;
  3105.         }
  3106.     }

  3107. #endif

  3108.     /*
  3109.      * special handling to preserve conf->headers in the "http" section
  3110.      * to inherit it to all servers
  3111.      */

  3112.     if (prev->headers.hash.buckets == NULL
  3113.         && conf->headers_source == prev->headers_source)
  3114.     {
  3115.         prev->headers = conf->headers;
  3116. #if (NGX_HTTP_CACHE)
  3117.         prev->headers_cache = conf->headers_cache;
  3118. #endif
  3119.     }

  3120.     return NGX_CONF_OK;
  3121. }


  3122. static ngx_int_t
  3123. ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
  3124.     ngx_http_proxy_headers_t *headers, ngx_keyval_t *default_headers)
  3125. {
  3126.     u_char                       *p;
  3127.     size_t                        size;
  3128.     uintptr_t                    *code;
  3129.     ngx_uint_t                    i;
  3130.     ngx_array_t                   headers_names, headers_merged;
  3131.     ngx_keyval_t                 *src, *s, *h;
  3132.     ngx_hash_key_t               *hk;
  3133.     ngx_hash_init_t               hash;
  3134.     ngx_http_script_compile_t     sc;
  3135.     ngx_http_script_copy_code_t  *copy;

  3136.     if (headers->hash.buckets) {
  3137.         return NGX_OK;
  3138.     }

  3139.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  3140.         != NGX_OK)
  3141.     {
  3142.         return NGX_ERROR;
  3143.     }

  3144.     if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
  3145.         != NGX_OK)
  3146.     {
  3147.         return NGX_ERROR;
  3148.     }

  3149.     headers->lengths = ngx_array_create(cf->pool, 64, 1);
  3150.     if (headers->lengths == NULL) {
  3151.         return NGX_ERROR;
  3152.     }

  3153.     headers->values = ngx_array_create(cf->pool, 512, 1);
  3154.     if (headers->values == NULL) {
  3155.         return NGX_ERROR;
  3156.     }

  3157.     if (conf->headers_source) {

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

  3160.             s = ngx_array_push(&headers_merged);
  3161.             if (s == NULL) {
  3162.                 return NGX_ERROR;
  3163.             }

  3164.             *s = src[i];
  3165.         }
  3166.     }

  3167.     h = default_headers;

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

  3169.         src = headers_merged.elts;
  3170.         for (i = 0; i < headers_merged.nelts; i++) {
  3171.             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  3172.                 goto next;
  3173.             }
  3174.         }

  3175.         s = ngx_array_push(&headers_merged);
  3176.         if (s == NULL) {
  3177.             return NGX_ERROR;
  3178.         }

  3179.         *s = *h;

  3180.     next:

  3181.         h++;
  3182.     }


  3183.     src = headers_merged.elts;
  3184.     for (i = 0; i < headers_merged.nelts; i++) {

  3185.         hk = ngx_array_push(&headers_names);
  3186.         if (hk == NULL) {
  3187.             return NGX_ERROR;
  3188.         }

  3189.         hk->key = src[i].key;
  3190.         hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
  3191.         hk->value = (void *) 1;

  3192.         if (src[i].value.len == 0) {
  3193.             continue;
  3194.         }

  3195.         copy = ngx_array_push_n(headers->lengths,
  3196.                                 sizeof(ngx_http_script_copy_code_t));
  3197.         if (copy == NULL) {
  3198.             return NGX_ERROR;
  3199.         }

  3200.         copy->code = (ngx_http_script_code_pt) (void *)
  3201.                                                  ngx_http_script_copy_len_code;
  3202.         copy->len = src[i].key.len;

  3203.         size = (sizeof(ngx_http_script_copy_code_t)
  3204.                 + src[i].key.len + sizeof(uintptr_t) - 1)
  3205.                & ~(sizeof(uintptr_t) - 1);

  3206.         copy = ngx_array_push_n(headers->values, size);
  3207.         if (copy == NULL) {
  3208.             return NGX_ERROR;
  3209.         }

  3210.         copy->code = ngx_http_script_copy_code;
  3211.         copy->len = src[i].key.len;

  3212.         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
  3213.         ngx_memcpy(p, src[i].key.data, src[i].key.len);

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

  3215.         sc.cf = cf;
  3216.         sc.source = &src[i].value;
  3217.         sc.flushes = &headers->flushes;
  3218.         sc.lengths = &headers->lengths;
  3219.         sc.values = &headers->values;

  3220.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  3221.             return NGX_ERROR;
  3222.         }

  3223.         code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
  3224.         if (code == NULL) {
  3225.             return NGX_ERROR;
  3226.         }

  3227.         *code = (uintptr_t) NULL;

  3228.         code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
  3229.         if (code == NULL) {
  3230.             return NGX_ERROR;
  3231.         }

  3232.         *code = (uintptr_t) NULL;
  3233.     }

  3234.     code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
  3235.     if (code == NULL) {
  3236.         return NGX_ERROR;
  3237.     }

  3238.     *code = (uintptr_t) NULL;


  3239.     hash.hash = &headers->hash;
  3240.     hash.key = ngx_hash_key_lc;
  3241.     hash.max_size = conf->headers_hash_max_size;
  3242.     hash.bucket_size = conf->headers_hash_bucket_size;
  3243.     hash.name = "proxy_headers_hash";
  3244.     hash.pool = cf->pool;
  3245.     hash.temp_pool = NULL;

  3246.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  3247. }


  3248. static char *
  3249. ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3250. {
  3251.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3252.     size_t                      add;
  3253.     u_short                     port;
  3254.     ngx_str_t                  *value, *url;
  3255.     ngx_url_t                   u;
  3256.     ngx_uint_t                  n;
  3257.     ngx_http_core_loc_conf_t   *clcf;
  3258.     ngx_http_script_compile_t   sc;

  3259.     if (plcf->upstream.upstream || plcf->proxy_lengths) {
  3260.         return "is duplicate";
  3261.     }

  3262.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  3263.     clcf->handler = ngx_http_proxy_handler;

  3264.     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
  3265.         clcf->auto_redirect = 1;
  3266.     }

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

  3268.     url = &value[1];

  3269.     n = ngx_http_script_variables_count(url);

  3270.     if (n) {

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

  3272.         sc.cf = cf;
  3273.         sc.source = url;
  3274.         sc.lengths = &plcf->proxy_lengths;
  3275.         sc.values = &plcf->proxy_values;
  3276.         sc.variables = n;
  3277.         sc.complete_lengths = 1;
  3278.         sc.complete_values = 1;

  3279.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  3280.             return NGX_CONF_ERROR;
  3281.         }

  3282. #if (NGX_HTTP_SSL)
  3283.         plcf->ssl = 1;
  3284. #endif

  3285.         return NGX_CONF_OK;
  3286.     }

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

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

  3291. #if (NGX_HTTP_SSL)
  3292.         plcf->ssl = 1;

  3293.         add = 8;
  3294.         port = 443;
  3295. #else
  3296.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3297.                            "https protocol requires SSL support");
  3298.         return NGX_CONF_ERROR;
  3299. #endif

  3300.     } else {
  3301.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
  3302.         return NGX_CONF_ERROR;
  3303.     }

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

  3305.     u.url.len = url->len - add;
  3306.     u.url.data = url->data + add;
  3307.     u.default_port = port;
  3308.     u.uri_part = 1;
  3309.     u.no_resolve = 1;

  3310.     plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  3311.     if (plcf->upstream.upstream == NULL) {
  3312.         return NGX_CONF_ERROR;
  3313.     }

  3314.     plcf->vars.schema.len = add;
  3315.     plcf->vars.schema.data = url->data;
  3316.     plcf->vars.key_start = plcf->vars.schema;

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

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

  3319.     if (clcf->named
  3320. #if (NGX_PCRE)
  3321.         || clcf->regex
  3322. #endif
  3323.         || clcf->noname)
  3324.     {
  3325.         if (plcf->vars.uri.len) {
  3326.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3327.                                "\"proxy_pass\" cannot have URI part in "
  3328.                                "location given by regular expression, "
  3329.                                "or inside named location, "
  3330.                                "or inside \"if\" statement, "
  3331.                                "or inside \"limit_except\" block");
  3332.             return NGX_CONF_ERROR;
  3333.         }

  3334.         plcf->location.len = 0;
  3335.     }

  3336.     plcf->url = *url;

  3337.     return NGX_CONF_OK;
  3338. }


  3339. static char *
  3340. ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3341. {
  3342.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3343.     u_char                            *p;
  3344.     ngx_str_t                         *value;
  3345.     ngx_http_proxy_rewrite_t          *pr;
  3346.     ngx_http_compile_complex_value_t   ccv;

  3347.     if (plcf->redirect == 0) {
  3348.         return "is duplicate";
  3349.     }

  3350.     plcf->redirect = 1;

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

  3352.     if (cf->args->nelts == 2) {
  3353.         if (ngx_strcmp(value[1].data, "off") == 0) {

  3354.             if (plcf->redirects) {
  3355.                 return "is duplicate";
  3356.             }

  3357.             plcf->redirect = 0;
  3358.             return NGX_CONF_OK;
  3359.         }

  3360.         if (ngx_strcmp(value[1].data, "default") != 0) {
  3361.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3362.                                "invalid parameter \"%V\"", &value[1]);
  3363.             return NGX_CONF_ERROR;
  3364.         }
  3365.     }

  3366.     if (plcf->redirects == NULL) {
  3367.         plcf->redirects = ngx_array_create(cf->pool, 1,
  3368.                                            sizeof(ngx_http_proxy_rewrite_t));
  3369.         if (plcf->redirects == NULL) {
  3370.             return NGX_CONF_ERROR;
  3371.         }
  3372.     }

  3373.     pr = ngx_array_push(plcf->redirects);
  3374.     if (pr == NULL) {
  3375.         return NGX_CONF_ERROR;
  3376.     }

  3377.     if (cf->args->nelts == 2
  3378.         && ngx_strcmp(value[1].data, "default") == 0)
  3379.     {
  3380.         if (plcf->proxy_lengths) {
  3381.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3382.                                "\"proxy_redirect default\" cannot be used "
  3383.                                "with \"proxy_pass\" directive with variables");
  3384.             return NGX_CONF_ERROR;
  3385.         }

  3386.         if (plcf->url.data == NULL) {
  3387.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3388.                                "\"proxy_redirect default\" should be placed "
  3389.                                "after the \"proxy_pass\" directive");
  3390.             return NGX_CONF_ERROR;
  3391.         }

  3392.         pr->handler = ngx_http_proxy_rewrite_complex_handler;

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

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

  3395.         if (plcf->vars.uri.len) {
  3396.             pr->pattern.complex.value = plcf->url;
  3397.             pr->replacement.value = plcf->location;

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

  3400.             p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
  3401.             if (p == NULL) {
  3402.                 return NGX_CONF_ERROR;
  3403.             }

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

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

  3407.             ngx_str_set(&pr->replacement.value, "/");
  3408.         }

  3409.         return NGX_CONF_OK;
  3410.     }


  3411.     if (value[1].data[0] == '~') {
  3412.         value[1].len--;
  3413.         value[1].data++;

  3414.         if (value[1].data[0] == '*') {
  3415.             value[1].len--;
  3416.             value[1].data++;

  3417.             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
  3418.                 return NGX_CONF_ERROR;
  3419.             }

  3420.         } else {
  3421.             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
  3422.                 return NGX_CONF_ERROR;
  3423.             }
  3424.         }

  3425.     } else {

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

  3427.         ccv.cf = cf;
  3428.         ccv.value = &value[1];
  3429.         ccv.complex_value = &pr->pattern.complex;

  3430.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3431.             return NGX_CONF_ERROR;
  3432.         }

  3433.         pr->handler = ngx_http_proxy_rewrite_complex_handler;
  3434.     }


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

  3436.     ccv.cf = cf;
  3437.     ccv.value = &value[2];
  3438.     ccv.complex_value = &pr->replacement;

  3439.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3440.         return NGX_CONF_ERROR;
  3441.     }

  3442.     return NGX_CONF_OK;
  3443. }


  3444. static char *
  3445. ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3446. {
  3447.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3448.     ngx_str_t                         *value;
  3449.     ngx_http_proxy_rewrite_t          *pr;
  3450.     ngx_http_compile_complex_value_t   ccv;

  3451.     if (plcf->cookie_domains == NULL) {
  3452.         return "is duplicate";
  3453.     }

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

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

  3456.         if (ngx_strcmp(value[1].data, "off") == 0) {

  3457.             if (plcf->cookie_domains != NGX_CONF_UNSET_PTR) {
  3458.                 return "is duplicate";
  3459.             }

  3460.             plcf->cookie_domains = NULL;
  3461.             return NGX_CONF_OK;
  3462.         }

  3463.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3464.                            "invalid parameter \"%V\"", &value[1]);
  3465.         return NGX_CONF_ERROR;
  3466.     }

  3467.     if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
  3468.         plcf->cookie_domains = ngx_array_create(cf->pool, 1,
  3469.                                      sizeof(ngx_http_proxy_rewrite_t));
  3470.         if (plcf->cookie_domains == NULL) {
  3471.             return NGX_CONF_ERROR;
  3472.         }
  3473.     }

  3474.     pr = ngx_array_push(plcf->cookie_domains);
  3475.     if (pr == NULL) {
  3476.         return NGX_CONF_ERROR;
  3477.     }

  3478.     if (value[1].data[0] == '~') {
  3479.         value[1].len--;
  3480.         value[1].data++;

  3481.         if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
  3482.             return NGX_CONF_ERROR;
  3483.         }

  3484.     } else {

  3485.         if (value[1].data[0] == '.') {
  3486.             value[1].len--;
  3487.             value[1].data++;
  3488.         }

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

  3490.         ccv.cf = cf;
  3491.         ccv.value = &value[1];
  3492.         ccv.complex_value = &pr->pattern.complex;

  3493.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3494.             return NGX_CONF_ERROR;
  3495.         }

  3496.         pr->handler = ngx_http_proxy_rewrite_domain_handler;

  3497.         if (value[2].data[0] == '.') {
  3498.             value[2].len--;
  3499.             value[2].data++;
  3500.         }
  3501.     }

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

  3503.     ccv.cf = cf;
  3504.     ccv.value = &value[2];
  3505.     ccv.complex_value = &pr->replacement;

  3506.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3507.         return NGX_CONF_ERROR;
  3508.     }

  3509.     return NGX_CONF_OK;
  3510. }


  3511. static char *
  3512. ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3513. {
  3514.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3515.     ngx_str_t                         *value;
  3516.     ngx_http_proxy_rewrite_t          *pr;
  3517.     ngx_http_compile_complex_value_t   ccv;

  3518.     if (plcf->cookie_paths == NULL) {
  3519.         return "is duplicate";
  3520.     }

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

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

  3523.         if (ngx_strcmp(value[1].data, "off") == 0) {

  3524.             if (plcf->cookie_paths != NGX_CONF_UNSET_PTR) {
  3525.                 return "is duplicate";
  3526.             }

  3527.             plcf->cookie_paths = NULL;
  3528.             return NGX_CONF_OK;
  3529.         }

  3530.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3531.                            "invalid parameter \"%V\"", &value[1]);
  3532.         return NGX_CONF_ERROR;
  3533.     }

  3534.     if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
  3535.         plcf->cookie_paths = ngx_array_create(cf->pool, 1,
  3536.                                      sizeof(ngx_http_proxy_rewrite_t));
  3537.         if (plcf->cookie_paths == NULL) {
  3538.             return NGX_CONF_ERROR;
  3539.         }
  3540.     }

  3541.     pr = ngx_array_push(plcf->cookie_paths);
  3542.     if (pr == NULL) {
  3543.         return NGX_CONF_ERROR;
  3544.     }

  3545.     if (value[1].data[0] == '~') {
  3546.         value[1].len--;
  3547.         value[1].data++;

  3548.         if (value[1].data[0] == '*') {
  3549.             value[1].len--;
  3550.             value[1].data++;

  3551.             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
  3552.                 return NGX_CONF_ERROR;
  3553.             }

  3554.         } else {
  3555.             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
  3556.                 return NGX_CONF_ERROR;
  3557.             }
  3558.         }

  3559.     } else {

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

  3561.         ccv.cf = cf;
  3562.         ccv.value = &value[1];
  3563.         ccv.complex_value = &pr->pattern.complex;

  3564.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3565.             return NGX_CONF_ERROR;
  3566.         }

  3567.         pr->handler = ngx_http_proxy_rewrite_complex_handler;
  3568.     }

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

  3570.     ccv.cf = cf;
  3571.     ccv.value = &value[2];
  3572.     ccv.complex_value = &pr->replacement;

  3573.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3574.         return NGX_CONF_ERROR;
  3575.     }

  3576.     return NGX_CONF_OK;
  3577. }


  3578. static char *
  3579. ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3580. {
  3581.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3582.     ngx_str_t                         *value;
  3583.     ngx_uint_t                         i;
  3584.     ngx_http_complex_value_t          *cv;
  3585.     ngx_http_proxy_cookie_flags_t     *pcf;
  3586.     ngx_http_compile_complex_value_t   ccv;
  3587. #if (NGX_PCRE)
  3588.     ngx_regex_compile_t                rc;
  3589.     u_char                             errstr[NGX_MAX_CONF_ERRSTR];
  3590. #endif

  3591.     if (plcf->cookie_flags == NULL) {
  3592.         return "is duplicate";
  3593.     }

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

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

  3596.         if (ngx_strcmp(value[1].data, "off") == 0) {

  3597.             if (plcf->cookie_flags != NGX_CONF_UNSET_PTR) {
  3598.                 return "is duplicate";
  3599.             }

  3600.             plcf->cookie_flags = NULL;
  3601.             return NGX_CONF_OK;
  3602.         }

  3603.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3604.                            "invalid parameter \"%V\"", &value[1]);
  3605.         return NGX_CONF_ERROR;
  3606.     }

  3607.     if (plcf->cookie_flags == NGX_CONF_UNSET_PTR) {
  3608.         plcf->cookie_flags = ngx_array_create(cf->pool, 1,
  3609.                                         sizeof(ngx_http_proxy_cookie_flags_t));
  3610.         if (plcf->cookie_flags == NULL) {
  3611.             return NGX_CONF_ERROR;
  3612.         }
  3613.     }

  3614.     pcf = ngx_array_push(plcf->cookie_flags);
  3615.     if (pcf == NULL) {
  3616.         return NGX_CONF_ERROR;
  3617.     }

  3618.     pcf->regex = 0;

  3619.     if (value[1].data[0] == '~') {
  3620.         value[1].len--;
  3621.         value[1].data++;

  3622. #if (NGX_PCRE)
  3623.         ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

  3624.         rc.pattern = value[1];
  3625.         rc.err.len = NGX_MAX_CONF_ERRSTR;
  3626.         rc.err.data = errstr;
  3627.         rc.options = NGX_REGEX_CASELESS;

  3628.         pcf->cookie.regex = ngx_http_regex_compile(cf, &rc);
  3629.         if (pcf->cookie.regex == NULL) {
  3630.             return NGX_CONF_ERROR;
  3631.         }

  3632.         pcf->regex = 1;
  3633. #else
  3634.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3635.                            "using regex \"%V\" requires PCRE library",
  3636.                            &value[1]);
  3637.         return NGX_CONF_ERROR;
  3638. #endif

  3639.     } else {

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

  3641.         ccv.cf = cf;
  3642.         ccv.value = &value[1];
  3643.         ccv.complex_value = &pcf->cookie.complex;

  3644.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3645.             return NGX_CONF_ERROR;
  3646.         }
  3647.     }

  3648.     if (ngx_array_init(&pcf->flags_values, cf->pool, cf->args->nelts - 2,
  3649.                        sizeof(ngx_http_complex_value_t))
  3650.         != NGX_OK)
  3651.     {
  3652.         return NGX_CONF_ERROR;
  3653.     }

  3654.     for (i = 2; i < cf->args->nelts; i++) {

  3655.         cv = ngx_array_push(&pcf->flags_values);
  3656.         if (cv == NULL) {
  3657.             return NGX_CONF_ERROR;
  3658.         }

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

  3660.         ccv.cf = cf;
  3661.         ccv.value = &value[i];
  3662.         ccv.complex_value = cv;

  3663.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3664.             return NGX_CONF_ERROR;
  3665.         }
  3666.     }

  3667.     return NGX_CONF_OK;
  3668. }


  3669. static ngx_int_t
  3670. ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
  3671.     ngx_str_t *regex, ngx_uint_t caseless)
  3672. {
  3673. #if (NGX_PCRE)
  3674.     u_char               errstr[NGX_MAX_CONF_ERRSTR];
  3675.     ngx_regex_compile_t  rc;

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

  3677.     rc.pattern = *regex;
  3678.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  3679.     rc.err.data = errstr;

  3680.     if (caseless) {
  3681.         rc.options = NGX_REGEX_CASELESS;
  3682.     }

  3683.     pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
  3684.     if (pr->pattern.regex == NULL) {
  3685.         return NGX_ERROR;
  3686.     }

  3687.     pr->handler = ngx_http_proxy_rewrite_regex_handler;

  3688.     return NGX_OK;

  3689. #else

  3690.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3691.                        "using regex \"%V\" requires PCRE library", regex);
  3692.     return NGX_ERROR;

  3693. #endif
  3694. }


  3695. static char *
  3696. ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3697. {
  3698.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3699.     ngx_str_t                  *value;
  3700.     ngx_http_script_compile_t   sc;

  3701.     if (plcf->upstream.store != NGX_CONF_UNSET) {
  3702.         return "is duplicate";
  3703.     }

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

  3705.     if (ngx_strcmp(value[1].data, "off") == 0) {
  3706.         plcf->upstream.store = 0;
  3707.         return NGX_CONF_OK;
  3708.     }

  3709.     if (value[1].len == 0) {
  3710.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
  3711.         return NGX_CONF_ERROR;
  3712.     }

  3713. #if (NGX_HTTP_CACHE)
  3714.     if (plcf->upstream.cache > 0) {
  3715.         return "is incompatible with \"proxy_cache\"";
  3716.     }
  3717. #endif

  3718.     plcf->upstream.store = 1;

  3719.     if (ngx_strcmp(value[1].data, "on") == 0) {
  3720.         return NGX_CONF_OK;
  3721.     }

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

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

  3725.     sc.cf = cf;
  3726.     sc.source = &value[1];
  3727.     sc.lengths = &plcf->upstream.store_lengths;
  3728.     sc.values = &plcf->upstream.store_values;
  3729.     sc.variables = ngx_http_script_variables_count(&value[1]);
  3730.     sc.complete_lengths = 1;
  3731.     sc.complete_values = 1;

  3732.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  3733.         return NGX_CONF_ERROR;
  3734.     }

  3735.     return NGX_CONF_OK;
  3736. }


  3737. #if (NGX_HTTP_CACHE)

  3738. static char *
  3739. ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3740. {
  3741.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3742.     ngx_str_t                         *value;
  3743.     ngx_http_complex_value_t           cv;
  3744.     ngx_http_compile_complex_value_t   ccv;

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

  3746.     if (plcf->upstream.cache != NGX_CONF_UNSET) {
  3747.         return "is duplicate";
  3748.     }

  3749.     if (ngx_strcmp(value[1].data, "off") == 0) {
  3750.         plcf->upstream.cache = 0;
  3751.         return NGX_CONF_OK;
  3752.     }

  3753.     if (plcf->upstream.store > 0) {
  3754.         return "is incompatible with \"proxy_store\"";
  3755.     }

  3756.     plcf->upstream.cache = 1;

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

  3758.     ccv.cf = cf;
  3759.     ccv.value = &value[1];
  3760.     ccv.complex_value = &cv;

  3761.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3762.         return NGX_CONF_ERROR;
  3763.     }

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

  3765.         plcf->upstream.cache_value = ngx_palloc(cf->pool,
  3766.                                              sizeof(ngx_http_complex_value_t));
  3767.         if (plcf->upstream.cache_value == NULL) {
  3768.             return NGX_CONF_ERROR;
  3769.         }

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

  3771.         return NGX_CONF_OK;
  3772.     }

  3773.     plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  3774.                                                       &ngx_http_proxy_module);
  3775.     if (plcf->upstream.cache_zone == NULL) {
  3776.         return NGX_CONF_ERROR;
  3777.     }

  3778.     return NGX_CONF_OK;
  3779. }


  3780. static char *
  3781. ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3782. {
  3783.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3784.     ngx_str_t                         *value;
  3785.     ngx_http_compile_complex_value_t   ccv;

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

  3787.     if (plcf->cache_key.value.data) {
  3788.         return "is duplicate";
  3789.     }

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

  3791.     ccv.cf = cf;
  3792.     ccv.value = &value[1];
  3793.     ccv.complex_value = &plcf->cache_key;

  3794.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3795.         return NGX_CONF_ERROR;
  3796.     }

  3797.     return NGX_CONF_OK;
  3798. }

  3799. #endif


  3800. #if (NGX_HTTP_SSL)

  3801. static char *
  3802. ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3803. {
  3804.     ngx_http_proxy_loc_conf_t *plcf = conf;

  3805.     ngx_str_t  *value;

  3806.     if (plcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) {
  3807.         return "is duplicate";
  3808.     }

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

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

  3811.     if (plcf->upstream.ssl_passwords == NULL) {
  3812.         return NGX_CONF_ERROR;
  3813.     }

  3814.     return NGX_CONF_OK;
  3815. }

  3816. #endif


  3817. static char *
  3818. ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
  3819. {
  3820. #if (NGX_FREEBSD)
  3821.     ssize_t *np = data;

  3822.     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
  3823.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3824.                            "\"proxy_send_lowat\" must be less than %d "
  3825.                            "(sysctl net.inet.tcp.sendspace)",
  3826.                            ngx_freebsd_net_inet_tcp_sendspace);

  3827.         return NGX_CONF_ERROR;
  3828.     }

  3829. #elif !(NGX_HAVE_SO_SNDLOWAT)
  3830.     ssize_t *np = data;

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

  3833.     *np = 0;

  3834. #endif

  3835.     return NGX_CONF_OK;
  3836. }


  3837. #if (NGX_HTTP_SSL)

  3838. static char *
  3839. ngx_http_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data)
  3840. {
  3841. #ifndef SSL_CONF_FLAG_FILE
  3842.     return "is not supported on this platform";
  3843. #else
  3844.     return NGX_CONF_OK;
  3845. #endif
  3846. }


  3847. static ngx_int_t
  3848. ngx_http_proxy_merge_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
  3849.     ngx_http_proxy_loc_conf_t *prev)
  3850. {
  3851.     ngx_uint_t  preserve;

  3852.     if (conf->ssl_protocols == 0
  3853.         && conf->ssl_ciphers.data == NULL
  3854.         && conf->upstream.ssl_certificate == NGX_CONF_UNSET_PTR
  3855.         && conf->upstream.ssl_certificate_key == NGX_CONF_UNSET_PTR
  3856.         && conf->upstream.ssl_passwords == NGX_CONF_UNSET_PTR
  3857.         && conf->upstream.ssl_verify == NGX_CONF_UNSET
  3858.         && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT
  3859.         && conf->ssl_trusted_certificate.data == NULL
  3860.         && conf->ssl_crl.data == NULL
  3861.         && conf->upstream.ssl_session_reuse == NGX_CONF_UNSET
  3862.         && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR)
  3863.     {
  3864.         if (prev->upstream.ssl) {
  3865.             conf->upstream.ssl = prev->upstream.ssl;
  3866.             return NGX_OK;
  3867.         }

  3868.         preserve = 1;

  3869.     } else {
  3870.         preserve = 0;
  3871.     }

  3872.     conf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
  3873.     if (conf->upstream.ssl == NULL) {
  3874.         return NGX_ERROR;
  3875.     }

  3876.     conf->upstream.ssl->log = cf->log;

  3877.     /*
  3878.      * special handling to preserve conf->upstream.ssl
  3879.      * in the "http" section to inherit it to all servers
  3880.      */

  3881.     if (preserve) {
  3882.         prev->upstream.ssl = conf->upstream.ssl;
  3883.     }

  3884.     return NGX_OK;
  3885. }


  3886. static ngx_int_t
  3887. ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
  3888. {
  3889.     ngx_pool_cleanup_t  *cln;

  3890.     if (plcf->upstream.ssl->ctx) {
  3891.         return NGX_OK;
  3892.     }

  3893.     if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL)
  3894.         != NGX_OK)
  3895.     {
  3896.         return NGX_ERROR;
  3897.     }

  3898.     cln = ngx_pool_cleanup_add(cf->pool, 0);
  3899.     if (cln == NULL) {
  3900.         ngx_ssl_cleanup_ctx(plcf->upstream.ssl);
  3901.         return NGX_ERROR;
  3902.     }

  3903.     cln->handler = ngx_ssl_cleanup_ctx;
  3904.     cln->data = plcf->upstream.ssl;

  3905.     if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0)
  3906.         != NGX_OK)
  3907.     {
  3908.         return NGX_ERROR;
  3909.     }

  3910.     if (plcf->upstream.ssl_certificate
  3911.         && plcf->upstream.ssl_certificate->value.len)
  3912.     {
  3913.         if (plcf->upstream.ssl_certificate_key == NULL) {
  3914.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  3915.                           "no \"proxy_ssl_certificate_key\" is defined "
  3916.                           "for certificate \"%V\"",
  3917.                           &plcf->upstream.ssl_certificate->value);
  3918.             return NGX_ERROR;
  3919.         }

  3920.         if (plcf->upstream.ssl_certificate->lengths
  3921.             || plcf->upstream.ssl_certificate_key->lengths)
  3922.         {
  3923.             plcf->upstream.ssl_passwords =
  3924.                   ngx_ssl_preserve_passwords(cf, plcf->upstream.ssl_passwords);
  3925.             if (plcf->upstream.ssl_passwords == NULL) {
  3926.                 return NGX_ERROR;
  3927.             }

  3928.         } else {
  3929.             if (ngx_ssl_certificate(cf, plcf->upstream.ssl,
  3930.                                     &plcf->upstream.ssl_certificate->value,
  3931.                                     &plcf->upstream.ssl_certificate_key->value,
  3932.                                     plcf->upstream.ssl_passwords)
  3933.                 != NGX_OK)
  3934.             {
  3935.                 return NGX_ERROR;
  3936.             }
  3937.         }
  3938.     }

  3939.     if (plcf->upstream.ssl_verify) {
  3940.         if (plcf->ssl_trusted_certificate.len == 0) {
  3941.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  3942.                       "no proxy_ssl_trusted_certificate for proxy_ssl_verify");
  3943.             return NGX_ERROR;
  3944.         }

  3945.         if (ngx_ssl_trusted_certificate(cf, plcf->upstream.ssl,
  3946.                                         &plcf->ssl_trusted_certificate,
  3947.                                         plcf->ssl_verify_depth)
  3948.             != NGX_OK)
  3949.         {
  3950.             return NGX_ERROR;
  3951.         }

  3952.         if (ngx_ssl_crl(cf, plcf->upstream.ssl, &plcf->ssl_crl) != NGX_OK) {
  3953.             return NGX_ERROR;
  3954.         }
  3955.     }

  3956.     if (ngx_ssl_client_session_cache(cf, plcf->upstream.ssl,
  3957.                                      plcf->upstream.ssl_session_reuse)
  3958.         != NGX_OK)
  3959.     {
  3960.         return NGX_ERROR;
  3961.     }

  3962.     if (ngx_ssl_conf_commands(cf, plcf->upstream.ssl, plcf->ssl_conf_commands)
  3963.         != NGX_OK)
  3964.     {
  3965.         return NGX_ERROR;
  3966.     }

  3967.     return NGX_OK;
  3968. }

  3969. #endif


  3970. static void
  3971. ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
  3972. {
  3973.     if (u->family != AF_UNIX) {

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

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

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

  3978.             } else {
  3979.                 ngx_str_set(&v->port, "443");
  3980.             }

  3981.         } else {
  3982.             v->host_header.len = u->host.len + 1 + u->port_text.len;
  3983.             v->host_header.data = u->host.data;
  3984.             v->port = u->port_text;
  3985.         }

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

  3987.     } else {
  3988.         ngx_str_set(&v->host_header, "localhost");
  3989.         ngx_str_null(&v->port);
  3990.         v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
  3991.     }

  3992.     v->uri = u->uri;
  3993. }