src/http/modules/ngx_http_fastcgi_module.c - nginx-1.31.7 nginx/ @ 939334eff

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


  11. ‌typedef struct {
  12.     ngx_array_t                   *flushes;
  13.     ngx_array_t                   *lengths;
  14.     ngx_array_t                   *values;
  15.     ngx_uint_t                     number;
  16.     ngx_hash_t                     hash;
  17. ‌} ngx_http_fastcgi_params_t;


  18. ‌typedef struct {
  19.     ngx_http_upstream_conf_t       upstream;

  20.     ngx_str_t                      index;

  21.     ngx_http_fastcgi_params_t      params;
  22. #if (NGX_HTTP_CACHE)
  23.     ngx_http_fastcgi_params_t      params_cache;
  24. #endif

  25.     ngx_array_t                   *params_source;
  26.     ngx_array_t                   *catch_stderr;

  27.     ngx_array_t                   *fastcgi_lengths;
  28.     ngx_array_t                   *fastcgi_values;

  29.     ngx_flag_t                     keep_conn;

  30. #if (NGX_HTTP_CACHE)
  31.     ngx_http_complex_value_t       cache_key;
  32. #endif

  33. #if (NGX_PCRE)
  34.     ngx_regex_t                   *split_regex;
  35.     ngx_str_t                      split_name;
  36. #endif
  37. ‌} ngx_http_fastcgi_loc_conf_t;


  38. ‌typedef enum {
  39.     ngx_http_fastcgi_st_version = 0,
  40.     ngx_http_fastcgi_st_type,
  41.     ngx_http_fastcgi_st_request_id_hi,
  42.     ngx_http_fastcgi_st_request_id_lo,
  43.     ngx_http_fastcgi_st_content_length_hi,
  44.     ngx_http_fastcgi_st_content_length_lo,
  45.     ngx_http_fastcgi_st_padding_length,
  46.     ngx_http_fastcgi_st_reserved,
  47.     ngx_http_fastcgi_st_data,
  48.     ngx_http_fastcgi_st_padding
  49. ‌} ngx_http_fastcgi_state_e;


  50. ‌typedef struct {
  51.     u_char                        *start;
  52.     u_char                        *end;
  53. ‌} ngx_http_fastcgi_split_part_t;


  54. ‌typedef struct {
  55.     ngx_http_fastcgi_state_e       state;
  56.     u_char                        *pos;
  57.     u_char                        *last;
  58.     ngx_uint_t                     type;
  59.     size_t                         length;
  60.     size_t                         padding;

  61.     off_t                          rest;

  62.     ngx_chain_t                   *free;
  63.     ngx_chain_t                   *busy;

  64.     unsigned                       fastcgi_stdout:1;
  65.     unsigned                       large_stderr:1;
  66.     unsigned                       header_sent:1;
  67.     unsigned                       closed:1;

  68.     ngx_array_t                   *split_parts;

  69.     ngx_str_t                      script_name;
  70.     ngx_str_t                      path_info;
  71. ‌} ngx_http_fastcgi_ctx_t;


  72. ‌#define NGX_HTTP_FASTCGI_RESPONDER      1

  73. ‌#define NGX_HTTP_FASTCGI_KEEP_CONN      1

  74. ‌#define NGX_HTTP_FASTCGI_BEGIN_REQUEST  1
  75. ‌#define NGX_HTTP_FASTCGI_ABORT_REQUEST  2
  76. ‌#define NGX_HTTP_FASTCGI_END_REQUEST    3
  77. ‌#define NGX_HTTP_FASTCGI_PARAMS         4
  78. ‌#define NGX_HTTP_FASTCGI_STDIN          5
  79. ‌#define NGX_HTTP_FASTCGI_STDOUT         6
  80. ‌#define NGX_HTTP_FASTCGI_STDERR         7
  81. ‌#define NGX_HTTP_FASTCGI_DATA           8


  82. ‌typedef struct {
  83.     u_char  version;
  84.     u_char  type;
  85.     u_char  request_id_hi;
  86.     u_char  request_id_lo;
  87.     u_char  content_length_hi;
  88.     u_char  content_length_lo;
  89.     u_char  padding_length;
  90.     u_char  reserved;
  91. ‌} ngx_http_fastcgi_header_t;


  92. ‌typedef struct {
  93.     u_char  role_hi;
  94.     u_char  role_lo;
  95.     u_char  flags;
  96.     u_char  reserved[5];
  97. ‌} ngx_http_fastcgi_begin_request_t;


  98. ‌typedef struct {
  99.     u_char  version;
  100.     u_char  type;
  101.     u_char  request_id_hi;
  102.     u_char  request_id_lo;
  103. ‌} ngx_http_fastcgi_header_small_t;


  104. ‌typedef struct {
  105.     ngx_http_fastcgi_header_t         h0;
  106.     ngx_http_fastcgi_begin_request_t  br;
  107.     ngx_http_fastcgi_header_small_t   h1;
  108. ‌} ngx_http_fastcgi_request_start_t;


  109. static ngx_int_t ngx_http_fastcgi_eval(ngx_http_request_t *r,
  110.     ngx_http_fastcgi_loc_conf_t *flcf);
  111. #if (NGX_HTTP_CACHE)
  112. static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r);
  113. #endif
  114. static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
  115. static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
  116. static ngx_int_t ngx_http_fastcgi_body_output_filter(void *data,
  117.     ngx_chain_t *in);
  118. static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
  119. static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data);
  120. static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
  121.     ngx_buf_t *buf);
  122. static ngx_int_t ngx_http_fastcgi_non_buffered_filter(void *data,
  123.     ssize_t bytes);
  124. static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
  125.     ngx_http_fastcgi_ctx_t *f);
  126. static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r);
  127. static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
  128.     ngx_int_t rc);

  129. static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf);
  130. static void *ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf);
  131. static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
  132. static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
  133.     void *parent, void *child);
  134. static ngx_int_t ngx_http_fastcgi_init_params(ngx_conf_t *cf,
  135.     ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_params_t *params,
  136.     ngx_keyval_t *default_params);

  137. static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
  138.     ngx_http_variable_value_t *v, uintptr_t data);
  139. static ngx_int_t ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
  140.     ngx_http_variable_value_t *v, uintptr_t data);
  141. static ngx_http_fastcgi_ctx_t *ngx_http_fastcgi_split(ngx_http_request_t *r,
  142.     ngx_http_fastcgi_loc_conf_t *flcf);

  143. static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
  144.     void *conf);
  145. static char *ngx_http_fastcgi_split_path_info(ngx_conf_t *cf,
  146.     ngx_command_t *cmd, void *conf);
  147. static char *ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
  148.     void *conf);
  149. #if (NGX_HTTP_CACHE)
  150. static char *ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  151.     void *conf);
  152. static char *ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
  153.     void *conf);
  154. #endif

  155. static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
  156.     void *data);


  157. ‌static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
  158.     { ngx_http_fastcgi_lowat_check };


  159. ‌static ngx_conf_bitmask_t  ngx_http_fastcgi_next_upstream_masks[] = {
  160.     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
  161.     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
  162.     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
  163.     { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
  164.     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
  165.     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
  166.     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
  167.     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
  168.     { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
  169.     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
  170.     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
  171.     { ngx_null_string, 0 }
  172. };


  173. ‌ngx_module_t  ngx_http_fastcgi_module;


  174. ‌static ngx_command_t  ngx_http_fastcgi_commands[] = {

  175.     { ngx_string("fastcgi_pass"),
  176.       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
  177.       ngx_http_fastcgi_pass,
  178.       NGX_HTTP_LOC_CONF_OFFSET,
  179.       0,
  180.       NULL },

  181.     { ngx_string("fastcgi_index"),
  182.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  183.       ngx_conf_set_str_slot,
  184.       NGX_HTTP_LOC_CONF_OFFSET,
  185.       offsetof(ngx_http_fastcgi_loc_conf_t, index),
  186.       NULL },

  187.     { ngx_string("fastcgi_split_path_info"),
  188.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  189.       ngx_http_fastcgi_split_path_info,
  190.       NGX_HTTP_LOC_CONF_OFFSET,
  191.       0,
  192.       NULL },

  193.     { ngx_string("fastcgi_store"),
  194.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  195.       ngx_http_fastcgi_store,
  196.       NGX_HTTP_LOC_CONF_OFFSET,
  197.       0,
  198.       NULL },

  199.     { ngx_string("fastcgi_store_access"),
  200.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
  201.       ngx_conf_set_access_slot,
  202.       NGX_HTTP_LOC_CONF_OFFSET,
  203.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store_access),
  204.       NULL },

  205.     { ngx_string("fastcgi_buffering"),
  206.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  207.       ngx_conf_set_flag_slot,
  208.       NGX_HTTP_LOC_CONF_OFFSET,
  209.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering),
  210.       NULL },

  211.     { ngx_string("fastcgi_request_buffering"),
  212.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  213.       ngx_conf_set_flag_slot,
  214.       NGX_HTTP_LOC_CONF_OFFSET,
  215.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.request_buffering),
  216.       NULL },

  217.     { ngx_string("fastcgi_ignore_client_abort"),
  218.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  219.       ngx_conf_set_flag_slot,
  220.       NGX_HTTP_LOC_CONF_OFFSET,
  221.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort),
  222.       NULL },

  223.     { ngx_string("fastcgi_bind"),
  224.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  225.       ngx_http_upstream_bind_set_slot,
  226.       NGX_HTTP_LOC_CONF_OFFSET,
  227.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local),
  228.       NULL },

  229.     { ngx_string("fastcgi_socket_keepalive"),
  230.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  231.       ngx_conf_set_flag_slot,
  232.       NGX_HTTP_LOC_CONF_OFFSET,
  233.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.socket_keepalive),
  234.       NULL },

  235.     { ngx_string("fastcgi_socket_rcvbuf"),
  236.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  237.       ngx_conf_set_size_slot,
  238.       NGX_HTTP_LOC_CONF_OFFSET,
  239.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.socket_rcvbuf),
  240.       NULL },

  241.     { ngx_string("fastcgi_socket_sndbuf"),
  242.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  243.       ngx_conf_set_size_slot,
  244.       NGX_HTTP_LOC_CONF_OFFSET,
  245.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.socket_sndbuf),
  246.       NULL },

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

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

  259.     { ngx_string("fastcgi_send_lowat"),
  260.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  261.       ngx_conf_set_size_slot,
  262.       NGX_HTTP_LOC_CONF_OFFSET,
  263.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat),
  264.       &ngx_http_fastcgi_lowat_post },

  265.     { ngx_string("fastcgi_buffer_size"),
  266.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  267.       ngx_conf_set_size_slot,
  268.       NGX_HTTP_LOC_CONF_OFFSET,
  269.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size),
  270.       &ngx_conf_size_nonzero_post },

  271.     { ngx_string("fastcgi_pass_request_headers"),
  272.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  273.       ngx_conf_set_flag_slot,
  274.       NGX_HTTP_LOC_CONF_OFFSET,
  275.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_headers),
  276.       NULL },

  277.     { ngx_string("fastcgi_pass_request_body"),
  278.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  279.       ngx_conf_set_flag_slot,
  280.       NGX_HTTP_LOC_CONF_OFFSET,
  281.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body),
  282.       NULL },

  283.     { ngx_string("fastcgi_intercept_errors"),
  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_fastcgi_loc_conf_t, upstream.intercept_errors),
  288.       NULL },

  289.     { ngx_string("fastcgi_read_timeout"),
  290.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  291.       ngx_conf_set_msec_slot,
  292.       NGX_HTTP_LOC_CONF_OFFSET,
  293.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout),
  294.       NULL },

  295.     { ngx_string("fastcgi_buffers"),
  296.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  297.       ngx_conf_set_bufs_slot,
  298.       NGX_HTTP_LOC_CONF_OFFSET,
  299.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs),
  300.       NULL },

  301.     { ngx_string("fastcgi_busy_buffers_size"),
  302.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  303.       ngx_conf_set_size_slot,
  304.       NGX_HTTP_LOC_CONF_OFFSET,
  305.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size_conf),
  306.       NULL },

  307.     { ngx_string("fastcgi_force_ranges"),
  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_fastcgi_loc_conf_t, upstream.force_ranges),
  312.       NULL },

  313.     { ngx_string("fastcgi_limit_rate"),
  314.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  315.       ngx_http_set_complex_value_size_slot,
  316.       NGX_HTTP_LOC_CONF_OFFSET,
  317.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.limit_rate),
  318.       NULL },

  319. #if (NGX_HTTP_CACHE)

  320.     { ngx_string("fastcgi_cache"),
  321.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  322.       ngx_http_fastcgi_cache,
  323.       NGX_HTTP_LOC_CONF_OFFSET,
  324.       0,
  325.       NULL },

  326.     { ngx_string("fastcgi_cache_key"),
  327.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  328.       ngx_http_fastcgi_cache_key,
  329.       NGX_HTTP_LOC_CONF_OFFSET,
  330.       0,
  331.       NULL },

  332.     { ngx_string("fastcgi_cache_path"),
  333.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  334.       ngx_http_file_cache_set_slot,
  335.       NGX_HTTP_MAIN_CONF_OFFSET,
  336.       offsetof(ngx_http_fastcgi_main_conf_t, caches),
  337.       &ngx_http_fastcgi_module },

  338.     { ngx_string("fastcgi_cache_bypass"),
  339.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  340.       ngx_http_set_predicate_slot,
  341.       NGX_HTTP_LOC_CONF_OFFSET,
  342.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_bypass),
  343.       NULL },

  344.     { ngx_string("fastcgi_no_cache"),
  345.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  346.       ngx_http_set_predicate_slot,
  347.       NGX_HTTP_LOC_CONF_OFFSET,
  348.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.no_cache),
  349.       NULL },

  350.     { ngx_string("fastcgi_cache_valid"),
  351.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  352.       ngx_http_file_cache_valid_set_slot,
  353.       NGX_HTTP_LOC_CONF_OFFSET,
  354.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_valid),
  355.       NULL },

  356.     { ngx_string("fastcgi_cache_min_uses"),
  357.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  358.       ngx_conf_set_num_slot,
  359.       NGX_HTTP_LOC_CONF_OFFSET,
  360.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_min_uses),
  361.       NULL },

  362.     { ngx_string("fastcgi_cache_max_range_offset"),
  363.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  364.       ngx_conf_set_off_slot,
  365.       NGX_HTTP_LOC_CONF_OFFSET,
  366.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_max_range_offset),
  367.       NULL },

  368.     { ngx_string("fastcgi_cache_use_stale"),
  369.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  370.       ngx_conf_set_bitmask_slot,
  371.       NGX_HTTP_LOC_CONF_OFFSET,
  372.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_use_stale),
  373.       &ngx_http_fastcgi_next_upstream_masks },

  374.     { ngx_string("fastcgi_cache_methods"),
  375.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  376.       ngx_conf_set_bitmask_slot,
  377.       NGX_HTTP_LOC_CONF_OFFSET,
  378.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods),
  379.       &ngx_http_upstream_cache_method_mask },

  380.     { ngx_string("fastcgi_cache_lock"),
  381.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  382.       ngx_conf_set_flag_slot,
  383.       NGX_HTTP_LOC_CONF_OFFSET,
  384.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock),
  385.       NULL },

  386.     { ngx_string("fastcgi_cache_lock_timeout"),
  387.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  388.       ngx_conf_set_msec_slot,
  389.       NGX_HTTP_LOC_CONF_OFFSET,
  390.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
  391.       NULL },

  392.     { ngx_string("fastcgi_cache_lock_age"),
  393.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  394.       ngx_conf_set_msec_slot,
  395.       NGX_HTTP_LOC_CONF_OFFSET,
  396.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_age),
  397.       NULL },

  398.     { ngx_string("fastcgi_cache_revalidate"),
  399.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  400.       ngx_conf_set_flag_slot,
  401.       NGX_HTTP_LOC_CONF_OFFSET,
  402.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_revalidate),
  403.       NULL },

  404.     { ngx_string("fastcgi_cache_background_update"),
  405.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  406.       ngx_conf_set_flag_slot,
  407.       NGX_HTTP_LOC_CONF_OFFSET,
  408.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_background_update),
  409.       NULL },

  410. #endif

  411.     { ngx_string("fastcgi_temp_path"),
  412.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  413.       ngx_conf_set_path_slot,
  414.       NGX_HTTP_LOC_CONF_OFFSET,
  415.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path),
  416.       NULL },

  417.     { ngx_string("fastcgi_max_temp_file_size"),
  418.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  419.       ngx_conf_set_size_slot,
  420.       NGX_HTTP_LOC_CONF_OFFSET,
  421.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size_conf),
  422.       NULL },

  423.     { ngx_string("fastcgi_temp_file_write_size"),
  424.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  425.       ngx_conf_set_size_slot,
  426.       NGX_HTTP_LOC_CONF_OFFSET,
  427.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size_conf),
  428.       NULL },

  429.     { ngx_string("fastcgi_next_upstream"),
  430.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  431.       ngx_conf_set_bitmask_slot,
  432.       NGX_HTTP_LOC_CONF_OFFSET,
  433.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
  434.       &ngx_http_fastcgi_next_upstream_masks },

  435.     { ngx_string("fastcgi_next_upstream_tries"),
  436.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  437.       ngx_conf_set_num_slot,
  438.       NGX_HTTP_LOC_CONF_OFFSET,
  439.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_tries),
  440.       NULL },

  441.     { ngx_string("fastcgi_next_upstream_timeout"),
  442.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  443.       ngx_conf_set_msec_slot,
  444.       NGX_HTTP_LOC_CONF_OFFSET,
  445.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_timeout),
  446.       NULL },

  447.     { ngx_string("fastcgi_param"),
  448.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
  449.       ngx_http_upstream_param_set_slot,
  450.       NGX_HTTP_LOC_CONF_OFFSET,
  451.       offsetof(ngx_http_fastcgi_loc_conf_t, params_source),
  452.       NULL },

  453.     { ngx_string("fastcgi_pass_header"),
  454.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  455.       ngx_conf_set_str_array_slot,
  456.       NGX_HTTP_LOC_CONF_OFFSET,
  457.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_headers),
  458.       NULL },

  459.     { ngx_string("fastcgi_hide_header"),
  460.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  461.       ngx_conf_set_str_array_slot,
  462.       NGX_HTTP_LOC_CONF_OFFSET,
  463.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers),
  464.       NULL },

  465.     { ngx_string("fastcgi_ignore_headers"),
  466.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  467.       ngx_conf_set_bitmask_slot,
  468.       NGX_HTTP_LOC_CONF_OFFSET,
  469.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_headers),
  470.       &ngx_http_upstream_ignore_headers_masks },

  471.     { ngx_string("fastcgi_catch_stderr"),
  472.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  473.       ngx_conf_set_str_array_slot,
  474.       NGX_HTTP_LOC_CONF_OFFSET,
  475.       offsetof(ngx_http_fastcgi_loc_conf_t, catch_stderr),
  476.       NULL },

  477.     { ngx_string("fastcgi_keep_conn"),
  478.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  479.       ngx_conf_set_flag_slot,
  480.       NGX_HTTP_LOC_CONF_OFFSET,
  481.       offsetof(ngx_http_fastcgi_loc_conf_t, keep_conn),
  482.       NULL },

  483.       ngx_null_command
  484. };


  485. ‌static ngx_http_module_t  ngx_http_fastcgi_module_ctx = {
  486.     ngx_http_fastcgi_add_variables,        /* preconfiguration */
  487.     NULL,                                  /* postconfiguration */

  488.     ngx_http_fastcgi_create_main_conf,     /* create main configuration */
  489.     NULL,                                  /* init main configuration */

  490.     NULL,                                  /* create server configuration */
  491.     NULL,                                  /* merge server configuration */

  492.     ngx_http_fastcgi_create_loc_conf,      /* create location configuration */
  493.     ngx_http_fastcgi_merge_loc_conf        /* merge location configuration */
  494. };


  495. ‌ngx_module_t  ngx_http_fastcgi_module = {
  496.     NGX_MODULE_V1,
  497.     &ngx_http_fastcgi_module_ctx,          /* module context */
  498.     ngx_http_fastcgi_commands,             /* module directives */
  499.     NGX_HTTP_MODULE,                       /* module type */
  500.     NULL,                                  /* init master */
  501.     NULL,                                  /* init module */
  502.     NULL,                                  /* init process */
  503.     NULL,                                  /* init thread */
  504.     NULL,                                  /* exit thread */
  505.     NULL,                                  /* exit process */
  506.     NULL,                                  /* exit master */
  507.     NGX_MODULE_V1_PADDING
  508. };


  509. ‌static ngx_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
  510.     { 1,                                               /* version */
  511.       NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
  512.       0,                                               /* request_id_hi */
  513.       1,                                               /* request_id_lo */
  514.       0,                                               /* content_length_hi */
  515.       sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
  516.       0,                                               /* padding_length */
  517.       0 },                                             /* reserved */

  518.     { 0,                                               /* role_hi */
  519.       NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
  520.       0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
  521.       { 0, 0, 0, 0, 0 } },                             /* reserved[5] */

  522.     { 1,                                               /* version */
  523.       NGX_HTTP_FASTCGI_PARAMS,                         /* type */
  524.       0,                                               /* request_id_hi */
  525.       1 },                                             /* request_id_lo */

  526. };


  527. ‌static ngx_http_variable_t  ngx_http_fastcgi_vars[] = {

  528.     { ngx_string("fastcgi_script_name"), NULL,
  529.       ngx_http_fastcgi_script_name_variable, 0,
  530.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  531.     { ngx_string("fastcgi_path_info"), NULL,
  532.       ngx_http_fastcgi_path_info_variable, 0,
  533.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  534.       ngx_http_null_variable
  535. };


  536. ‌static ngx_str_t  ngx_http_fastcgi_hide_headers[] = {
  537.     ngx_string("Status"),
  538.     ngx_string("X-Accel-Expires"),
  539.     ngx_string("X-Accel-Redirect"),
  540.     ngx_string("X-Accel-Limit-Rate"),
  541.     ngx_string("X-Accel-Buffering"),
  542.     ngx_string("X-Accel-Charset"),
  543.     ngx_null_string
  544. };


  545. ‌static ngx_keyval_t  ngx_http_fastcgi_headers[] = {
  546.     { ngx_string("HTTP_HOST"),
  547.       ngx_string("$host$is_request_port$request_port") },
  548.     { ngx_null_string, ngx_null_string }
  549. };


  550. #if (NGX_HTTP_CACHE)

  551. ‌static ngx_keyval_t  ngx_http_fastcgi_cache_headers[] = {
  552.     { ngx_string("HTTP_HOST"),
  553.       ngx_string("$host$is_request_port$request_port") },
  554.     { ngx_string("HTTP_IF_MODIFIED_SINCE"),
  555.       ngx_string("$upstream_cache_last_modified") },
  556.     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
  557.     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
  558.     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
  559.     { ngx_string("HTTP_RANGE"), ngx_string("") },
  560.     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
  561.     { ngx_null_string, ngx_null_string }
  562. };

  563. #endif


  564. ‌static ngx_path_init_t  ngx_http_fastcgi_temp_path = {
  565.     ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
  566. };


  567. static ngx_int_t
  568. ‌ngx_http_fastcgi_handler(ngx_http_request_t *r)
  569. {
  570.     ngx_int_t                      rc;
  571.     ngx_http_upstream_t           *u;
  572.     ngx_http_fastcgi_ctx_t        *f;
  573.     ngx_http_fastcgi_loc_conf_t   *flcf;
  574. #if (NGX_HTTP_CACHE)
  575.     ngx_http_fastcgi_main_conf_t  *fmcf;
  576. #endif

  577.     if (ngx_http_upstream_create(r) != NGX_OK) {
  578.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  579.     }

  580.     f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  581.     if (f == NULL) {
  582.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  583.     }

  584.     ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);

  585.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  586.     if (flcf->fastcgi_lengths) {
  587.         if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {
  588.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  589.         }
  590.     }

  591.     u = r->upstream;

  592.     ngx_str_set(&u->schema, "fastcgi://");
  593.     u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;

  594.     u->conf = &flcf->upstream;

  595. #if (NGX_HTTP_CACHE)
  596.     fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module);

  597.     u->caches = &fmcf->caches;
  598.     u->create_key = ngx_http_fastcgi_create_key;
  599. #endif

  600.     u->create_request = ngx_http_fastcgi_create_request;
  601.     u->reinit_request = ngx_http_fastcgi_reinit_request;
  602.     u->process_header = ngx_http_fastcgi_process_header;
  603.     u->abort_request = ngx_http_fastcgi_abort_request;
  604.     u->finalize_request = ngx_http_fastcgi_finalize_request;
  605.     r->state = 0;

  606.     u->buffering = flcf->upstream.buffering;

  607.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  608.     if (u->pipe == NULL) {
  609.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  610.     }

  611.     u->pipe->input_filter = ngx_http_fastcgi_input_filter;
  612.     u->pipe->input_ctx = r;

  613.     u->input_filter_init = ngx_http_fastcgi_input_filter_init;
  614.     u->input_filter = ngx_http_fastcgi_non_buffered_filter;
  615.     u->input_filter_ctx = r;

  616.     if (!flcf->upstream.request_buffering
  617.         && flcf->upstream.pass_request_body)
  618.     {
  619.         r->request_body_no_buffering = 1;
  620.     }

  621.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  622.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  623.         return rc;
  624.     }

  625.     return NGX_DONE;
  626. }


  627. static ngx_int_t
  628. ‌ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  629. {
  630.     ngx_url_t             url;
  631.     ngx_http_upstream_t  *u;

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

  633.     if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
  634.                             flcf->fastcgi_values->elts)
  635.         == NULL)
  636.     {
  637.         return NGX_ERROR;
  638.     }

  639.     url.no_resolve = 1;

  640.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  641.         if (url.err) {
  642.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  643.                           "%s in upstream \"%V\"", url.err, &url.url);
  644.         }

  645.         return NGX_ERROR;
  646.     }

  647.     u = r->upstream;

  648.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  649.     if (u->resolved == NULL) {
  650.         return NGX_ERROR;
  651.     }

  652.     if (url.addrs) {
  653.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  654.         u->resolved->socklen = url.addrs[0].socklen;
  655.         u->resolved->name = url.addrs[0].name;
  656.         u->resolved->naddrs = 1;
  657.     }

  658.     u->resolved->host = url.host;
  659.     u->resolved->port = url.port;
  660.     u->resolved->no_port = url.no_port;

  661.     return NGX_OK;
  662. }


  663. #if (NGX_HTTP_CACHE)

  664. static ngx_int_t
  665. ‌ngx_http_fastcgi_create_key(ngx_http_request_t *r)
  666. {
  667.     ngx_str_t                    *key;
  668.     ngx_http_fastcgi_loc_conf_t  *flcf;

  669.     key = ngx_array_push(&r->cache->keys);
  670.     if (key == NULL) {
  671.         return NGX_ERROR;
  672.     }

  673.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  674.     if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) {
  675.         return NGX_ERROR;
  676.     }

  677.     return NGX_OK;
  678. }

  679. #endif


  680. static ngx_int_t
  681. ‌ngx_http_fastcgi_create_request(ngx_http_request_t *r)
  682. {
  683.     off_t                         file_pos;
  684.     u_char                        ch, sep, *pos, *lowcase_key;
  685.     size_t                        size, len, params_len,
  686.                                   key_len, val_len, padding, allocated;
  687.     ngx_uint_t                    i, n, next, hash, skip_empty, header_params;
  688.     ngx_buf_t                    *b;
  689.     ngx_chain_t                  *cl, *body;
  690.     ngx_list_part_t              *part;
  691.     ngx_table_elt_t              *header, *hn, **ignored;
  692.     ngx_http_upstream_t          *u;
  693.     ngx_http_script_code_pt       code;
  694.     ngx_http_script_engine_t      e, le;
  695.     ngx_http_fastcgi_header_t    *h;
  696.     ngx_http_fastcgi_params_t    *params;
  697.     ngx_http_fastcgi_loc_conf_t  *flcf;
  698.     ngx_http_script_len_code_pt   lcode;

  699.     len = 0;
  700.     params_len = 0;
  701.     header_params = 0;
  702.     ignored = NULL;

  703.     u = r->upstream;

  704.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  705. #if (NGX_HTTP_CACHE)
  706.     params = u->cacheable ? &flcf->params_cache : &flcf->params;
  707. #else
  708.     params = &flcf->params;
  709. #endif

  710.     if (params->lengths) {
  711.         ngx_memzero(&le, sizeof(ngx_http_script_engine_t));

  712.         ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
  713.         le.flushed = 1;

  714.         le.ip = params->lengths->elts;
  715.         le.request = r;

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

  717.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  718.             key_len = lcode(&le);

  719.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  720.             skip_empty = lcode(&le);

  721.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  722.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  723.             }
  724.             le.ip += sizeof(uintptr_t);

  725.             if (skip_empty && val_len == 0) {
  726.                 continue;
  727.             }

  728.             params_len += ((key_len > 127) ? 4 : 1) + key_len
  729.                           + ((val_len > 127) ? 4 : 1) + val_len;
  730.         }

  731.         len += params_len;
  732.     }

  733.     if (flcf->upstream.pass_request_headers) {

  734.         allocated = 0;
  735.         lowcase_key = NULL;

  736.         if (ngx_http_link_multi_headers(r) != NGX_OK) {
  737.             return NGX_ERROR;
  738.         }

  739.         if (params->number || r->headers_in.multi) {
  740.             n = 0;
  741.             part = &r->headers_in.headers.part;

  742.             while (part) {
  743.                 n += part->nelts;
  744.                 part = part->next;
  745.             }

  746.             ignored = ngx_palloc(r->pool, n * sizeof(void *));
  747.             if (ignored == NULL) {
  748.                 return NGX_ERROR;
  749.             }
  750.         }

  751.         part = &r->headers_in.headers.part;
  752.         header = part->elts;

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

  754.             if (i >= part->nelts) {
  755.                 if (part->next == NULL) {
  756.                     break;
  757.                 }

  758.                 part = part->next;
  759.                 header = part->elts;
  760.                 i = 0;
  761.             }

  762.             for (n = 0; n < header_params; n++) {
  763.                 if (&header[i] == ignored[n]) {
  764.                     goto next_length;
  765.                 }
  766.             }

  767.             if (params->number) {
  768.                 if (allocated < header[i].key.len) {
  769.                     allocated = header[i].key.len + 16;
  770.                     lowcase_key = ngx_pnalloc(r->pool, allocated);
  771.                     if (lowcase_key == NULL) {
  772.                         return NGX_ERROR;
  773.                     }
  774.                 }

  775.                 hash = 0;

  776.                 for (n = 0; n < header[i].key.len; n++) {
  777.                     ch = header[i].key.data[n];

  778.                     if (ch >= 'A' && ch <= 'Z') {
  779.                         ch |= 0x20;

  780.                     } else if (ch == '-') {
  781.                         ch = '_';
  782.                     }

  783.                     hash = ngx_hash(hash, ch);
  784.                     lowcase_key[n] = ch;
  785.                 }

  786.                 if (ngx_hash_find(&params->hash, hash, lowcase_key, n)) {
  787.                     ignored[header_params++] = &header[i];
  788.                     continue;
  789.                 }
  790.             }

  791.             key_len = sizeof("HTTP_") - 1 + header[i].key.len;

  792.             val_len = header[i].value.len;

  793.             for (hn = header[i].next; hn; hn = hn->next) {
  794.                 val_len += hn->value.len + 2;
  795.                 ignored[header_params++] = hn;
  796.             }

  797.             len += ((key_len > 127) ? 4 : 1) + key_len
  798.                    + ((val_len > 127) ? 4 : 1) + val_len;

  799.         next_length:

  800.             continue;
  801.         }
  802.     }


  803.     if (len > 65535) {
  804.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  805.                       "fastcgi request record is too big: %uz", len);
  806.         return NGX_ERROR;
  807.     }


  808.     padding = 8 - len % 8;
  809.     padding = (padding == 8) ? 0 : padding;


  810.     size = sizeof(ngx_http_fastcgi_header_t)
  811.            + sizeof(ngx_http_fastcgi_begin_request_t)

  812.            + sizeof(ngx_http_fastcgi_header_t)  /* NGX_HTTP_FASTCGI_PARAMS */
  813.            + len + padding
  814.            + sizeof(ngx_http_fastcgi_header_t)  /* NGX_HTTP_FASTCGI_PARAMS */

  815.            + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */


  816.     b = ngx_create_temp_buf(r->pool, size);
  817.     if (b == NULL) {
  818.         return NGX_ERROR;
  819.     }

  820.     cl = ngx_alloc_chain_link(r->pool);
  821.     if (cl == NULL) {
  822.         return NGX_ERROR;
  823.     }

  824.     cl->buf = b;

  825.     ngx_http_fastcgi_request_start.br.flags =
  826.         flcf->keep_conn ? NGX_HTTP_FASTCGI_KEEP_CONN : 0;

  827.     ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
  828.                sizeof(ngx_http_fastcgi_request_start_t));

  829.     h = (ngx_http_fastcgi_header_t *)
  830.              (b->pos + sizeof(ngx_http_fastcgi_header_t)
  831.                      + sizeof(ngx_http_fastcgi_begin_request_t));

  832.     h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  833.     h->content_length_lo = (u_char) (len & 0xff);
  834.     h->padding_length = (u_char) padding;
  835.     h->reserved = 0;

  836.     b->last = b->pos + sizeof(ngx_http_fastcgi_header_t)
  837.                      + sizeof(ngx_http_fastcgi_begin_request_t)
  838.                      + sizeof(ngx_http_fastcgi_header_t);


  839.     if (params->lengths) {
  840.         ngx_memzero(&e, sizeof(ngx_http_script_engine_t));

  841.         e.ip = params->values->elts;
  842.         e.pos = b->last;
  843.         e.end = b->last + params_len;
  844.         e.request = r;
  845.         e.flushed = 1;

  846.         le.ip = params->lengths->elts;

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

  848.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  849.             key_len = lcode(&le);

  850.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  851.             skip_empty = lcode(&le);

  852.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  853.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  854.             }
  855.             le.ip += sizeof(uintptr_t);

  856.             if (skip_empty && val_len == 0) {
  857.                 e.skip = 1;

  858.                 while (*(uintptr_t *) e.ip) {
  859.                     code = *(ngx_http_script_code_pt *) e.ip;
  860.                     code((ngx_http_script_engine_t *) &e);
  861.                 }
  862.                 e.ip += sizeof(uintptr_t);

  863.                 e.skip = 0;

  864.                 continue;
  865.             }

  866.             if (ngx_http_script_check_length(&e,
  867.                                              ((key_len > 127) ? 4 : 1)
  868.                                              + ((val_len > 127) ? 4 : 1))
  869.                 != NGX_OK)
  870.             {
  871.                 return NGX_ERROR;
  872.             }

  873.             if (key_len > 127) {
  874.                 *e.pos++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
  875.                 *e.pos++ = (u_char) ((key_len >> 16) & 0xff);
  876.                 *e.pos++ = (u_char) ((key_len >> 8) & 0xff);
  877.                 *e.pos++ = (u_char) (key_len & 0xff);

  878.             } else {
  879.                 *e.pos++ = (u_char) key_len;
  880.             }

  881.             if (val_len > 127) {
  882.                 *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  883.                 *e.pos++ = (u_char) ((val_len >> 16) & 0xff);
  884.                 *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
  885.                 *e.pos++ = (u_char) (val_len & 0xff);

  886.             } else {
  887.                 *e.pos++ = (u_char) val_len;
  888.             }

  889.             while (*(uintptr_t *) e.ip) {
  890.                 code = *(ngx_http_script_code_pt *) e.ip;
  891.                 code((ngx_http_script_engine_t *) &e);
  892.             }
  893.             e.ip += sizeof(uintptr_t);

  894.             if (e.status) {
  895.                 return NGX_ERROR;
  896.             }

  897.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  898.                            "fastcgi param: \"%*s: %*s\"",
  899.                            key_len, e.pos - (key_len + val_len),
  900.                            val_len, e.pos - val_len);
  901.         }

  902.         if (e.pos != e.end) {
  903.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  904.                           "fastcgi request length mismatch");
  905.             return NGX_ERROR;
  906.         }

  907.         b->last = e.pos;
  908.     }


  909.     if (flcf->upstream.pass_request_headers) {

  910.         part = &r->headers_in.headers.part;
  911.         header = part->elts;

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

  913.             if (i >= part->nelts) {
  914.                 if (part->next == NULL) {
  915.                     break;
  916.                 }

  917.                 part = part->next;
  918.                 header = part->elts;
  919.                 i = 0;
  920.             }

  921.             for (n = 0; n < header_params; n++) {
  922.                 if (&header[i] == ignored[n]) {
  923.                     goto next_value;
  924.                 }
  925.             }

  926.             key_len = sizeof("HTTP_") - 1 + header[i].key.len;
  927.             if (key_len > 127) {
  928.                 *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
  929.                 *b->last++ = (u_char) ((key_len >> 16) & 0xff);
  930.                 *b->last++ = (u_char) ((key_len >> 8) & 0xff);
  931.                 *b->last++ = (u_char) (key_len & 0xff);

  932.             } else {
  933.                 *b->last++ = (u_char) key_len;
  934.             }

  935.             val_len = header[i].value.len;

  936.             for (hn = header[i].next; hn; hn = hn->next) {
  937.                 val_len += hn->value.len + 2;
  938.             }

  939.             if (val_len > 127) {
  940.                 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  941.                 *b->last++ = (u_char) ((val_len >> 16) & 0xff);
  942.                 *b->last++ = (u_char) ((val_len >> 8) & 0xff);
  943.                 *b->last++ = (u_char) (val_len & 0xff);

  944.             } else {
  945.                 *b->last++ = (u_char) val_len;
  946.             }

  947.             b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);

  948.             for (n = 0; n < header[i].key.len; n++) {
  949.                 ch = header[i].key.data[n];

  950.                 if (ch >= 'a' && ch <= 'z') {
  951.                     ch &= ~0x20;

  952.                 } else if (ch == '-') {
  953.                     ch = '_';
  954.                 }

  955.                 *b->last++ = ch;
  956.             }

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

  959.             if (header[i].next) {

  960.                 if (header[i].key.len == sizeof("Cookie") - 1
  961.                     && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
  962.                                        sizeof("Cookie") - 1)
  963.                        == 0)
  964.                 {
  965.                     sep = ';';

  966.                 } else {
  967.                     sep = ',';
  968.                 }

  969.                 for (hn = header[i].next; hn; hn = hn->next) {
  970.                     *b->last++ = sep;
  971.                     *b->last++ = ' ';
  972.                     b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
  973.                 }
  974.             }

  975.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  976.                            "fastcgi param: \"%*s: %*s\"",
  977.                            key_len, b->last - (key_len + val_len),
  978.                            val_len, b->last - val_len);
  979.         next_value:

  980.             continue;
  981.         }
  982.     }


  983.     if (padding) {
  984.         ngx_memzero(b->last, padding);
  985.         b->last += padding;
  986.     }


  987.     h = (ngx_http_fastcgi_header_t *) b->last;
  988.     b->last += sizeof(ngx_http_fastcgi_header_t);

  989.     h->version = 1;
  990.     h->type = NGX_HTTP_FASTCGI_PARAMS;
  991.     h->request_id_hi = 0;
  992.     h->request_id_lo = 1;
  993.     h->content_length_hi = 0;
  994.     h->content_length_lo = 0;
  995.     h->padding_length = 0;
  996.     h->reserved = 0;

  997.     if (r->request_body_no_buffering) {

  998.         u->request_bufs = cl;

  999.         u->output.output_filter = ngx_http_fastcgi_body_output_filter;
  1000.         u->output.filter_ctx = r;

  1001.     } else if (flcf->upstream.pass_request_body) {

  1002.         body = u->request_bufs;
  1003.         u->request_bufs = cl;

  1004. #if (NGX_SUPPRESS_WARN)
  1005.         file_pos = 0;
  1006.         pos = NULL;
  1007. #endif

  1008.         while (body) {

  1009.             if (ngx_buf_special(body->buf)) {
  1010.                 body = body->next;
  1011.                 continue;
  1012.             }

  1013.             if (body->buf->in_file) {
  1014.                 file_pos = body->buf->file_pos;

  1015.             } else {
  1016.                 pos = body->buf->pos;
  1017.             }

  1018.             next = 0;

  1019.             do {
  1020.                 b = ngx_alloc_buf(r->pool);
  1021.                 if (b == NULL) {
  1022.                     return NGX_ERROR;
  1023.                 }

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

  1025.                 if (body->buf->in_file) {
  1026.                     b->file_pos = file_pos;
  1027.                     file_pos += 32 * 1024;

  1028.                     if (file_pos >= body->buf->file_last) {
  1029.                         file_pos = body->buf->file_last;
  1030.                         next = 1;
  1031.                     }

  1032.                     b->file_last = file_pos;
  1033.                     len = (ngx_uint_t) (file_pos - b->file_pos);

  1034.                 } else {
  1035.                     b->pos = pos;
  1036.                     b->start = pos;
  1037.                     pos += 32 * 1024;

  1038.                     if (pos >= body->buf->last) {
  1039.                         pos = body->buf->last;
  1040.                         next = 1;
  1041.                     }

  1042.                     b->last = pos;
  1043.                     len = (ngx_uint_t) (pos - b->pos);
  1044.                 }

  1045.                 padding = 8 - len % 8;
  1046.                 padding = (padding == 8) ? 0 : padding;

  1047.                 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1048.                 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1049.                 h->version = 1;
  1050.                 h->type = NGX_HTTP_FASTCGI_STDIN;
  1051.                 h->request_id_hi = 0;
  1052.                 h->request_id_lo = 1;
  1053.                 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1054.                 h->content_length_lo = (u_char) (len & 0xff);
  1055.                 h->padding_length = (u_char) padding;
  1056.                 h->reserved = 0;

  1057.                 cl->next = ngx_alloc_chain_link(r->pool);
  1058.                 if (cl->next == NULL) {
  1059.                     return NGX_ERROR;
  1060.                 }

  1061.                 cl = cl->next;
  1062.                 cl->buf = b;

  1063.                 b = ngx_create_temp_buf(r->pool,
  1064.                                         sizeof(ngx_http_fastcgi_header_t)
  1065.                                         + padding);
  1066.                 if (b == NULL) {
  1067.                     return NGX_ERROR;
  1068.                 }

  1069.                 if (padding) {
  1070.                     ngx_memzero(b->last, padding);
  1071.                     b->last += padding;
  1072.                 }

  1073.                 cl->next = ngx_alloc_chain_link(r->pool);
  1074.                 if (cl->next == NULL) {
  1075.                     return NGX_ERROR;
  1076.                 }

  1077.                 cl = cl->next;
  1078.                 cl->buf = b;

  1079.             } while (!next);

  1080.             body = body->next;
  1081.         }

  1082.     } else {
  1083.         u->request_bufs = cl;
  1084.     }

  1085.     if (!r->request_body_no_buffering) {
  1086.         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1087.         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1088.         h->version = 1;
  1089.         h->type = NGX_HTTP_FASTCGI_STDIN;
  1090.         h->request_id_hi = 0;
  1091.         h->request_id_lo = 1;
  1092.         h->content_length_hi = 0;
  1093.         h->content_length_lo = 0;
  1094.         h->padding_length = 0;
  1095.         h->reserved = 0;
  1096.     }

  1097.     cl->next = NULL;

  1098.     return NGX_OK;
  1099. }


  1100. static ngx_int_t
  1101. ‌ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
  1102. {
  1103.     ngx_http_fastcgi_ctx_t  *f;

  1104.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1105.     if (f == NULL) {
  1106.         return NGX_OK;
  1107.     }

  1108.     f->state = ngx_http_fastcgi_st_version;
  1109.     f->fastcgi_stdout = 0;
  1110.     f->large_stderr = 0;

  1111.     if (f->split_parts) {
  1112.         f->split_parts->nelts = 0;
  1113.     }

  1114.     r->state = 0;

  1115.     return NGX_OK;
  1116. }


  1117. static ngx_int_t
  1118. ‌ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in)
  1119. {
  1120.     ngx_http_request_t  *r = data;

  1121.     off_t                       file_pos;
  1122.     u_char                     *pos, *start;
  1123.     size_t                      len, padding;
  1124.     ngx_buf_t                  *b;
  1125.     ngx_int_t                   rc;
  1126.     ngx_uint_t                  next, last;
  1127.     ngx_chain_t                *cl, *tl, *out, **ll;
  1128.     ngx_http_fastcgi_ctx_t     *f;
  1129.     ngx_http_fastcgi_header_t  *h;

  1130.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1131.                    "fastcgi output filter");

  1132.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1133.     if (in == NULL) {
  1134.         out = in;
  1135.         goto out;
  1136.     }

  1137.     out = NULL;
  1138.     ll = &out;

  1139.     if (!f->header_sent) {
  1140.         /* first buffer contains headers, pass it unmodified */

  1141.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1142.                        "fastcgi output header");

  1143.         f->header_sent = 1;

  1144.         tl = ngx_alloc_chain_link(r->pool);
  1145.         if (tl == NULL) {
  1146.             return NGX_ERROR;
  1147.         }

  1148.         tl->buf = in->buf;
  1149.         *ll = tl;
  1150.         ll = &tl->next;

  1151.         in = in->next;

  1152.         if (in == NULL) {
  1153.             tl->next = NULL;
  1154.             goto out;
  1155.         }
  1156.     }

  1157.     cl = ngx_chain_get_free_buf(r->pool, &f->free);
  1158.     if (cl == NULL) {
  1159.         return NGX_ERROR;
  1160.     }

  1161.     b = cl->buf;

  1162.     b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1163.     b->temporary = 1;

  1164.     if (b->start == NULL) {
  1165.         /* reserve space for maximum possible padding, 7 bytes */

  1166.         b->start = ngx_palloc(r->pool,
  1167.                               sizeof(ngx_http_fastcgi_header_t) + 7);
  1168.         if (b->start == NULL) {
  1169.             return NGX_ERROR;
  1170.         }

  1171.         b->pos = b->start;
  1172.         b->last = b->start;

  1173.         b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
  1174.     }

  1175.     *ll = cl;

  1176.     last = 0;
  1177.     padding = 0;

  1178. #if (NGX_SUPPRESS_WARN)
  1179.     file_pos = 0;
  1180.     pos = NULL;
  1181. #endif

  1182.     while (in) {

  1183.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1184.                        "fastcgi output in  l:%d f:%d %p, pos %p, size: %z "
  1185.                        "file: %O, size: %O",
  1186.                        in->buf->last_buf,
  1187.                        in->buf->in_file,
  1188.                        in->buf->start, in->buf->pos,
  1189.                        in->buf->last - in->buf->pos,
  1190.                        in->buf->file_pos,
  1191.                        in->buf->file_last - in->buf->file_pos);

  1192.         if (in->buf->last_buf) {
  1193.             last = 1;
  1194.         }

  1195.         if (ngx_buf_special(in->buf)) {
  1196.             in = in->next;
  1197.             continue;
  1198.         }

  1199.         if (in->buf->in_file) {
  1200.             file_pos = in->buf->file_pos;

  1201.         } else {
  1202.             pos = in->buf->pos;
  1203.         }

  1204.         next = 0;

  1205.         do {
  1206.             tl = ngx_chain_get_free_buf(r->pool, &f->free);
  1207.             if (tl == NULL) {
  1208.                 return NGX_ERROR;
  1209.             }

  1210.             b = tl->buf;
  1211.             start = b->start;

  1212.             ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));

  1213.             /*
  1214.              * restore b->start to preserve memory allocated in the buffer,
  1215.              * to reuse it later for headers and padding
  1216.              */

  1217.             b->start = start;

  1218.             if (in->buf->in_file) {
  1219.                 b->file_pos = file_pos;
  1220.                 file_pos += 32 * 1024;

  1221.                 if (file_pos >= in->buf->file_last) {
  1222.                     file_pos = in->buf->file_last;
  1223.                     next = 1;
  1224.                 }

  1225.                 b->file_last = file_pos;
  1226.                 len = (ngx_uint_t) (file_pos - b->file_pos);

  1227.             } else {
  1228.                 b->pos = pos;
  1229.                 pos += 32 * 1024;

  1230.                 if (pos >= in->buf->last) {
  1231.                     pos = in->buf->last;
  1232.                     next = 1;
  1233.                 }

  1234.                 b->last = pos;
  1235.                 len = (ngx_uint_t) (pos - b->pos);
  1236.             }

  1237.             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1238.             b->shadow = in->buf;
  1239.             b->last_shadow = next;

  1240.             b->last_buf = 0;
  1241.             b->last_in_chain = 0;

  1242.             padding = 8 - len % 8;
  1243.             padding = (padding == 8) ? 0 : padding;

  1244.             h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1245.             cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1246.             h->version = 1;
  1247.             h->type = NGX_HTTP_FASTCGI_STDIN;
  1248.             h->request_id_hi = 0;
  1249.             h->request_id_lo = 1;
  1250.             h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1251.             h->content_length_lo = (u_char) (len & 0xff);
  1252.             h->padding_length = (u_char) padding;
  1253.             h->reserved = 0;

  1254.             cl->next = tl;
  1255.             cl = tl;

  1256.             tl = ngx_chain_get_free_buf(r->pool, &f->free);
  1257.             if (tl == NULL) {
  1258.                 return NGX_ERROR;
  1259.             }

  1260.             b = tl->buf;

  1261.             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1262.             b->temporary = 1;

  1263.             if (b->start == NULL) {
  1264.                 /* reserve space for maximum possible padding, 7 bytes */

  1265.                 b->start = ngx_palloc(r->pool,
  1266.                                       sizeof(ngx_http_fastcgi_header_t) + 7);
  1267.                 if (b->start == NULL) {
  1268.                     return NGX_ERROR;
  1269.                 }

  1270.                 b->pos = b->start;
  1271.                 b->last = b->start;

  1272.                 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
  1273.             }

  1274.             if (padding) {
  1275.                 ngx_memzero(b->last, padding);
  1276.                 b->last += padding;
  1277.             }

  1278.             cl->next = tl;
  1279.             cl = tl;

  1280.         } while (!next);

  1281.         in = in->next;
  1282.     }

  1283.     if (last) {
  1284.         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1285.         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1286.         h->version = 1;
  1287.         h->type = NGX_HTTP_FASTCGI_STDIN;
  1288.         h->request_id_hi = 0;
  1289.         h->request_id_lo = 1;
  1290.         h->content_length_hi = 0;
  1291.         h->content_length_lo = 0;
  1292.         h->padding_length = 0;
  1293.         h->reserved = 0;

  1294.         cl->buf->last_buf = 1;

  1295.     } else if (padding == 0) {
  1296.         /* TODO: do not allocate buffers instead */
  1297.         cl->buf->temporary = 0;
  1298.         cl->buf->sync = 1;
  1299.     }

  1300.     cl->next = NULL;

  1301. out:

  1302. #if (NGX_DEBUG)

  1303.     for (cl = out; cl; cl = cl->next) {
  1304.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1305.                        "fastcgi output out l:%d f:%d %p, pos %p, size: %z "
  1306.                        "file: %O, size: %O",
  1307.                        cl->buf->last_buf,
  1308.                        cl->buf->in_file,
  1309.                        cl->buf->start, cl->buf->pos,
  1310.                        cl->buf->last - cl->buf->pos,
  1311.                        cl->buf->file_pos,
  1312.                        cl->buf->file_last - cl->buf->file_pos);
  1313.     }

  1314. #endif

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

  1316.     ngx_chain_update_chains(r->pool, &f->free, &f->busy, &out,
  1317.                          (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter);

  1318.     for (cl = f->free; cl; cl = cl->next) {

  1319.         /* mark original buffers as sent */

  1320.         if (cl->buf->shadow) {
  1321.             if (cl->buf->last_shadow) {
  1322.                 b = cl->buf->shadow;
  1323.                 b->pos = b->last;
  1324.             }

  1325.             cl->buf->shadow = NULL;
  1326.         }
  1327.     }

  1328.     return rc;
  1329. }


  1330. static ngx_int_t
  1331. ‌ngx_http_fastcgi_process_header(ngx_http_request_t *r)
  1332. {
  1333.     u_char                         *p, *msg, *start, *last,
  1334.                                    *part_start, *part_end;
  1335.     size_t                          size;
  1336.     ngx_str_t                      *status_line, *pattern;
  1337.     ngx_int_t                       rc, status;
  1338.     ngx_buf_t                       buf;
  1339.     ngx_uint_t                      i;
  1340.     ngx_table_elt_t                *h;
  1341.     ngx_http_upstream_t            *u;
  1342.     ngx_http_fastcgi_ctx_t         *f;
  1343.     ngx_http_upstream_header_t     *hh;
  1344.     ngx_http_fastcgi_loc_conf_t    *flcf;
  1345.     ngx_http_fastcgi_split_part_t  *part;
  1346.     ngx_http_upstream_main_conf_t  *umcf;

  1347.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1348.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1349.     u = r->upstream;

  1350.     for ( ;; ) {

  1351.         if (f->state < ngx_http_fastcgi_st_data) {

  1352.             f->pos = u->buffer.pos;
  1353.             f->last = u->buffer.last;

  1354.             rc = ngx_http_fastcgi_process_record(r, f);

  1355.             u->buffer.pos = f->pos;
  1356.             u->buffer.last = f->last;

  1357.             if (rc == NGX_AGAIN) {
  1358.                 return NGX_AGAIN;
  1359.             }

  1360.             if (rc == NGX_ERROR) {
  1361.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1362.             }

  1363.             if (f->type != NGX_HTTP_FASTCGI_STDOUT
  1364.                 && f->type != NGX_HTTP_FASTCGI_STDERR)
  1365.             {
  1366.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1367.                               "upstream sent unexpected FastCGI record: %ui",
  1368.                               f->type);

  1369.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1370.             }

  1371.             if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
  1372.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1373.                               "upstream prematurely closed FastCGI stdout");

  1374.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1375.             }
  1376.         }

  1377.         if (f->state == ngx_http_fastcgi_st_padding) {

  1378.             if (u->buffer.pos + f->padding < u->buffer.last) {
  1379.                 f->state = ngx_http_fastcgi_st_version;
  1380.                 u->buffer.pos += f->padding;

  1381.                 continue;
  1382.             }

  1383.             if (u->buffer.pos + f->padding == u->buffer.last) {
  1384.                 f->state = ngx_http_fastcgi_st_version;
  1385.                 u->buffer.pos = u->buffer.last;

  1386.                 return NGX_AGAIN;
  1387.             }

  1388.             f->padding -= u->buffer.last - u->buffer.pos;
  1389.             u->buffer.pos = u->buffer.last;

  1390.             return NGX_AGAIN;
  1391.         }


  1392.         /* f->state == ngx_http_fastcgi_st_data */

  1393.         if (f->type == NGX_HTTP_FASTCGI_STDERR) {

  1394.             if (f->length) {
  1395.                 msg = u->buffer.pos;

  1396.                 if (u->buffer.pos + f->length <= u->buffer.last) {
  1397.                     u->buffer.pos += f->length;
  1398.                     f->length = 0;
  1399.                     f->state = ngx_http_fastcgi_st_padding;

  1400.                 } else {
  1401.                     f->length -= u->buffer.last - u->buffer.pos;
  1402.                     u->buffer.pos = u->buffer.last;
  1403.                 }

  1404.                 for (p = u->buffer.pos - 1; msg < p; p--) {
  1405.                     if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
  1406.                         break;
  1407.                     }
  1408.                 }

  1409.                 p++;

  1410.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1411.                               "FastCGI sent in stderr: \"%*s\"", p - msg, msg);

  1412.                 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1413.                 if (flcf->catch_stderr) {
  1414.                     pattern = flcf->catch_stderr->elts;

  1415.                     for (i = 0; i < flcf->catch_stderr->nelts; i++) {
  1416.                         if (ngx_strnstr(msg, (char *) pattern[i].data,
  1417.                                         p - msg)
  1418.                             != NULL)
  1419.                         {
  1420.                             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1421.                         }
  1422.                     }
  1423.                 }

  1424.                 if (u->buffer.pos == u->buffer.last) {

  1425.                     if (!f->fastcgi_stdout) {

  1426.                         /*
  1427.                          * the special handling the large number
  1428.                          * of the PHP warnings to not allocate memory
  1429.                          */

  1430. #if (NGX_HTTP_CACHE)
  1431.                         if (r->cache) {
  1432.                             u->buffer.pos = u->buffer.start
  1433.                                                      + r->cache->header_start;
  1434.                         } else {
  1435.                             u->buffer.pos = u->buffer.start;
  1436.                         }
  1437. #else
  1438.                         u->buffer.pos = u->buffer.start;
  1439. #endif
  1440.                         u->buffer.last = u->buffer.pos;
  1441.                         f->large_stderr = 1;
  1442.                     }

  1443.                     return NGX_AGAIN;
  1444.                 }

  1445.             } else {
  1446.                 f->state = ngx_http_fastcgi_st_padding;
  1447.             }

  1448.             continue;
  1449.         }


  1450.         /* f->type == NGX_HTTP_FASTCGI_STDOUT */

  1451. #if (NGX_HTTP_CACHE)

  1452.         if (f->large_stderr && r->cache) {
  1453.             ssize_t                     len;
  1454.             ngx_http_fastcgi_header_t  *fh;

  1455.             start = u->buffer.start + r->cache->header_start;

  1456.             len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t);

  1457.             /*
  1458.              * A tail of large stderr output before HTTP header is placed
  1459.              * in a cache file without a FastCGI record header.
  1460.              * To workaround it we put a dummy FastCGI record header at the
  1461.              * start of the stderr output or update r->cache_header_start,
  1462.              * if there is no enough place for the record header.
  1463.              */

  1464.             if (len >= 0) {
  1465.                 fh = (ngx_http_fastcgi_header_t *) start;
  1466.                 fh->version = 1;
  1467.                 fh->type = NGX_HTTP_FASTCGI_STDERR;
  1468.                 fh->request_id_hi = 0;
  1469.                 fh->request_id_lo = 1;
  1470.                 fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1471.                 fh->content_length_lo = (u_char) (len & 0xff);
  1472.                 fh->padding_length = 0;
  1473.                 fh->reserved = 0;

  1474.             } else {
  1475.                 r->cache->header_start += u->buffer.pos - start
  1476.                                           - sizeof(ngx_http_fastcgi_header_t);
  1477.             }

  1478.             f->large_stderr = 0;
  1479.         }

  1480. #endif

  1481.         f->fastcgi_stdout = 1;

  1482.         start = u->buffer.pos;

  1483.         if (u->buffer.pos + f->length < u->buffer.last) {

  1484.             /*
  1485.              * set u->buffer.last to the end of the FastCGI record data
  1486.              * for ngx_http_parse_header_line()
  1487.              */

  1488.             last = u->buffer.last;
  1489.             u->buffer.last = u->buffer.pos + f->length;

  1490.         } else {
  1491.             last = NULL;
  1492.         }

  1493.         for ( ;; ) {

  1494.             part_start = u->buffer.pos;
  1495.             part_end = u->buffer.last;

  1496.             rc = ngx_http_parse_header_line(r, &u->buffer, 1);

  1497.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1498.                            "http fastcgi parser: %i", rc);

  1499.             if (rc == NGX_AGAIN) {
  1500.                 break;
  1501.             }

  1502.             if (rc == NGX_OK) {

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

  1504.                 h = ngx_list_push(&u->headers_in.headers);
  1505.                 if (h == NULL) {
  1506.                     return NGX_ERROR;
  1507.                 }

  1508.                 if (f->split_parts && f->split_parts->nelts) {

  1509.                     part = f->split_parts->elts;
  1510.                     size = u->buffer.pos - part_start;

  1511.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1512.                         size += part[i].end - part[i].start;
  1513.                     }

  1514.                     p = ngx_pnalloc(r->pool, size);
  1515.                     if (p == NULL) {
  1516.                         h->hash = 0;
  1517.                         return NGX_ERROR;
  1518.                     }

  1519.                     buf.pos = p;

  1520.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1521.                         p = ngx_cpymem(p, part[i].start,
  1522.                                        part[i].end - part[i].start);
  1523.                     }

  1524.                     p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);

  1525.                     buf.last = p;

  1526.                     f->split_parts->nelts = 0;

  1527.                     rc = ngx_http_parse_header_line(r, &buf, 1);

  1528.                     if (rc != NGX_OK) {
  1529.                         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  1530.                                       "invalid header after joining "
  1531.                                       "FastCGI records");
  1532.                         h->hash = 0;
  1533.                         return NGX_ERROR;
  1534.                     }

  1535.                     h->key.len = r->header_name_end - r->header_name_start;
  1536.                     h->key.data = r->header_name_start;
  1537.                     h->key.data[h->key.len] = '\0';

  1538.                     h->value.len = r->header_end - r->header_start;
  1539.                     h->value.data = r->header_start;
  1540.                     h->value.data[h->value.len] = '\0';

  1541.                     h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
  1542.                     if (h->lowcase_key == NULL) {
  1543.                         return NGX_ERROR;
  1544.                     }

  1545.                 } else {

  1546.                     h->key.len = r->header_name_end - r->header_name_start;
  1547.                     h->value.len = r->header_end - r->header_start;

  1548.                     h->key.data = ngx_pnalloc(r->pool,
  1549.                                               h->key.len + 1 + h->value.len + 1
  1550.                                               + h->key.len);
  1551.                     if (h->key.data == NULL) {
  1552.                         h->hash = 0;
  1553.                         return NGX_ERROR;
  1554.                     }

  1555.                     h->value.data = h->key.data + h->key.len + 1;
  1556.                     h->lowcase_key = h->key.data + h->key.len + 1
  1557.                                      + h->value.len + 1;

  1558.                     ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  1559.                     h->key.data[h->key.len] = '\0';
  1560.                     ngx_memcpy(h->value.data, r->header_start, h->value.len);
  1561.                     h->value.data[h->value.len] = '\0';
  1562.                 }

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

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

  1566.                 } else {
  1567.                     ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  1568.                 }

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

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

  1573.                     if (rc != NGX_OK) {
  1574.                         return rc;
  1575.                     }
  1576.                 }

  1577.                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1578.                                "http fastcgi header: \"%V: %V\"",
  1579.                                &h->key, &h->value);

  1580.                 if (u->buffer.pos < u->buffer.last) {
  1581.                     continue;
  1582.                 }

  1583.                 /* the end of the FastCGI record */

  1584.                 break;
  1585.             }

  1586.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

  1588.                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1589.                                "http fastcgi header done");

  1590.                 if (u->headers_in.status) {
  1591.                     status_line = &u->headers_in.status->value;

  1592.                     status = ngx_atoi(status_line->data, 3);

  1593.                     if (status == NGX_ERROR) {
  1594.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1595.                                       "upstream sent invalid status \"%V\"",
  1596.                                       status_line);
  1597.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1598.                     }

  1599.                     u->headers_in.status_n = status;

  1600.                     if (status_line->len > 3) {
  1601.                         u->headers_in.status_line = *status_line;
  1602.                     }

  1603.                 } else if (u->headers_in.location) {
  1604.                     u->headers_in.status_n = 302;
  1605.                     ngx_str_set(&u->headers_in.status_line,
  1606.                                 "302 Moved Temporarily");

  1607.                 } else {
  1608.                     u->headers_in.status_n = 200;
  1609.                     ngx_str_set(&u->headers_in.status_line, "200 OK");
  1610.                 }

  1611.                 if (u->state && u->state->status == 0) {
  1612.                     u->state->status = u->headers_in.status_n;
  1613.                 }

  1614.                 break;
  1615.             }

  1616.             /* rc == NGX_HTTP_PARSE_INVALID_HEADER */

  1617.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1618.                           "upstream sent invalid header: \"%*s\\x%02xd...\"",
  1619.                           r->header_end - r->header_name_start,
  1620.                           r->header_name_start, *r->header_end);

  1621.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1622.         }

  1623.         if (last) {
  1624.             u->buffer.last = last;
  1625.         }

  1626.         f->length -= u->buffer.pos - start;

  1627.         if (f->length == 0) {
  1628.             f->state = ngx_http_fastcgi_st_padding;
  1629.         }

  1630.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1631.             return NGX_OK;
  1632.         }

  1633.         if (rc == NGX_OK) {
  1634.             continue;
  1635.         }

  1636.         /* rc == NGX_AGAIN */

  1637.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1638.                        "upstream split a header line in FastCGI records");

  1639.         if (f->split_parts == NULL) {
  1640.             f->split_parts = ngx_array_create(r->pool, 1,
  1641.                                         sizeof(ngx_http_fastcgi_split_part_t));
  1642.             if (f->split_parts == NULL) {
  1643.                 return NGX_ERROR;
  1644.             }
  1645.         }

  1646.         part = ngx_array_push(f->split_parts);
  1647.         if (part == NULL) {
  1648.             return NGX_ERROR;
  1649.         }

  1650.         part->start = part_start;
  1651.         part->end = part_end;

  1652.         if (u->buffer.pos < u->buffer.last) {
  1653.             continue;
  1654.         }

  1655.         return NGX_AGAIN;
  1656.     }
  1657. }


  1658. static ngx_int_t
  1659. ‌ngx_http_fastcgi_input_filter_init(void *data)
  1660. {
  1661.     ngx_http_request_t  *r = data;

  1662.     ngx_http_upstream_t          *u;
  1663.     ngx_http_fastcgi_ctx_t       *f;
  1664.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1665.     u = r->upstream;

  1666.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1667.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1668.     u->pipe->length = flcf->keep_conn ?
  1669.                       (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;

  1670.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1671.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
  1672.     {
  1673.         f->rest = 0;

  1674.     } else if (r->method == NGX_HTTP_HEAD) {
  1675.         f->rest = -2;

  1676.     } else {
  1677.         f->rest = u->headers_in.content_length_n;
  1678.     }

  1679.     return NGX_OK;
  1680. }


  1681. static ngx_int_t
  1682. ‌ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1683. {
  1684.     u_char                       *m, *msg;
  1685.     ngx_int_t                     rc;
  1686.     ngx_buf_t                    *b, **prev;
  1687.     ngx_chain_t                  *cl;
  1688.     ngx_http_request_t           *r;
  1689.     ngx_http_fastcgi_ctx_t       *f;
  1690.     ngx_http_fastcgi_loc_conf_t  *flcf;

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

  1694.     r = p->input_ctx;
  1695.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1696.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1697.     if (p->upstream_done || f->closed) {
  1698.         r->upstream->keepalive = 0;

  1699.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
  1700.                        "http fastcgi data after close");

  1701.         return NGX_OK;
  1702.     }

  1703.     b = NULL;
  1704.     prev = &buf->shadow;

  1705.     f->pos = buf->pos;
  1706.     f->last = buf->last;

  1707.     for ( ;; ) {
  1708.         if (f->state < ngx_http_fastcgi_st_data) {

  1709.             rc = ngx_http_fastcgi_process_record(r, f);

  1710.             if (rc == NGX_AGAIN) {
  1711.                 break;
  1712.             }

  1713.             if (rc == NGX_ERROR) {
  1714.                 return NGX_ERROR;
  1715.             }

  1716.             if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
  1717.                 f->state = ngx_http_fastcgi_st_padding;

  1718.                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
  1719.                                "http fastcgi closed stdout");

  1720.                 if (f->rest > 0) {
  1721.                     ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1722.                                   "upstream prematurely closed "
  1723.                                   "FastCGI stdout");

  1724.                     p->upstream_error = 1;
  1725.                     p->upstream_eof = 0;
  1726.                     f->closed = 1;

  1727.                     break;
  1728.                 }

  1729.                 if (!flcf->keep_conn) {
  1730.                     p->upstream_done = 1;
  1731.                 }

  1732.                 continue;
  1733.             }

  1734.             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {

  1735.                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
  1736.                                "http fastcgi sent end request");

  1737.                 if (f->rest > 0) {
  1738.                     ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1739.                                   "upstream prematurely closed "
  1740.                                   "FastCGI request");

  1741.                     p->upstream_error = 1;
  1742.                     p->upstream_eof = 0;
  1743.                     f->closed = 1;

  1744.                     break;
  1745.                 }

  1746.                 if (!flcf->keep_conn) {
  1747.                     p->upstream_done = 1;
  1748.                     break;
  1749.                 }

  1750.                 continue;
  1751.             }
  1752.         }


  1753.         if (f->state == ngx_http_fastcgi_st_padding) {

  1754.             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {

  1755.                 if (f->pos + f->padding < f->last) {
  1756.                     p->upstream_done = 1;
  1757.                     break;
  1758.                 }

  1759.                 if (f->pos + f->padding == f->last) {
  1760.                     p->upstream_done = 1;
  1761.                     r->upstream->keepalive = 1;
  1762.                     break;
  1763.                 }

  1764.                 f->padding -= f->last - f->pos;

  1765.                 break;
  1766.             }

  1767.             if (f->pos + f->padding < f->last) {
  1768.                 f->state = ngx_http_fastcgi_st_version;
  1769.                 f->pos += f->padding;

  1770.                 continue;
  1771.             }

  1772.             if (f->pos + f->padding == f->last) {
  1773.                 f->state = ngx_http_fastcgi_st_version;

  1774.                 break;
  1775.             }

  1776.             f->padding -= f->last - f->pos;

  1777.             break;
  1778.         }


  1779.         /* f->state == ngx_http_fastcgi_st_data */

  1780.         if (f->type == NGX_HTTP_FASTCGI_STDERR) {

  1781.             if (f->length) {

  1782.                 if (f->pos == f->last) {
  1783.                     break;
  1784.                 }

  1785.                 msg = f->pos;

  1786.                 if (f->pos + f->length <= f->last) {
  1787.                     f->pos += f->length;
  1788.                     f->length = 0;
  1789.                     f->state = ngx_http_fastcgi_st_padding;

  1790.                 } else {
  1791.                     f->length -= f->last - f->pos;
  1792.                     f->pos = f->last;
  1793.                 }

  1794.                 for (m = f->pos - 1; msg < m; m--) {
  1795.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1796.                         break;
  1797.                     }
  1798.                 }

  1799.                 ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1800.                               "FastCGI sent in stderr: \"%*s\"",
  1801.                               m + 1 - msg, msg);

  1802.             } else {
  1803.                 f->state = ngx_http_fastcgi_st_padding;
  1804.             }

  1805.             continue;
  1806.         }

  1807.         if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {

  1808.             if (f->pos + f->length <= f->last) {
  1809.                 f->state = ngx_http_fastcgi_st_padding;
  1810.                 f->pos += f->length;

  1811.                 continue;
  1812.             }

  1813.             f->length -= f->last - f->pos;

  1814.             break;
  1815.         }


  1816.         /* f->type == NGX_HTTP_FASTCGI_STDOUT */

  1817.         if (f->pos == f->last) {
  1818.             break;
  1819.         }

  1820.         if (f->rest == -2) {
  1821.             f->rest = r->upstream->headers_in.content_length_n;
  1822.         }

  1823.         if (f->rest == 0) {
  1824.             ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1825.                           "upstream sent more data than specified in "
  1826.                           "\"Content-Length\" header");
  1827.             p->upstream_done = 1;
  1828.             break;
  1829.         }

  1830.         cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1831.         if (cl == NULL) {
  1832.             return NGX_ERROR;
  1833.         }

  1834.         b = cl->buf;

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

  1836.         b->pos = f->pos;
  1837.         b->start = buf->start;
  1838.         b->end = buf->end;
  1839.         b->tag = p->tag;
  1840.         b->temporary = 1;
  1841.         b->recycled = 1;

  1842.         *prev = b;
  1843.         prev = &b->shadow;

  1844.         if (p->in) {
  1845.             *p->last_in = cl;
  1846.         } else {
  1847.             p->in = cl;
  1848.         }
  1849.         p->last_in = &cl->next;


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

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

  1853.         if (f->pos + f->length <= f->last) {
  1854.             f->state = ngx_http_fastcgi_st_padding;
  1855.             f->pos += f->length;
  1856.             b->last = f->pos;

  1857.         } else {
  1858.             f->length -= f->last - f->pos;
  1859.             f->pos = f->last;
  1860.             b->last = f->last;
  1861.         }

  1862.         if (f->rest > 0) {

  1863.             if (b->last - b->pos > f->rest) {
  1864.                 ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1865.                               "upstream sent more data than specified in "
  1866.                               "\"Content-Length\" header");

  1867.                 b->last = b->pos + f->rest;
  1868.                 p->upstream_done = 1;

  1869.                 break;
  1870.             }

  1871.             f->rest -= b->last - b->pos;
  1872.         }
  1873.     }

  1874.     if (flcf->keep_conn) {

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

  1876.         if (f->state < ngx_http_fastcgi_st_data) {
  1877.             p->length = 1;

  1878.         } else if (f->state == ngx_http_fastcgi_st_padding) {
  1879.             p->length = f->padding;

  1880.         } else {
  1881.             /* ngx_http_fastcgi_st_data */

  1882.             p->length = f->length;
  1883.         }
  1884.     }

  1885.     if (b) {
  1886.         b->shadow = buf;
  1887.         b->last_shadow = 1;

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

  1890.         return NGX_OK;
  1891.     }

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

  1893.     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
  1894.         return NGX_ERROR;
  1895.     }

  1896.     return NGX_OK;
  1897. }


  1898. static ngx_int_t
  1899. ‌ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
  1900. {
  1901.     u_char                  *m, *msg;
  1902.     ngx_int_t                rc;
  1903.     ngx_buf_t               *b, *buf;
  1904.     ngx_chain_t             *cl, **ll;
  1905.     ngx_http_request_t      *r;
  1906.     ngx_http_upstream_t     *u;
  1907.     ngx_http_fastcgi_ctx_t  *f;

  1908.     r = data;
  1909.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1910.     u = r->upstream;
  1911.     buf = &u->buffer;

  1912.     buf->pos = buf->last;
  1913.     buf->last += bytes;

  1914.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1915.         ll = &cl->next;
  1916.     }

  1917.     f->pos = buf->pos;
  1918.     f->last = buf->last;

  1919.     for ( ;; ) {
  1920.         if (f->state < ngx_http_fastcgi_st_data) {

  1921.             rc = ngx_http_fastcgi_process_record(r, f);

  1922.             if (rc == NGX_AGAIN) {
  1923.                 break;
  1924.             }

  1925.             if (rc == NGX_ERROR) {
  1926.                 return NGX_ERROR;
  1927.             }

  1928.             if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
  1929.                 f->state = ngx_http_fastcgi_st_padding;

  1930.                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1931.                                "http fastcgi closed stdout");

  1932.                 continue;
  1933.             }
  1934.         }

  1935.         if (f->state == ngx_http_fastcgi_st_padding) {

  1936.             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {

  1937.                 if (f->rest > 0) {
  1938.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1939.                                   "upstream prematurely closed "
  1940.                                   "FastCGI request");
  1941.                     u->error = 1;
  1942.                     break;
  1943.                 }

  1944.                 if (f->pos + f->padding < f->last) {
  1945.                     u->length = 0;
  1946.                     break;
  1947.                 }

  1948.                 if (f->pos + f->padding == f->last) {
  1949.                     u->length = 0;
  1950.                     u->keepalive = 1;
  1951.                     break;
  1952.                 }

  1953.                 f->padding -= f->last - f->pos;

  1954.                 break;
  1955.             }

  1956.             if (f->pos + f->padding < f->last) {
  1957.                 f->state = ngx_http_fastcgi_st_version;
  1958.                 f->pos += f->padding;

  1959.                 continue;
  1960.             }

  1961.             if (f->pos + f->padding == f->last) {
  1962.                 f->state = ngx_http_fastcgi_st_version;

  1963.                 break;
  1964.             }

  1965.             f->padding -= f->last - f->pos;

  1966.             break;
  1967.         }


  1968.         /* f->state == ngx_http_fastcgi_st_data */

  1969.         if (f->type == NGX_HTTP_FASTCGI_STDERR) {

  1970.             if (f->length) {

  1971.                 if (f->pos == f->last) {
  1972.                     break;
  1973.                 }

  1974.                 msg = f->pos;

  1975.                 if (f->pos + f->length <= f->last) {
  1976.                     f->pos += f->length;
  1977.                     f->length = 0;
  1978.                     f->state = ngx_http_fastcgi_st_padding;

  1979.                 } else {
  1980.                     f->length -= f->last - f->pos;
  1981.                     f->pos = f->last;
  1982.                 }

  1983.                 for (m = f->pos - 1; msg < m; m--) {
  1984.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1985.                         break;
  1986.                     }
  1987.                 }

  1988.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1989.                               "FastCGI sent in stderr: \"%*s\"",
  1990.                               m + 1 - msg, msg);

  1991.             } else {
  1992.                 f->state = ngx_http_fastcgi_st_padding;
  1993.             }

  1994.             continue;
  1995.         }

  1996.         if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {

  1997.             if (f->pos + f->length <= f->last) {
  1998.                 f->state = ngx_http_fastcgi_st_padding;
  1999.                 f->pos += f->length;

  2000.                 continue;
  2001.             }

  2002.             f->length -= f->last - f->pos;

  2003.             break;
  2004.         }


  2005.         /* f->type == NGX_HTTP_FASTCGI_STDOUT */

  2006.         if (f->pos == f->last) {
  2007.             break;
  2008.         }

  2009.         if (f->rest == 0) {
  2010.             ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  2011.                           "upstream sent more data than specified in "
  2012.                           "\"Content-Length\" header");
  2013.             u->length = 0;
  2014.             break;
  2015.         }

  2016.         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  2017.         if (cl == NULL) {
  2018.             return NGX_ERROR;
  2019.         }

  2020.         *ll = cl;
  2021.         ll = &cl->next;

  2022.         b = cl->buf;

  2023.         b->flush = 1;
  2024.         b->memory = 1;

  2025.         b->pos = f->pos;
  2026.         b->tag = u->output.tag;

  2027.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2028.                        "http fastcgi output buf %p", b->pos);

  2029.         if (f->pos + f->length <= f->last) {
  2030.             f->state = ngx_http_fastcgi_st_padding;
  2031.             f->pos += f->length;
  2032.             b->last = f->pos;

  2033.         } else {
  2034.             f->length -= f->last - f->pos;
  2035.             f->pos = f->last;
  2036.             b->last = f->last;
  2037.         }

  2038.         if (f->rest > 0) {

  2039.             if (b->last - b->pos > f->rest) {
  2040.                 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  2041.                               "upstream sent more data than specified in "
  2042.                               "\"Content-Length\" header");

  2043.                 b->last = b->pos + f->rest;
  2044.                 u->length = 0;

  2045.                 break;
  2046.             }

  2047.             f->rest -= b->last - b->pos;
  2048.         }
  2049.     }

  2050.     return NGX_OK;
  2051. }


  2052. static ngx_int_t
  2053. ‌ngx_http_fastcgi_process_record(ngx_http_request_t *r,
  2054.     ngx_http_fastcgi_ctx_t *f)
  2055. {
  2056.     u_char                     ch, *p;
  2057.     ngx_http_fastcgi_state_e   state;

  2058.     state = f->state;

  2059.     for (p = f->pos; p < f->last; p++) {

  2060.         ch = *p;

  2061.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2062.                        "http fastcgi record byte: %02Xd", ch);

  2063.         switch (state) {

  2064.         case ngx_http_fastcgi_st_version:
  2065.             if (ch != 1) {
  2066.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2067.                               "upstream sent unsupported FastCGI "
  2068.                               "protocol version: %d", ch);
  2069.                 return NGX_ERROR;
  2070.             }
  2071.             state = ngx_http_fastcgi_st_type;
  2072.             break;

  2073.         case ngx_http_fastcgi_st_type:
  2074.             switch (ch) {
  2075.             case NGX_HTTP_FASTCGI_STDOUT:
  2076.             case NGX_HTTP_FASTCGI_STDERR:
  2077.             case NGX_HTTP_FASTCGI_END_REQUEST:
  2078.                 f->type = (ngx_uint_t) ch;
  2079.                 break;
  2080.             default:
  2081.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2082.                               "upstream sent invalid FastCGI "
  2083.                               "record type: %d", ch);
  2084.                 return NGX_ERROR;

  2085.             }
  2086.             state = ngx_http_fastcgi_st_request_id_hi;
  2087.             break;

  2088.         /* we support the single request per connection */

  2089.         case ngx_http_fastcgi_st_request_id_hi:
  2090.             if (ch != 0) {
  2091.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2092.                               "upstream sent unexpected FastCGI "
  2093.                               "request id high byte: %d", ch);
  2094.                 return NGX_ERROR;
  2095.             }
  2096.             state = ngx_http_fastcgi_st_request_id_lo;
  2097.             break;

  2098.         case ngx_http_fastcgi_st_request_id_lo:
  2099.             if (ch != 1) {
  2100.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2101.                               "upstream sent unexpected FastCGI "
  2102.                               "request id low byte: %d", ch);
  2103.                 return NGX_ERROR;
  2104.             }
  2105.             state = ngx_http_fastcgi_st_content_length_hi;
  2106.             break;

  2107.         case ngx_http_fastcgi_st_content_length_hi:
  2108.             f->length = ch << 8;
  2109.             state = ngx_http_fastcgi_st_content_length_lo;
  2110.             break;

  2111.         case ngx_http_fastcgi_st_content_length_lo:
  2112.             f->length |= (size_t) ch;
  2113.             state = ngx_http_fastcgi_st_padding_length;
  2114.             break;

  2115.         case ngx_http_fastcgi_st_padding_length:
  2116.             f->padding = (size_t) ch;
  2117.             state = ngx_http_fastcgi_st_reserved;
  2118.             break;

  2119.         case ngx_http_fastcgi_st_reserved:
  2120.             state = ngx_http_fastcgi_st_data;

  2121.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2122.                            "http fastcgi record length: %z", f->length);

  2123.             f->pos = p + 1;
  2124.             f->state = state;

  2125.             return NGX_OK;

  2126.         /* suppress warning */
  2127.         case ngx_http_fastcgi_st_data:
  2128.         case ngx_http_fastcgi_st_padding:
  2129.             break;
  2130.         }
  2131.     }

  2132.     f->pos = p;
  2133.     f->state = state;

  2134.     return NGX_AGAIN;
  2135. }


  2136. static void
  2137. ‌ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
  2138. {
  2139.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2140.                    "abort http fastcgi request");

  2141.     return;
  2142. }


  2143. static void
  2144. ‌ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  2145. {
  2146.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2147.                    "finalize http fastcgi request");

  2148.     return;
  2149. }


  2150. static ngx_int_t
  2151. ‌ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
  2152. {
  2153.     ngx_http_variable_t  *var, *v;

  2154.     for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
  2155.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  2156.         if (var == NULL) {
  2157.             return NGX_ERROR;
  2158.         }

  2159.         var->get_handler = v->get_handler;
  2160.         var->data = v->data;
  2161.     }

  2162.     return NGX_OK;
  2163. }


  2164. static void *
  2165. ‌ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
  2166. {
  2167.     ngx_http_fastcgi_main_conf_t  *conf;

  2168.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
  2169.     if (conf == NULL) {
  2170.         return NULL;
  2171.     }

  2172. #if (NGX_HTTP_CACHE)
  2173.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  2174.                        sizeof(ngx_http_file_cache_t *))
  2175.         != NGX_OK)
  2176.     {
  2177.         return NULL;
  2178.     }
  2179. #endif

  2180.     return conf;
  2181. }


  2182. static void *
  2183. ‌ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
  2184. {
  2185.     ngx_http_fastcgi_loc_conf_t  *conf;

  2186.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
  2187.     if (conf == NULL) {
  2188.         return NULL;
  2189.     }

  2190.     /*
  2191.      * set by ngx_pcalloc():
  2192.      *
  2193.      *     conf->upstream.bufs.num = 0;
  2194.      *     conf->upstream.ignore_headers = 0;
  2195.      *     conf->upstream.next_upstream = 0;
  2196.      *     conf->upstream.cache_zone = NULL;
  2197.      *     conf->upstream.cache_use_stale = 0;
  2198.      *     conf->upstream.cache_methods = 0;
  2199.      *     conf->upstream.temp_path = NULL;
  2200.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  2201.      *     conf->upstream.store_lengths = NULL;
  2202.      *     conf->upstream.store_values = NULL;
  2203.      *
  2204.      *     conf->index = { 0, NULL };
  2205.      */

  2206.     conf->upstream.store = NGX_CONF_UNSET;
  2207.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  2208.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  2209.     conf->upstream.buffering = NGX_CONF_UNSET;
  2210.     conf->upstream.request_buffering = NGX_CONF_UNSET;
  2211.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  2212.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  2213.     conf->upstream.local = NGX_CONF_UNSET_PTR;
  2214.     conf->upstream.socket_keepalive = NGX_CONF_UNSET;
  2215.     conf->upstream.socket_rcvbuf = NGX_CONF_UNSET_SIZE;
  2216.     conf->upstream.socket_sndbuf = NGX_CONF_UNSET_SIZE;

  2217.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  2218.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  2219.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  2220.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  2221.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  2222.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  2223.     conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;

  2224.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  2225.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  2226.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  2227.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  2228.     conf->upstream.pass_request_body = NGX_CONF_UNSET;

  2229. #if (NGX_HTTP_CACHE)
  2230.     conf->upstream.cache = NGX_CONF_UNSET;
  2231.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  2232.     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
  2233.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  2234.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  2235.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  2236.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  2237.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  2238.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  2239.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  2240.     conf->upstream.cache_background_update = NGX_CONF_UNSET;
  2241. #endif

  2242.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  2243.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  2244.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  2245.     /* "fastcgi_cyclic_temp_file" is disabled */
  2246.     conf->upstream.cyclic_temp_file = 0;

  2247.     conf->upstream.change_buffering = 1;

  2248.     conf->catch_stderr = NGX_CONF_UNSET_PTR;

  2249.     conf->keep_conn = NGX_CONF_UNSET;

  2250.     ngx_str_set(&conf->upstream.module, "fastcgi");

  2251.     return conf;
  2252. }


  2253. static char *
  2254. ‌ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  2255. {
  2256.     ngx_http_fastcgi_loc_conf_t *prev = parent;
  2257.     ngx_http_fastcgi_loc_conf_t *conf = child;

  2258.     size_t                        size;
  2259.     ngx_int_t                     rc;
  2260.     ngx_hash_init_t               hash;
  2261.     ngx_http_core_loc_conf_t     *clcf;

  2262. #if (NGX_HTTP_CACHE)

  2263.     if (conf->upstream.store > 0) {
  2264.         conf->upstream.cache = 0;
  2265.     }

  2266.     if (conf->upstream.cache > 0) {
  2267.         conf->upstream.store = 0;
  2268.     }

  2269. #endif

  2270.     if (conf->upstream.store == NGX_CONF_UNSET) {
  2271.         ngx_conf_merge_value(conf->upstream.store,
  2272.                               prev->upstream.store, 0);

  2273.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  2274.         conf->upstream.store_values = prev->upstream.store_values;
  2275.     }

  2276.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  2277.                               prev->upstream.store_access, 0600);

  2278.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  2279.                               prev->upstream.next_upstream_tries, 0);

  2280.     ngx_conf_merge_value(conf->upstream.buffering,
  2281.                               prev->upstream.buffering, 1);

  2282.     ngx_conf_merge_value(conf->upstream.request_buffering,
  2283.                               prev->upstream.request_buffering, 1);

  2284.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  2285.                               prev->upstream.ignore_client_abort, 0);

  2286.     ngx_conf_merge_value(conf->upstream.force_ranges,
  2287.                               prev->upstream.force_ranges, 0);

  2288.     ngx_conf_merge_ptr_value(conf->upstream.local,
  2289.                               prev->upstream.local, NULL);

  2290.     ngx_conf_merge_value(conf->upstream.socket_keepalive,
  2291.                               prev->upstream.socket_keepalive, 0);

  2292.     ngx_conf_merge_size_value(conf->upstream.socket_rcvbuf,
  2293.                               prev->upstream.socket_rcvbuf, 0);

  2294.     ngx_conf_merge_size_value(conf->upstream.socket_sndbuf,
  2295.                               prev->upstream.socket_sndbuf, 0);

  2296.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  2297.                               prev->upstream.connect_timeout, 60000);

  2298.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  2299.                               prev->upstream.send_timeout, 60000);

  2300.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  2301.                               prev->upstream.read_timeout, 60000);

  2302.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  2303.                               prev->upstream.next_upstream_timeout, 0);

  2304.     ngx_conf_merge_size_value(conf->upstream.send_lowat,
  2305.                               prev->upstream.send_lowat, 0);

  2306.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  2307.                               prev->upstream.buffer_size,
  2308.                               (size_t) ngx_pagesize);

  2309.     ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
  2310.                               prev->upstream.limit_rate, NULL);


  2311.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  2312.                               8, ngx_pagesize);

  2313.     if (conf->upstream.bufs.num < 2) {
  2314.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2315.                            "there must be at least 2 \"fastcgi_buffers\"");
  2316.         return NGX_CONF_ERROR;
  2317.     }


  2318.     size = conf->upstream.buffer_size;
  2319.     if (size < conf->upstream.bufs.size) {
  2320.         size = conf->upstream.bufs.size;
  2321.     }


  2322.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  2323.                               prev->upstream.busy_buffers_size_conf,
  2324.                               NGX_CONF_UNSET_SIZE);

  2325.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  2326.         conf->upstream.busy_buffers_size = 2 * size;
  2327.     } else {
  2328.         conf->upstream.busy_buffers_size =
  2329.                                          conf->upstream.busy_buffers_size_conf;
  2330.     }

  2331.     if (conf->upstream.busy_buffers_size < size) {
  2332.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2333.              "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
  2334.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  2335.              "one of the \"fastcgi_buffers\"");

  2336.         return NGX_CONF_ERROR;
  2337.     }

  2338.     if (conf->upstream.busy_buffers_size
  2339.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  2340.     {
  2341.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2342.              "\"fastcgi_busy_buffers_size\" must be less than "
  2343.              "the size of all \"fastcgi_buffers\" minus one buffer");

  2344.         return NGX_CONF_ERROR;
  2345.     }


  2346.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  2347.                               prev->upstream.temp_file_write_size_conf,
  2348.                               NGX_CONF_UNSET_SIZE);

  2349.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  2350.         conf->upstream.temp_file_write_size = 2 * size;
  2351.     } else {
  2352.         conf->upstream.temp_file_write_size =
  2353.                                       conf->upstream.temp_file_write_size_conf;
  2354.     }

  2355.     if (conf->upstream.temp_file_write_size < size) {
  2356.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2357.              "\"fastcgi_temp_file_write_size\" must be equal to or greater "
  2358.              "than the maximum of the value of \"fastcgi_buffer_size\" and "
  2359.              "one of the \"fastcgi_buffers\"");

  2360.         return NGX_CONF_ERROR;
  2361.     }


  2362.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  2363.                               prev->upstream.max_temp_file_size_conf,
  2364.                               NGX_CONF_UNSET_SIZE);

  2365.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  2366.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  2367.     } else {
  2368.         conf->upstream.max_temp_file_size =
  2369.                                         conf->upstream.max_temp_file_size_conf;
  2370.     }

  2371.     if (conf->upstream.max_temp_file_size != 0
  2372.         && conf->upstream.max_temp_file_size < size)
  2373.     {
  2374.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2375.              "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
  2376.              "temporary files usage or must be equal to or greater than "
  2377.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  2378.              "one of the \"fastcgi_buffers\"");

  2379.         return NGX_CONF_ERROR;
  2380.     }


  2381.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  2382.                               prev->upstream.ignore_headers,
  2383.                               NGX_CONF_BITMASK_SET);


  2384.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  2385.                               prev->upstream.next_upstream,
  2386.                               (NGX_CONF_BITMASK_SET
  2387.                                |NGX_HTTP_UPSTREAM_FT_ERROR
  2388.                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  2389.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  2390.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  2391.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  2392.     }

  2393.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  2394.                               prev->upstream.temp_path,
  2395.                               &ngx_http_fastcgi_temp_path)
  2396.         != NGX_CONF_OK)
  2397.     {
  2398.         return NGX_CONF_ERROR;
  2399.     }

  2400. #if (NGX_HTTP_CACHE)

  2401.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  2402.         ngx_conf_merge_value(conf->upstream.cache,
  2403.                               prev->upstream.cache, 0);

  2404.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  2405.         conf->upstream.cache_value = prev->upstream.cache_value;
  2406.     }

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

  2409.         shm_zone = conf->upstream.cache_zone;

  2410.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2411.                            "\"fastcgi_cache\" zone \"%V\" is unknown",
  2412.                            &shm_zone->shm.name);

  2413.         return NGX_CONF_ERROR;
  2414.     }

  2415.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  2416.                               prev->upstream.cache_min_uses, 1);

  2417.     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
  2418.                               prev->upstream.cache_max_range_offset,
  2419.                               NGX_MAX_OFF_T_VALUE);

  2420.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  2421.                               prev->upstream.cache_use_stale,
  2422.                               (NGX_CONF_BITMASK_SET
  2423.                                |NGX_HTTP_UPSTREAM_FT_OFF));

  2424.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
  2425.         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
  2426.                                          |NGX_HTTP_UPSTREAM_FT_OFF;
  2427.     }

  2428.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  2429.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  2430.     }

  2431.     if (conf->upstream.cache_methods == 0) {
  2432.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  2433.     }

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

  2435.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  2436.                              prev->upstream.cache_bypass, NULL);

  2437.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  2438.                              prev->upstream.no_cache, NULL);

  2439.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  2440.                              prev->upstream.cache_valid, NULL);

  2441.     if (conf->cache_key.value.data == NULL) {
  2442.         conf->cache_key = prev->cache_key;
  2443.     }

  2444.     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
  2445.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  2446.                            "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
  2447.     }

  2448.     ngx_conf_merge_value(conf->upstream.cache_lock,
  2449.                               prev->upstream.cache_lock, 0);

  2450.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  2451.                               prev->upstream.cache_lock_timeout, 5000);

  2452.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  2453.                               prev->upstream.cache_lock_age, 5000);

  2454.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  2455.                               prev->upstream.cache_revalidate, 0);

  2456.     ngx_conf_merge_value(conf->upstream.cache_background_update,
  2457.                               prev->upstream.cache_background_update, 0);

  2458. #endif

  2459.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  2460.                               prev->upstream.pass_request_headers, 1);
  2461.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  2462.                               prev->upstream.pass_request_body, 1);

  2463.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  2464.                               prev->upstream.intercept_errors, 0);

  2465.     ngx_conf_merge_ptr_value(conf->catch_stderr, prev->catch_stderr, NULL);

  2466.     ngx_conf_merge_value(conf->keep_conn, prev->keep_conn, 0);


  2467.     ngx_conf_merge_str_value(conf->index, prev->index, "");

  2468.     hash.max_size = 512;
  2469.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  2470.     hash.name = "fastcgi_hide_headers_hash";

  2471.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  2472.              &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
  2473.         != NGX_OK)
  2474.     {
  2475.         return NGX_CONF_ERROR;
  2476.     }

  2477.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2478.     if (clcf->noname
  2479.         && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
  2480.     {
  2481.         conf->upstream.upstream = prev->upstream.upstream;
  2482.         conf->fastcgi_lengths = prev->fastcgi_lengths;
  2483.         conf->fastcgi_values = prev->fastcgi_values;
  2484.     }

  2485.     if (clcf->lmt_excpt && clcf->handler == NULL
  2486.         && (conf->upstream.upstream || conf->fastcgi_lengths))
  2487.     {
  2488.         clcf->handler = ngx_http_fastcgi_handler;
  2489.     }

  2490. #if (NGX_PCRE)
  2491.     if (conf->split_regex == NULL) {
  2492.         conf->split_regex = prev->split_regex;
  2493.         conf->split_name = prev->split_name;
  2494.     }
  2495. #endif

  2496.     if (conf->params_source == NULL) {
  2497.         conf->params = prev->params;
  2498. #if (NGX_HTTP_CACHE)
  2499.         conf->params_cache = prev->params_cache;
  2500. #endif
  2501.         conf->params_source = prev->params_source;
  2502.     }

  2503.     rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params,
  2504.                                       ngx_http_fastcgi_headers);
  2505.     if (rc != NGX_OK) {
  2506.         return NGX_CONF_ERROR;
  2507.     }

  2508. #if (NGX_HTTP_CACHE)

  2509.     if (conf->upstream.cache) {
  2510.         rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
  2511.                                           ngx_http_fastcgi_cache_headers);
  2512.         if (rc != NGX_OK) {
  2513.             return NGX_CONF_ERROR;
  2514.         }
  2515.     }

  2516. #endif

  2517.     /*
  2518.      * special handling to preserve conf->params in the "http" section
  2519.      * to inherit it to all servers
  2520.      */

  2521.     if (prev->params.hash.buckets == NULL
  2522.         && conf->params_source == prev->params_source)
  2523.     {
  2524.         prev->params = conf->params;
  2525. #if (NGX_HTTP_CACHE)
  2526.         prev->params_cache = conf->params_cache;
  2527. #endif
  2528.     }

  2529.     return NGX_CONF_OK;
  2530. }


  2531. static ngx_int_t
  2532. ‌ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
  2533.     ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
  2534. {
  2535.     u_char                       *p;
  2536.     size_t                        size;
  2537.     uintptr_t                    *code;
  2538.     ngx_uint_t                    i, nsrc;
  2539.     ngx_array_t                   headers_names, params_merged;
  2540.     ngx_keyval_t                 *h;
  2541.     ngx_hash_key_t               *hk;
  2542.     ngx_hash_init_t               hash;
  2543.     ngx_http_upstream_param_t    *src, *s;
  2544.     ngx_http_script_compile_t     sc;
  2545.     ngx_http_script_copy_code_t  *copy;

  2546.     if (params->hash.buckets) {
  2547.         return NGX_OK;
  2548.     }

  2549.     if (conf->params_source == NULL && default_params == NULL) {
  2550.         params->hash.buckets = (void *) 1;
  2551.         return NGX_OK;
  2552.     }

  2553.     params->lengths = ngx_array_create(cf->pool, 64, 1);
  2554.     if (params->lengths == NULL) {
  2555.         return NGX_ERROR;
  2556.     }

  2557.     params->values = ngx_array_create(cf->pool, 512, 1);
  2558.     if (params->values == NULL) {
  2559.         return NGX_ERROR;
  2560.     }

  2561.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  2562.         != NGX_OK)
  2563.     {
  2564.         return NGX_ERROR;
  2565.     }

  2566.     if (conf->params_source) {
  2567.         src = conf->params_source->elts;
  2568.         nsrc = conf->params_source->nelts;

  2569.     } else {
  2570.         src = NULL;
  2571.         nsrc = 0;
  2572.     }

  2573.     if (default_params) {
  2574.         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
  2575.                            sizeof(ngx_http_upstream_param_t))
  2576.             != NGX_OK)
  2577.         {
  2578.             return NGX_ERROR;
  2579.         }

  2580.         for (i = 0; i < nsrc; i++) {

  2581.             s = ngx_array_push(&params_merged);
  2582.             if (s == NULL) {
  2583.                 return NGX_ERROR;
  2584.             }

  2585.             *s = src[i];
  2586.         }

  2587.         h = default_params;

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

  2589.             src = params_merged.elts;
  2590.             nsrc = params_merged.nelts;

  2591.             for (i = 0; i < nsrc; i++) {
  2592.                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  2593.                     goto next;
  2594.                 }
  2595.             }

  2596.             s = ngx_array_push(&params_merged);
  2597.             if (s == NULL) {
  2598.                 return NGX_ERROR;
  2599.             }

  2600.             s->key = h->key;
  2601.             s->value = h->value;
  2602.             s->skip_empty = 1;

  2603.         next:

  2604.             h++;
  2605.         }

  2606.         src = params_merged.elts;
  2607.         nsrc = params_merged.nelts;
  2608.     }

  2609.     for (i = 0; i < nsrc; i++) {

  2610.         if (src[i].key.len > sizeof("HTTP_") - 1
  2611.             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
  2612.         {
  2613.             hk = ngx_array_push(&headers_names);
  2614.             if (hk == NULL) {
  2615.                 return NGX_ERROR;
  2616.             }

  2617.             hk->key.len = src[i].key.len - 5;
  2618.             hk->key.data = src[i].key.data + 5;
  2619.             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
  2620.             hk->value = (void *) 1;

  2621.             if (src[i].value.len == 0) {
  2622.                 continue;
  2623.             }
  2624.         }

  2625.         copy = ngx_array_push_n(params->lengths,
  2626.                                 sizeof(ngx_http_script_copy_code_t));
  2627.         if (copy == NULL) {
  2628.             return NGX_ERROR;
  2629.         }

  2630.         copy->code = (ngx_http_script_code_pt) (void *)
  2631.                                                  ngx_http_script_copy_len_code;
  2632.         copy->len = src[i].key.len;

  2633.         copy = ngx_array_push_n(params->lengths,
  2634.                                 sizeof(ngx_http_script_copy_code_t));
  2635.         if (copy == NULL) {
  2636.             return NGX_ERROR;
  2637.         }

  2638.         copy->code = (ngx_http_script_code_pt) (void *)
  2639.                                                  ngx_http_script_copy_len_code;
  2640.         copy->len = src[i].skip_empty;


  2641.         size = (sizeof(ngx_http_script_copy_code_t)
  2642.                 + src[i].key.len + sizeof(uintptr_t) - 1)
  2643.                & ~(sizeof(uintptr_t) - 1);

  2644.         copy = ngx_array_push_n(params->values, size);
  2645.         if (copy == NULL) {
  2646.             return NGX_ERROR;
  2647.         }

  2648.         copy->code = ngx_http_script_copy_code;
  2649.         copy->len = src[i].key.len;

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


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

  2653.         sc.cf = cf;
  2654.         sc.source = &src[i].value;
  2655.         sc.flushes = &params->flushes;
  2656.         sc.lengths = &params->lengths;
  2657.         sc.values = &params->values;

  2658.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2659.             return NGX_ERROR;
  2660.         }

  2661.         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2662.         if (code == NULL) {
  2663.             return NGX_ERROR;
  2664.         }

  2665.         *code = (uintptr_t) NULL;


  2666.         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
  2667.         if (code == NULL) {
  2668.             return NGX_ERROR;
  2669.         }

  2670.         *code = (uintptr_t) NULL;
  2671.     }

  2672.     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2673.     if (code == NULL) {
  2674.         return NGX_ERROR;
  2675.     }

  2676.     *code = (uintptr_t) NULL;

  2677.     params->number = headers_names.nelts;

  2678.     hash.hash = &params->hash;
  2679.     hash.key = ngx_hash_key_lc;
  2680.     hash.max_size = 512;
  2681.     hash.bucket_size = 64;
  2682.     hash.name = "fastcgi_params_hash";
  2683.     hash.pool = cf->pool;
  2684.     hash.temp_pool = NULL;

  2685.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  2686. }


  2687. static ngx_int_t
  2688. ‌ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
  2689.     ngx_http_variable_value_t *v, uintptr_t data)
  2690. {
  2691.     u_char                       *p;
  2692.     ngx_http_fastcgi_ctx_t       *f;
  2693.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2694.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2695.     f = ngx_http_fastcgi_split(r, flcf);

  2696.     if (f == NULL) {
  2697.         return NGX_ERROR;
  2698.     }

  2699.     if (f->script_name.len == 0
  2700.         || f->script_name.data[f->script_name.len - 1] != '/')
  2701.     {
  2702.         v->len = f->script_name.len;
  2703.         v->valid = 1;
  2704.         v->no_cacheable = 0;
  2705.         v->not_found = 0;
  2706.         v->data = f->script_name.data;

  2707.         return NGX_OK;
  2708.     }

  2709.     v->len = f->script_name.len + flcf->index.len;

  2710.     v->data = ngx_pnalloc(r->pool, v->len);
  2711.     if (v->data == NULL) {
  2712.         return NGX_ERROR;
  2713.     }

  2714.     p = ngx_copy(v->data, f->script_name.data, f->script_name.len);
  2715.     ngx_memcpy(p, flcf->index.data, flcf->index.len);

  2716.     return NGX_OK;
  2717. }


  2718. static ngx_int_t
  2719. ‌ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
  2720.     ngx_http_variable_value_t *v, uintptr_t data)
  2721. {
  2722.     ngx_http_fastcgi_ctx_t       *f;
  2723.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2724.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2725.     f = ngx_http_fastcgi_split(r, flcf);

  2726.     if (f == NULL) {
  2727.         return NGX_ERROR;
  2728.     }

  2729.     v->len = f->path_info.len;
  2730.     v->valid = 1;
  2731.     v->no_cacheable = 0;
  2732.     v->not_found = 0;
  2733.     v->data = f->path_info.data;

  2734.     return NGX_OK;
  2735. }


  2736. static ngx_http_fastcgi_ctx_t *
  2737. ‌ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  2738. {
  2739.     ngx_http_fastcgi_ctx_t       *f;
  2740. #if (NGX_PCRE)
  2741.     ngx_int_t                     n;
  2742.     int                           captures[(1 + 2) * 3];

  2743.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2744.     if (f == NULL) {
  2745.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2746.         if (f == NULL) {
  2747.             return NULL;
  2748.         }

  2749.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2750.     }

  2751.     if (f->script_name.len) {
  2752.         return f;
  2753.     }

  2754.     if (flcf->split_regex == NULL) {
  2755.         f->script_name = r->uri;
  2756.         return f;
  2757.     }

  2758.     n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);

  2759.     if (n >= 0) { /* match */
  2760.         f->script_name.len = captures[3] - captures[2];
  2761.         f->script_name.data = r->uri.data + captures[2];

  2762.         f->path_info.len = captures[5] - captures[4];
  2763.         f->path_info.data = r->uri.data + captures[4];

  2764.         return f;
  2765.     }

  2766.     if (n == NGX_REGEX_NO_MATCHED) {
  2767.         f->script_name = r->uri;
  2768.         return f;
  2769.     }

  2770.     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  2771.                   ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
  2772.                   n, &r->uri, &flcf->split_name);
  2773.     return NULL;

  2774. #else

  2775.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2776.     if (f == NULL) {
  2777.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2778.         if (f == NULL) {
  2779.             return NULL;
  2780.         }

  2781.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2782.     }

  2783.     f->script_name = r->uri;

  2784.     return f;

  2785. #endif
  2786. }


  2787. static char *
  2788. ‌ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2789. {
  2790.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2791.     ngx_url_t                   u;
  2792.     ngx_str_t                  *value, *url;
  2793.     ngx_uint_t                  n;
  2794.     ngx_http_core_loc_conf_t   *clcf;
  2795.     ngx_http_script_compile_t   sc;

  2796.     if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
  2797.         return "is duplicate";
  2798.     }

  2799.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2800.     clcf->handler = ngx_http_fastcgi_handler;

  2801.     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
  2802.         clcf->auto_redirect = 1;
  2803.     }

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

  2805.     url = &value[1];

  2806.     n = ngx_http_script_variables_count(url);

  2807.     if (n) {

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

  2809.         sc.cf = cf;
  2810.         sc.source = url;
  2811.         sc.lengths = &flcf->fastcgi_lengths;
  2812.         sc.values = &flcf->fastcgi_values;
  2813.         sc.variables = n;
  2814.         sc.complete_lengths = 1;
  2815.         sc.complete_values = 1;

  2816.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2817.             return NGX_CONF_ERROR;
  2818.         }

  2819.         return NGX_CONF_OK;
  2820.     }

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

  2822.     u.url = value[1];
  2823.     u.no_resolve = 1;

  2824.     flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  2825.     if (flcf->upstream.upstream == NULL) {
  2826.         return NGX_CONF_ERROR;
  2827.     }

  2828.     return NGX_CONF_OK;
  2829. }


  2830. static char *
  2831. ‌ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2832. {
  2833. #if (NGX_PCRE)
  2834.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2835.     ngx_str_t            *value;
  2836.     ngx_regex_compile_t   rc;
  2837.     u_char                errstr[NGX_MAX_CONF_ERRSTR];

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

  2839.     flcf->split_name = value[1];

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

  2841.     rc.pattern = value[1];
  2842.     rc.pool = cf->pool;
  2843.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  2844.     rc.err.data = errstr;

  2845.     if (ngx_regex_compile(&rc) != NGX_OK) {
  2846.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
  2847.         return NGX_CONF_ERROR;
  2848.     }

  2849.     if (rc.captures != 2) {
  2850.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2851.                            "pattern \"%V\" must have 2 captures", &value[1]);
  2852.         return NGX_CONF_ERROR;
  2853.     }

  2854.     flcf->split_regex = rc.regex;

  2855.     return NGX_CONF_OK;

  2856. #else

  2857.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2858.                        "\"%V\" requires PCRE library", &cmd->name);
  2859.     return NGX_CONF_ERROR;

  2860. #endif
  2861. }


  2862. static char *
  2863. ‌ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2864. {
  2865.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2866.     ngx_str_t                  *value;
  2867.     ngx_http_script_compile_t   sc;

  2868.     if (flcf->upstream.store != NGX_CONF_UNSET) {
  2869.         return "is duplicate";
  2870.     }

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

  2872.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2873.         flcf->upstream.store = 0;
  2874.         return NGX_CONF_OK;
  2875.     }

  2876.     if (value[1].len == 0) {
  2877.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
  2878.         return NGX_CONF_ERROR;
  2879.     }

  2880. #if (NGX_HTTP_CACHE)
  2881.     if (flcf->upstream.cache > 0) {
  2882.         return "is incompatible with \"fastcgi_cache\"";
  2883.     }
  2884. #endif

  2885.     flcf->upstream.store = 1;

  2886.     if (ngx_strcmp(value[1].data, "on") == 0) {
  2887.         return NGX_CONF_OK;
  2888.     }

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

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

  2892.     sc.cf = cf;
  2893.     sc.source = &value[1];
  2894.     sc.lengths = &flcf->upstream.store_lengths;
  2895.     sc.values = &flcf->upstream.store_values;
  2896.     sc.variables = ngx_http_script_variables_count(&value[1]);
  2897.     sc.complete_lengths = 1;
  2898.     sc.complete_values = 1;

  2899.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  2900.         return NGX_CONF_ERROR;
  2901.     }

  2902.     return NGX_CONF_OK;
  2903. }


  2904. #if (NGX_HTTP_CACHE)

  2905. static char *
  2906. ‌ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2907. {
  2908.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2909.     ngx_str_t                         *value;
  2910.     ngx_http_complex_value_t           cv;
  2911.     ngx_http_compile_complex_value_t   ccv;

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

  2913.     if (flcf->upstream.cache != NGX_CONF_UNSET) {
  2914.         return "is duplicate";
  2915.     }

  2916.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2917.         flcf->upstream.cache = 0;
  2918.         return NGX_CONF_OK;
  2919.     }

  2920.     if (flcf->upstream.store > 0) {
  2921.         return "is incompatible with \"fastcgi_store\"";
  2922.     }

  2923.     flcf->upstream.cache = 1;

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

  2925.     ccv.cf = cf;
  2926.     ccv.value = &value[1];
  2927.     ccv.complex_value = &cv;

  2928.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2929.         return NGX_CONF_ERROR;
  2930.     }

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

  2932.         flcf->upstream.cache_value = ngx_palloc(cf->pool,
  2933.                                              sizeof(ngx_http_complex_value_t));
  2934.         if (flcf->upstream.cache_value == NULL) {
  2935.             return NGX_CONF_ERROR;
  2936.         }

  2937.         *flcf->upstream.cache_value = cv;

  2938.         return NGX_CONF_OK;
  2939.     }

  2940.     flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  2941.                                                       &ngx_http_fastcgi_module);
  2942.     if (flcf->upstream.cache_zone == NULL) {
  2943.         return NGX_CONF_ERROR;
  2944.     }

  2945.     return NGX_CONF_OK;
  2946. }


  2947. static char *
  2948. ‌ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2949. {
  2950.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2951.     ngx_str_t                         *value;
  2952.     ngx_http_compile_complex_value_t   ccv;

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

  2954.     if (flcf->cache_key.value.data) {
  2955.         return "is duplicate";
  2956.     }

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

  2958.     ccv.cf = cf;
  2959.     ccv.value = &value[1];
  2960.     ccv.complex_value = &flcf->cache_key;

  2961.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2962.         return NGX_CONF_ERROR;
  2963.     }

  2964.     return NGX_CONF_OK;
  2965. }

  2966. #endif


  2967. static char *
  2968. ‌ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
  2969. {
  2970. #if (NGX_FREEBSD)
  2971.     ssize_t *np = data;

  2972.     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
  2973.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2974.                            "\"fastcgi_send_lowat\" must be less than %d "
  2975.                            "(sysctl net.inet.tcp.sendspace)",
  2976.                            ngx_freebsd_net_inet_tcp_sendspace);

  2977.         return NGX_CONF_ERROR;
  2978.     }

  2979. #elif !(NGX_HAVE_SO_SNDLOWAT)
  2980.     ssize_t *np = data;

  2981.     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  2982.                        "\"fastcgi_send_lowat\" is not supported, ignored");

  2983.     *np = 0;

  2984. #endif

  2985.     return NGX_CONF_OK;
  2986. }