src/http/modules/ngx_http_fastcgi_module.c - nginx-1.31.4 nginx/ @ 8d9666701

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.       NULL },

  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 += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
  729.         }

  730.         len += params_len;
  731.     }

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

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

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

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

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

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

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

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

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

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

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

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

  774.                 hash = 0;

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

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

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

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

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

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

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

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

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

  798.         next_length:

  799.             continue;
  800.         }
  801.     }


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


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


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

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

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


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

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

  823.     cl->buf = b;

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

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

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

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

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


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

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

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

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

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

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

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

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

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

  862.                 e.skip = 0;

  863.                 continue;
  864.             }

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

  870.             *e.pos++ = (u_char) key_len;

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

  876.             } else {
  877.                 *e.pos++ = (u_char) val_len;
  878.             }

  879.             while (*(uintptr_t *) e.ip) {
  880.                 code = *(ngx_http_script_code_pt *) e.ip;
  881.                 code((ngx_http_script_engine_t *) &e);
  882.             }
  883.             e.ip += sizeof(uintptr_t);

  884.             if (e.status) {
  885.                 return NGX_ERROR;
  886.             }

  887.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  888.                            "fastcgi param: \"%*s: %*s\"",
  889.                            key_len, e.pos - (key_len + val_len),
  890.                            val_len, e.pos - val_len);
  891.         }

  892.         if (e.pos != e.end) {
  893.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  894.                           "fastcgi request length mismatch");
  895.             return NGX_ERROR;
  896.         }

  897.         b->last = e.pos;
  898.     }


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

  900.         part = &r->headers_in.headers.part;
  901.         header = part->elts;

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

  903.             if (i >= part->nelts) {
  904.                 if (part->next == NULL) {
  905.                     break;
  906.                 }

  907.                 part = part->next;
  908.                 header = part->elts;
  909.                 i = 0;
  910.             }

  911.             for (n = 0; n < header_params; n++) {
  912.                 if (&header[i] == ignored[n]) {
  913.                     goto next_value;
  914.                 }
  915.             }

  916.             key_len = sizeof("HTTP_") - 1 + header[i].key.len;
  917.             if (key_len > 127) {
  918.                 *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
  919.                 *b->last++ = (u_char) ((key_len >> 16) & 0xff);
  920.                 *b->last++ = (u_char) ((key_len >> 8) & 0xff);
  921.                 *b->last++ = (u_char) (key_len & 0xff);

  922.             } else {
  923.                 *b->last++ = (u_char) key_len;
  924.             }

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

  926.             for (hn = header[i].next; hn; hn = hn->next) {
  927.                 val_len += hn->value.len + 2;
  928.             }

  929.             if (val_len > 127) {
  930.                 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  931.                 *b->last++ = (u_char) ((val_len >> 16) & 0xff);
  932.                 *b->last++ = (u_char) ((val_len >> 8) & 0xff);
  933.                 *b->last++ = (u_char) (val_len & 0xff);

  934.             } else {
  935.                 *b->last++ = (u_char) val_len;
  936.             }

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

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

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

  942.                 } else if (ch == '-') {
  943.                     ch = '_';
  944.                 }

  945.                 *b->last++ = ch;
  946.             }

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

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

  950.                 if (header[i].key.len == sizeof("Cookie") - 1
  951.                     && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
  952.                                        sizeof("Cookie") - 1)
  953.                        == 0)
  954.                 {
  955.                     sep = ';';

  956.                 } else {
  957.                     sep = ',';
  958.                 }

  959.                 for (hn = header[i].next; hn; hn = hn->next) {
  960.                     *b->last++ = sep;
  961.                     *b->last++ = ' ';
  962.                     b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
  963.                 }
  964.             }

  965.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  966.                            "fastcgi param: \"%*s: %*s\"",
  967.                            key_len, b->last - (key_len + val_len),
  968.                            val_len, b->last - val_len);
  969.         next_value:

  970.             continue;
  971.         }
  972.     }


  973.     if (padding) {
  974.         ngx_memzero(b->last, padding);
  975.         b->last += padding;
  976.     }


  977.     h = (ngx_http_fastcgi_header_t *) b->last;
  978.     b->last += sizeof(ngx_http_fastcgi_header_t);

  979.     h->version = 1;
  980.     h->type = NGX_HTTP_FASTCGI_PARAMS;
  981.     h->request_id_hi = 0;
  982.     h->request_id_lo = 1;
  983.     h->content_length_hi = 0;
  984.     h->content_length_lo = 0;
  985.     h->padding_length = 0;
  986.     h->reserved = 0;

  987.     if (r->request_body_no_buffering) {

  988.         u->request_bufs = cl;

  989.         u->output.output_filter = ngx_http_fastcgi_body_output_filter;
  990.         u->output.filter_ctx = r;

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

  992.         body = u->request_bufs;
  993.         u->request_bufs = cl;

  994. #if (NGX_SUPPRESS_WARN)
  995.         file_pos = 0;
  996.         pos = NULL;
  997. #endif

  998.         while (body) {

  999.             if (ngx_buf_special(body->buf)) {
  1000.                 body = body->next;
  1001.                 continue;
  1002.             }

  1003.             if (body->buf->in_file) {
  1004.                 file_pos = body->buf->file_pos;

  1005.             } else {
  1006.                 pos = body->buf->pos;
  1007.             }

  1008.             next = 0;

  1009.             do {
  1010.                 b = ngx_alloc_buf(r->pool);
  1011.                 if (b == NULL) {
  1012.                     return NGX_ERROR;
  1013.                 }

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

  1015.                 if (body->buf->in_file) {
  1016.                     b->file_pos = file_pos;
  1017.                     file_pos += 32 * 1024;

  1018.                     if (file_pos >= body->buf->file_last) {
  1019.                         file_pos = body->buf->file_last;
  1020.                         next = 1;
  1021.                     }

  1022.                     b->file_last = file_pos;
  1023.                     len = (ngx_uint_t) (file_pos - b->file_pos);

  1024.                 } else {
  1025.                     b->pos = pos;
  1026.                     b->start = pos;
  1027.                     pos += 32 * 1024;

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

  1032.                     b->last = pos;
  1033.                     len = (ngx_uint_t) (pos - b->pos);
  1034.                 }

  1035.                 padding = 8 - len % 8;
  1036.                 padding = (padding == 8) ? 0 : padding;

  1037.                 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1038.                 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1039.                 h->version = 1;
  1040.                 h->type = NGX_HTTP_FASTCGI_STDIN;
  1041.                 h->request_id_hi = 0;
  1042.                 h->request_id_lo = 1;
  1043.                 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1044.                 h->content_length_lo = (u_char) (len & 0xff);
  1045.                 h->padding_length = (u_char) padding;
  1046.                 h->reserved = 0;

  1047.                 cl->next = ngx_alloc_chain_link(r->pool);
  1048.                 if (cl->next == NULL) {
  1049.                     return NGX_ERROR;
  1050.                 }

  1051.                 cl = cl->next;
  1052.                 cl->buf = b;

  1053.                 b = ngx_create_temp_buf(r->pool,
  1054.                                         sizeof(ngx_http_fastcgi_header_t)
  1055.                                         + padding);
  1056.                 if (b == NULL) {
  1057.                     return NGX_ERROR;
  1058.                 }

  1059.                 if (padding) {
  1060.                     ngx_memzero(b->last, padding);
  1061.                     b->last += padding;
  1062.                 }

  1063.                 cl->next = ngx_alloc_chain_link(r->pool);
  1064.                 if (cl->next == NULL) {
  1065.                     return NGX_ERROR;
  1066.                 }

  1067.                 cl = cl->next;
  1068.                 cl->buf = b;

  1069.             } while (!next);

  1070.             body = body->next;
  1071.         }

  1072.     } else {
  1073.         u->request_bufs = cl;
  1074.     }

  1075.     if (!r->request_body_no_buffering) {
  1076.         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1077.         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1078.         h->version = 1;
  1079.         h->type = NGX_HTTP_FASTCGI_STDIN;
  1080.         h->request_id_hi = 0;
  1081.         h->request_id_lo = 1;
  1082.         h->content_length_hi = 0;
  1083.         h->content_length_lo = 0;
  1084.         h->padding_length = 0;
  1085.         h->reserved = 0;
  1086.     }

  1087.     cl->next = NULL;

  1088.     return NGX_OK;
  1089. }


  1090. static ngx_int_t
  1091. ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
  1092. {
  1093.     ngx_http_fastcgi_ctx_t  *f;

  1094.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1095.     if (f == NULL) {
  1096.         return NGX_OK;
  1097.     }

  1098.     f->state = ngx_http_fastcgi_st_version;
  1099.     f->fastcgi_stdout = 0;
  1100.     f->large_stderr = 0;

  1101.     if (f->split_parts) {
  1102.         f->split_parts->nelts = 0;
  1103.     }

  1104.     r->state = 0;

  1105.     return NGX_OK;
  1106. }


  1107. static ngx_int_t
  1108. ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in)
  1109. {
  1110.     ngx_http_request_t  *r = data;

  1111.     off_t                       file_pos;
  1112.     u_char                     *pos, *start;
  1113.     size_t                      len, padding;
  1114.     ngx_buf_t                  *b;
  1115.     ngx_int_t                   rc;
  1116.     ngx_uint_t                  next, last;
  1117.     ngx_chain_t                *cl, *tl, *out, **ll;
  1118.     ngx_http_fastcgi_ctx_t     *f;
  1119.     ngx_http_fastcgi_header_t  *h;

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

  1122.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1123.     if (in == NULL) {
  1124.         out = in;
  1125.         goto out;
  1126.     }

  1127.     out = NULL;
  1128.     ll = &out;

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

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

  1133.         f->header_sent = 1;

  1134.         tl = ngx_alloc_chain_link(r->pool);
  1135.         if (tl == NULL) {
  1136.             return NGX_ERROR;
  1137.         }

  1138.         tl->buf = in->buf;
  1139.         *ll = tl;
  1140.         ll = &tl->next;

  1141.         in = in->next;

  1142.         if (in == NULL) {
  1143.             tl->next = NULL;
  1144.             goto out;
  1145.         }
  1146.     }

  1147.     cl = ngx_chain_get_free_buf(r->pool, &f->free);
  1148.     if (cl == NULL) {
  1149.         return NGX_ERROR;
  1150.     }

  1151.     b = cl->buf;

  1152.     b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1153.     b->temporary = 1;

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

  1156.         b->start = ngx_palloc(r->pool,
  1157.                               sizeof(ngx_http_fastcgi_header_t) + 7);
  1158.         if (b->start == NULL) {
  1159.             return NGX_ERROR;
  1160.         }

  1161.         b->pos = b->start;
  1162.         b->last = b->start;

  1163.         b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
  1164.     }

  1165.     *ll = cl;

  1166.     last = 0;
  1167.     padding = 0;

  1168. #if (NGX_SUPPRESS_WARN)
  1169.     file_pos = 0;
  1170.     pos = NULL;
  1171. #endif

  1172.     while (in) {

  1173.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1174.                        "fastcgi output in  l:%d f:%d %p, pos %p, size: %z "
  1175.                        "file: %O, size: %O",
  1176.                        in->buf->last_buf,
  1177.                        in->buf->in_file,
  1178.                        in->buf->start, in->buf->pos,
  1179.                        in->buf->last - in->buf->pos,
  1180.                        in->buf->file_pos,
  1181.                        in->buf->file_last - in->buf->file_pos);

  1182.         if (in->buf->last_buf) {
  1183.             last = 1;
  1184.         }

  1185.         if (ngx_buf_special(in->buf)) {
  1186.             in = in->next;
  1187.             continue;
  1188.         }

  1189.         if (in->buf->in_file) {
  1190.             file_pos = in->buf->file_pos;

  1191.         } else {
  1192.             pos = in->buf->pos;
  1193.         }

  1194.         next = 0;

  1195.         do {
  1196.             tl = ngx_chain_get_free_buf(r->pool, &f->free);
  1197.             if (tl == NULL) {
  1198.                 return NGX_ERROR;
  1199.             }

  1200.             b = tl->buf;
  1201.             start = b->start;

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

  1203.             /*
  1204.              * restore b->start to preserve memory allocated in the buffer,
  1205.              * to reuse it later for headers and padding
  1206.              */

  1207.             b->start = start;

  1208.             if (in->buf->in_file) {
  1209.                 b->file_pos = file_pos;
  1210.                 file_pos += 32 * 1024;

  1211.                 if (file_pos >= in->buf->file_last) {
  1212.                     file_pos = in->buf->file_last;
  1213.                     next = 1;
  1214.                 }

  1215.                 b->file_last = file_pos;
  1216.                 len = (ngx_uint_t) (file_pos - b->file_pos);

  1217.             } else {
  1218.                 b->pos = pos;
  1219.                 pos += 32 * 1024;

  1220.                 if (pos >= in->buf->last) {
  1221.                     pos = in->buf->last;
  1222.                     next = 1;
  1223.                 }

  1224.                 b->last = pos;
  1225.                 len = (ngx_uint_t) (pos - b->pos);
  1226.             }

  1227.             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1228.             b->shadow = in->buf;
  1229.             b->last_shadow = next;

  1230.             b->last_buf = 0;
  1231.             b->last_in_chain = 0;

  1232.             padding = 8 - len % 8;
  1233.             padding = (padding == 8) ? 0 : padding;

  1234.             h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1235.             cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1236.             h->version = 1;
  1237.             h->type = NGX_HTTP_FASTCGI_STDIN;
  1238.             h->request_id_hi = 0;
  1239.             h->request_id_lo = 1;
  1240.             h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1241.             h->content_length_lo = (u_char) (len & 0xff);
  1242.             h->padding_length = (u_char) padding;
  1243.             h->reserved = 0;

  1244.             cl->next = tl;
  1245.             cl = tl;

  1246.             tl = ngx_chain_get_free_buf(r->pool, &f->free);
  1247.             if (tl == NULL) {
  1248.                 return NGX_ERROR;
  1249.             }

  1250.             b = tl->buf;

  1251.             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1252.             b->temporary = 1;

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

  1255.                 b->start = ngx_palloc(r->pool,
  1256.                                       sizeof(ngx_http_fastcgi_header_t) + 7);
  1257.                 if (b->start == NULL) {
  1258.                     return NGX_ERROR;
  1259.                 }

  1260.                 b->pos = b->start;
  1261.                 b->last = b->start;

  1262.                 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
  1263.             }

  1264.             if (padding) {
  1265.                 ngx_memzero(b->last, padding);
  1266.                 b->last += padding;
  1267.             }

  1268.             cl->next = tl;
  1269.             cl = tl;

  1270.         } while (!next);

  1271.         in = in->next;
  1272.     }

  1273.     if (last) {
  1274.         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1275.         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1276.         h->version = 1;
  1277.         h->type = NGX_HTTP_FASTCGI_STDIN;
  1278.         h->request_id_hi = 0;
  1279.         h->request_id_lo = 1;
  1280.         h->content_length_hi = 0;
  1281.         h->content_length_lo = 0;
  1282.         h->padding_length = 0;
  1283.         h->reserved = 0;

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

  1285.     } else if (padding == 0) {
  1286.         /* TODO: do not allocate buffers instead */
  1287.         cl->buf->temporary = 0;
  1288.         cl->buf->sync = 1;
  1289.     }

  1290.     cl->next = NULL;

  1291. out:

  1292. #if (NGX_DEBUG)

  1293.     for (cl = out; cl; cl = cl->next) {
  1294.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1295.                        "fastcgi output out l:%d f:%d %p, pos %p, size: %z "
  1296.                        "file: %O, size: %O",
  1297.                        cl->buf->last_buf,
  1298.                        cl->buf->in_file,
  1299.                        cl->buf->start, cl->buf->pos,
  1300.                        cl->buf->last - cl->buf->pos,
  1301.                        cl->buf->file_pos,
  1302.                        cl->buf->file_last - cl->buf->file_pos);
  1303.     }

  1304. #endif

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

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

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

  1309.         /* mark original buffers as sent */

  1310.         if (cl->buf->shadow) {
  1311.             if (cl->buf->last_shadow) {
  1312.                 b = cl->buf->shadow;
  1313.                 b->pos = b->last;
  1314.             }

  1315.             cl->buf->shadow = NULL;
  1316.         }
  1317.     }

  1318.     return rc;
  1319. }


  1320. static ngx_int_t
  1321. ngx_http_fastcgi_process_header(ngx_http_request_t *r)
  1322. {
  1323.     u_char                         *p, *msg, *start, *last,
  1324.                                    *part_start, *part_end;
  1325.     size_t                          size;
  1326.     ngx_str_t                      *status_line, *pattern;
  1327.     ngx_int_t                       rc, status;
  1328.     ngx_buf_t                       buf;
  1329.     ngx_uint_t                      i;
  1330.     ngx_table_elt_t                *h;
  1331.     ngx_http_upstream_t            *u;
  1332.     ngx_http_fastcgi_ctx_t         *f;
  1333.     ngx_http_upstream_header_t     *hh;
  1334.     ngx_http_fastcgi_loc_conf_t    *flcf;
  1335.     ngx_http_fastcgi_split_part_t  *part;
  1336.     ngx_http_upstream_main_conf_t  *umcf;

  1337.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1338.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1339.     u = r->upstream;

  1340.     for ( ;; ) {

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

  1342.             f->pos = u->buffer.pos;
  1343.             f->last = u->buffer.last;

  1344.             rc = ngx_http_fastcgi_process_record(r, f);

  1345.             u->buffer.pos = f->pos;
  1346.             u->buffer.last = f->last;

  1347.             if (rc == NGX_AGAIN) {
  1348.                 return NGX_AGAIN;
  1349.             }

  1350.             if (rc == NGX_ERROR) {
  1351.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1352.             }

  1353.             if (f->type != NGX_HTTP_FASTCGI_STDOUT
  1354.                 && f->type != NGX_HTTP_FASTCGI_STDERR)
  1355.             {
  1356.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1357.                               "upstream sent unexpected FastCGI record: %ui",
  1358.                               f->type);

  1359.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1360.             }

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

  1364.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1365.             }
  1366.         }

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

  1368.             if (u->buffer.pos + f->padding < u->buffer.last) {
  1369.                 f->state = ngx_http_fastcgi_st_version;
  1370.                 u->buffer.pos += f->padding;

  1371.                 continue;
  1372.             }

  1373.             if (u->buffer.pos + f->padding == u->buffer.last) {
  1374.                 f->state = ngx_http_fastcgi_st_version;
  1375.                 u->buffer.pos = u->buffer.last;

  1376.                 return NGX_AGAIN;
  1377.             }

  1378.             f->padding -= u->buffer.last - u->buffer.pos;
  1379.             u->buffer.pos = u->buffer.last;

  1380.             return NGX_AGAIN;
  1381.         }


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

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

  1384.             if (f->length) {
  1385.                 msg = u->buffer.pos;

  1386.                 if (u->buffer.pos + f->length <= u->buffer.last) {
  1387.                     u->buffer.pos += f->length;
  1388.                     f->length = 0;
  1389.                     f->state = ngx_http_fastcgi_st_padding;

  1390.                 } else {
  1391.                     f->length -= u->buffer.last - u->buffer.pos;
  1392.                     u->buffer.pos = u->buffer.last;
  1393.                 }

  1394.                 for (p = u->buffer.pos - 1; msg < p; p--) {
  1395.                     if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
  1396.                         break;
  1397.                     }
  1398.                 }

  1399.                 p++;

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

  1402.                 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1403.                 if (flcf->catch_stderr) {
  1404.                     pattern = flcf->catch_stderr->elts;

  1405.                     for (i = 0; i < flcf->catch_stderr->nelts; i++) {
  1406.                         if (ngx_strnstr(msg, (char *) pattern[i].data,
  1407.                                         p - msg)
  1408.                             != NULL)
  1409.                         {
  1410.                             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1411.                         }
  1412.                     }
  1413.                 }

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

  1415.                     if (!f->fastcgi_stdout) {

  1416.                         /*
  1417.                          * the special handling the large number
  1418.                          * of the PHP warnings to not allocate memory
  1419.                          */

  1420. #if (NGX_HTTP_CACHE)
  1421.                         if (r->cache) {
  1422.                             u->buffer.pos = u->buffer.start
  1423.                                                      + r->cache->header_start;
  1424.                         } else {
  1425.                             u->buffer.pos = u->buffer.start;
  1426.                         }
  1427. #else
  1428.                         u->buffer.pos = u->buffer.start;
  1429. #endif
  1430.                         u->buffer.last = u->buffer.pos;
  1431.                         f->large_stderr = 1;
  1432.                     }

  1433.                     return NGX_AGAIN;
  1434.                 }

  1435.             } else {
  1436.                 f->state = ngx_http_fastcgi_st_padding;
  1437.             }

  1438.             continue;
  1439.         }


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

  1441. #if (NGX_HTTP_CACHE)

  1442.         if (f->large_stderr && r->cache) {
  1443.             ssize_t                     len;
  1444.             ngx_http_fastcgi_header_t  *fh;

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

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

  1447.             /*
  1448.              * A tail of large stderr output before HTTP header is placed
  1449.              * in a cache file without a FastCGI record header.
  1450.              * To workaround it we put a dummy FastCGI record header at the
  1451.              * start of the stderr output or update r->cache_header_start,
  1452.              * if there is no enough place for the record header.
  1453.              */

  1454.             if (len >= 0) {
  1455.                 fh = (ngx_http_fastcgi_header_t *) start;
  1456.                 fh->version = 1;
  1457.                 fh->type = NGX_HTTP_FASTCGI_STDERR;
  1458.                 fh->request_id_hi = 0;
  1459.                 fh->request_id_lo = 1;
  1460.                 fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1461.                 fh->content_length_lo = (u_char) (len & 0xff);
  1462.                 fh->padding_length = 0;
  1463.                 fh->reserved = 0;

  1464.             } else {
  1465.                 r->cache->header_start += u->buffer.pos - start
  1466.                                           - sizeof(ngx_http_fastcgi_header_t);
  1467.             }

  1468.             f->large_stderr = 0;
  1469.         }

  1470. #endif

  1471.         f->fastcgi_stdout = 1;

  1472.         start = u->buffer.pos;

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

  1474.             /*
  1475.              * set u->buffer.last to the end of the FastCGI record data
  1476.              * for ngx_http_parse_header_line()
  1477.              */

  1478.             last = u->buffer.last;
  1479.             u->buffer.last = u->buffer.pos + f->length;

  1480.         } else {
  1481.             last = NULL;
  1482.         }

  1483.         for ( ;; ) {

  1484.             part_start = u->buffer.pos;
  1485.             part_end = u->buffer.last;

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

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

  1489.             if (rc == NGX_AGAIN) {
  1490.                 break;
  1491.             }

  1492.             if (rc == NGX_OK) {

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

  1494.                 h = ngx_list_push(&u->headers_in.headers);
  1495.                 if (h == NULL) {
  1496.                     return NGX_ERROR;
  1497.                 }

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

  1499.                     part = f->split_parts->elts;
  1500.                     size = u->buffer.pos - part_start;

  1501.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1502.                         size += part[i].end - part[i].start;
  1503.                     }

  1504.                     p = ngx_pnalloc(r->pool, size);
  1505.                     if (p == NULL) {
  1506.                         h->hash = 0;
  1507.                         return NGX_ERROR;
  1508.                     }

  1509.                     buf.pos = p;

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

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

  1515.                     buf.last = p;

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

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

  1518.                     if (rc != NGX_OK) {
  1519.                         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  1520.                                       "invalid header after joining "
  1521.                                       "FastCGI records");
  1522.                         h->hash = 0;
  1523.                         return NGX_ERROR;
  1524.                     }

  1525.                     h->key.len = r->header_name_end - r->header_name_start;
  1526.                     h->key.data = r->header_name_start;
  1527.                     h->key.data[h->key.len] = '\0';

  1528.                     h->value.len = r->header_end - r->header_start;
  1529.                     h->value.data = r->header_start;
  1530.                     h->value.data[h->value.len] = '\0';

  1531.                     h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
  1532.                     if (h->lowcase_key == NULL) {
  1533.                         return NGX_ERROR;
  1534.                     }

  1535.                 } else {

  1536.                     h->key.len = r->header_name_end - r->header_name_start;
  1537.                     h->value.len = r->header_end - r->header_start;

  1538.                     h->key.data = ngx_pnalloc(r->pool,
  1539.                                               h->key.len + 1 + h->value.len + 1
  1540.                                               + h->key.len);
  1541.                     if (h->key.data == NULL) {
  1542.                         h->hash = 0;
  1543.                         return NGX_ERROR;
  1544.                     }

  1545.                     h->value.data = h->key.data + h->key.len + 1;
  1546.                     h->lowcase_key = h->key.data + h->key.len + 1
  1547.                                      + h->value.len + 1;

  1548.                     ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  1549.                     h->key.data[h->key.len] = '\0';
  1550.                     ngx_memcpy(h->value.data, r->header_start, h->value.len);
  1551.                     h->value.data[h->value.len] = '\0';
  1552.                 }

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

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

  1556.                 } else {
  1557.                     ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  1558.                 }

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

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

  1563.                     if (rc != NGX_OK) {
  1564.                         return rc;
  1565.                     }
  1566.                 }

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

  1570.                 if (u->buffer.pos < u->buffer.last) {
  1571.                     continue;
  1572.                 }

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

  1574.                 break;
  1575.             }

  1576.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1580.                 if (u->headers_in.status) {
  1581.                     status_line = &u->headers_in.status->value;

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

  1583.                     if (status == NGX_ERROR) {
  1584.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1585.                                       "upstream sent invalid status \"%V\"",
  1586.                                       status_line);
  1587.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1588.                     }

  1589.                     u->headers_in.status_n = status;

  1590.                     if (status_line->len > 3) {
  1591.                         u->headers_in.status_line = *status_line;
  1592.                     }

  1593.                 } else if (u->headers_in.location) {
  1594.                     u->headers_in.status_n = 302;
  1595.                     ngx_str_set(&u->headers_in.status_line,
  1596.                                 "302 Moved Temporarily");

  1597.                 } else {
  1598.                     u->headers_in.status_n = 200;
  1599.                     ngx_str_set(&u->headers_in.status_line, "200 OK");
  1600.                 }

  1601.                 if (u->state && u->state->status == 0) {
  1602.                     u->state->status = u->headers_in.status_n;
  1603.                 }

  1604.                 break;
  1605.             }

  1606.             /* rc == NGX_HTTP_PARSE_INVALID_HEADER */

  1607.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1608.                           "upstream sent invalid header: \"%*s\\x%02xd...\"",
  1609.                           r->header_end - r->header_name_start,
  1610.                           r->header_name_start, *r->header_end);

  1611.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1612.         }

  1613.         if (last) {
  1614.             u->buffer.last = last;
  1615.         }

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

  1617.         if (f->length == 0) {
  1618.             f->state = ngx_http_fastcgi_st_padding;
  1619.         }

  1620.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1621.             return NGX_OK;
  1622.         }

  1623.         if (rc == NGX_OK) {
  1624.             continue;
  1625.         }

  1626.         /* rc == NGX_AGAIN */

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

  1629.         if (f->split_parts == NULL) {
  1630.             f->split_parts = ngx_array_create(r->pool, 1,
  1631.                                         sizeof(ngx_http_fastcgi_split_part_t));
  1632.             if (f->split_parts == NULL) {
  1633.                 return NGX_ERROR;
  1634.             }
  1635.         }

  1636.         part = ngx_array_push(f->split_parts);
  1637.         if (part == NULL) {
  1638.             return NGX_ERROR;
  1639.         }

  1640.         part->start = part_start;
  1641.         part->end = part_end;

  1642.         if (u->buffer.pos < u->buffer.last) {
  1643.             continue;
  1644.         }

  1645.         return NGX_AGAIN;
  1646.     }
  1647. }


  1648. static ngx_int_t
  1649. ngx_http_fastcgi_input_filter_init(void *data)
  1650. {
  1651.     ngx_http_request_t  *r = data;

  1652.     ngx_http_upstream_t          *u;
  1653.     ngx_http_fastcgi_ctx_t       *f;
  1654.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1655.     u = r->upstream;

  1656.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1657.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

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

  1660.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1661.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
  1662.     {
  1663.         f->rest = 0;

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

  1666.     } else {
  1667.         f->rest = u->headers_in.content_length_n;
  1668.     }

  1669.     return NGX_OK;
  1670. }


  1671. static ngx_int_t
  1672. ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1673. {
  1674.     u_char                       *m, *msg;
  1675.     ngx_int_t                     rc;
  1676.     ngx_buf_t                    *b, **prev;
  1677.     ngx_chain_t                  *cl;
  1678.     ngx_http_request_t           *r;
  1679.     ngx_http_fastcgi_ctx_t       *f;
  1680.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1681.     if (buf->pos == buf->last) {
  1682.         return NGX_OK;
  1683.     }

  1684.     r = p->input_ctx;
  1685.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1686.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

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

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

  1691.         return NGX_OK;
  1692.     }

  1693.     b = NULL;
  1694.     prev = &buf->shadow;

  1695.     f->pos = buf->pos;
  1696.     f->last = buf->last;

  1697.     for ( ;; ) {
  1698.         if (f->state < ngx_http_fastcgi_st_data) {

  1699.             rc = ngx_http_fastcgi_process_record(r, f);

  1700.             if (rc == NGX_AGAIN) {
  1701.                 break;
  1702.             }

  1703.             if (rc == NGX_ERROR) {
  1704.                 return NGX_ERROR;
  1705.             }

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

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

  1710.                 if (f->rest > 0) {
  1711.                     ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1712.                                   "upstream prematurely closed "
  1713.                                   "FastCGI stdout");

  1714.                     p->upstream_error = 1;
  1715.                     p->upstream_eof = 0;
  1716.                     f->closed = 1;

  1717.                     break;
  1718.                 }

  1719.                 if (!flcf->keep_conn) {
  1720.                     p->upstream_done = 1;
  1721.                 }

  1722.                 continue;
  1723.             }

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

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

  1727.                 if (f->rest > 0) {
  1728.                     ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1729.                                   "upstream prematurely closed "
  1730.                                   "FastCGI request");

  1731.                     p->upstream_error = 1;
  1732.                     p->upstream_eof = 0;
  1733.                     f->closed = 1;

  1734.                     break;
  1735.                 }

  1736.                 if (!flcf->keep_conn) {
  1737.                     p->upstream_done = 1;
  1738.                     break;
  1739.                 }

  1740.                 continue;
  1741.             }
  1742.         }


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

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

  1745.                 if (f->pos + f->padding < f->last) {
  1746.                     p->upstream_done = 1;
  1747.                     break;
  1748.                 }

  1749.                 if (f->pos + f->padding == f->last) {
  1750.                     p->upstream_done = 1;
  1751.                     r->upstream->keepalive = 1;
  1752.                     break;
  1753.                 }

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

  1755.                 break;
  1756.             }

  1757.             if (f->pos + f->padding < f->last) {
  1758.                 f->state = ngx_http_fastcgi_st_version;
  1759.                 f->pos += f->padding;

  1760.                 continue;
  1761.             }

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

  1764.                 break;
  1765.             }

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

  1767.             break;
  1768.         }


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

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

  1771.             if (f->length) {

  1772.                 if (f->pos == f->last) {
  1773.                     break;
  1774.                 }

  1775.                 msg = f->pos;

  1776.                 if (f->pos + f->length <= f->last) {
  1777.                     f->pos += f->length;
  1778.                     f->length = 0;
  1779.                     f->state = ngx_http_fastcgi_st_padding;

  1780.                 } else {
  1781.                     f->length -= f->last - f->pos;
  1782.                     f->pos = f->last;
  1783.                 }

  1784.                 for (m = f->pos - 1; msg < m; m--) {
  1785.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1786.                         break;
  1787.                     }
  1788.                 }

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

  1792.             } else {
  1793.                 f->state = ngx_http_fastcgi_st_padding;
  1794.             }

  1795.             continue;
  1796.         }

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

  1798.             if (f->pos + f->length <= f->last) {
  1799.                 f->state = ngx_http_fastcgi_st_padding;
  1800.                 f->pos += f->length;

  1801.                 continue;
  1802.             }

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

  1804.             break;
  1805.         }


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

  1807.         if (f->pos == f->last) {
  1808.             break;
  1809.         }

  1810.         if (f->rest == -2) {
  1811.             f->rest = r->upstream->headers_in.content_length_n;
  1812.         }

  1813.         if (f->rest == 0) {
  1814.             ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1815.                           "upstream sent more data than specified in "
  1816.                           "\"Content-Length\" header");
  1817.             p->upstream_done = 1;
  1818.             break;
  1819.         }

  1820.         cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1821.         if (cl == NULL) {
  1822.             return NGX_ERROR;
  1823.         }

  1824.         b = cl->buf;

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

  1826.         b->pos = f->pos;
  1827.         b->start = buf->start;
  1828.         b->end = buf->end;
  1829.         b->tag = p->tag;
  1830.         b->temporary = 1;
  1831.         b->recycled = 1;

  1832.         *prev = b;
  1833.         prev = &b->shadow;

  1834.         if (p->in) {
  1835.             *p->last_in = cl;
  1836.         } else {
  1837.             p->in = cl;
  1838.         }
  1839.         p->last_in = &cl->next;


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

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

  1843.         if (f->pos + f->length <= f->last) {
  1844.             f->state = ngx_http_fastcgi_st_padding;
  1845.             f->pos += f->length;
  1846.             b->last = f->pos;

  1847.         } else {
  1848.             f->length -= f->last - f->pos;
  1849.             f->pos = f->last;
  1850.             b->last = f->last;
  1851.         }

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

  1853.             if (b->last - b->pos > f->rest) {
  1854.                 ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1855.                               "upstream sent more data than specified in "
  1856.                               "\"Content-Length\" header");

  1857.                 b->last = b->pos + f->rest;
  1858.                 p->upstream_done = 1;

  1859.                 break;
  1860.             }

  1861.             f->rest -= b->last - b->pos;
  1862.         }
  1863.     }

  1864.     if (flcf->keep_conn) {

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

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

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

  1870.         } else {
  1871.             /* ngx_http_fastcgi_st_data */

  1872.             p->length = f->length;
  1873.         }
  1874.     }

  1875.     if (b) {
  1876.         b->shadow = buf;
  1877.         b->last_shadow = 1;

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

  1880.         return NGX_OK;
  1881.     }

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

  1883.     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
  1884.         return NGX_ERROR;
  1885.     }

  1886.     return NGX_OK;
  1887. }


  1888. static ngx_int_t
  1889. ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
  1890. {
  1891.     u_char                  *m, *msg;
  1892.     ngx_int_t                rc;
  1893.     ngx_buf_t               *b, *buf;
  1894.     ngx_chain_t             *cl, **ll;
  1895.     ngx_http_request_t      *r;
  1896.     ngx_http_upstream_t     *u;
  1897.     ngx_http_fastcgi_ctx_t  *f;

  1898.     r = data;
  1899.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1900.     u = r->upstream;
  1901.     buf = &u->buffer;

  1902.     buf->pos = buf->last;
  1903.     buf->last += bytes;

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

  1907.     f->pos = buf->pos;
  1908.     f->last = buf->last;

  1909.     for ( ;; ) {
  1910.         if (f->state < ngx_http_fastcgi_st_data) {

  1911.             rc = ngx_http_fastcgi_process_record(r, f);

  1912.             if (rc == NGX_AGAIN) {
  1913.                 break;
  1914.             }

  1915.             if (rc == NGX_ERROR) {
  1916.                 return NGX_ERROR;
  1917.             }

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

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

  1922.                 continue;
  1923.             }
  1924.         }

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

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

  1927.                 if (f->rest > 0) {
  1928.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1929.                                   "upstream prematurely closed "
  1930.                                   "FastCGI request");
  1931.                     u->error = 1;
  1932.                     break;
  1933.                 }

  1934.                 if (f->pos + f->padding < f->last) {
  1935.                     u->length = 0;
  1936.                     break;
  1937.                 }

  1938.                 if (f->pos + f->padding == f->last) {
  1939.                     u->length = 0;
  1940.                     u->keepalive = 1;
  1941.                     break;
  1942.                 }

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

  1944.                 break;
  1945.             }

  1946.             if (f->pos + f->padding < f->last) {
  1947.                 f->state = ngx_http_fastcgi_st_version;
  1948.                 f->pos += f->padding;

  1949.                 continue;
  1950.             }

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

  1953.                 break;
  1954.             }

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

  1956.             break;
  1957.         }


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

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

  1960.             if (f->length) {

  1961.                 if (f->pos == f->last) {
  1962.                     break;
  1963.                 }

  1964.                 msg = f->pos;

  1965.                 if (f->pos + f->length <= f->last) {
  1966.                     f->pos += f->length;
  1967.                     f->length = 0;
  1968.                     f->state = ngx_http_fastcgi_st_padding;

  1969.                 } else {
  1970.                     f->length -= f->last - f->pos;
  1971.                     f->pos = f->last;
  1972.                 }

  1973.                 for (m = f->pos - 1; msg < m; m--) {
  1974.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1975.                         break;
  1976.                     }
  1977.                 }

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

  1981.             } else {
  1982.                 f->state = ngx_http_fastcgi_st_padding;
  1983.             }

  1984.             continue;
  1985.         }

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

  1987.             if (f->pos + f->length <= f->last) {
  1988.                 f->state = ngx_http_fastcgi_st_padding;
  1989.                 f->pos += f->length;

  1990.                 continue;
  1991.             }

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

  1993.             break;
  1994.         }


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

  1996.         if (f->pos == f->last) {
  1997.             break;
  1998.         }

  1999.         if (f->rest == 0) {
  2000.             ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  2001.                           "upstream sent more data than specified in "
  2002.                           "\"Content-Length\" header");
  2003.             u->length = 0;
  2004.             break;
  2005.         }

  2006.         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  2007.         if (cl == NULL) {
  2008.             return NGX_ERROR;
  2009.         }

  2010.         *ll = cl;
  2011.         ll = &cl->next;

  2012.         b = cl->buf;

  2013.         b->flush = 1;
  2014.         b->memory = 1;

  2015.         b->pos = f->pos;
  2016.         b->tag = u->output.tag;

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

  2019.         if (f->pos + f->length <= f->last) {
  2020.             f->state = ngx_http_fastcgi_st_padding;
  2021.             f->pos += f->length;
  2022.             b->last = f->pos;

  2023.         } else {
  2024.             f->length -= f->last - f->pos;
  2025.             f->pos = f->last;
  2026.             b->last = f->last;
  2027.         }

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

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

  2033.                 b->last = b->pos + f->rest;
  2034.                 u->length = 0;

  2035.                 break;
  2036.             }

  2037.             f->rest -= b->last - b->pos;
  2038.         }
  2039.     }

  2040.     return NGX_OK;
  2041. }


  2042. static ngx_int_t
  2043. ngx_http_fastcgi_process_record(ngx_http_request_t *r,
  2044.     ngx_http_fastcgi_ctx_t *f)
  2045. {
  2046.     u_char                     ch, *p;
  2047.     ngx_http_fastcgi_state_e   state;

  2048.     state = f->state;

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

  2050.         ch = *p;

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

  2053.         switch (state) {

  2054.         case ngx_http_fastcgi_st_version:
  2055.             if (ch != 1) {
  2056.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2057.                               "upstream sent unsupported FastCGI "
  2058.                               "protocol version: %d", ch);
  2059.                 return NGX_ERROR;
  2060.             }
  2061.             state = ngx_http_fastcgi_st_type;
  2062.             break;

  2063.         case ngx_http_fastcgi_st_type:
  2064.             switch (ch) {
  2065.             case NGX_HTTP_FASTCGI_STDOUT:
  2066.             case NGX_HTTP_FASTCGI_STDERR:
  2067.             case NGX_HTTP_FASTCGI_END_REQUEST:
  2068.                 f->type = (ngx_uint_t) ch;
  2069.                 break;
  2070.             default:
  2071.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2072.                               "upstream sent invalid FastCGI "
  2073.                               "record type: %d", ch);
  2074.                 return NGX_ERROR;

  2075.             }
  2076.             state = ngx_http_fastcgi_st_request_id_hi;
  2077.             break;

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

  2079.         case ngx_http_fastcgi_st_request_id_hi:
  2080.             if (ch != 0) {
  2081.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2082.                               "upstream sent unexpected FastCGI "
  2083.                               "request id high byte: %d", ch);
  2084.                 return NGX_ERROR;
  2085.             }
  2086.             state = ngx_http_fastcgi_st_request_id_lo;
  2087.             break;

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

  2097.         case ngx_http_fastcgi_st_content_length_hi:
  2098.             f->length = ch << 8;
  2099.             state = ngx_http_fastcgi_st_content_length_lo;
  2100.             break;

  2101.         case ngx_http_fastcgi_st_content_length_lo:
  2102.             f->length |= (size_t) ch;
  2103.             state = ngx_http_fastcgi_st_padding_length;
  2104.             break;

  2105.         case ngx_http_fastcgi_st_padding_length:
  2106.             f->padding = (size_t) ch;
  2107.             state = ngx_http_fastcgi_st_reserved;
  2108.             break;

  2109.         case ngx_http_fastcgi_st_reserved:
  2110.             state = ngx_http_fastcgi_st_data;

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

  2113.             f->pos = p + 1;
  2114.             f->state = state;

  2115.             return NGX_OK;

  2116.         /* suppress warning */
  2117.         case ngx_http_fastcgi_st_data:
  2118.         case ngx_http_fastcgi_st_padding:
  2119.             break;
  2120.         }
  2121.     }

  2122.     f->pos = p;
  2123.     f->state = state;

  2124.     return NGX_AGAIN;
  2125. }


  2126. static void
  2127. ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
  2128. {
  2129.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2130.                    "abort http fastcgi request");

  2131.     return;
  2132. }


  2133. static void
  2134. ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  2135. {
  2136.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2137.                    "finalize http fastcgi request");

  2138.     return;
  2139. }


  2140. static ngx_int_t
  2141. ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
  2142. {
  2143.     ngx_http_variable_t  *var, *v;

  2144.     for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
  2145.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  2146.         if (var == NULL) {
  2147.             return NGX_ERROR;
  2148.         }

  2149.         var->get_handler = v->get_handler;
  2150.         var->data = v->data;
  2151.     }

  2152.     return NGX_OK;
  2153. }


  2154. static void *
  2155. ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
  2156. {
  2157.     ngx_http_fastcgi_main_conf_t  *conf;

  2158.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
  2159.     if (conf == NULL) {
  2160.         return NULL;
  2161.     }

  2162. #if (NGX_HTTP_CACHE)
  2163.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  2164.                        sizeof(ngx_http_file_cache_t *))
  2165.         != NGX_OK)
  2166.     {
  2167.         return NULL;
  2168.     }
  2169. #endif

  2170.     return conf;
  2171. }


  2172. static void *
  2173. ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
  2174. {
  2175.     ngx_http_fastcgi_loc_conf_t  *conf;

  2176.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
  2177.     if (conf == NULL) {
  2178.         return NULL;
  2179.     }

  2180.     /*
  2181.      * set by ngx_pcalloc():
  2182.      *
  2183.      *     conf->upstream.bufs.num = 0;
  2184.      *     conf->upstream.ignore_headers = 0;
  2185.      *     conf->upstream.next_upstream = 0;
  2186.      *     conf->upstream.cache_zone = NULL;
  2187.      *     conf->upstream.cache_use_stale = 0;
  2188.      *     conf->upstream.cache_methods = 0;
  2189.      *     conf->upstream.temp_path = NULL;
  2190.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  2191.      *     conf->upstream.store_lengths = NULL;
  2192.      *     conf->upstream.store_values = NULL;
  2193.      *
  2194.      *     conf->index = { 0, NULL };
  2195.      */

  2196.     conf->upstream.store = NGX_CONF_UNSET;
  2197.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  2198.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  2199.     conf->upstream.buffering = NGX_CONF_UNSET;
  2200.     conf->upstream.request_buffering = NGX_CONF_UNSET;
  2201.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  2202.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  2203.     conf->upstream.local = NGX_CONF_UNSET_PTR;
  2204.     conf->upstream.socket_keepalive = NGX_CONF_UNSET;
  2205.     conf->upstream.socket_rcvbuf = NGX_CONF_UNSET_SIZE;
  2206.     conf->upstream.socket_sndbuf = NGX_CONF_UNSET_SIZE;

  2207.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  2208.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  2209.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  2210.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  2211.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  2212.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  2213.     conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;

  2214.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  2215.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  2216.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  2217.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  2218.     conf->upstream.pass_request_body = NGX_CONF_UNSET;

  2219. #if (NGX_HTTP_CACHE)
  2220.     conf->upstream.cache = NGX_CONF_UNSET;
  2221.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  2222.     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
  2223.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  2224.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  2225.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  2226.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  2227.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  2228.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  2229.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  2230.     conf->upstream.cache_background_update = NGX_CONF_UNSET;
  2231. #endif

  2232.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  2233.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  2234.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  2235.     /* "fastcgi_cyclic_temp_file" is disabled */
  2236.     conf->upstream.cyclic_temp_file = 0;

  2237.     conf->upstream.change_buffering = 1;

  2238.     conf->catch_stderr = NGX_CONF_UNSET_PTR;

  2239.     conf->keep_conn = NGX_CONF_UNSET;

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

  2241.     return conf;
  2242. }


  2243. static char *
  2244. ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  2245. {
  2246.     ngx_http_fastcgi_loc_conf_t *prev = parent;
  2247.     ngx_http_fastcgi_loc_conf_t *conf = child;

  2248.     size_t                        size;
  2249.     ngx_int_t                     rc;
  2250.     ngx_hash_init_t               hash;
  2251.     ngx_http_core_loc_conf_t     *clcf;

  2252. #if (NGX_HTTP_CACHE)

  2253.     if (conf->upstream.store > 0) {
  2254.         conf->upstream.cache = 0;
  2255.     }

  2256.     if (conf->upstream.cache > 0) {
  2257.         conf->upstream.store = 0;
  2258.     }

  2259. #endif

  2260.     if (conf->upstream.store == NGX_CONF_UNSET) {
  2261.         ngx_conf_merge_value(conf->upstream.store,
  2262.                               prev->upstream.store, 0);

  2263.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  2264.         conf->upstream.store_values = prev->upstream.store_values;
  2265.     }

  2266.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  2267.                               prev->upstream.store_access, 0600);

  2268.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  2269.                               prev->upstream.next_upstream_tries, 0);

  2270.     ngx_conf_merge_value(conf->upstream.buffering,
  2271.                               prev->upstream.buffering, 1);

  2272.     ngx_conf_merge_value(conf->upstream.request_buffering,
  2273.                               prev->upstream.request_buffering, 1);

  2274.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  2275.                               prev->upstream.ignore_client_abort, 0);

  2276.     ngx_conf_merge_value(conf->upstream.force_ranges,
  2277.                               prev->upstream.force_ranges, 0);

  2278.     ngx_conf_merge_ptr_value(conf->upstream.local,
  2279.                               prev->upstream.local, NULL);

  2280.     ngx_conf_merge_value(conf->upstream.socket_keepalive,
  2281.                               prev->upstream.socket_keepalive, 0);

  2282.     ngx_conf_merge_size_value(conf->upstream.socket_rcvbuf,
  2283.                               prev->upstream.socket_rcvbuf, 0);

  2284.     ngx_conf_merge_size_value(conf->upstream.socket_sndbuf,
  2285.                               prev->upstream.socket_sndbuf, 0);

  2286.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  2287.                               prev->upstream.connect_timeout, 60000);

  2288.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  2289.                               prev->upstream.send_timeout, 60000);

  2290.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  2291.                               prev->upstream.read_timeout, 60000);

  2292.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  2293.                               prev->upstream.next_upstream_timeout, 0);

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

  2296.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  2297.                               prev->upstream.buffer_size,
  2298.                               (size_t) ngx_pagesize);

  2299.     ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
  2300.                               prev->upstream.limit_rate, NULL);


  2301.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  2302.                               8, ngx_pagesize);

  2303.     if (conf->upstream.bufs.num < 2) {
  2304.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2305.                            "there must be at least 2 \"fastcgi_buffers\"");
  2306.         return NGX_CONF_ERROR;
  2307.     }


  2308.     size = conf->upstream.buffer_size;
  2309.     if (size < conf->upstream.bufs.size) {
  2310.         size = conf->upstream.bufs.size;
  2311.     }


  2312.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  2313.                               prev->upstream.busy_buffers_size_conf,
  2314.                               NGX_CONF_UNSET_SIZE);

  2315.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  2316.         conf->upstream.busy_buffers_size = 2 * size;
  2317.     } else {
  2318.         conf->upstream.busy_buffers_size =
  2319.                                          conf->upstream.busy_buffers_size_conf;
  2320.     }

  2321.     if (conf->upstream.busy_buffers_size < size) {
  2322.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2323.              "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
  2324.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  2325.              "one of the \"fastcgi_buffers\"");

  2326.         return NGX_CONF_ERROR;
  2327.     }

  2328.     if (conf->upstream.busy_buffers_size
  2329.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  2330.     {
  2331.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2332.              "\"fastcgi_busy_buffers_size\" must be less than "
  2333.              "the size of all \"fastcgi_buffers\" minus one buffer");

  2334.         return NGX_CONF_ERROR;
  2335.     }


  2336.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  2337.                               prev->upstream.temp_file_write_size_conf,
  2338.                               NGX_CONF_UNSET_SIZE);

  2339.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  2340.         conf->upstream.temp_file_write_size = 2 * size;
  2341.     } else {
  2342.         conf->upstream.temp_file_write_size =
  2343.                                       conf->upstream.temp_file_write_size_conf;
  2344.     }

  2345.     if (conf->upstream.temp_file_write_size < size) {
  2346.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2347.              "\"fastcgi_temp_file_write_size\" must be equal to or greater "
  2348.              "than the maximum of the value of \"fastcgi_buffer_size\" and "
  2349.              "one of the \"fastcgi_buffers\"");

  2350.         return NGX_CONF_ERROR;
  2351.     }


  2352.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  2353.                               prev->upstream.max_temp_file_size_conf,
  2354.                               NGX_CONF_UNSET_SIZE);

  2355.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  2356.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  2357.     } else {
  2358.         conf->upstream.max_temp_file_size =
  2359.                                         conf->upstream.max_temp_file_size_conf;
  2360.     }

  2361.     if (conf->upstream.max_temp_file_size != 0
  2362.         && conf->upstream.max_temp_file_size < size)
  2363.     {
  2364.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2365.              "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
  2366.              "temporary files usage or must be equal to or greater than "
  2367.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  2368.              "one of the \"fastcgi_buffers\"");

  2369.         return NGX_CONF_ERROR;
  2370.     }


  2371.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  2372.                               prev->upstream.ignore_headers,
  2373.                               NGX_CONF_BITMASK_SET);


  2374.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  2375.                               prev->upstream.next_upstream,
  2376.                               (NGX_CONF_BITMASK_SET
  2377.                                |NGX_HTTP_UPSTREAM_FT_ERROR
  2378.                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  2379.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  2380.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  2381.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  2382.     }

  2383.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  2384.                               prev->upstream.temp_path,
  2385.                               &ngx_http_fastcgi_temp_path)
  2386.         != NGX_CONF_OK)
  2387.     {
  2388.         return NGX_CONF_ERROR;
  2389.     }

  2390. #if (NGX_HTTP_CACHE)

  2391.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  2392.         ngx_conf_merge_value(conf->upstream.cache,
  2393.                               prev->upstream.cache, 0);

  2394.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  2395.         conf->upstream.cache_value = prev->upstream.cache_value;
  2396.     }

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

  2399.         shm_zone = conf->upstream.cache_zone;

  2400.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2401.                            "\"fastcgi_cache\" zone \"%V\" is unknown",
  2402.                            &shm_zone->shm.name);

  2403.         return NGX_CONF_ERROR;
  2404.     }

  2405.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  2406.                               prev->upstream.cache_min_uses, 1);

  2407.     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
  2408.                               prev->upstream.cache_max_range_offset,
  2409.                               NGX_MAX_OFF_T_VALUE);

  2410.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  2411.                               prev->upstream.cache_use_stale,
  2412.                               (NGX_CONF_BITMASK_SET
  2413.                                |NGX_HTTP_UPSTREAM_FT_OFF));

  2414.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
  2415.         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
  2416.                                          |NGX_HTTP_UPSTREAM_FT_OFF;
  2417.     }

  2418.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  2419.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  2420.     }

  2421.     if (conf->upstream.cache_methods == 0) {
  2422.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  2423.     }

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

  2425.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  2426.                              prev->upstream.cache_bypass, NULL);

  2427.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  2428.                              prev->upstream.no_cache, NULL);

  2429.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  2430.                              prev->upstream.cache_valid, NULL);

  2431.     if (conf->cache_key.value.data == NULL) {
  2432.         conf->cache_key = prev->cache_key;
  2433.     }

  2434.     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
  2435.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  2436.                            "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
  2437.     }

  2438.     ngx_conf_merge_value(conf->upstream.cache_lock,
  2439.                               prev->upstream.cache_lock, 0);

  2440.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  2441.                               prev->upstream.cache_lock_timeout, 5000);

  2442.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  2443.                               prev->upstream.cache_lock_age, 5000);

  2444.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  2445.                               prev->upstream.cache_revalidate, 0);

  2446.     ngx_conf_merge_value(conf->upstream.cache_background_update,
  2447.                               prev->upstream.cache_background_update, 0);

  2448. #endif

  2449.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  2450.                               prev->upstream.pass_request_headers, 1);
  2451.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  2452.                               prev->upstream.pass_request_body, 1);

  2453.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  2454.                               prev->upstream.intercept_errors, 0);

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

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


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

  2458.     hash.max_size = 512;
  2459.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  2460.     hash.name = "fastcgi_hide_headers_hash";

  2461.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  2462.              &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
  2463.         != NGX_OK)
  2464.     {
  2465.         return NGX_CONF_ERROR;
  2466.     }

  2467.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2468.     if (clcf->noname
  2469.         && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
  2470.     {
  2471.         conf->upstream.upstream = prev->upstream.upstream;
  2472.         conf->fastcgi_lengths = prev->fastcgi_lengths;
  2473.         conf->fastcgi_values = prev->fastcgi_values;
  2474.     }

  2475.     if (clcf->lmt_excpt && clcf->handler == NULL
  2476.         && (conf->upstream.upstream || conf->fastcgi_lengths))
  2477.     {
  2478.         clcf->handler = ngx_http_fastcgi_handler;
  2479.     }

  2480. #if (NGX_PCRE)
  2481.     if (conf->split_regex == NULL) {
  2482.         conf->split_regex = prev->split_regex;
  2483.         conf->split_name = prev->split_name;
  2484.     }
  2485. #endif

  2486.     if (conf->params_source == NULL) {
  2487.         conf->params = prev->params;
  2488. #if (NGX_HTTP_CACHE)
  2489.         conf->params_cache = prev->params_cache;
  2490. #endif
  2491.         conf->params_source = prev->params_source;
  2492.     }

  2493.     rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params,
  2494.                                       ngx_http_fastcgi_headers);
  2495.     if (rc != NGX_OK) {
  2496.         return NGX_CONF_ERROR;
  2497.     }

  2498. #if (NGX_HTTP_CACHE)

  2499.     if (conf->upstream.cache) {
  2500.         rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
  2501.                                           ngx_http_fastcgi_cache_headers);
  2502.         if (rc != NGX_OK) {
  2503.             return NGX_CONF_ERROR;
  2504.         }
  2505.     }

  2506. #endif

  2507.     /*
  2508.      * special handling to preserve conf->params in the "http" section
  2509.      * to inherit it to all servers
  2510.      */

  2511.     if (prev->params.hash.buckets == NULL
  2512.         && conf->params_source == prev->params_source)
  2513.     {
  2514.         prev->params = conf->params;
  2515. #if (NGX_HTTP_CACHE)
  2516.         prev->params_cache = conf->params_cache;
  2517. #endif
  2518.     }

  2519.     return NGX_CONF_OK;
  2520. }


  2521. static ngx_int_t
  2522. ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
  2523.     ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
  2524. {
  2525.     u_char                       *p;
  2526.     size_t                        size;
  2527.     uintptr_t                    *code;
  2528.     ngx_uint_t                    i, nsrc;
  2529.     ngx_array_t                   headers_names, params_merged;
  2530.     ngx_keyval_t                 *h;
  2531.     ngx_hash_key_t               *hk;
  2532.     ngx_hash_init_t               hash;
  2533.     ngx_http_upstream_param_t    *src, *s;
  2534.     ngx_http_script_compile_t     sc;
  2535.     ngx_http_script_copy_code_t  *copy;

  2536.     if (params->hash.buckets) {
  2537.         return NGX_OK;
  2538.     }

  2539.     if (conf->params_source == NULL && default_params == NULL) {
  2540.         params->hash.buckets = (void *) 1;
  2541.         return NGX_OK;
  2542.     }

  2543.     params->lengths = ngx_array_create(cf->pool, 64, 1);
  2544.     if (params->lengths == NULL) {
  2545.         return NGX_ERROR;
  2546.     }

  2547.     params->values = ngx_array_create(cf->pool, 512, 1);
  2548.     if (params->values == NULL) {
  2549.         return NGX_ERROR;
  2550.     }

  2551.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  2552.         != NGX_OK)
  2553.     {
  2554.         return NGX_ERROR;
  2555.     }

  2556.     if (conf->params_source) {
  2557.         src = conf->params_source->elts;
  2558.         nsrc = conf->params_source->nelts;

  2559.     } else {
  2560.         src = NULL;
  2561.         nsrc = 0;
  2562.     }

  2563.     if (default_params) {
  2564.         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
  2565.                            sizeof(ngx_http_upstream_param_t))
  2566.             != NGX_OK)
  2567.         {
  2568.             return NGX_ERROR;
  2569.         }

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

  2571.             s = ngx_array_push(&params_merged);
  2572.             if (s == NULL) {
  2573.                 return NGX_ERROR;
  2574.             }

  2575.             *s = src[i];
  2576.         }

  2577.         h = default_params;

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

  2579.             src = params_merged.elts;
  2580.             nsrc = params_merged.nelts;

  2581.             for (i = 0; i < nsrc; i++) {
  2582.                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  2583.                     goto next;
  2584.                 }
  2585.             }

  2586.             s = ngx_array_push(&params_merged);
  2587.             if (s == NULL) {
  2588.                 return NGX_ERROR;
  2589.             }

  2590.             s->key = h->key;
  2591.             s->value = h->value;
  2592.             s->skip_empty = 1;

  2593.         next:

  2594.             h++;
  2595.         }

  2596.         src = params_merged.elts;
  2597.         nsrc = params_merged.nelts;
  2598.     }

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

  2600.         if (src[i].key.len > sizeof("HTTP_") - 1
  2601.             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
  2602.         {
  2603.             hk = ngx_array_push(&headers_names);
  2604.             if (hk == NULL) {
  2605.                 return NGX_ERROR;
  2606.             }

  2607.             hk->key.len = src[i].key.len - 5;
  2608.             hk->key.data = src[i].key.data + 5;
  2609.             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
  2610.             hk->value = (void *) 1;

  2611.             if (src[i].value.len == 0) {
  2612.                 continue;
  2613.             }
  2614.         }

  2615.         copy = ngx_array_push_n(params->lengths,
  2616.                                 sizeof(ngx_http_script_copy_code_t));
  2617.         if (copy == NULL) {
  2618.             return NGX_ERROR;
  2619.         }

  2620.         copy->code = (ngx_http_script_code_pt) (void *)
  2621.                                                  ngx_http_script_copy_len_code;
  2622.         copy->len = src[i].key.len;

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

  2628.         copy->code = (ngx_http_script_code_pt) (void *)
  2629.                                                  ngx_http_script_copy_len_code;
  2630.         copy->len = src[i].skip_empty;


  2631.         size = (sizeof(ngx_http_script_copy_code_t)
  2632.                 + src[i].key.len + sizeof(uintptr_t) - 1)
  2633.                & ~(sizeof(uintptr_t) - 1);

  2634.         copy = ngx_array_push_n(params->values, size);
  2635.         if (copy == NULL) {
  2636.             return NGX_ERROR;
  2637.         }

  2638.         copy->code = ngx_http_script_copy_code;
  2639.         copy->len = src[i].key.len;

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


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

  2643.         sc.cf = cf;
  2644.         sc.source = &src[i].value;
  2645.         sc.flushes = &params->flushes;
  2646.         sc.lengths = &params->lengths;
  2647.         sc.values = &params->values;

  2648.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2649.             return NGX_ERROR;
  2650.         }

  2651.         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2652.         if (code == NULL) {
  2653.             return NGX_ERROR;
  2654.         }

  2655.         *code = (uintptr_t) NULL;


  2656.         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
  2657.         if (code == NULL) {
  2658.             return NGX_ERROR;
  2659.         }

  2660.         *code = (uintptr_t) NULL;
  2661.     }

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

  2666.     *code = (uintptr_t) NULL;

  2667.     params->number = headers_names.nelts;

  2668.     hash.hash = &params->hash;
  2669.     hash.key = ngx_hash_key_lc;
  2670.     hash.max_size = 512;
  2671.     hash.bucket_size = 64;
  2672.     hash.name = "fastcgi_params_hash";
  2673.     hash.pool = cf->pool;
  2674.     hash.temp_pool = NULL;

  2675.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  2676. }


  2677. static ngx_int_t
  2678. ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
  2679.     ngx_http_variable_value_t *v, uintptr_t data)
  2680. {
  2681.     u_char                       *p;
  2682.     ngx_http_fastcgi_ctx_t       *f;
  2683.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2684.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2685.     f = ngx_http_fastcgi_split(r, flcf);

  2686.     if (f == NULL) {
  2687.         return NGX_ERROR;
  2688.     }

  2689.     if (f->script_name.len == 0
  2690.         || f->script_name.data[f->script_name.len - 1] != '/')
  2691.     {
  2692.         v->len = f->script_name.len;
  2693.         v->valid = 1;
  2694.         v->no_cacheable = 0;
  2695.         v->not_found = 0;
  2696.         v->data = f->script_name.data;

  2697.         return NGX_OK;
  2698.     }

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

  2700.     v->data = ngx_pnalloc(r->pool, v->len);
  2701.     if (v->data == NULL) {
  2702.         return NGX_ERROR;
  2703.     }

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

  2706.     return NGX_OK;
  2707. }


  2708. static ngx_int_t
  2709. ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
  2710.     ngx_http_variable_value_t *v, uintptr_t data)
  2711. {
  2712.     ngx_http_fastcgi_ctx_t       *f;
  2713.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2714.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2715.     f = ngx_http_fastcgi_split(r, flcf);

  2716.     if (f == NULL) {
  2717.         return NGX_ERROR;
  2718.     }

  2719.     v->len = f->path_info.len;
  2720.     v->valid = 1;
  2721.     v->no_cacheable = 0;
  2722.     v->not_found = 0;
  2723.     v->data = f->path_info.data;

  2724.     return NGX_OK;
  2725. }


  2726. static ngx_http_fastcgi_ctx_t *
  2727. ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  2728. {
  2729.     ngx_http_fastcgi_ctx_t       *f;
  2730. #if (NGX_PCRE)
  2731.     ngx_int_t                     n;
  2732.     int                           captures[(1 + 2) * 3];

  2733.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2734.     if (f == NULL) {
  2735.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2736.         if (f == NULL) {
  2737.             return NULL;
  2738.         }

  2739.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2740.     }

  2741.     if (f->script_name.len) {
  2742.         return f;
  2743.     }

  2744.     if (flcf->split_regex == NULL) {
  2745.         f->script_name = r->uri;
  2746.         return f;
  2747.     }

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

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

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

  2754.         return f;
  2755.     }

  2756.     if (n == NGX_REGEX_NO_MATCHED) {
  2757.         f->script_name = r->uri;
  2758.         return f;
  2759.     }

  2760.     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  2761.                   ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
  2762.                   n, &r->uri, &flcf->split_name);
  2763.     return NULL;

  2764. #else

  2765.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2766.     if (f == NULL) {
  2767.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2768.         if (f == NULL) {
  2769.             return NULL;
  2770.         }

  2771.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2772.     }

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

  2774.     return f;

  2775. #endif
  2776. }


  2777. static char *
  2778. ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2779. {
  2780.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2781.     ngx_url_t                   u;
  2782.     ngx_str_t                  *value, *url;
  2783.     ngx_uint_t                  n;
  2784.     ngx_http_core_loc_conf_t   *clcf;
  2785.     ngx_http_script_compile_t   sc;

  2786.     if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
  2787.         return "is duplicate";
  2788.     }

  2789.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2790.     clcf->handler = ngx_http_fastcgi_handler;

  2791.     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
  2792.         clcf->auto_redirect = 1;
  2793.     }

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

  2795.     url = &value[1];

  2796.     n = ngx_http_script_variables_count(url);

  2797.     if (n) {

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

  2799.         sc.cf = cf;
  2800.         sc.source = url;
  2801.         sc.lengths = &flcf->fastcgi_lengths;
  2802.         sc.values = &flcf->fastcgi_values;
  2803.         sc.variables = n;
  2804.         sc.complete_lengths = 1;
  2805.         sc.complete_values = 1;

  2806.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2807.             return NGX_CONF_ERROR;
  2808.         }

  2809.         return NGX_CONF_OK;
  2810.     }

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

  2812.     u.url = value[1];
  2813.     u.no_resolve = 1;

  2814.     flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  2815.     if (flcf->upstream.upstream == NULL) {
  2816.         return NGX_CONF_ERROR;
  2817.     }

  2818.     return NGX_CONF_OK;
  2819. }


  2820. static char *
  2821. ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2822. {
  2823. #if (NGX_PCRE)
  2824.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2825.     ngx_str_t            *value;
  2826.     ngx_regex_compile_t   rc;
  2827.     u_char                errstr[NGX_MAX_CONF_ERRSTR];

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

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

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

  2831.     rc.pattern = value[1];
  2832.     rc.pool = cf->pool;
  2833.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  2834.     rc.err.data = errstr;

  2835.     if (ngx_regex_compile(&rc) != NGX_OK) {
  2836.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
  2837.         return NGX_CONF_ERROR;
  2838.     }

  2839.     if (rc.captures != 2) {
  2840.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2841.                            "pattern \"%V\" must have 2 captures", &value[1]);
  2842.         return NGX_CONF_ERROR;
  2843.     }

  2844.     flcf->split_regex = rc.regex;

  2845.     return NGX_CONF_OK;

  2846. #else

  2847.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2848.                        "\"%V\" requires PCRE library", &cmd->name);
  2849.     return NGX_CONF_ERROR;

  2850. #endif
  2851. }


  2852. static char *
  2853. ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2854. {
  2855.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2856.     ngx_str_t                  *value;
  2857.     ngx_http_script_compile_t   sc;

  2858.     if (flcf->upstream.store != NGX_CONF_UNSET) {
  2859.         return "is duplicate";
  2860.     }

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

  2862.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2863.         flcf->upstream.store = 0;
  2864.         return NGX_CONF_OK;
  2865.     }

  2866.     if (value[1].len == 0) {
  2867.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
  2868.         return NGX_CONF_ERROR;
  2869.     }

  2870. #if (NGX_HTTP_CACHE)
  2871.     if (flcf->upstream.cache > 0) {
  2872.         return "is incompatible with \"fastcgi_cache\"";
  2873.     }
  2874. #endif

  2875.     flcf->upstream.store = 1;

  2876.     if (ngx_strcmp(value[1].data, "on") == 0) {
  2877.         return NGX_CONF_OK;
  2878.     }

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

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

  2882.     sc.cf = cf;
  2883.     sc.source = &value[1];
  2884.     sc.lengths = &flcf->upstream.store_lengths;
  2885.     sc.values = &flcf->upstream.store_values;
  2886.     sc.variables = ngx_http_script_variables_count(&value[1]);
  2887.     sc.complete_lengths = 1;
  2888.     sc.complete_values = 1;

  2889.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  2890.         return NGX_CONF_ERROR;
  2891.     }

  2892.     return NGX_CONF_OK;
  2893. }


  2894. #if (NGX_HTTP_CACHE)

  2895. static char *
  2896. ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2897. {
  2898.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2899.     ngx_str_t                         *value;
  2900.     ngx_http_complex_value_t           cv;
  2901.     ngx_http_compile_complex_value_t   ccv;

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

  2903.     if (flcf->upstream.cache != NGX_CONF_UNSET) {
  2904.         return "is duplicate";
  2905.     }

  2906.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2907.         flcf->upstream.cache = 0;
  2908.         return NGX_CONF_OK;
  2909.     }

  2910.     if (flcf->upstream.store > 0) {
  2911.         return "is incompatible with \"fastcgi_store\"";
  2912.     }

  2913.     flcf->upstream.cache = 1;

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

  2915.     ccv.cf = cf;
  2916.     ccv.value = &value[1];
  2917.     ccv.complex_value = &cv;

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

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

  2922.         flcf->upstream.cache_value = ngx_palloc(cf->pool,
  2923.                                              sizeof(ngx_http_complex_value_t));
  2924.         if (flcf->upstream.cache_value == NULL) {
  2925.             return NGX_CONF_ERROR;
  2926.         }

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

  2928.         return NGX_CONF_OK;
  2929.     }

  2930.     flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  2931.                                                       &ngx_http_fastcgi_module);
  2932.     if (flcf->upstream.cache_zone == NULL) {
  2933.         return NGX_CONF_ERROR;
  2934.     }

  2935.     return NGX_CONF_OK;
  2936. }


  2937. static char *
  2938. ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2939. {
  2940.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2941.     ngx_str_t                         *value;
  2942.     ngx_http_compile_complex_value_t   ccv;

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

  2944.     if (flcf->cache_key.value.data) {
  2945.         return "is duplicate";
  2946.     }

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

  2948.     ccv.cf = cf;
  2949.     ccv.value = &value[1];
  2950.     ccv.complex_value = &flcf->cache_key;

  2951.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2952.         return NGX_CONF_ERROR;
  2953.     }

  2954.     return NGX_CONF_OK;
  2955. }

  2956. #endif


  2957. static char *
  2958. ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
  2959. {
  2960. #if (NGX_FREEBSD)
  2961.     ssize_t *np = data;

  2962.     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
  2963.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2964.                            "\"fastcgi_send_lowat\" must be less than %d "
  2965.                            "(sysctl net.inet.tcp.sendspace)",
  2966.                            ngx_freebsd_net_inet_tcp_sendspace);

  2967.         return NGX_CONF_ERROR;
  2968.     }

  2969. #elif !(NGX_HAVE_SO_SNDLOWAT)
  2970.     ssize_t *np = data;

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

  2973.     *np = 0;

  2974. #endif

  2975.     return NGX_CONF_OK;
  2976. }