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

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


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


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


  8. 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_connect_timeout"),
  236.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  237.       ngx_conf_set_msec_slot,
  238.       NGX_HTTP_LOC_CONF_OFFSET,
  239.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.connect_timeout),
  240.       NULL },

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

  247.     { ngx_string("fastcgi_send_lowat"),
  248.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  249.       ngx_conf_set_size_slot,
  250.       NGX_HTTP_LOC_CONF_OFFSET,
  251.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat),
  252.       &ngx_http_fastcgi_lowat_post },

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

  259.     { ngx_string("fastcgi_pass_request_headers"),
  260.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  261.       ngx_conf_set_flag_slot,
  262.       NGX_HTTP_LOC_CONF_OFFSET,
  263.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_headers),
  264.       NULL },

  265.     { ngx_string("fastcgi_pass_request_body"),
  266.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  267.       ngx_conf_set_flag_slot,
  268.       NGX_HTTP_LOC_CONF_OFFSET,
  269.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body),
  270.       NULL },

  271.     { ngx_string("fastcgi_intercept_errors"),
  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.intercept_errors),
  276.       NULL },

  277.     { ngx_string("fastcgi_read_timeout"),
  278.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  279.       ngx_conf_set_msec_slot,
  280.       NGX_HTTP_LOC_CONF_OFFSET,
  281.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout),
  282.       NULL },

  283.     { ngx_string("fastcgi_buffers"),
  284.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  285.       ngx_conf_set_bufs_slot,
  286.       NGX_HTTP_LOC_CONF_OFFSET,
  287.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs),
  288.       NULL },

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

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

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

  307. #if (NGX_HTTP_CACHE)

  308.     { ngx_string("fastcgi_cache"),
  309.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  310.       ngx_http_fastcgi_cache,
  311.       NGX_HTTP_LOC_CONF_OFFSET,
  312.       0,
  313.       NULL },

  314.     { ngx_string("fastcgi_cache_key"),
  315.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  316.       ngx_http_fastcgi_cache_key,
  317.       NGX_HTTP_LOC_CONF_OFFSET,
  318.       0,
  319.       NULL },

  320.     { ngx_string("fastcgi_cache_path"),
  321.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  322.       ngx_http_file_cache_set_slot,
  323.       NGX_HTTP_MAIN_CONF_OFFSET,
  324.       offsetof(ngx_http_fastcgi_main_conf_t, caches),
  325.       &ngx_http_fastcgi_module },

  326.     { ngx_string("fastcgi_cache_bypass"),
  327.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  328.       ngx_http_set_predicate_slot,
  329.       NGX_HTTP_LOC_CONF_OFFSET,
  330.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_bypass),
  331.       NULL },

  332.     { ngx_string("fastcgi_no_cache"),
  333.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  334.       ngx_http_set_predicate_slot,
  335.       NGX_HTTP_LOC_CONF_OFFSET,
  336.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.no_cache),
  337.       NULL },

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

  344.     { ngx_string("fastcgi_cache_min_uses"),
  345.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  346.       ngx_conf_set_num_slot,
  347.       NGX_HTTP_LOC_CONF_OFFSET,
  348.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_min_uses),
  349.       NULL },

  350.     { ngx_string("fastcgi_cache_max_range_offset"),
  351.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  352.       ngx_conf_set_off_slot,
  353.       NGX_HTTP_LOC_CONF_OFFSET,
  354.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_max_range_offset),
  355.       NULL },

  356.     { ngx_string("fastcgi_cache_use_stale"),
  357.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  358.       ngx_conf_set_bitmask_slot,
  359.       NGX_HTTP_LOC_CONF_OFFSET,
  360.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_use_stale),
  361.       &ngx_http_fastcgi_next_upstream_masks },

  362.     { ngx_string("fastcgi_cache_methods"),
  363.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  364.       ngx_conf_set_bitmask_slot,
  365.       NGX_HTTP_LOC_CONF_OFFSET,
  366.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods),
  367.       &ngx_http_upstream_cache_method_mask },

  368.     { ngx_string("fastcgi_cache_lock"),
  369.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  370.       ngx_conf_set_flag_slot,
  371.       NGX_HTTP_LOC_CONF_OFFSET,
  372.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock),
  373.       NULL },

  374.     { ngx_string("fastcgi_cache_lock_timeout"),
  375.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  376.       ngx_conf_set_msec_slot,
  377.       NGX_HTTP_LOC_CONF_OFFSET,
  378.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
  379.       NULL },

  380.     { ngx_string("fastcgi_cache_lock_age"),
  381.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  382.       ngx_conf_set_msec_slot,
  383.       NGX_HTTP_LOC_CONF_OFFSET,
  384.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_age),
  385.       NULL },

  386.     { ngx_string("fastcgi_cache_revalidate"),
  387.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  388.       ngx_conf_set_flag_slot,
  389.       NGX_HTTP_LOC_CONF_OFFSET,
  390.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_revalidate),
  391.       NULL },

  392.     { ngx_string("fastcgi_cache_background_update"),
  393.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  394.       ngx_conf_set_flag_slot,
  395.       NGX_HTTP_LOC_CONF_OFFSET,
  396.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_background_update),
  397.       NULL },

  398. #endif

  399.     { ngx_string("fastcgi_temp_path"),
  400.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  401.       ngx_conf_set_path_slot,
  402.       NGX_HTTP_LOC_CONF_OFFSET,
  403.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path),
  404.       NULL },

  405.     { ngx_string("fastcgi_max_temp_file_size"),
  406.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  407.       ngx_conf_set_size_slot,
  408.       NGX_HTTP_LOC_CONF_OFFSET,
  409.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size_conf),
  410.       NULL },

  411.     { ngx_string("fastcgi_temp_file_write_size"),
  412.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  413.       ngx_conf_set_size_slot,
  414.       NGX_HTTP_LOC_CONF_OFFSET,
  415.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size_conf),
  416.       NULL },

  417.     { ngx_string("fastcgi_next_upstream"),
  418.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  419.       ngx_conf_set_bitmask_slot,
  420.       NGX_HTTP_LOC_CONF_OFFSET,
  421.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
  422.       &ngx_http_fastcgi_next_upstream_masks },

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

  429.     { ngx_string("fastcgi_next_upstream_timeout"),
  430.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  431.       ngx_conf_set_msec_slot,
  432.       NGX_HTTP_LOC_CONF_OFFSET,
  433.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_timeout),
  434.       NULL },

  435.     { ngx_string("fastcgi_param"),
  436.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
  437.       ngx_http_upstream_param_set_slot,
  438.       NGX_HTTP_LOC_CONF_OFFSET,
  439.       offsetof(ngx_http_fastcgi_loc_conf_t, params_source),
  440.       NULL },

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

  447.     { ngx_string("fastcgi_hide_header"),
  448.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  449.       ngx_conf_set_str_array_slot,
  450.       NGX_HTTP_LOC_CONF_OFFSET,
  451.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers),
  452.       NULL },

  453.     { ngx_string("fastcgi_ignore_headers"),
  454.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  455.       ngx_conf_set_bitmask_slot,
  456.       NGX_HTTP_LOC_CONF_OFFSET,
  457.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_headers),
  458.       &ngx_http_upstream_ignore_headers_masks },

  459.     { ngx_string("fastcgi_catch_stderr"),
  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, catch_stderr),
  464.       NULL },

  465.     { ngx_string("fastcgi_keep_conn"),
  466.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  467.       ngx_conf_set_flag_slot,
  468.       NGX_HTTP_LOC_CONF_OFFSET,
  469.       offsetof(ngx_http_fastcgi_loc_conf_t, keep_conn),
  470.       NULL },

  471.       ngx_null_command
  472. };


  473. static ngx_http_module_t  ngx_http_fastcgi_module_ctx = {
  474.     ngx_http_fastcgi_add_variables,        /* preconfiguration */
  475.     NULL,                                  /* postconfiguration */

  476.     ngx_http_fastcgi_create_main_conf,     /* create main configuration */
  477.     NULL,                                  /* init main configuration */

  478.     NULL,                                  /* create server configuration */
  479.     NULL,                                  /* merge server configuration */

  480.     ngx_http_fastcgi_create_loc_conf,      /* create location configuration */
  481.     ngx_http_fastcgi_merge_loc_conf        /* merge location configuration */
  482. };


  483. ngx_module_t  ngx_http_fastcgi_module = {
  484.     NGX_MODULE_V1,
  485.     &ngx_http_fastcgi_module_ctx,          /* module context */
  486.     ngx_http_fastcgi_commands,             /* module directives */
  487.     NGX_HTTP_MODULE,                       /* module type */
  488.     NULL,                                  /* init master */
  489.     NULL,                                  /* init module */
  490.     NULL,                                  /* init process */
  491.     NULL,                                  /* init thread */
  492.     NULL,                                  /* exit thread */
  493.     NULL,                                  /* exit process */
  494.     NULL,                                  /* exit master */
  495.     NGX_MODULE_V1_PADDING
  496. };


  497. static ngx_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
  498.     { 1,                                               /* version */
  499.       NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
  500.       0,                                               /* request_id_hi */
  501.       1,                                               /* request_id_lo */
  502.       0,                                               /* content_length_hi */
  503.       sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
  504.       0,                                               /* padding_length */
  505.       0 },                                             /* reserved */

  506.     { 0,                                               /* role_hi */
  507.       NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
  508.       0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
  509.       { 0, 0, 0, 0, 0 } },                             /* reserved[5] */

  510.     { 1,                                               /* version */
  511.       NGX_HTTP_FASTCGI_PARAMS,                         /* type */
  512.       0,                                               /* request_id_hi */
  513.       1 },                                             /* request_id_lo */

  514. };


  515. static ngx_http_variable_t  ngx_http_fastcgi_vars[] = {

  516.     { ngx_string("fastcgi_script_name"), NULL,
  517.       ngx_http_fastcgi_script_name_variable, 0,
  518.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  519.     { ngx_string("fastcgi_path_info"), NULL,
  520.       ngx_http_fastcgi_path_info_variable, 0,
  521.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  522.       ngx_http_null_variable
  523. };


  524. static ngx_str_t  ngx_http_fastcgi_hide_headers[] = {
  525.     ngx_string("Status"),
  526.     ngx_string("X-Accel-Expires"),
  527.     ngx_string("X-Accel-Redirect"),
  528.     ngx_string("X-Accel-Limit-Rate"),
  529.     ngx_string("X-Accel-Buffering"),
  530.     ngx_string("X-Accel-Charset"),
  531.     ngx_null_string
  532. };


  533. #if (NGX_HTTP_CACHE)

  534. static ngx_keyval_t  ngx_http_fastcgi_cache_headers[] = {
  535.     { ngx_string("HTTP_IF_MODIFIED_SINCE"),
  536.       ngx_string("$upstream_cache_last_modified") },
  537.     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
  538.     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
  539.     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
  540.     { ngx_string("HTTP_RANGE"), ngx_string("") },
  541.     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
  542.     { ngx_null_string, ngx_null_string }
  543. };

  544. #endif


  545. static ngx_path_init_t  ngx_http_fastcgi_temp_path = {
  546.     ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
  547. };


  548. static ngx_int_t
  549. ngx_http_fastcgi_handler(ngx_http_request_t *r)
  550. {
  551.     ngx_int_t                      rc;
  552.     ngx_http_upstream_t           *u;
  553.     ngx_http_fastcgi_ctx_t        *f;
  554.     ngx_http_fastcgi_loc_conf_t   *flcf;
  555. #if (NGX_HTTP_CACHE)
  556.     ngx_http_fastcgi_main_conf_t  *fmcf;
  557. #endif

  558.     if (ngx_http_upstream_create(r) != NGX_OK) {
  559.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  560.     }

  561.     f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  562.     if (f == NULL) {
  563.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  564.     }

  565.     ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);

  566.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  567.     if (flcf->fastcgi_lengths) {
  568.         if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {
  569.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  570.         }
  571.     }

  572.     u = r->upstream;

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

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

  576. #if (NGX_HTTP_CACHE)
  577.     fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module);

  578.     u->caches = &fmcf->caches;
  579.     u->create_key = ngx_http_fastcgi_create_key;
  580. #endif

  581.     u->create_request = ngx_http_fastcgi_create_request;
  582.     u->reinit_request = ngx_http_fastcgi_reinit_request;
  583.     u->process_header = ngx_http_fastcgi_process_header;
  584.     u->abort_request = ngx_http_fastcgi_abort_request;
  585.     u->finalize_request = ngx_http_fastcgi_finalize_request;
  586.     r->state = 0;

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

  588.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  589.     if (u->pipe == NULL) {
  590.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  591.     }

  592.     u->pipe->input_filter = ngx_http_fastcgi_input_filter;
  593.     u->pipe->input_ctx = r;

  594.     u->input_filter_init = ngx_http_fastcgi_input_filter_init;
  595.     u->input_filter = ngx_http_fastcgi_non_buffered_filter;
  596.     u->input_filter_ctx = r;

  597.     if (!flcf->upstream.request_buffering
  598.         && flcf->upstream.pass_request_body)
  599.     {
  600.         r->request_body_no_buffering = 1;
  601.     }

  602.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  603.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  604.         return rc;
  605.     }

  606.     return NGX_DONE;
  607. }


  608. static ngx_int_t
  609. ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  610. {
  611.     ngx_url_t             url;
  612.     ngx_http_upstream_t  *u;

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

  614.     if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
  615.                             flcf->fastcgi_values->elts)
  616.         == NULL)
  617.     {
  618.         return NGX_ERROR;
  619.     }

  620.     url.no_resolve = 1;

  621.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  622.         if (url.err) {
  623.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  624.                           "%s in upstream \"%V\"", url.err, &url.url);
  625.         }

  626.         return NGX_ERROR;
  627.     }

  628.     u = r->upstream;

  629.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  630.     if (u->resolved == NULL) {
  631.         return NGX_ERROR;
  632.     }

  633.     if (url.addrs) {
  634.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  635.         u->resolved->socklen = url.addrs[0].socklen;
  636.         u->resolved->name = url.addrs[0].name;
  637.         u->resolved->naddrs = 1;
  638.     }

  639.     u->resolved->host = url.host;
  640.     u->resolved->port = url.port;
  641.     u->resolved->no_port = url.no_port;

  642.     return NGX_OK;
  643. }


  644. #if (NGX_HTTP_CACHE)

  645. static ngx_int_t
  646. ngx_http_fastcgi_create_key(ngx_http_request_t *r)
  647. {
  648.     ngx_str_t                    *key;
  649.     ngx_http_fastcgi_loc_conf_t  *flcf;

  650.     key = ngx_array_push(&r->cache->keys);
  651.     if (key == NULL) {
  652.         return NGX_ERROR;
  653.     }

  654.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  655.     if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) {
  656.         return NGX_ERROR;
  657.     }

  658.     return NGX_OK;
  659. }

  660. #endif


  661. static ngx_int_t
  662. ngx_http_fastcgi_create_request(ngx_http_request_t *r)
  663. {
  664.     off_t                         file_pos;
  665.     u_char                        ch, sep, *pos, *lowcase_key;
  666.     size_t                        size, len, key_len, val_len, padding,
  667.                                   allocated;
  668.     ngx_uint_t                    i, n, next, hash, skip_empty, header_params;
  669.     ngx_buf_t                    *b;
  670.     ngx_chain_t                  *cl, *body;
  671.     ngx_list_part_t              *part;
  672.     ngx_table_elt_t              *header, *hn, **ignored;
  673.     ngx_http_upstream_t          *u;
  674.     ngx_http_script_code_pt       code;
  675.     ngx_http_script_engine_t      e, le;
  676.     ngx_http_fastcgi_header_t    *h;
  677.     ngx_http_fastcgi_params_t    *params;
  678.     ngx_http_fastcgi_loc_conf_t  *flcf;
  679.     ngx_http_script_len_code_pt   lcode;

  680.     len = 0;
  681.     header_params = 0;
  682.     ignored = NULL;

  683.     u = r->upstream;

  684.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  685. #if (NGX_HTTP_CACHE)
  686.     params = u->cacheable ? &flcf->params_cache : &flcf->params;
  687. #else
  688.     params = &flcf->params;
  689. #endif

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

  692.         ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
  693.         le.flushed = 1;

  694.         le.ip = params->lengths->elts;
  695.         le.request = r;

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

  697.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  698.             key_len = lcode(&le);

  699.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  700.             skip_empty = lcode(&le);

  701.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  702.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  703.             }
  704.             le.ip += sizeof(uintptr_t);

  705.             if (skip_empty && val_len == 0) {
  706.                 continue;
  707.             }

  708.             len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
  709.         }
  710.     }

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

  712.         allocated = 0;
  713.         lowcase_key = NULL;

  714.         if (ngx_http_link_multi_headers(r) != NGX_OK) {
  715.             return NGX_ERROR;
  716.         }

  717.         if (params->number || r->headers_in.multi) {
  718.             n = 0;
  719.             part = &r->headers_in.headers.part;

  720.             while (part) {
  721.                 n += part->nelts;
  722.                 part = part->next;
  723.             }

  724.             ignored = ngx_palloc(r->pool, n * sizeof(void *));
  725.             if (ignored == NULL) {
  726.                 return NGX_ERROR;
  727.             }
  728.         }

  729.         part = &r->headers_in.headers.part;
  730.         header = part->elts;

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

  732.             if (i >= part->nelts) {
  733.                 if (part->next == NULL) {
  734.                     break;
  735.                 }

  736.                 part = part->next;
  737.                 header = part->elts;
  738.                 i = 0;
  739.             }

  740.             for (n = 0; n < header_params; n++) {
  741.                 if (&header[i] == ignored[n]) {
  742.                     goto next_length;
  743.                 }
  744.             }

  745.             if (params->number) {
  746.                 if (allocated < header[i].key.len) {
  747.                     allocated = header[i].key.len + 16;
  748.                     lowcase_key = ngx_pnalloc(r->pool, allocated);
  749.                     if (lowcase_key == NULL) {
  750.                         return NGX_ERROR;
  751.                     }
  752.                 }

  753.                 hash = 0;

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

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

  758.                     } else if (ch == '-') {
  759.                         ch = '_';
  760.                     }

  761.                     hash = ngx_hash(hash, ch);
  762.                     lowcase_key[n] = ch;
  763.                 }

  764.                 if (ngx_hash_find(&params->hash, hash, lowcase_key, n)) {
  765.                     ignored[header_params++] = &header[i];
  766.                     continue;
  767.                 }
  768.             }

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

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

  771.             for (hn = header[i].next; hn; hn = hn->next) {
  772.                 val_len += hn->value.len + 2;
  773.                 ignored[header_params++] = hn;
  774.             }

  775.             len += ((key_len > 127) ? 4 : 1) + key_len
  776.                    + ((val_len > 127) ? 4 : 1) + val_len;

  777.         next_length:

  778.             continue;
  779.         }
  780.     }


  781.     if (len > 65535) {
  782.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  783.                       "fastcgi request record is too big: %uz", len);
  784.         return NGX_ERROR;
  785.     }


  786.     padding = 8 - len % 8;
  787.     padding = (padding == 8) ? 0 : padding;


  788.     size = sizeof(ngx_http_fastcgi_header_t)
  789.            + sizeof(ngx_http_fastcgi_begin_request_t)

  790.            + sizeof(ngx_http_fastcgi_header_t/* NGX_HTTP_FASTCGI_PARAMS */
  791.            + len + padding
  792.            + sizeof(ngx_http_fastcgi_header_t/* NGX_HTTP_FASTCGI_PARAMS */

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


  794.     b = ngx_create_temp_buf(r->pool, size);
  795.     if (b == NULL) {
  796.         return NGX_ERROR;
  797.     }

  798.     cl = ngx_alloc_chain_link(r->pool);
  799.     if (cl == NULL) {
  800.         return NGX_ERROR;
  801.     }

  802.     cl->buf = b;

  803.     ngx_http_fastcgi_request_start.br.flags =
  804.         flcf->keep_conn ? NGX_HTTP_FASTCGI_KEEP_CONN : 0;

  805.     ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
  806.                sizeof(ngx_http_fastcgi_request_start_t));

  807.     h = (ngx_http_fastcgi_header_t *)
  808.              (b->pos + sizeof(ngx_http_fastcgi_header_t)
  809.                      + sizeof(ngx_http_fastcgi_begin_request_t));

  810.     h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  811.     h->content_length_lo = (u_char) (len & 0xff);
  812.     h->padding_length = (u_char) padding;
  813.     h->reserved = 0;

  814.     b->last = b->pos + sizeof(ngx_http_fastcgi_header_t)
  815.                      + sizeof(ngx_http_fastcgi_begin_request_t)
  816.                      + sizeof(ngx_http_fastcgi_header_t);


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

  819.         e.ip = params->values->elts;
  820.         e.pos = b->last;
  821.         e.request = r;
  822.         e.flushed = 1;

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

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

  825.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  826.             key_len = (u_char) lcode(&le);

  827.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  828.             skip_empty = lcode(&le);

  829.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  830.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  831.             }
  832.             le.ip += sizeof(uintptr_t);

  833.             if (skip_empty && val_len == 0) {
  834.                 e.skip = 1;

  835.                 while (*(uintptr_t *) e.ip) {
  836.                     code = *(ngx_http_script_code_pt *) e.ip;
  837.                     code((ngx_http_script_engine_t *) &e);
  838.                 }
  839.                 e.ip += sizeof(uintptr_t);

  840.                 e.skip = 0;

  841.                 continue;
  842.             }

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

  844.             if (val_len > 127) {
  845.                 *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  846.                 *e.pos++ = (u_char) ((val_len >> 16) & 0xff);
  847.                 *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
  848.                 *e.pos++ = (u_char) (val_len & 0xff);

  849.             } else {
  850.                 *e.pos++ = (u_char) val_len;
  851.             }

  852.             while (*(uintptr_t *) e.ip) {
  853.                 code = *(ngx_http_script_code_pt *) e.ip;
  854.                 code((ngx_http_script_engine_t *) &e);
  855.             }
  856.             e.ip += sizeof(uintptr_t);

  857.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  858.                            "fastcgi param: \"%*s: %*s\"",
  859.                            key_len, e.pos - (key_len + val_len),
  860.                            val_len, e.pos - val_len);
  861.         }

  862.         b->last = e.pos;
  863.     }


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

  865.         part = &r->headers_in.headers.part;
  866.         header = part->elts;

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

  868.             if (i >= part->nelts) {
  869.                 if (part->next == NULL) {
  870.                     break;
  871.                 }

  872.                 part = part->next;
  873.                 header = part->elts;
  874.                 i = 0;
  875.             }

  876.             for (n = 0; n < header_params; n++) {
  877.                 if (&header[i] == ignored[n]) {
  878.                     goto next_value;
  879.                 }
  880.             }

  881.             key_len = sizeof("HTTP_") - 1 + header[i].key.len;
  882.             if (key_len > 127) {
  883.                 *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
  884.                 *b->last++ = (u_char) ((key_len >> 16) & 0xff);
  885.                 *b->last++ = (u_char) ((key_len >> 8) & 0xff);
  886.                 *b->last++ = (u_char) (key_len & 0xff);

  887.             } else {
  888.                 *b->last++ = (u_char) key_len;
  889.             }

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

  891.             for (hn = header[i].next; hn; hn = hn->next) {
  892.                 val_len += hn->value.len + 2;
  893.             }

  894.             if (val_len > 127) {
  895.                 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  896.                 *b->last++ = (u_char) ((val_len >> 16) & 0xff);
  897.                 *b->last++ = (u_char) ((val_len >> 8) & 0xff);
  898.                 *b->last++ = (u_char) (val_len & 0xff);

  899.             } else {
  900.                 *b->last++ = (u_char) val_len;
  901.             }

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

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

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

  907.                 } else if (ch == '-') {
  908.                     ch = '_';
  909.                 }

  910.                 *b->last++ = ch;
  911.             }

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

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

  915.                 if (header[i].key.len == sizeof("Cookie") - 1
  916.                     && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
  917.                                        sizeof("Cookie") - 1)
  918.                        == 0)
  919.                 {
  920.                     sep = ';';

  921.                 } else {
  922.                     sep = ',';
  923.                 }

  924.                 for (hn = header[i].next; hn; hn = hn->next) {
  925.                     *b->last++ = sep;
  926.                     *b->last++ = ' ';
  927.                     b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
  928.                 }
  929.             }

  930.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  931.                            "fastcgi param: \"%*s: %*s\"",
  932.                            key_len, b->last - (key_len + val_len),
  933.                            val_len, b->last - val_len);
  934.         next_value:

  935.             continue;
  936.         }
  937.     }


  938.     if (padding) {
  939.         ngx_memzero(b->last, padding);
  940.         b->last += padding;
  941.     }


  942.     h = (ngx_http_fastcgi_header_t *) b->last;
  943.     b->last += sizeof(ngx_http_fastcgi_header_t);

  944.     h->version = 1;
  945.     h->type = NGX_HTTP_FASTCGI_PARAMS;
  946.     h->request_id_hi = 0;
  947.     h->request_id_lo = 1;
  948.     h->content_length_hi = 0;
  949.     h->content_length_lo = 0;
  950.     h->padding_length = 0;
  951.     h->reserved = 0;

  952.     if (r->request_body_no_buffering) {

  953.         u->request_bufs = cl;

  954.         u->output.output_filter = ngx_http_fastcgi_body_output_filter;
  955.         u->output.filter_ctx = r;

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

  957.         body = u->request_bufs;
  958.         u->request_bufs = cl;

  959. #if (NGX_SUPPRESS_WARN)
  960.         file_pos = 0;
  961.         pos = NULL;
  962. #endif

  963.         while (body) {

  964.             if (ngx_buf_special(body->buf)) {
  965.                 body = body->next;
  966.                 continue;
  967.             }

  968.             if (body->buf->in_file) {
  969.                 file_pos = body->buf->file_pos;

  970.             } else {
  971.                 pos = body->buf->pos;
  972.             }

  973.             next = 0;

  974.             do {
  975.                 b = ngx_alloc_buf(r->pool);
  976.                 if (b == NULL) {
  977.                     return NGX_ERROR;
  978.                 }

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

  980.                 if (body->buf->in_file) {
  981.                     b->file_pos = file_pos;
  982.                     file_pos += 32 * 1024;

  983.                     if (file_pos >= body->buf->file_last) {
  984.                         file_pos = body->buf->file_last;
  985.                         next = 1;
  986.                     }

  987.                     b->file_last = file_pos;
  988.                     len = (ngx_uint_t) (file_pos - b->file_pos);

  989.                 } else {
  990.                     b->pos = pos;
  991.                     b->start = pos;
  992.                     pos += 32 * 1024;

  993.                     if (pos >= body->buf->last) {
  994.                         pos = body->buf->last;
  995.                         next = 1;
  996.                     }

  997.                     b->last = pos;
  998.                     len = (ngx_uint_t) (pos - b->pos);
  999.                 }

  1000.                 padding = 8 - len % 8;
  1001.                 padding = (padding == 8) ? 0 : padding;

  1002.                 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1003.                 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1004.                 h->version = 1;
  1005.                 h->type = NGX_HTTP_FASTCGI_STDIN;
  1006.                 h->request_id_hi = 0;
  1007.                 h->request_id_lo = 1;
  1008.                 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1009.                 h->content_length_lo = (u_char) (len & 0xff);
  1010.                 h->padding_length = (u_char) padding;
  1011.                 h->reserved = 0;

  1012.                 cl->next = ngx_alloc_chain_link(r->pool);
  1013.                 if (cl->next == NULL) {
  1014.                     return NGX_ERROR;
  1015.                 }

  1016.                 cl = cl->next;
  1017.                 cl->buf = b;

  1018.                 b = ngx_create_temp_buf(r->pool,
  1019.                                         sizeof(ngx_http_fastcgi_header_t)
  1020.                                         + padding);
  1021.                 if (b == NULL) {
  1022.                     return NGX_ERROR;
  1023.                 }

  1024.                 if (padding) {
  1025.                     ngx_memzero(b->last, padding);
  1026.                     b->last += padding;
  1027.                 }

  1028.                 cl->next = ngx_alloc_chain_link(r->pool);
  1029.                 if (cl->next == NULL) {
  1030.                     return NGX_ERROR;
  1031.                 }

  1032.                 cl = cl->next;
  1033.                 cl->buf = b;

  1034.             } while (!next);

  1035.             body = body->next;
  1036.         }

  1037.     } else {
  1038.         u->request_bufs = cl;
  1039.     }

  1040.     if (!r->request_body_no_buffering) {
  1041.         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1042.         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1043.         h->version = 1;
  1044.         h->type = NGX_HTTP_FASTCGI_STDIN;
  1045.         h->request_id_hi = 0;
  1046.         h->request_id_lo = 1;
  1047.         h->content_length_hi = 0;
  1048.         h->content_length_lo = 0;
  1049.         h->padding_length = 0;
  1050.         h->reserved = 0;
  1051.     }

  1052.     cl->next = NULL;

  1053.     return NGX_OK;
  1054. }


  1055. static ngx_int_t
  1056. ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
  1057. {
  1058.     ngx_http_fastcgi_ctx_t  *f;

  1059.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1060.     if (f == NULL) {
  1061.         return NGX_OK;
  1062.     }

  1063.     f->state = ngx_http_fastcgi_st_version;
  1064.     f->fastcgi_stdout = 0;
  1065.     f->large_stderr = 0;

  1066.     if (f->split_parts) {
  1067.         f->split_parts->nelts = 0;
  1068.     }

  1069.     r->state = 0;

  1070.     return NGX_OK;
  1071. }


  1072. static ngx_int_t
  1073. ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in)
  1074. {
  1075.     ngx_http_request_t  *r = data;

  1076.     off_t                       file_pos;
  1077.     u_char                     *pos, *start;
  1078.     size_t                      len, padding;
  1079.     ngx_buf_t                  *b;
  1080.     ngx_int_t                   rc;
  1081.     ngx_uint_t                  next, last;
  1082.     ngx_chain_t                *cl, *tl, *out, **ll;
  1083.     ngx_http_fastcgi_ctx_t     *f;
  1084.     ngx_http_fastcgi_header_t  *h;

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

  1087.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1088.     if (in == NULL) {
  1089.         out = in;
  1090.         goto out;
  1091.     }

  1092.     out = NULL;
  1093.     ll = &out;

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

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

  1098.         f->header_sent = 1;

  1099.         tl = ngx_alloc_chain_link(r->pool);
  1100.         if (tl == NULL) {
  1101.             return NGX_ERROR;
  1102.         }

  1103.         tl->buf = in->buf;
  1104.         *ll = tl;
  1105.         ll = &tl->next;

  1106.         in = in->next;

  1107.         if (in == NULL) {
  1108.             tl->next = NULL;
  1109.             goto out;
  1110.         }
  1111.     }

  1112.     cl = ngx_chain_get_free_buf(r->pool, &f->free);
  1113.     if (cl == NULL) {
  1114.         return NGX_ERROR;
  1115.     }

  1116.     b = cl->buf;

  1117.     b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1118.     b->temporary = 1;

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

  1121.         b->start = ngx_palloc(r->pool,
  1122.                               sizeof(ngx_http_fastcgi_header_t) + 7);
  1123.         if (b->start == NULL) {
  1124.             return NGX_ERROR;
  1125.         }

  1126.         b->pos = b->start;
  1127.         b->last = b->start;

  1128.         b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
  1129.     }

  1130.     *ll = cl;

  1131.     last = 0;
  1132.     padding = 0;

  1133. #if (NGX_SUPPRESS_WARN)
  1134.     file_pos = 0;
  1135.     pos = NULL;
  1136. #endif

  1137.     while (in) {

  1138.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1139.                        "fastcgi output in  l:%d f:%d %p, pos %p, size: %z "
  1140.                        "file: %O, size: %O",
  1141.                        in->buf->last_buf,
  1142.                        in->buf->in_file,
  1143.                        in->buf->start, in->buf->pos,
  1144.                        in->buf->last - in->buf->pos,
  1145.                        in->buf->file_pos,
  1146.                        in->buf->file_last - in->buf->file_pos);

  1147.         if (in->buf->last_buf) {
  1148.             last = 1;
  1149.         }

  1150.         if (ngx_buf_special(in->buf)) {
  1151.             in = in->next;
  1152.             continue;
  1153.         }

  1154.         if (in->buf->in_file) {
  1155.             file_pos = in->buf->file_pos;

  1156.         } else {
  1157.             pos = in->buf->pos;
  1158.         }

  1159.         next = 0;

  1160.         do {
  1161.             tl = ngx_chain_get_free_buf(r->pool, &f->free);
  1162.             if (tl == NULL) {
  1163.                 return NGX_ERROR;
  1164.             }

  1165.             b = tl->buf;
  1166.             start = b->start;

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

  1168.             /*
  1169.              * restore b->start to preserve memory allocated in the buffer,
  1170.              * to reuse it later for headers and padding
  1171.              */

  1172.             b->start = start;

  1173.             if (in->buf->in_file) {
  1174.                 b->file_pos = file_pos;
  1175.                 file_pos += 32 * 1024;

  1176.                 if (file_pos >= in->buf->file_last) {
  1177.                     file_pos = in->buf->file_last;
  1178.                     next = 1;
  1179.                 }

  1180.                 b->file_last = file_pos;
  1181.                 len = (ngx_uint_t) (file_pos - b->file_pos);

  1182.             } else {
  1183.                 b->pos = pos;
  1184.                 pos += 32 * 1024;

  1185.                 if (pos >= in->buf->last) {
  1186.                     pos = in->buf->last;
  1187.                     next = 1;
  1188.                 }

  1189.                 b->last = pos;
  1190.                 len = (ngx_uint_t) (pos - b->pos);
  1191.             }

  1192.             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1193.             b->shadow = in->buf;
  1194.             b->last_shadow = next;

  1195.             b->last_buf = 0;
  1196.             b->last_in_chain = 0;

  1197.             padding = 8 - len % 8;
  1198.             padding = (padding == 8) ? 0 : padding;

  1199.             h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1200.             cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1201.             h->version = 1;
  1202.             h->type = NGX_HTTP_FASTCGI_STDIN;
  1203.             h->request_id_hi = 0;
  1204.             h->request_id_lo = 1;
  1205.             h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1206.             h->content_length_lo = (u_char) (len & 0xff);
  1207.             h->padding_length = (u_char) padding;
  1208.             h->reserved = 0;

  1209.             cl->next = tl;
  1210.             cl = tl;

  1211.             tl = ngx_chain_get_free_buf(r->pool, &f->free);
  1212.             if (tl == NULL) {
  1213.                 return NGX_ERROR;
  1214.             }

  1215.             b = tl->buf;

  1216.             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1217.             b->temporary = 1;

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

  1220.                 b->start = ngx_palloc(r->pool,
  1221.                                       sizeof(ngx_http_fastcgi_header_t) + 7);
  1222.                 if (b->start == NULL) {
  1223.                     return NGX_ERROR;
  1224.                 }

  1225.                 b->pos = b->start;
  1226.                 b->last = b->start;

  1227.                 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
  1228.             }

  1229.             if (padding) {
  1230.                 ngx_memzero(b->last, padding);
  1231.                 b->last += padding;
  1232.             }

  1233.             cl->next = tl;
  1234.             cl = tl;

  1235.         } while (!next);

  1236.         in = in->next;
  1237.     }

  1238.     if (last) {
  1239.         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1240.         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1241.         h->version = 1;
  1242.         h->type = NGX_HTTP_FASTCGI_STDIN;
  1243.         h->request_id_hi = 0;
  1244.         h->request_id_lo = 1;
  1245.         h->content_length_hi = 0;
  1246.         h->content_length_lo = 0;
  1247.         h->padding_length = 0;
  1248.         h->reserved = 0;

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

  1250.     } else if (padding == 0) {
  1251.         /* TODO: do not allocate buffers instead */
  1252.         cl->buf->temporary = 0;
  1253.         cl->buf->sync = 1;
  1254.     }

  1255.     cl->next = NULL;

  1256. out:

  1257. #if (NGX_DEBUG)

  1258.     for (cl = out; cl; cl = cl->next) {
  1259.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1260.                        "fastcgi output out l:%d f:%d %p, pos %p, size: %z "
  1261.                        "file: %O, size: %O",
  1262.                        cl->buf->last_buf,
  1263.                        cl->buf->in_file,
  1264.                        cl->buf->start, cl->buf->pos,
  1265.                        cl->buf->last - cl->buf->pos,
  1266.                        cl->buf->file_pos,
  1267.                        cl->buf->file_last - cl->buf->file_pos);
  1268.     }

  1269. #endif

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

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

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

  1274.         /* mark original buffers as sent */

  1275.         if (cl->buf->shadow) {
  1276.             if (cl->buf->last_shadow) {
  1277.                 b = cl->buf->shadow;
  1278.                 b->pos = b->last;
  1279.             }

  1280.             cl->buf->shadow = NULL;
  1281.         }
  1282.     }

  1283.     return rc;
  1284. }


  1285. static ngx_int_t
  1286. ngx_http_fastcgi_process_header(ngx_http_request_t *r)
  1287. {
  1288.     u_char                         *p, *msg, *start, *last,
  1289.                                    *part_start, *part_end;
  1290.     size_t                          size;
  1291.     ngx_str_t                      *status_line, *pattern;
  1292.     ngx_int_t                       rc, status;
  1293.     ngx_buf_t                       buf;
  1294.     ngx_uint_t                      i;
  1295.     ngx_table_elt_t                *h;
  1296.     ngx_http_upstream_t            *u;
  1297.     ngx_http_fastcgi_ctx_t         *f;
  1298.     ngx_http_upstream_header_t     *hh;
  1299.     ngx_http_fastcgi_loc_conf_t    *flcf;
  1300.     ngx_http_fastcgi_split_part_t  *part;
  1301.     ngx_http_upstream_main_conf_t  *umcf;

  1302.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1303.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1304.     u = r->upstream;

  1305.     for ( ;; ) {

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

  1307.             f->pos = u->buffer.pos;
  1308.             f->last = u->buffer.last;

  1309.             rc = ngx_http_fastcgi_process_record(r, f);

  1310.             u->buffer.pos = f->pos;
  1311.             u->buffer.last = f->last;

  1312.             if (rc == NGX_AGAIN) {
  1313.                 return NGX_AGAIN;
  1314.             }

  1315.             if (rc == NGX_ERROR) {
  1316.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1317.             }

  1318.             if (f->type != NGX_HTTP_FASTCGI_STDOUT
  1319.                 && f->type != NGX_HTTP_FASTCGI_STDERR)
  1320.             {
  1321.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1322.                               "upstream sent unexpected FastCGI record: %ui",
  1323.                               f->type);

  1324.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1325.             }

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

  1329.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1330.             }
  1331.         }

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

  1333.             if (u->buffer.pos + f->padding < u->buffer.last) {
  1334.                 f->state = ngx_http_fastcgi_st_version;
  1335.                 u->buffer.pos += f->padding;

  1336.                 continue;
  1337.             }

  1338.             if (u->buffer.pos + f->padding == u->buffer.last) {
  1339.                 f->state = ngx_http_fastcgi_st_version;
  1340.                 u->buffer.pos = u->buffer.last;

  1341.                 return NGX_AGAIN;
  1342.             }

  1343.             f->padding -= u->buffer.last - u->buffer.pos;
  1344.             u->buffer.pos = u->buffer.last;

  1345.             return NGX_AGAIN;
  1346.         }


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

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

  1349.             if (f->length) {
  1350.                 msg = u->buffer.pos;

  1351.                 if (u->buffer.pos + f->length <= u->buffer.last) {
  1352.                     u->buffer.pos += f->length;
  1353.                     f->length = 0;
  1354.                     f->state = ngx_http_fastcgi_st_padding;

  1355.                 } else {
  1356.                     f->length -= u->buffer.last - u->buffer.pos;
  1357.                     u->buffer.pos = u->buffer.last;
  1358.                 }

  1359.                 for (p = u->buffer.pos - 1; msg < p; p--) {
  1360.                     if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
  1361.                         break;
  1362.                     }
  1363.                 }

  1364.                 p++;

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

  1367.                 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1368.                 if (flcf->catch_stderr) {
  1369.                     pattern = flcf->catch_stderr->elts;

  1370.                     for (i = 0; i < flcf->catch_stderr->nelts; i++) {
  1371.                         if (ngx_strnstr(msg, (char *) pattern[i].data,
  1372.                                         p - msg)
  1373.                             != NULL)
  1374.                         {
  1375.                             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1376.                         }
  1377.                     }
  1378.                 }

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

  1380.                     if (!f->fastcgi_stdout) {

  1381.                         /*
  1382.                          * the special handling the large number
  1383.                          * of the PHP warnings to not allocate memory
  1384.                          */

  1385. #if (NGX_HTTP_CACHE)
  1386.                         if (r->cache) {
  1387.                             u->buffer.pos = u->buffer.start
  1388.                                                      + r->cache->header_start;
  1389.                         } else {
  1390.                             u->buffer.pos = u->buffer.start;
  1391.                         }
  1392. #else
  1393.                         u->buffer.pos = u->buffer.start;
  1394. #endif
  1395.                         u->buffer.last = u->buffer.pos;
  1396.                         f->large_stderr = 1;
  1397.                     }

  1398.                     return NGX_AGAIN;
  1399.                 }

  1400.             } else {
  1401.                 f->state = ngx_http_fastcgi_st_padding;
  1402.             }

  1403.             continue;
  1404.         }


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

  1406. #if (NGX_HTTP_CACHE)

  1407.         if (f->large_stderr && r->cache) {
  1408.             ssize_t                     len;
  1409.             ngx_http_fastcgi_header_t  *fh;

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

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

  1412.             /*
  1413.              * A tail of large stderr output before HTTP header is placed
  1414.              * in a cache file without a FastCGI record header.
  1415.              * To workaround it we put a dummy FastCGI record header at the
  1416.              * start of the stderr output or update r->cache_header_start,
  1417.              * if there is no enough place for the record header.
  1418.              */

  1419.             if (len >= 0) {
  1420.                 fh = (ngx_http_fastcgi_header_t *) start;
  1421.                 fh->version = 1;
  1422.                 fh->type = NGX_HTTP_FASTCGI_STDERR;
  1423.                 fh->request_id_hi = 0;
  1424.                 fh->request_id_lo = 1;
  1425.                 fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1426.                 fh->content_length_lo = (u_char) (len & 0xff);
  1427.                 fh->padding_length = 0;
  1428.                 fh->reserved = 0;

  1429.             } else {
  1430.                 r->cache->header_start += u->buffer.pos - start
  1431.                                           - sizeof(ngx_http_fastcgi_header_t);
  1432.             }

  1433.             f->large_stderr = 0;
  1434.         }

  1435. #endif

  1436.         f->fastcgi_stdout = 1;

  1437.         start = u->buffer.pos;

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

  1439.             /*
  1440.              * set u->buffer.last to the end of the FastCGI record data
  1441.              * for ngx_http_parse_header_line()
  1442.              */

  1443.             last = u->buffer.last;
  1444.             u->buffer.last = u->buffer.pos + f->length;

  1445.         } else {
  1446.             last = NULL;
  1447.         }

  1448.         for ( ;; ) {

  1449.             part_start = u->buffer.pos;
  1450.             part_end = u->buffer.last;

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

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

  1454.             if (rc == NGX_AGAIN) {
  1455.                 break;
  1456.             }

  1457.             if (rc == NGX_OK) {

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

  1459.                 h = ngx_list_push(&u->headers_in.headers);
  1460.                 if (h == NULL) {
  1461.                     return NGX_ERROR;
  1462.                 }

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

  1464.                     part = f->split_parts->elts;
  1465.                     size = u->buffer.pos - part_start;

  1466.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1467.                         size += part[i].end - part[i].start;
  1468.                     }

  1469.                     p = ngx_pnalloc(r->pool, size);
  1470.                     if (p == NULL) {
  1471.                         h->hash = 0;
  1472.                         return NGX_ERROR;
  1473.                     }

  1474.                     buf.pos = p;

  1475.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1476.                         p = ngx_cpymem(p, part[i].start,
  1477.                                        part[i].end - part[i].start);
  1478.                     }

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

  1480.                     buf.last = p;

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

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

  1483.                     if (rc != NGX_OK) {
  1484.                         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  1485.                                       "invalid header after joining "
  1486.                                       "FastCGI records");
  1487.                         h->hash = 0;
  1488.                         return NGX_ERROR;
  1489.                     }

  1490.                     h->key.len = r->header_name_end - r->header_name_start;
  1491.                     h->key.data = r->header_name_start;
  1492.                     h->key.data[h->key.len] = '\0';

  1493.                     h->value.len = r->header_end - r->header_start;
  1494.                     h->value.data = r->header_start;
  1495.                     h->value.data[h->value.len] = '\0';

  1496.                     h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
  1497.                     if (h->lowcase_key == NULL) {
  1498.                         return NGX_ERROR;
  1499.                     }

  1500.                 } else {

  1501.                     h->key.len = r->header_name_end - r->header_name_start;
  1502.                     h->value.len = r->header_end - r->header_start;

  1503.                     h->key.data = ngx_pnalloc(r->pool,
  1504.                                               h->key.len + 1 + h->value.len + 1
  1505.                                               + h->key.len);
  1506.                     if (h->key.data == NULL) {
  1507.                         h->hash = 0;
  1508.                         return NGX_ERROR;
  1509.                     }

  1510.                     h->value.data = h->key.data + h->key.len + 1;
  1511.                     h->lowcase_key = h->key.data + h->key.len + 1
  1512.                                      + h->value.len + 1;

  1513.                     ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  1514.                     h->key.data[h->key.len] = '\0';
  1515.                     ngx_memcpy(h->value.data, r->header_start, h->value.len);
  1516.                     h->value.data[h->value.len] = '\0';
  1517.                 }

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

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

  1521.                 } else {
  1522.                     ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  1523.                 }

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

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

  1528.                     if (rc != NGX_OK) {
  1529.                         return rc;
  1530.                     }
  1531.                 }

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

  1535.                 if (u->buffer.pos < u->buffer.last) {
  1536.                     continue;
  1537.                 }

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

  1539.                 break;
  1540.             }

  1541.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1545.                 if (u->headers_in.status) {
  1546.                     status_line = &u->headers_in.status->value;

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

  1548.                     if (status == NGX_ERROR) {
  1549.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1550.                                       "upstream sent invalid status \"%V\"",
  1551.                                       status_line);
  1552.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1553.                     }

  1554.                     u->headers_in.status_n = status;

  1555.                     if (status_line->len > 3) {
  1556.                         u->headers_in.status_line = *status_line;
  1557.                     }

  1558.                 } else if (u->headers_in.location) {
  1559.                     u->headers_in.status_n = 302;
  1560.                     ngx_str_set(&u->headers_in.status_line,
  1561.                                 "302 Moved Temporarily");

  1562.                 } else {
  1563.                     u->headers_in.status_n = 200;
  1564.                     ngx_str_set(&u->headers_in.status_line, "200 OK");
  1565.                 }

  1566.                 if (u->state && u->state->status == 0) {
  1567.                     u->state->status = u->headers_in.status_n;
  1568.                 }

  1569.                 break;
  1570.             }

  1571.             /* rc == NGX_HTTP_PARSE_INVALID_HEADER */

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

  1576.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1577.         }

  1578.         if (last) {
  1579.             u->buffer.last = last;
  1580.         }

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

  1582.         if (f->length == 0) {
  1583.             f->state = ngx_http_fastcgi_st_padding;
  1584.         }

  1585.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1586.             return NGX_OK;
  1587.         }

  1588.         if (rc == NGX_OK) {
  1589.             continue;
  1590.         }

  1591.         /* rc == NGX_AGAIN */

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

  1594.         if (f->split_parts == NULL) {
  1595.             f->split_parts = ngx_array_create(r->pool, 1,
  1596.                                         sizeof(ngx_http_fastcgi_split_part_t));
  1597.             if (f->split_parts == NULL) {
  1598.                 return NGX_ERROR;
  1599.             }
  1600.         }

  1601.         part = ngx_array_push(f->split_parts);
  1602.         if (part == NULL) {
  1603.             return NGX_ERROR;
  1604.         }

  1605.         part->start = part_start;
  1606.         part->end = part_end;

  1607.         if (u->buffer.pos < u->buffer.last) {
  1608.             continue;
  1609.         }

  1610.         return NGX_AGAIN;
  1611.     }
  1612. }


  1613. static ngx_int_t
  1614. ngx_http_fastcgi_input_filter_init(void *data)
  1615. {
  1616.     ngx_http_request_t  *r = data;

  1617.     ngx_http_upstream_t          *u;
  1618.     ngx_http_fastcgi_ctx_t       *f;
  1619.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1620.     u = r->upstream;

  1621.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1622.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

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

  1625.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1626.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
  1627.     {
  1628.         f->rest = 0;

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

  1631.     } else {
  1632.         f->rest = u->headers_in.content_length_n;
  1633.     }

  1634.     return NGX_OK;
  1635. }


  1636. static ngx_int_t
  1637. ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1638. {
  1639.     u_char                       *m, *msg;
  1640.     ngx_int_t                     rc;
  1641.     ngx_buf_t                    *b, **prev;
  1642.     ngx_chain_t                  *cl;
  1643.     ngx_http_request_t           *r;
  1644.     ngx_http_fastcgi_ctx_t       *f;
  1645.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1646.     if (buf->pos == buf->last) {
  1647.         return NGX_OK;
  1648.     }

  1649.     r = p->input_ctx;
  1650.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1651.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

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

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

  1656.         return NGX_OK;
  1657.     }

  1658.     b = NULL;
  1659.     prev = &buf->shadow;

  1660.     f->pos = buf->pos;
  1661.     f->last = buf->last;

  1662.     for ( ;; ) {
  1663.         if (f->state < ngx_http_fastcgi_st_data) {

  1664.             rc = ngx_http_fastcgi_process_record(r, f);

  1665.             if (rc == NGX_AGAIN) {
  1666.                 break;
  1667.             }

  1668.             if (rc == NGX_ERROR) {
  1669.                 return NGX_ERROR;
  1670.             }

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

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

  1675.                 if (f->rest > 0) {
  1676.                     ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1677.                                   "upstream prematurely closed "
  1678.                                   "FastCGI stdout");

  1679.                     p->upstream_error = 1;
  1680.                     p->upstream_eof = 0;
  1681.                     f->closed = 1;

  1682.                     break;
  1683.                 }

  1684.                 if (!flcf->keep_conn) {
  1685.                     p->upstream_done = 1;
  1686.                 }

  1687.                 continue;
  1688.             }

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

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

  1692.                 if (f->rest > 0) {
  1693.                     ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1694.                                   "upstream prematurely closed "
  1695.                                   "FastCGI request");

  1696.                     p->upstream_error = 1;
  1697.                     p->upstream_eof = 0;
  1698.                     f->closed = 1;

  1699.                     break;
  1700.                 }

  1701.                 if (!flcf->keep_conn) {
  1702.                     p->upstream_done = 1;
  1703.                     break;
  1704.                 }

  1705.                 continue;
  1706.             }
  1707.         }


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

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

  1710.                 if (f->pos + f->padding < f->last) {
  1711.                     p->upstream_done = 1;
  1712.                     break;
  1713.                 }

  1714.                 if (f->pos + f->padding == f->last) {
  1715.                     p->upstream_done = 1;
  1716.                     r->upstream->keepalive = 1;
  1717.                     break;
  1718.                 }

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

  1720.                 break;
  1721.             }

  1722.             if (f->pos + f->padding < f->last) {
  1723.                 f->state = ngx_http_fastcgi_st_version;
  1724.                 f->pos += f->padding;

  1725.                 continue;
  1726.             }

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

  1729.                 break;
  1730.             }

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

  1732.             break;
  1733.         }


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

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

  1736.             if (f->length) {

  1737.                 if (f->pos == f->last) {
  1738.                     break;
  1739.                 }

  1740.                 msg = f->pos;

  1741.                 if (f->pos + f->length <= f->last) {
  1742.                     f->pos += f->length;
  1743.                     f->length = 0;
  1744.                     f->state = ngx_http_fastcgi_st_padding;

  1745.                 } else {
  1746.                     f->length -= f->last - f->pos;
  1747.                     f->pos = f->last;
  1748.                 }

  1749.                 for (m = f->pos - 1; msg < m; m--) {
  1750.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1751.                         break;
  1752.                     }
  1753.                 }

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

  1757.             } else {
  1758.                 f->state = ngx_http_fastcgi_st_padding;
  1759.             }

  1760.             continue;
  1761.         }

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

  1763.             if (f->pos + f->length <= f->last) {
  1764.                 f->state = ngx_http_fastcgi_st_padding;
  1765.                 f->pos += f->length;

  1766.                 continue;
  1767.             }

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

  1769.             break;
  1770.         }


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

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

  1775.         if (f->rest == -2) {
  1776.             f->rest = r->upstream->headers_in.content_length_n;
  1777.         }

  1778.         if (f->rest == 0) {
  1779.             ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1780.                           "upstream sent more data than specified in "
  1781.                           "\"Content-Length\" header");
  1782.             p->upstream_done = 1;
  1783.             break;
  1784.         }

  1785.         cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1786.         if (cl == NULL) {
  1787.             return NGX_ERROR;
  1788.         }

  1789.         b = cl->buf;

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

  1791.         b->pos = f->pos;
  1792.         b->start = buf->start;
  1793.         b->end = buf->end;
  1794.         b->tag = p->tag;
  1795.         b->temporary = 1;
  1796.         b->recycled = 1;

  1797.         *prev = b;
  1798.         prev = &b->shadow;

  1799.         if (p->in) {
  1800.             *p->last_in = cl;
  1801.         } else {
  1802.             p->in = cl;
  1803.         }
  1804.         p->last_in = &cl->next;


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

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

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

  1812.         } else {
  1813.             f->length -= f->last - f->pos;
  1814.             f->pos = f->last;
  1815.             b->last = f->last;
  1816.         }

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

  1818.             if (b->last - b->pos > f->rest) {
  1819.                 ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1820.                               "upstream sent more data than specified in "
  1821.                               "\"Content-Length\" header");

  1822.                 b->last = b->pos + f->rest;
  1823.                 p->upstream_done = 1;

  1824.                 break;
  1825.             }

  1826.             f->rest -= b->last - b->pos;
  1827.         }
  1828.     }

  1829.     if (flcf->keep_conn) {

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

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

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

  1835.         } else {
  1836.             /* ngx_http_fastcgi_st_data */

  1837.             p->length = f->length;
  1838.         }
  1839.     }

  1840.     if (b) {
  1841.         b->shadow = buf;
  1842.         b->last_shadow = 1;

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

  1845.         return NGX_OK;
  1846.     }

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

  1848.     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
  1849.         return NGX_ERROR;
  1850.     }

  1851.     return NGX_OK;
  1852. }


  1853. static ngx_int_t
  1854. ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
  1855. {
  1856.     u_char                  *m, *msg;
  1857.     ngx_int_t                rc;
  1858.     ngx_buf_t               *b, *buf;
  1859.     ngx_chain_t             *cl, **ll;
  1860.     ngx_http_request_t      *r;
  1861.     ngx_http_upstream_t     *u;
  1862.     ngx_http_fastcgi_ctx_t  *f;

  1863.     r = data;
  1864.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1865.     u = r->upstream;
  1866.     buf = &u->buffer;

  1867.     buf->pos = buf->last;
  1868.     buf->last += bytes;

  1869.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1870.         ll = &cl->next;
  1871.     }

  1872.     f->pos = buf->pos;
  1873.     f->last = buf->last;

  1874.     for ( ;; ) {
  1875.         if (f->state < ngx_http_fastcgi_st_data) {

  1876.             rc = ngx_http_fastcgi_process_record(r, f);

  1877.             if (rc == NGX_AGAIN) {
  1878.                 break;
  1879.             }

  1880.             if (rc == NGX_ERROR) {
  1881.                 return NGX_ERROR;
  1882.             }

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

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

  1887.                 continue;
  1888.             }
  1889.         }

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

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

  1892.                 if (f->rest > 0) {
  1893.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1894.                                   "upstream prematurely closed "
  1895.                                   "FastCGI request");
  1896.                     u->error = 1;
  1897.                     break;
  1898.                 }

  1899.                 if (f->pos + f->padding < f->last) {
  1900.                     u->length = 0;
  1901.                     break;
  1902.                 }

  1903.                 if (f->pos + f->padding == f->last) {
  1904.                     u->length = 0;
  1905.                     u->keepalive = 1;
  1906.                     break;
  1907.                 }

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

  1909.                 break;
  1910.             }

  1911.             if (f->pos + f->padding < f->last) {
  1912.                 f->state = ngx_http_fastcgi_st_version;
  1913.                 f->pos += f->padding;

  1914.                 continue;
  1915.             }

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

  1918.                 break;
  1919.             }

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

  1921.             break;
  1922.         }


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

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

  1925.             if (f->length) {

  1926.                 if (f->pos == f->last) {
  1927.                     break;
  1928.                 }

  1929.                 msg = f->pos;

  1930.                 if (f->pos + f->length <= f->last) {
  1931.                     f->pos += f->length;
  1932.                     f->length = 0;
  1933.                     f->state = ngx_http_fastcgi_st_padding;

  1934.                 } else {
  1935.                     f->length -= f->last - f->pos;
  1936.                     f->pos = f->last;
  1937.                 }

  1938.                 for (m = f->pos - 1; msg < m; m--) {
  1939.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1940.                         break;
  1941.                     }
  1942.                 }

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

  1946.             } else {
  1947.                 f->state = ngx_http_fastcgi_st_padding;
  1948.             }

  1949.             continue;
  1950.         }

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

  1952.             if (f->pos + f->length <= f->last) {
  1953.                 f->state = ngx_http_fastcgi_st_padding;
  1954.                 f->pos += f->length;

  1955.                 continue;
  1956.             }

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

  1958.             break;
  1959.         }


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

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

  1964.         if (f->rest == 0) {
  1965.             ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  1966.                           "upstream sent more data than specified in "
  1967.                           "\"Content-Length\" header");
  1968.             u->length = 0;
  1969.             break;
  1970.         }

  1971.         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1972.         if (cl == NULL) {
  1973.             return NGX_ERROR;
  1974.         }

  1975.         *ll = cl;
  1976.         ll = &cl->next;

  1977.         b = cl->buf;

  1978.         b->flush = 1;
  1979.         b->memory = 1;

  1980.         b->pos = f->pos;
  1981.         b->tag = u->output.tag;

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

  1984.         if (f->pos + f->length <= f->last) {
  1985.             f->state = ngx_http_fastcgi_st_padding;
  1986.             f->pos += f->length;
  1987.             b->last = f->pos;

  1988.         } else {
  1989.             f->length -= f->last - f->pos;
  1990.             f->pos = f->last;
  1991.             b->last = f->last;
  1992.         }

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

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

  1998.                 b->last = b->pos + f->rest;
  1999.                 u->length = 0;

  2000.                 break;
  2001.             }

  2002.             f->rest -= b->last - b->pos;
  2003.         }
  2004.     }

  2005.     return NGX_OK;
  2006. }


  2007. static ngx_int_t
  2008. ngx_http_fastcgi_process_record(ngx_http_request_t *r,
  2009.     ngx_http_fastcgi_ctx_t *f)
  2010. {
  2011.     u_char                     ch, *p;
  2012.     ngx_http_fastcgi_state_e   state;

  2013.     state = f->state;

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

  2015.         ch = *p;

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

  2018.         switch (state) {

  2019.         case ngx_http_fastcgi_st_version:
  2020.             if (ch != 1) {
  2021.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2022.                               "upstream sent unsupported FastCGI "
  2023.                               "protocol version: %d", ch);
  2024.                 return NGX_ERROR;
  2025.             }
  2026.             state = ngx_http_fastcgi_st_type;
  2027.             break;

  2028.         case ngx_http_fastcgi_st_type:
  2029.             switch (ch) {
  2030.             case NGX_HTTP_FASTCGI_STDOUT:
  2031.             case NGX_HTTP_FASTCGI_STDERR:
  2032.             case NGX_HTTP_FASTCGI_END_REQUEST:
  2033.                 f->type = (ngx_uint_t) ch;
  2034.                 break;
  2035.             default:
  2036.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2037.                               "upstream sent invalid FastCGI "
  2038.                               "record type: %d", ch);
  2039.                 return NGX_ERROR;

  2040.             }
  2041.             state = ngx_http_fastcgi_st_request_id_hi;
  2042.             break;

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

  2044.         case ngx_http_fastcgi_st_request_id_hi:
  2045.             if (ch != 0) {
  2046.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2047.                               "upstream sent unexpected FastCGI "
  2048.                               "request id high byte: %d", ch);
  2049.                 return NGX_ERROR;
  2050.             }
  2051.             state = ngx_http_fastcgi_st_request_id_lo;
  2052.             break;

  2053.         case ngx_http_fastcgi_st_request_id_lo:
  2054.             if (ch != 1) {
  2055.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2056.                               "upstream sent unexpected FastCGI "
  2057.                               "request id low byte: %d", ch);
  2058.                 return NGX_ERROR;
  2059.             }
  2060.             state = ngx_http_fastcgi_st_content_length_hi;
  2061.             break;

  2062.         case ngx_http_fastcgi_st_content_length_hi:
  2063.             f->length = ch << 8;
  2064.             state = ngx_http_fastcgi_st_content_length_lo;
  2065.             break;

  2066.         case ngx_http_fastcgi_st_content_length_lo:
  2067.             f->length |= (size_t) ch;
  2068.             state = ngx_http_fastcgi_st_padding_length;
  2069.             break;

  2070.         case ngx_http_fastcgi_st_padding_length:
  2071.             f->padding = (size_t) ch;
  2072.             state = ngx_http_fastcgi_st_reserved;
  2073.             break;

  2074.         case ngx_http_fastcgi_st_reserved:
  2075.             state = ngx_http_fastcgi_st_data;

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

  2078.             f->pos = p + 1;
  2079.             f->state = state;

  2080.             return NGX_OK;

  2081.         /* suppress warning */
  2082.         case ngx_http_fastcgi_st_data:
  2083.         case ngx_http_fastcgi_st_padding:
  2084.             break;
  2085.         }
  2086.     }

  2087.     f->pos = p;
  2088.     f->state = state;

  2089.     return NGX_AGAIN;
  2090. }


  2091. static void
  2092. ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
  2093. {
  2094.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2095.                    "abort http fastcgi request");

  2096.     return;
  2097. }


  2098. static void
  2099. ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  2100. {
  2101.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2102.                    "finalize http fastcgi request");

  2103.     return;
  2104. }


  2105. static ngx_int_t
  2106. ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
  2107. {
  2108.     ngx_http_variable_t  *var, *v;

  2109.     for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
  2110.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  2111.         if (var == NULL) {
  2112.             return NGX_ERROR;
  2113.         }

  2114.         var->get_handler = v->get_handler;
  2115.         var->data = v->data;
  2116.     }

  2117.     return NGX_OK;
  2118. }


  2119. static void *
  2120. ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
  2121. {
  2122.     ngx_http_fastcgi_main_conf_t  *conf;

  2123.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
  2124.     if (conf == NULL) {
  2125.         return NULL;
  2126.     }

  2127. #if (NGX_HTTP_CACHE)
  2128.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  2129.                        sizeof(ngx_http_file_cache_t *))
  2130.         != NGX_OK)
  2131.     {
  2132.         return NULL;
  2133.     }
  2134. #endif

  2135.     return conf;
  2136. }


  2137. static void *
  2138. ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
  2139. {
  2140.     ngx_http_fastcgi_loc_conf_t  *conf;

  2141.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
  2142.     if (conf == NULL) {
  2143.         return NULL;
  2144.     }

  2145.     /*
  2146.      * set by ngx_pcalloc():
  2147.      *
  2148.      *     conf->upstream.bufs.num = 0;
  2149.      *     conf->upstream.ignore_headers = 0;
  2150.      *     conf->upstream.next_upstream = 0;
  2151.      *     conf->upstream.cache_zone = NULL;
  2152.      *     conf->upstream.cache_use_stale = 0;
  2153.      *     conf->upstream.cache_methods = 0;
  2154.      *     conf->upstream.temp_path = NULL;
  2155.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  2156.      *     conf->upstream.store_lengths = NULL;
  2157.      *     conf->upstream.store_values = NULL;
  2158.      *
  2159.      *     conf->index = { 0, NULL };
  2160.      */

  2161.     conf->upstream.store = NGX_CONF_UNSET;
  2162.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  2163.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  2164.     conf->upstream.buffering = NGX_CONF_UNSET;
  2165.     conf->upstream.request_buffering = NGX_CONF_UNSET;
  2166.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  2167.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  2168.     conf->upstream.local = NGX_CONF_UNSET_PTR;
  2169.     conf->upstream.socket_keepalive = NGX_CONF_UNSET;

  2170.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  2171.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  2172.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  2173.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  2174.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  2175.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  2176.     conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;

  2177.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  2178.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  2179.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  2180.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  2181.     conf->upstream.pass_request_body = NGX_CONF_UNSET;

  2182. #if (NGX_HTTP_CACHE)
  2183.     conf->upstream.cache = NGX_CONF_UNSET;
  2184.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  2185.     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
  2186.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  2187.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  2188.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  2189.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  2190.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  2191.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  2192.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  2193.     conf->upstream.cache_background_update = NGX_CONF_UNSET;
  2194. #endif

  2195.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  2196.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  2197.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  2198.     /* "fastcgi_cyclic_temp_file" is disabled */
  2199.     conf->upstream.cyclic_temp_file = 0;

  2200.     conf->upstream.change_buffering = 1;

  2201.     conf->catch_stderr = NGX_CONF_UNSET_PTR;

  2202.     conf->keep_conn = NGX_CONF_UNSET;

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

  2204.     return conf;
  2205. }


  2206. static char *
  2207. ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  2208. {
  2209.     ngx_http_fastcgi_loc_conf_t *prev = parent;
  2210.     ngx_http_fastcgi_loc_conf_t *conf = child;

  2211.     size_t                        size;
  2212.     ngx_int_t                     rc;
  2213.     ngx_hash_init_t               hash;
  2214.     ngx_http_core_loc_conf_t     *clcf;

  2215. #if (NGX_HTTP_CACHE)

  2216.     if (conf->upstream.store > 0) {
  2217.         conf->upstream.cache = 0;
  2218.     }

  2219.     if (conf->upstream.cache > 0) {
  2220.         conf->upstream.store = 0;
  2221.     }

  2222. #endif

  2223.     if (conf->upstream.store == NGX_CONF_UNSET) {
  2224.         ngx_conf_merge_value(conf->upstream.store,
  2225.                               prev->upstream.store, 0);

  2226.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  2227.         conf->upstream.store_values = prev->upstream.store_values;
  2228.     }

  2229.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  2230.                               prev->upstream.store_access, 0600);

  2231.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  2232.                               prev->upstream.next_upstream_tries, 0);

  2233.     ngx_conf_merge_value(conf->upstream.buffering,
  2234.                               prev->upstream.buffering, 1);

  2235.     ngx_conf_merge_value(conf->upstream.request_buffering,
  2236.                               prev->upstream.request_buffering, 1);

  2237.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  2238.                               prev->upstream.ignore_client_abort, 0);

  2239.     ngx_conf_merge_value(conf->upstream.force_ranges,
  2240.                               prev->upstream.force_ranges, 0);

  2241.     ngx_conf_merge_ptr_value(conf->upstream.local,
  2242.                               prev->upstream.local, NULL);

  2243.     ngx_conf_merge_value(conf->upstream.socket_keepalive,
  2244.                               prev->upstream.socket_keepalive, 0);

  2245.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  2246.                               prev->upstream.connect_timeout, 60000);

  2247.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  2248.                               prev->upstream.send_timeout, 60000);

  2249.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  2250.                               prev->upstream.read_timeout, 60000);

  2251.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  2252.                               prev->upstream.next_upstream_timeout, 0);

  2253.     ngx_conf_merge_size_value(conf->upstream.send_lowat,
  2254.                               prev->upstream.send_lowat, 0);

  2255.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  2256.                               prev->upstream.buffer_size,
  2257.                               (size_t) ngx_pagesize);

  2258.     ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
  2259.                               prev->upstream.limit_rate, NULL);


  2260.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  2261.                               8, ngx_pagesize);

  2262.     if (conf->upstream.bufs.num < 2) {
  2263.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2264.                            "there must be at least 2 \"fastcgi_buffers\"");
  2265.         return NGX_CONF_ERROR;
  2266.     }


  2267.     size = conf->upstream.buffer_size;
  2268.     if (size < conf->upstream.bufs.size) {
  2269.         size = conf->upstream.bufs.size;
  2270.     }


  2271.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  2272.                               prev->upstream.busy_buffers_size_conf,
  2273.                               NGX_CONF_UNSET_SIZE);

  2274.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  2275.         conf->upstream.busy_buffers_size = 2 * size;
  2276.     } else {
  2277.         conf->upstream.busy_buffers_size =
  2278.                                          conf->upstream.busy_buffers_size_conf;
  2279.     }

  2280.     if (conf->upstream.busy_buffers_size < size) {
  2281.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2282.              "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
  2283.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  2284.              "one of the \"fastcgi_buffers\"");

  2285.         return NGX_CONF_ERROR;
  2286.     }

  2287.     if (conf->upstream.busy_buffers_size
  2288.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  2289.     {
  2290.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2291.              "\"fastcgi_busy_buffers_size\" must be less than "
  2292.              "the size of all \"fastcgi_buffers\" minus one buffer");

  2293.         return NGX_CONF_ERROR;
  2294.     }


  2295.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  2296.                               prev->upstream.temp_file_write_size_conf,
  2297.                               NGX_CONF_UNSET_SIZE);

  2298.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  2299.         conf->upstream.temp_file_write_size = 2 * size;
  2300.     } else {
  2301.         conf->upstream.temp_file_write_size =
  2302.                                       conf->upstream.temp_file_write_size_conf;
  2303.     }

  2304.     if (conf->upstream.temp_file_write_size < size) {
  2305.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2306.              "\"fastcgi_temp_file_write_size\" must be equal to or greater "
  2307.              "than the maximum of the value of \"fastcgi_buffer_size\" and "
  2308.              "one of the \"fastcgi_buffers\"");

  2309.         return NGX_CONF_ERROR;
  2310.     }


  2311.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  2312.                               prev->upstream.max_temp_file_size_conf,
  2313.                               NGX_CONF_UNSET_SIZE);

  2314.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  2315.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  2316.     } else {
  2317.         conf->upstream.max_temp_file_size =
  2318.                                         conf->upstream.max_temp_file_size_conf;
  2319.     }

  2320.     if (conf->upstream.max_temp_file_size != 0
  2321.         && conf->upstream.max_temp_file_size < size)
  2322.     {
  2323.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2324.              "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
  2325.              "temporary files usage or must be equal to or greater than "
  2326.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  2327.              "one of the \"fastcgi_buffers\"");

  2328.         return NGX_CONF_ERROR;
  2329.     }


  2330.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  2331.                               prev->upstream.ignore_headers,
  2332.                               NGX_CONF_BITMASK_SET);


  2333.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  2334.                               prev->upstream.next_upstream,
  2335.                               (NGX_CONF_BITMASK_SET
  2336.                                |NGX_HTTP_UPSTREAM_FT_ERROR
  2337.                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  2338.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  2339.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  2340.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  2341.     }

  2342.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  2343.                               prev->upstream.temp_path,
  2344.                               &ngx_http_fastcgi_temp_path)
  2345.         != NGX_OK)
  2346.     {
  2347.         return NGX_CONF_ERROR;
  2348.     }

  2349. #if (NGX_HTTP_CACHE)

  2350.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  2351.         ngx_conf_merge_value(conf->upstream.cache,
  2352.                               prev->upstream.cache, 0);

  2353.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  2354.         conf->upstream.cache_value = prev->upstream.cache_value;
  2355.     }

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

  2358.         shm_zone = conf->upstream.cache_zone;

  2359.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2360.                            "\"fastcgi_cache\" zone \"%V\" is unknown",
  2361.                            &shm_zone->shm.name);

  2362.         return NGX_CONF_ERROR;
  2363.     }

  2364.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  2365.                               prev->upstream.cache_min_uses, 1);

  2366.     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
  2367.                               prev->upstream.cache_max_range_offset,
  2368.                               NGX_MAX_OFF_T_VALUE);

  2369.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  2370.                               prev->upstream.cache_use_stale,
  2371.                               (NGX_CONF_BITMASK_SET
  2372.                                |NGX_HTTP_UPSTREAM_FT_OFF));

  2373.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
  2374.         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
  2375.                                          |NGX_HTTP_UPSTREAM_FT_OFF;
  2376.     }

  2377.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  2378.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  2379.     }

  2380.     if (conf->upstream.cache_methods == 0) {
  2381.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  2382.     }

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

  2384.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  2385.                              prev->upstream.cache_bypass, NULL);

  2386.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  2387.                              prev->upstream.no_cache, NULL);

  2388.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  2389.                              prev->upstream.cache_valid, NULL);

  2390.     if (conf->cache_key.value.data == NULL) {
  2391.         conf->cache_key = prev->cache_key;
  2392.     }

  2393.     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
  2394.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  2395.                            "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
  2396.     }

  2397.     ngx_conf_merge_value(conf->upstream.cache_lock,
  2398.                               prev->upstream.cache_lock, 0);

  2399.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  2400.                               prev->upstream.cache_lock_timeout, 5000);

  2401.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  2402.                               prev->upstream.cache_lock_age, 5000);

  2403.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  2404.                               prev->upstream.cache_revalidate, 0);

  2405.     ngx_conf_merge_value(conf->upstream.cache_background_update,
  2406.                               prev->upstream.cache_background_update, 0);

  2407. #endif

  2408.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  2409.                               prev->upstream.pass_request_headers, 1);
  2410.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  2411.                               prev->upstream.pass_request_body, 1);

  2412.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  2413.                               prev->upstream.intercept_errors, 0);

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

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


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

  2417.     hash.max_size = 512;
  2418.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  2419.     hash.name = "fastcgi_hide_headers_hash";

  2420.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  2421.              &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
  2422.         != NGX_OK)
  2423.     {
  2424.         return NGX_CONF_ERROR;
  2425.     }

  2426.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2427.     if (clcf->noname
  2428.         && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
  2429.     {
  2430.         conf->upstream.upstream = prev->upstream.upstream;
  2431.         conf->fastcgi_lengths = prev->fastcgi_lengths;
  2432.         conf->fastcgi_values = prev->fastcgi_values;
  2433.     }

  2434.     if (clcf->lmt_excpt && clcf->handler == NULL
  2435.         && (conf->upstream.upstream || conf->fastcgi_lengths))
  2436.     {
  2437.         clcf->handler = ngx_http_fastcgi_handler;
  2438.     }

  2439. #if (NGX_PCRE)
  2440.     if (conf->split_regex == NULL) {
  2441.         conf->split_regex = prev->split_regex;
  2442.         conf->split_name = prev->split_name;
  2443.     }
  2444. #endif

  2445.     if (conf->params_source == NULL) {
  2446.         conf->params = prev->params;
  2447. #if (NGX_HTTP_CACHE)
  2448.         conf->params_cache = prev->params_cache;
  2449. #endif
  2450.         conf->params_source = prev->params_source;
  2451.     }

  2452.     rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params, NULL);
  2453.     if (rc != NGX_OK) {
  2454.         return NGX_CONF_ERROR;
  2455.     }

  2456. #if (NGX_HTTP_CACHE)

  2457.     if (conf->upstream.cache) {
  2458.         rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
  2459.                                           ngx_http_fastcgi_cache_headers);
  2460.         if (rc != NGX_OK) {
  2461.             return NGX_CONF_ERROR;
  2462.         }
  2463.     }

  2464. #endif

  2465.     /*
  2466.      * special handling to preserve conf->params in the "http" section
  2467.      * to inherit it to all servers
  2468.      */

  2469.     if (prev->params.hash.buckets == NULL
  2470.         && conf->params_source == prev->params_source)
  2471.     {
  2472.         prev->params = conf->params;
  2473. #if (NGX_HTTP_CACHE)
  2474.         prev->params_cache = conf->params_cache;
  2475. #endif
  2476.     }

  2477.     return NGX_CONF_OK;
  2478. }


  2479. static ngx_int_t
  2480. ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
  2481.     ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
  2482. {
  2483.     u_char                       *p;
  2484.     size_t                        size;
  2485.     uintptr_t                    *code;
  2486.     ngx_uint_t                    i, nsrc;
  2487.     ngx_array_t                   headers_names, params_merged;
  2488.     ngx_keyval_t                 *h;
  2489.     ngx_hash_key_t               *hk;
  2490.     ngx_hash_init_t               hash;
  2491.     ngx_http_upstream_param_t    *src, *s;
  2492.     ngx_http_script_compile_t     sc;
  2493.     ngx_http_script_copy_code_t  *copy;

  2494.     if (params->hash.buckets) {
  2495.         return NGX_OK;
  2496.     }

  2497.     if (conf->params_source == NULL && default_params == NULL) {
  2498.         params->hash.buckets = (void *) 1;
  2499.         return NGX_OK;
  2500.     }

  2501.     params->lengths = ngx_array_create(cf->pool, 64, 1);
  2502.     if (params->lengths == NULL) {
  2503.         return NGX_ERROR;
  2504.     }

  2505.     params->values = ngx_array_create(cf->pool, 512, 1);
  2506.     if (params->values == NULL) {
  2507.         return NGX_ERROR;
  2508.     }

  2509.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  2510.         != NGX_OK)
  2511.     {
  2512.         return NGX_ERROR;
  2513.     }

  2514.     if (conf->params_source) {
  2515.         src = conf->params_source->elts;
  2516.         nsrc = conf->params_source->nelts;

  2517.     } else {
  2518.         src = NULL;
  2519.         nsrc = 0;
  2520.     }

  2521.     if (default_params) {
  2522.         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
  2523.                            sizeof(ngx_http_upstream_param_t))
  2524.             != NGX_OK)
  2525.         {
  2526.             return NGX_ERROR;
  2527.         }

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

  2529.             s = ngx_array_push(&params_merged);
  2530.             if (s == NULL) {
  2531.                 return NGX_ERROR;
  2532.             }

  2533.             *s = src[i];
  2534.         }

  2535.         h = default_params;

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

  2537.             src = params_merged.elts;
  2538.             nsrc = params_merged.nelts;

  2539.             for (i = 0; i < nsrc; i++) {
  2540.                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  2541.                     goto next;
  2542.                 }
  2543.             }

  2544.             s = ngx_array_push(&params_merged);
  2545.             if (s == NULL) {
  2546.                 return NGX_ERROR;
  2547.             }

  2548.             s->key = h->key;
  2549.             s->value = h->value;
  2550.             s->skip_empty = 1;

  2551.         next:

  2552.             h++;
  2553.         }

  2554.         src = params_merged.elts;
  2555.         nsrc = params_merged.nelts;
  2556.     }

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

  2558.         if (src[i].key.len > sizeof("HTTP_") - 1
  2559.             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
  2560.         {
  2561.             hk = ngx_array_push(&headers_names);
  2562.             if (hk == NULL) {
  2563.                 return NGX_ERROR;
  2564.             }

  2565.             hk->key.len = src[i].key.len - 5;
  2566.             hk->key.data = src[i].key.data + 5;
  2567.             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
  2568.             hk->value = (void *) 1;

  2569.             if (src[i].value.len == 0) {
  2570.                 continue;
  2571.             }
  2572.         }

  2573.         copy = ngx_array_push_n(params->lengths,
  2574.                                 sizeof(ngx_http_script_copy_code_t));
  2575.         if (copy == NULL) {
  2576.             return NGX_ERROR;
  2577.         }

  2578.         copy->code = (ngx_http_script_code_pt) (void *)
  2579.                                                  ngx_http_script_copy_len_code;
  2580.         copy->len = src[i].key.len;

  2581.         copy = ngx_array_push_n(params->lengths,
  2582.                                 sizeof(ngx_http_script_copy_code_t));
  2583.         if (copy == NULL) {
  2584.             return NGX_ERROR;
  2585.         }

  2586.         copy->code = (ngx_http_script_code_pt) (void *)
  2587.                                                  ngx_http_script_copy_len_code;
  2588.         copy->len = src[i].skip_empty;


  2589.         size = (sizeof(ngx_http_script_copy_code_t)
  2590.                 + src[i].key.len + sizeof(uintptr_t) - 1)
  2591.                & ~(sizeof(uintptr_t) - 1);

  2592.         copy = ngx_array_push_n(params->values, size);
  2593.         if (copy == NULL) {
  2594.             return NGX_ERROR;
  2595.         }

  2596.         copy->code = ngx_http_script_copy_code;
  2597.         copy->len = src[i].key.len;

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


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

  2601.         sc.cf = cf;
  2602.         sc.source = &src[i].value;
  2603.         sc.flushes = &params->flushes;
  2604.         sc.lengths = &params->lengths;
  2605.         sc.values = &params->values;

  2606.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2607.             return NGX_ERROR;
  2608.         }

  2609.         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2610.         if (code == NULL) {
  2611.             return NGX_ERROR;
  2612.         }

  2613.         *code = (uintptr_t) NULL;


  2614.         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
  2615.         if (code == NULL) {
  2616.             return NGX_ERROR;
  2617.         }

  2618.         *code = (uintptr_t) NULL;
  2619.     }

  2620.     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2621.     if (code == NULL) {
  2622.         return NGX_ERROR;
  2623.     }

  2624.     *code = (uintptr_t) NULL;

  2625.     params->number = headers_names.nelts;

  2626.     hash.hash = &params->hash;
  2627.     hash.key = ngx_hash_key_lc;
  2628.     hash.max_size = 512;
  2629.     hash.bucket_size = 64;
  2630.     hash.name = "fastcgi_params_hash";
  2631.     hash.pool = cf->pool;
  2632.     hash.temp_pool = NULL;

  2633.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  2634. }


  2635. static ngx_int_t
  2636. ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
  2637.     ngx_http_variable_value_t *v, uintptr_t data)
  2638. {
  2639.     u_char                       *p;
  2640.     ngx_http_fastcgi_ctx_t       *f;
  2641.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2642.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2643.     f = ngx_http_fastcgi_split(r, flcf);

  2644.     if (f == NULL) {
  2645.         return NGX_ERROR;
  2646.     }

  2647.     if (f->script_name.len == 0
  2648.         || f->script_name.data[f->script_name.len - 1] != '/')
  2649.     {
  2650.         v->len = f->script_name.len;
  2651.         v->valid = 1;
  2652.         v->no_cacheable = 0;
  2653.         v->not_found = 0;
  2654.         v->data = f->script_name.data;

  2655.         return NGX_OK;
  2656.     }

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

  2658.     v->data = ngx_pnalloc(r->pool, v->len);
  2659.     if (v->data == NULL) {
  2660.         return NGX_ERROR;
  2661.     }

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

  2664.     return NGX_OK;
  2665. }


  2666. static ngx_int_t
  2667. ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
  2668.     ngx_http_variable_value_t *v, uintptr_t data)
  2669. {
  2670.     ngx_http_fastcgi_ctx_t       *f;
  2671.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2672.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2673.     f = ngx_http_fastcgi_split(r, flcf);

  2674.     if (f == NULL) {
  2675.         return NGX_ERROR;
  2676.     }

  2677.     v->len = f->path_info.len;
  2678.     v->valid = 1;
  2679.     v->no_cacheable = 0;
  2680.     v->not_found = 0;
  2681.     v->data = f->path_info.data;

  2682.     return NGX_OK;
  2683. }


  2684. static ngx_http_fastcgi_ctx_t *
  2685. ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  2686. {
  2687.     ngx_http_fastcgi_ctx_t       *f;
  2688. #if (NGX_PCRE)
  2689.     ngx_int_t                     n;
  2690.     int                           captures[(1 + 2) * 3];

  2691.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2692.     if (f == NULL) {
  2693.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2694.         if (f == NULL) {
  2695.             return NULL;
  2696.         }

  2697.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2698.     }

  2699.     if (f->script_name.len) {
  2700.         return f;
  2701.     }

  2702.     if (flcf->split_regex == NULL) {
  2703.         f->script_name = r->uri;
  2704.         return f;
  2705.     }

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

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

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

  2712.         return f;
  2713.     }

  2714.     if (n == NGX_REGEX_NO_MATCHED) {
  2715.         f->script_name = r->uri;
  2716.         return f;
  2717.     }

  2718.     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  2719.                   ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
  2720.                   n, &r->uri, &flcf->split_name);
  2721.     return NULL;

  2722. #else

  2723.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2724.     if (f == NULL) {
  2725.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2726.         if (f == NULL) {
  2727.             return NULL;
  2728.         }

  2729.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2730.     }

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

  2732.     return f;

  2733. #endif
  2734. }


  2735. static char *
  2736. ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2737. {
  2738.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2739.     ngx_url_t                   u;
  2740.     ngx_str_t                  *value, *url;
  2741.     ngx_uint_t                  n;
  2742.     ngx_http_core_loc_conf_t   *clcf;
  2743.     ngx_http_script_compile_t   sc;

  2744.     if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
  2745.         return "is duplicate";
  2746.     }

  2747.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2748.     clcf->handler = ngx_http_fastcgi_handler;

  2749.     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
  2750.         clcf->auto_redirect = 1;
  2751.     }

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

  2753.     url = &value[1];

  2754.     n = ngx_http_script_variables_count(url);

  2755.     if (n) {

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

  2757.         sc.cf = cf;
  2758.         sc.source = url;
  2759.         sc.lengths = &flcf->fastcgi_lengths;
  2760.         sc.values = &flcf->fastcgi_values;
  2761.         sc.variables = n;
  2762.         sc.complete_lengths = 1;
  2763.         sc.complete_values = 1;

  2764.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2765.             return NGX_CONF_ERROR;
  2766.         }

  2767.         return NGX_CONF_OK;
  2768.     }

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

  2770.     u.url = value[1];
  2771.     u.no_resolve = 1;

  2772.     flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  2773.     if (flcf->upstream.upstream == NULL) {
  2774.         return NGX_CONF_ERROR;
  2775.     }

  2776.     return NGX_CONF_OK;
  2777. }


  2778. static char *
  2779. ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2780. {
  2781. #if (NGX_PCRE)
  2782.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2783.     ngx_str_t            *value;
  2784.     ngx_regex_compile_t   rc;
  2785.     u_char                errstr[NGX_MAX_CONF_ERRSTR];

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

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

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

  2789.     rc.pattern = value[1];
  2790.     rc.pool = cf->pool;
  2791.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  2792.     rc.err.data = errstr;

  2793.     if (ngx_regex_compile(&rc) != NGX_OK) {
  2794.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
  2795.         return NGX_CONF_ERROR;
  2796.     }

  2797.     if (rc.captures != 2) {
  2798.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2799.                            "pattern \"%V\" must have 2 captures", &value[1]);
  2800.         return NGX_CONF_ERROR;
  2801.     }

  2802.     flcf->split_regex = rc.regex;

  2803.     return NGX_CONF_OK;

  2804. #else

  2805.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2806.                        "\"%V\" requires PCRE library", &cmd->name);
  2807.     return NGX_CONF_ERROR;

  2808. #endif
  2809. }


  2810. static char *
  2811. ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2812. {
  2813.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2814.     ngx_str_t                  *value;
  2815.     ngx_http_script_compile_t   sc;

  2816.     if (flcf->upstream.store != NGX_CONF_UNSET) {
  2817.         return "is duplicate";
  2818.     }

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

  2820.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2821.         flcf->upstream.store = 0;
  2822.         return NGX_CONF_OK;
  2823.     }

  2824.     if (value[1].len == 0) {
  2825.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
  2826.         return NGX_CONF_ERROR;
  2827.     }

  2828. #if (NGX_HTTP_CACHE)
  2829.     if (flcf->upstream.cache > 0) {
  2830.         return "is incompatible with \"fastcgi_cache\"";
  2831.     }
  2832. #endif

  2833.     flcf->upstream.store = 1;

  2834.     if (ngx_strcmp(value[1].data, "on") == 0) {
  2835.         return NGX_CONF_OK;
  2836.     }

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

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

  2840.     sc.cf = cf;
  2841.     sc.source = &value[1];
  2842.     sc.lengths = &flcf->upstream.store_lengths;
  2843.     sc.values = &flcf->upstream.store_values;
  2844.     sc.variables = ngx_http_script_variables_count(&value[1]);
  2845.     sc.complete_lengths = 1;
  2846.     sc.complete_values = 1;

  2847.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  2848.         return NGX_CONF_ERROR;
  2849.     }

  2850.     return NGX_CONF_OK;
  2851. }


  2852. #if (NGX_HTTP_CACHE)

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

  2857.     ngx_str_t                         *value;
  2858.     ngx_http_complex_value_t           cv;
  2859.     ngx_http_compile_complex_value_t   ccv;

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

  2861.     if (flcf->upstream.cache != NGX_CONF_UNSET) {
  2862.         return "is duplicate";
  2863.     }

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

  2868.     if (flcf->upstream.store > 0) {
  2869.         return "is incompatible with \"fastcgi_store\"";
  2870.     }

  2871.     flcf->upstream.cache = 1;

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

  2873.     ccv.cf = cf;
  2874.     ccv.value = &value[1];
  2875.     ccv.complex_value = &cv;

  2876.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2877.         return NGX_CONF_ERROR;
  2878.     }

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

  2880.         flcf->upstream.cache_value = ngx_palloc(cf->pool,
  2881.                                              sizeof(ngx_http_complex_value_t));
  2882.         if (flcf->upstream.cache_value == NULL) {
  2883.             return NGX_CONF_ERROR;
  2884.         }

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

  2886.         return NGX_CONF_OK;
  2887.     }

  2888.     flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  2889.                                                       &ngx_http_fastcgi_module);
  2890.     if (flcf->upstream.cache_zone == NULL) {
  2891.         return NGX_CONF_ERROR;
  2892.     }

  2893.     return NGX_CONF_OK;
  2894. }


  2895. static char *
  2896. ngx_http_fastcgi_cache_key(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_compile_complex_value_t   ccv;

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

  2902.     if (flcf->cache_key.value.data) {
  2903.         return "is duplicate";
  2904.     }

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

  2906.     ccv.cf = cf;
  2907.     ccv.value = &value[1];
  2908.     ccv.complex_value = &flcf->cache_key;

  2909.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2910.         return NGX_CONF_ERROR;
  2911.     }

  2912.     return NGX_CONF_OK;
  2913. }

  2914. #endif


  2915. static char *
  2916. ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
  2917. {
  2918. #if (NGX_FREEBSD)
  2919.     ssize_t *np = data;

  2920.     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
  2921.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2922.                            "\"fastcgi_send_lowat\" must be less than %d "
  2923.                            "(sysctl net.inet.tcp.sendspace)",
  2924.                            ngx_freebsd_net_inet_tcp_sendspace);

  2925.         return NGX_CONF_ERROR;
  2926.     }

  2927. #elif !(NGX_HAVE_SO_SNDLOWAT)
  2928.     ssize_t *np = data;

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

  2931.     *np = 0;

  2932. #endif

  2933.     return NGX_CONF_OK;
  2934. }