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

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.     unsigned                       fastcgi_stdout:1;
  62.     unsigned                       large_stderr:1;

  63.     ngx_array_t                   *split_parts;

  64.     ngx_str_t                      script_name;
  65.     ngx_str_t                      path_info;
  66. } ngx_http_fastcgi_ctx_t;


  67. #define NGX_HTTP_FASTCGI_RESPONDER      1

  68. #define NGX_HTTP_FASTCGI_KEEP_CONN      1

  69. #define NGX_HTTP_FASTCGI_BEGIN_REQUEST  1
  70. #define NGX_HTTP_FASTCGI_ABORT_REQUEST  2
  71. #define NGX_HTTP_FASTCGI_END_REQUEST    3
  72. #define NGX_HTTP_FASTCGI_PARAMS         4
  73. #define NGX_HTTP_FASTCGI_STDIN          5
  74. #define NGX_HTTP_FASTCGI_STDOUT         6
  75. #define NGX_HTTP_FASTCGI_STDERR         7
  76. #define NGX_HTTP_FASTCGI_DATA           8


  77. typedef struct {
  78.     u_char  version;
  79.     u_char  type;
  80.     u_char  request_id_hi;
  81.     u_char  request_id_lo;
  82.     u_char  content_length_hi;
  83.     u_char  content_length_lo;
  84.     u_char  padding_length;
  85.     u_char  reserved;
  86. } ngx_http_fastcgi_header_t;


  87. typedef struct {
  88.     u_char  role_hi;
  89.     u_char  role_lo;
  90.     u_char  flags;
  91.     u_char  reserved[5];
  92. } ngx_http_fastcgi_begin_request_t;


  93. typedef struct {
  94.     u_char  version;
  95.     u_char  type;
  96.     u_char  request_id_hi;
  97.     u_char  request_id_lo;
  98. } ngx_http_fastcgi_header_small_t;


  99. typedef struct {
  100.     ngx_http_fastcgi_header_t         h0;
  101.     ngx_http_fastcgi_begin_request_t  br;
  102.     ngx_http_fastcgi_header_small_t   h1;
  103. } ngx_http_fastcgi_request_start_t;


  104. static ngx_int_t ngx_http_fastcgi_eval(ngx_http_request_t *r,
  105.     ngx_http_fastcgi_loc_conf_t *flcf);
  106. #if (NGX_HTTP_CACHE)
  107. static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r);
  108. #endif
  109. static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
  110. static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
  111. static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
  112. static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data);
  113. static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
  114.     ngx_buf_t *buf);
  115. static ngx_int_t ngx_http_fastcgi_non_buffered_filter(void *data,
  116.     ssize_t bytes);
  117. static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
  118.     ngx_http_fastcgi_ctx_t *f);
  119. static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r);
  120. static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
  121.     ngx_int_t rc);

  122. static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf);
  123. static void *ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf);
  124. static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
  125. static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
  126.     void *parent, void *child);
  127. static ngx_int_t ngx_http_fastcgi_init_params(ngx_conf_t *cf,
  128.     ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_params_t *params,
  129.     ngx_keyval_t *default_params);

  130. static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
  131.     ngx_http_variable_value_t *v, uintptr_t data);
  132. static ngx_int_t ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
  133.     ngx_http_variable_value_t *v, uintptr_t data);
  134. static ngx_http_fastcgi_ctx_t *ngx_http_fastcgi_split(ngx_http_request_t *r,
  135.     ngx_http_fastcgi_loc_conf_t *flcf);

  136. static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
  137.     void *conf);
  138. static char *ngx_http_fastcgi_split_path_info(ngx_conf_t *cf,
  139.     ngx_command_t *cmd, void *conf);
  140. static char *ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
  141.     void *conf);
  142. #if (NGX_HTTP_CACHE)
  143. static char *ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  144.     void *conf);
  145. static char *ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
  146.     void *conf);
  147. #endif

  148. static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
  149.     void *data);


  150. static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
  151.     { ngx_http_fastcgi_lowat_check };


  152. static ngx_conf_bitmask_t  ngx_http_fastcgi_next_upstream_masks[] = {
  153.     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
  154.     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
  155.     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
  156.     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
  157.     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
  158.     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
  159.     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
  160.     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
  161.     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
  162.     { ngx_null_string, 0 }
  163. };


  164. ngx_module_t  ngx_http_fastcgi_module;


  165. static ngx_command_t  ngx_http_fastcgi_commands[] = {

  166.     { ngx_string("fastcgi_pass"),
  167.       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
  168.       ngx_http_fastcgi_pass,
  169.       NGX_HTTP_LOC_CONF_OFFSET,
  170.       0,
  171.       NULL },

  172.     { ngx_string("fastcgi_index"),
  173.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  174.       ngx_conf_set_str_slot,
  175.       NGX_HTTP_LOC_CONF_OFFSET,
  176.       offsetof(ngx_http_fastcgi_loc_conf_t, index),
  177.       NULL },

  178.     { ngx_string("fastcgi_split_path_info"),
  179.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  180.       ngx_http_fastcgi_split_path_info,
  181.       NGX_HTTP_LOC_CONF_OFFSET,
  182.       0,
  183.       NULL },

  184.     { ngx_string("fastcgi_store"),
  185.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  186.       ngx_http_fastcgi_store,
  187.       NGX_HTTP_LOC_CONF_OFFSET,
  188.       0,
  189.       NULL },

  190.     { ngx_string("fastcgi_store_access"),
  191.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
  192.       ngx_conf_set_access_slot,
  193.       NGX_HTTP_LOC_CONF_OFFSET,
  194.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store_access),
  195.       NULL },

  196.     { ngx_string("fastcgi_buffering"),
  197.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  198.       ngx_conf_set_flag_slot,
  199.       NGX_HTTP_LOC_CONF_OFFSET,
  200.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering),
  201.       NULL },

  202.     { ngx_string("fastcgi_ignore_client_abort"),
  203.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  204.       ngx_conf_set_flag_slot,
  205.       NGX_HTTP_LOC_CONF_OFFSET,
  206.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort),
  207.       NULL },

  208.     { ngx_string("fastcgi_bind"),
  209.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  210.       ngx_http_upstream_bind_set_slot,
  211.       NGX_HTTP_LOC_CONF_OFFSET,
  212.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local),
  213.       NULL },

  214.     { ngx_string("fastcgi_connect_timeout"),
  215.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  216.       ngx_conf_set_msec_slot,
  217.       NGX_HTTP_LOC_CONF_OFFSET,
  218.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.connect_timeout),
  219.       NULL },

  220.     { ngx_string("fastcgi_send_timeout"),
  221.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  222.       ngx_conf_set_msec_slot,
  223.       NGX_HTTP_LOC_CONF_OFFSET,
  224.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_timeout),
  225.       NULL },

  226.     { ngx_string("fastcgi_send_lowat"),
  227.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  228.       ngx_conf_set_size_slot,
  229.       NGX_HTTP_LOC_CONF_OFFSET,
  230.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat),
  231.       &ngx_http_fastcgi_lowat_post },

  232.     { ngx_string("fastcgi_buffer_size"),
  233.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  234.       ngx_conf_set_size_slot,
  235.       NGX_HTTP_LOC_CONF_OFFSET,
  236.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size),
  237.       NULL },

  238.     { ngx_string("fastcgi_pass_request_headers"),
  239.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  240.       ngx_conf_set_flag_slot,
  241.       NGX_HTTP_LOC_CONF_OFFSET,
  242.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_headers),
  243.       NULL },

  244.     { ngx_string("fastcgi_pass_request_body"),
  245.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  246.       ngx_conf_set_flag_slot,
  247.       NGX_HTTP_LOC_CONF_OFFSET,
  248.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body),
  249.       NULL },

  250.     { ngx_string("fastcgi_intercept_errors"),
  251.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  252.       ngx_conf_set_flag_slot,
  253.       NGX_HTTP_LOC_CONF_OFFSET,
  254.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.intercept_errors),
  255.       NULL },

  256.     { ngx_string("fastcgi_read_timeout"),
  257.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  258.       ngx_conf_set_msec_slot,
  259.       NGX_HTTP_LOC_CONF_OFFSET,
  260.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout),
  261.       NULL },

  262.     { ngx_string("fastcgi_buffers"),
  263.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  264.       ngx_conf_set_bufs_slot,
  265.       NGX_HTTP_LOC_CONF_OFFSET,
  266.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs),
  267.       NULL },

  268.     { ngx_string("fastcgi_busy_buffers_size"),
  269.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  270.       ngx_conf_set_size_slot,
  271.       NGX_HTTP_LOC_CONF_OFFSET,
  272.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size_conf),
  273.       NULL },

  274.     { ngx_string("fastcgi_force_ranges"),
  275.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  276.       ngx_conf_set_flag_slot,
  277.       NGX_HTTP_LOC_CONF_OFFSET,
  278.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.force_ranges),
  279.       NULL },

  280.     { ngx_string("fastcgi_limit_rate"),
  281.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  282.       ngx_conf_set_size_slot,
  283.       NGX_HTTP_LOC_CONF_OFFSET,
  284.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.limit_rate),
  285.       NULL },

  286. #if (NGX_HTTP_CACHE)

  287.     { ngx_string("fastcgi_cache"),
  288.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  289.       ngx_http_fastcgi_cache,
  290.       NGX_HTTP_LOC_CONF_OFFSET,
  291.       0,
  292.       NULL },

  293.     { ngx_string("fastcgi_cache_key"),
  294.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  295.       ngx_http_fastcgi_cache_key,
  296.       NGX_HTTP_LOC_CONF_OFFSET,
  297.       0,
  298.       NULL },

  299.     { ngx_string("fastcgi_cache_path"),
  300.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  301.       ngx_http_file_cache_set_slot,
  302.       NGX_HTTP_MAIN_CONF_OFFSET,
  303.       offsetof(ngx_http_fastcgi_main_conf_t, caches),
  304.       &ngx_http_fastcgi_module },

  305.     { ngx_string("fastcgi_cache_bypass"),
  306.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  307.       ngx_http_set_predicate_slot,
  308.       NGX_HTTP_LOC_CONF_OFFSET,
  309.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_bypass),
  310.       NULL },

  311.     { ngx_string("fastcgi_no_cache"),
  312.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  313.       ngx_http_set_predicate_slot,
  314.       NGX_HTTP_LOC_CONF_OFFSET,
  315.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.no_cache),
  316.       NULL },

  317.     { ngx_string("fastcgi_cache_valid"),
  318.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  319.       ngx_http_file_cache_valid_set_slot,
  320.       NGX_HTTP_LOC_CONF_OFFSET,
  321.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_valid),
  322.       NULL },

  323.     { ngx_string("fastcgi_cache_min_uses"),
  324.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  325.       ngx_conf_set_num_slot,
  326.       NGX_HTTP_LOC_CONF_OFFSET,
  327.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_min_uses),
  328.       NULL },

  329.     { ngx_string("fastcgi_cache_use_stale"),
  330.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  331.       ngx_conf_set_bitmask_slot,
  332.       NGX_HTTP_LOC_CONF_OFFSET,
  333.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_use_stale),
  334.       &ngx_http_fastcgi_next_upstream_masks },

  335.     { ngx_string("fastcgi_cache_methods"),
  336.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  337.       ngx_conf_set_bitmask_slot,
  338.       NGX_HTTP_LOC_CONF_OFFSET,
  339.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods),
  340.       &ngx_http_upstream_cache_method_mask },

  341.     { ngx_string("fastcgi_cache_lock"),
  342.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  343.       ngx_conf_set_flag_slot,
  344.       NGX_HTTP_LOC_CONF_OFFSET,
  345.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock),
  346.       NULL },

  347.     { ngx_string("fastcgi_cache_lock_timeout"),
  348.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  349.       ngx_conf_set_msec_slot,
  350.       NGX_HTTP_LOC_CONF_OFFSET,
  351.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
  352.       NULL },

  353.     { ngx_string("fastcgi_cache_lock_age"),
  354.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  355.       ngx_conf_set_msec_slot,
  356.       NGX_HTTP_LOC_CONF_OFFSET,
  357.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_age),
  358.       NULL },

  359.     { ngx_string("fastcgi_cache_revalidate"),
  360.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  361.       ngx_conf_set_flag_slot,
  362.       NGX_HTTP_LOC_CONF_OFFSET,
  363.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_revalidate),
  364.       NULL },

  365. #endif

  366.     { ngx_string("fastcgi_temp_path"),
  367.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  368.       ngx_conf_set_path_slot,
  369.       NGX_HTTP_LOC_CONF_OFFSET,
  370.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path),
  371.       NULL },

  372.     { ngx_string("fastcgi_max_temp_file_size"),
  373.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  374.       ngx_conf_set_size_slot,
  375.       NGX_HTTP_LOC_CONF_OFFSET,
  376.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size_conf),
  377.       NULL },

  378.     { ngx_string("fastcgi_temp_file_write_size"),
  379.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  380.       ngx_conf_set_size_slot,
  381.       NGX_HTTP_LOC_CONF_OFFSET,
  382.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size_conf),
  383.       NULL },

  384.     { ngx_string("fastcgi_next_upstream"),
  385.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  386.       ngx_conf_set_bitmask_slot,
  387.       NGX_HTTP_LOC_CONF_OFFSET,
  388.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
  389.       &ngx_http_fastcgi_next_upstream_masks },

  390.     { ngx_string("fastcgi_next_upstream_tries"),
  391.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  392.       ngx_conf_set_num_slot,
  393.       NGX_HTTP_LOC_CONF_OFFSET,
  394.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_tries),
  395.       NULL },

  396.     { ngx_string("fastcgi_next_upstream_timeout"),
  397.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  398.       ngx_conf_set_msec_slot,
  399.       NGX_HTTP_LOC_CONF_OFFSET,
  400.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_timeout),
  401.       NULL },

  402.     { ngx_string("fastcgi_param"),
  403.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
  404.       ngx_http_upstream_param_set_slot,
  405.       NGX_HTTP_LOC_CONF_OFFSET,
  406.       offsetof(ngx_http_fastcgi_loc_conf_t, params_source),
  407.       NULL },

  408.     { ngx_string("fastcgi_pass_header"),
  409.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  410.       ngx_conf_set_str_array_slot,
  411.       NGX_HTTP_LOC_CONF_OFFSET,
  412.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_headers),
  413.       NULL },

  414.     { ngx_string("fastcgi_hide_header"),
  415.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  416.       ngx_conf_set_str_array_slot,
  417.       NGX_HTTP_LOC_CONF_OFFSET,
  418.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers),
  419.       NULL },

  420.     { ngx_string("fastcgi_ignore_headers"),
  421.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  422.       ngx_conf_set_bitmask_slot,
  423.       NGX_HTTP_LOC_CONF_OFFSET,
  424.       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_headers),
  425.       &ngx_http_upstream_ignore_headers_masks },

  426.     { ngx_string("fastcgi_catch_stderr"),
  427.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  428.       ngx_conf_set_str_array_slot,
  429.       NGX_HTTP_LOC_CONF_OFFSET,
  430.       offsetof(ngx_http_fastcgi_loc_conf_t, catch_stderr),
  431.       NULL },

  432.     { ngx_string("fastcgi_keep_conn"),
  433.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  434.       ngx_conf_set_flag_slot,
  435.       NGX_HTTP_LOC_CONF_OFFSET,
  436.       offsetof(ngx_http_fastcgi_loc_conf_t, keep_conn),
  437.       NULL },

  438.       ngx_null_command
  439. };


  440. static ngx_http_module_t  ngx_http_fastcgi_module_ctx = {
  441.     ngx_http_fastcgi_add_variables,        /* preconfiguration */
  442.     NULL,                                  /* postconfiguration */

  443.     ngx_http_fastcgi_create_main_conf,     /* create main configuration */
  444.     NULL,                                  /* init main configuration */

  445.     NULL,                                  /* create server configuration */
  446.     NULL,                                  /* merge server configuration */

  447.     ngx_http_fastcgi_create_loc_conf,      /* create location configuration */
  448.     ngx_http_fastcgi_merge_loc_conf        /* merge location configuration */
  449. };


  450. ngx_module_t  ngx_http_fastcgi_module = {
  451.     NGX_MODULE_V1,
  452.     &ngx_http_fastcgi_module_ctx,          /* module context */
  453.     ngx_http_fastcgi_commands,             /* module directives */
  454.     NGX_HTTP_MODULE,                       /* module type */
  455.     NULL,                                  /* init master */
  456.     NULL,                                  /* init module */
  457.     NULL,                                  /* init process */
  458.     NULL,                                  /* init thread */
  459.     NULL,                                  /* exit thread */
  460.     NULL,                                  /* exit process */
  461.     NULL,                                  /* exit master */
  462.     NGX_MODULE_V1_PADDING
  463. };


  464. static ngx_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
  465.     { 1,                                               /* version */
  466.       NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
  467.       0,                                               /* request_id_hi */
  468.       1,                                               /* request_id_lo */
  469.       0,                                               /* content_length_hi */
  470.       sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
  471.       0,                                               /* padding_length */
  472.       0 },                                             /* reserved */

  473.     { 0,                                               /* role_hi */
  474.       NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
  475.       0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
  476.       { 0, 0, 0, 0, 0 } },                             /* reserved[5] */

  477.     { 1,                                               /* version */
  478.       NGX_HTTP_FASTCGI_PARAMS,                         /* type */
  479.       0,                                               /* request_id_hi */
  480.       1 },                                             /* request_id_lo */

  481. };


  482. static ngx_http_variable_t  ngx_http_fastcgi_vars[] = {

  483.     { ngx_string("fastcgi_script_name"), NULL,
  484.       ngx_http_fastcgi_script_name_variable, 0,
  485.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  486.     { ngx_string("fastcgi_path_info"), NULL,
  487.       ngx_http_fastcgi_path_info_variable, 0,
  488.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  489.     { ngx_null_string, NULL, NULL, 0, 0, 0 }
  490. };


  491. static ngx_str_t  ngx_http_fastcgi_hide_headers[] = {
  492.     ngx_string("Status"),
  493.     ngx_string("X-Accel-Expires"),
  494.     ngx_string("X-Accel-Redirect"),
  495.     ngx_string("X-Accel-Limit-Rate"),
  496.     ngx_string("X-Accel-Buffering"),
  497.     ngx_string("X-Accel-Charset"),
  498.     ngx_null_string
  499. };


  500. #if (NGX_HTTP_CACHE)

  501. static ngx_keyval_t  ngx_http_fastcgi_cache_headers[] = {
  502.     { ngx_string("HTTP_IF_MODIFIED_SINCE"),
  503.       ngx_string("$upstream_cache_last_modified") },
  504.     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
  505.     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
  506.     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
  507.     { ngx_string("HTTP_RANGE"), ngx_string("") },
  508.     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
  509.     { ngx_null_string, ngx_null_string }
  510. };

  511. #endif


  512. static ngx_path_init_t  ngx_http_fastcgi_temp_path = {
  513.     ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
  514. };


  515. static ngx_int_t
  516. ngx_http_fastcgi_handler(ngx_http_request_t *r)
  517. {
  518.     ngx_int_t                      rc;
  519.     ngx_http_upstream_t           *u;
  520.     ngx_http_fastcgi_ctx_t        *f;
  521.     ngx_http_fastcgi_loc_conf_t   *flcf;
  522. #if (NGX_HTTP_CACHE)
  523.     ngx_http_fastcgi_main_conf_t  *fmcf;
  524. #endif

  525.     if (ngx_http_upstream_create(r) != NGX_OK) {
  526.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  527.     }

  528.     f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  529.     if (f == NULL) {
  530.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  531.     }

  532.     ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);

  533.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  534.     if (flcf->fastcgi_lengths) {
  535.         if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {
  536.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  537.         }
  538.     }

  539.     u = r->upstream;

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

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

  543. #if (NGX_HTTP_CACHE)
  544.     fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module);

  545.     u->caches = &fmcf->caches;
  546.     u->create_key = ngx_http_fastcgi_create_key;
  547. #endif

  548.     u->create_request = ngx_http_fastcgi_create_request;
  549.     u->reinit_request = ngx_http_fastcgi_reinit_request;
  550.     u->process_header = ngx_http_fastcgi_process_header;
  551.     u->abort_request = ngx_http_fastcgi_abort_request;
  552.     u->finalize_request = ngx_http_fastcgi_finalize_request;
  553.     r->state = 0;

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

  555.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  556.     if (u->pipe == NULL) {
  557.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  558.     }

  559.     u->pipe->input_filter = ngx_http_fastcgi_input_filter;
  560.     u->pipe->input_ctx = r;

  561.     u->input_filter_init = ngx_http_fastcgi_input_filter_init;
  562.     u->input_filter = ngx_http_fastcgi_non_buffered_filter;
  563.     u->input_filter_ctx = r;

  564.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  565.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  566.         return rc;
  567.     }

  568.     return NGX_DONE;
  569. }


  570. static ngx_int_t
  571. ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  572. {
  573.     ngx_url_t             url;
  574.     ngx_http_upstream_t  *u;

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

  576.     if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
  577.                             flcf->fastcgi_values->elts)
  578.         == NULL)
  579.     {
  580.         return NGX_ERROR;
  581.     }

  582.     url.no_resolve = 1;

  583.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  584.          if (url.err) {
  585.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  586.                           "%s in upstream \"%V\"", url.err, &url.url);
  587.         }

  588.         return NGX_ERROR;
  589.     }

  590.     u = r->upstream;

  591.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  592.     if (u->resolved == NULL) {
  593.         return NGX_ERROR;
  594.     }

  595.     if (url.addrs && url.addrs[0].sockaddr) {
  596.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  597.         u->resolved->socklen = url.addrs[0].socklen;
  598.         u->resolved->naddrs = 1;
  599.         u->resolved->host = url.addrs[0].name;

  600.     } else {
  601.         u->resolved->host = url.host;
  602.         u->resolved->port = url.port;
  603.         u->resolved->no_port = url.no_port;
  604.     }

  605.     return NGX_OK;
  606. }


  607. #if (NGX_HTTP_CACHE)

  608. static ngx_int_t
  609. ngx_http_fastcgi_create_key(ngx_http_request_t *r)
  610. {
  611.     ngx_str_t                    *key;
  612.     ngx_http_fastcgi_loc_conf_t  *flcf;

  613.     key = ngx_array_push(&r->cache->keys);
  614.     if (key == NULL) {
  615.         return NGX_ERROR;
  616.     }

  617.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  618.     if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) {
  619.         return NGX_ERROR;
  620.     }

  621.     return NGX_OK;
  622. }

  623. #endif


  624. static ngx_int_t
  625. ngx_http_fastcgi_create_request(ngx_http_request_t *r)
  626. {
  627.     off_t                         file_pos;
  628.     u_char                        ch, *pos, *lowcase_key;
  629.     size_t                        size, len, key_len, val_len, padding,
  630.                                   allocated;
  631.     ngx_uint_t                    i, n, next, hash, skip_empty, header_params;
  632.     ngx_buf_t                    *b;
  633.     ngx_chain_t                  *cl, *body;
  634.     ngx_list_part_t              *part;
  635.     ngx_table_elt_t              *header, **ignored;
  636.     ngx_http_script_code_pt       code;
  637.     ngx_http_script_engine_t      e, le;
  638.     ngx_http_fastcgi_header_t    *h;
  639.     ngx_http_fastcgi_params_t    *params;
  640.     ngx_http_fastcgi_loc_conf_t  *flcf;
  641.     ngx_http_script_len_code_pt   lcode;

  642.     len = 0;
  643.     header_params = 0;
  644.     ignored = NULL;

  645.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  646. #if (NGX_HTTP_CACHE)
  647.     params = r->upstream->cacheable ? &flcf->params_cache : &flcf->params;
  648. #else
  649.     params = &flcf->params;
  650. #endif

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

  653.         ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
  654.         le.flushed = 1;

  655.         le.ip = params->lengths->elts;
  656.         le.request = r;

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

  658.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  659.             key_len = lcode(&le);

  660.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  661.             skip_empty = lcode(&le);

  662.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  663.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  664.             }
  665.             le.ip += sizeof(uintptr_t);

  666.             if (skip_empty && val_len == 0) {
  667.                 continue;
  668.             }

  669.             len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
  670.         }
  671.     }

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

  673.         allocated = 0;
  674.         lowcase_key = NULL;

  675.         if (params->number) {
  676.             n = 0;
  677.             part = &r->headers_in.headers.part;

  678.             while (part) {
  679.                 n += part->nelts;
  680.                 part = part->next;
  681.             }

  682.             ignored = ngx_palloc(r->pool, n * sizeof(void *));
  683.             if (ignored == NULL) {
  684.                 return NGX_ERROR;
  685.             }
  686.         }

  687.         part = &r->headers_in.headers.part;
  688.         header = part->elts;

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

  690.             if (i >= part->nelts) {
  691.                 if (part->next == NULL) {
  692.                     break;
  693.                 }

  694.                 part = part->next;
  695.                 header = part->elts;
  696.                 i = 0;
  697.             }

  698.             if (params->number) {
  699.                 if (allocated < header[i].key.len) {
  700.                     allocated = header[i].key.len + 16;
  701.                     lowcase_key = ngx_pnalloc(r->pool, allocated);
  702.                     if (lowcase_key == NULL) {
  703.                         return NGX_ERROR;
  704.                     }
  705.                 }

  706.                 hash = 0;

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

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

  711.                     } else if (ch == '-') {
  712.                         ch = '_';
  713.                     }

  714.                     hash = ngx_hash(hash, ch);
  715.                     lowcase_key[n] = ch;
  716.                 }

  717.                 if (ngx_hash_find(&params->hash, hash, lowcase_key, n)) {
  718.                     ignored[header_params++] = &header[i];
  719.                     continue;
  720.                 }

  721.                 n += sizeof("HTTP_") - 1;

  722.             } else {
  723.                 n = sizeof("HTTP_") - 1 + header[i].key.len;
  724.             }

  725.             len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1)
  726.                 + n + header[i].value.len;
  727.         }
  728.     }


  729.     if (len > 65535) {
  730.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  731.                       "fastcgi request record is too big: %uz", len);
  732.         return NGX_ERROR;
  733.     }


  734.     padding = 8 - len % 8;
  735.     padding = (padding == 8) ? 0 : padding;


  736.     size = sizeof(ngx_http_fastcgi_header_t)
  737.            + sizeof(ngx_http_fastcgi_begin_request_t)

  738.            + sizeof(ngx_http_fastcgi_header_t/* NGX_HTTP_FASTCGI_PARAMS */
  739.            + len + padding
  740.            + sizeof(ngx_http_fastcgi_header_t/* NGX_HTTP_FASTCGI_PARAMS */

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


  742.     b = ngx_create_temp_buf(r->pool, size);
  743.     if (b == NULL) {
  744.         return NGX_ERROR;
  745.     }

  746.     cl = ngx_alloc_chain_link(r->pool);
  747.     if (cl == NULL) {
  748.         return NGX_ERROR;
  749.     }

  750.     cl->buf = b;

  751.     ngx_http_fastcgi_request_start.br.flags =
  752.         flcf->keep_conn ? NGX_HTTP_FASTCGI_KEEP_CONN : 0;

  753.     ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
  754.                sizeof(ngx_http_fastcgi_request_start_t));

  755.     h = (ngx_http_fastcgi_header_t *)
  756.              (b->pos + sizeof(ngx_http_fastcgi_header_t)
  757.                      + sizeof(ngx_http_fastcgi_begin_request_t));

  758.     h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  759.     h->content_length_lo = (u_char) (len & 0xff);
  760.     h->padding_length = (u_char) padding;
  761.     h->reserved = 0;

  762.     b->last = b->pos + sizeof(ngx_http_fastcgi_header_t)
  763.                      + sizeof(ngx_http_fastcgi_begin_request_t)
  764.                      + sizeof(ngx_http_fastcgi_header_t);


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

  767.         e.ip = params->values->elts;
  768.         e.pos = b->last;
  769.         e.request = r;
  770.         e.flushed = 1;

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

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

  773.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  774.             key_len = (u_char) lcode(&le);

  775.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  776.             skip_empty = lcode(&le);

  777.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  778.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  779.             }
  780.             le.ip += sizeof(uintptr_t);

  781.             if (skip_empty && val_len == 0) {
  782.                 e.skip = 1;

  783.                 while (*(uintptr_t *) e.ip) {
  784.                     code = *(ngx_http_script_code_pt *) e.ip;
  785.                     code((ngx_http_script_engine_t *) &e);
  786.                 }
  787.                 e.ip += sizeof(uintptr_t);

  788.                 e.skip = 0;

  789.                 continue;
  790.             }

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

  792.             if (val_len > 127) {
  793.                 *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  794.                 *e.pos++ = (u_char) ((val_len >> 16) & 0xff);
  795.                 *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
  796.                 *e.pos++ = (u_char) (val_len & 0xff);

  797.             } else {
  798.                 *e.pos++ = (u_char) val_len;
  799.             }

  800.             while (*(uintptr_t *) e.ip) {
  801.                 code = *(ngx_http_script_code_pt *) e.ip;
  802.                 code((ngx_http_script_engine_t *) &e);
  803.             }
  804.             e.ip += sizeof(uintptr_t);

  805.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  806.                            "fastcgi param: \"%*s: %*s\"",
  807.                            key_len, e.pos - (key_len + val_len),
  808.                            val_len, e.pos - val_len);
  809.         }

  810.         b->last = e.pos;
  811.     }


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

  813.         part = &r->headers_in.headers.part;
  814.         header = part->elts;

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

  816.             if (i >= part->nelts) {
  817.                 if (part->next == NULL) {
  818.                     break;
  819.                 }

  820.                 part = part->next;
  821.                 header = part->elts;
  822.                 i = 0;
  823.             }

  824.             for (n = 0; n < header_params; n++) {
  825.                 if (&header[i] == ignored[n]) {
  826.                     goto next;
  827.                 }
  828.             }

  829.             key_len = sizeof("HTTP_") - 1 + header[i].key.len;
  830.             if (key_len > 127) {
  831.                 *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
  832.                 *b->last++ = (u_char) ((key_len >> 16) & 0xff);
  833.                 *b->last++ = (u_char) ((key_len >> 8) & 0xff);
  834.                 *b->last++ = (u_char) (key_len & 0xff);

  835.             } else {
  836.                 *b->last++ = (u_char) key_len;
  837.             }

  838.             val_len = header[i].value.len;
  839.             if (val_len > 127) {
  840.                 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  841.                 *b->last++ = (u_char) ((val_len >> 16) & 0xff);
  842.                 *b->last++ = (u_char) ((val_len >> 8) & 0xff);
  843.                 *b->last++ = (u_char) (val_len & 0xff);

  844.             } else {
  845.                 *b->last++ = (u_char) val_len;
  846.             }

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

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

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

  852.                 } else if (ch == '-') {
  853.                     ch = '_';
  854.                 }

  855.                 *b->last++ = ch;
  856.             }

  857.             b->last = ngx_copy(b->last, header[i].value.data, val_len);

  858.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  859.                            "fastcgi param: \"%*s: %*s\"",
  860.                            key_len, b->last - (key_len + val_len),
  861.                            val_len, b->last - val_len);
  862.         next:

  863.             continue;
  864.         }
  865.     }


  866.     if (padding) {
  867.         ngx_memzero(b->last, padding);
  868.         b->last += padding;
  869.     }


  870.     h = (ngx_http_fastcgi_header_t *) b->last;
  871.     b->last += sizeof(ngx_http_fastcgi_header_t);

  872.     h->version = 1;
  873.     h->type = NGX_HTTP_FASTCGI_PARAMS;
  874.     h->request_id_hi = 0;
  875.     h->request_id_lo = 1;
  876.     h->content_length_hi = 0;
  877.     h->content_length_lo = 0;
  878.     h->padding_length = 0;
  879.     h->reserved = 0;

  880.     h = (ngx_http_fastcgi_header_t *) b->last;
  881.     b->last += sizeof(ngx_http_fastcgi_header_t);

  882.     if (flcf->upstream.pass_request_body) {
  883.         body = r->upstream->request_bufs;
  884.         r->upstream->request_bufs = cl;

  885. #if (NGX_SUPPRESS_WARN)
  886.         file_pos = 0;
  887.         pos = NULL;
  888. #endif

  889.         while (body) {

  890.             if (body->buf->in_file) {
  891.                 file_pos = body->buf->file_pos;

  892.             } else {
  893.                 pos = body->buf->pos;
  894.             }

  895.             next = 0;

  896.             do {
  897.                 b = ngx_alloc_buf(r->pool);
  898.                 if (b == NULL) {
  899.                     return NGX_ERROR;
  900.                 }

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

  902.                 if (body->buf->in_file) {
  903.                     b->file_pos = file_pos;
  904.                     file_pos += 32 * 1024;

  905.                     if (file_pos >= body->buf->file_last) {
  906.                         file_pos = body->buf->file_last;
  907.                         next = 1;
  908.                     }

  909.                     b->file_last = file_pos;
  910.                     len = (ngx_uint_t) (file_pos - b->file_pos);

  911.                 } else {
  912.                     b->pos = pos;
  913.                     b->start = pos;
  914.                     pos += 32 * 1024;

  915.                     if (pos >= body->buf->last) {
  916.                         pos = body->buf->last;
  917.                         next = 1;
  918.                     }

  919.                     b->last = pos;
  920.                     len = (ngx_uint_t) (pos - b->pos);
  921.                 }

  922.                 padding = 8 - len % 8;
  923.                 padding = (padding == 8) ? 0 : padding;

  924.                 h->version = 1;
  925.                 h->type = NGX_HTTP_FASTCGI_STDIN;
  926.                 h->request_id_hi = 0;
  927.                 h->request_id_lo = 1;
  928.                 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  929.                 h->content_length_lo = (u_char) (len & 0xff);
  930.                 h->padding_length = (u_char) padding;
  931.                 h->reserved = 0;

  932.                 cl->next = ngx_alloc_chain_link(r->pool);
  933.                 if (cl->next == NULL) {
  934.                     return NGX_ERROR;
  935.                 }

  936.                 cl = cl->next;
  937.                 cl->buf = b;

  938.                 b = ngx_create_temp_buf(r->pool,
  939.                                         sizeof(ngx_http_fastcgi_header_t)
  940.                                         + padding);
  941.                 if (b == NULL) {
  942.                     return NGX_ERROR;
  943.                 }

  944.                 if (padding) {
  945.                     ngx_memzero(b->last, padding);
  946.                     b->last += padding;
  947.                 }

  948.                 h = (ngx_http_fastcgi_header_t *) b->last;
  949.                 b->last += sizeof(ngx_http_fastcgi_header_t);

  950.                 cl->next = ngx_alloc_chain_link(r->pool);
  951.                 if (cl->next == NULL) {
  952.                     return NGX_ERROR;
  953.                 }

  954.                 cl = cl->next;
  955.                 cl->buf = b;

  956.             } while (!next);

  957.             body = body->next;
  958.         }

  959.     } else {
  960.         r->upstream->request_bufs = cl;
  961.     }

  962.     h->version = 1;
  963.     h->type = NGX_HTTP_FASTCGI_STDIN;
  964.     h->request_id_hi = 0;
  965.     h->request_id_lo = 1;
  966.     h->content_length_hi = 0;
  967.     h->content_length_lo = 0;
  968.     h->padding_length = 0;
  969.     h->reserved = 0;

  970.     cl->next = NULL;

  971.     return NGX_OK;
  972. }


  973. static ngx_int_t
  974. ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
  975. {
  976.     ngx_http_fastcgi_ctx_t  *f;

  977.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  978.     if (f == NULL) {
  979.         return NGX_OK;
  980.     }

  981.     f->state = ngx_http_fastcgi_st_version;
  982.     f->fastcgi_stdout = 0;
  983.     f->large_stderr = 0;

  984.     if (f->split_parts) {
  985.         f->split_parts->nelts = 0;
  986.     }

  987.     r->state = 0;

  988.     return NGX_OK;
  989. }


  990. static ngx_int_t
  991. ngx_http_fastcgi_process_header(ngx_http_request_t *r)
  992. {
  993.     u_char                         *p, *msg, *start, *last,
  994.                                    *part_start, *part_end;
  995.     size_t                          size;
  996.     ngx_str_t                      *status_line, *pattern;
  997.     ngx_int_t                       rc, status;
  998.     ngx_buf_t                       buf;
  999.     ngx_uint_t                      i;
  1000.     ngx_table_elt_t                *h;
  1001.     ngx_http_upstream_t            *u;
  1002.     ngx_http_fastcgi_ctx_t         *f;
  1003.     ngx_http_upstream_header_t     *hh;
  1004.     ngx_http_fastcgi_loc_conf_t    *flcf;
  1005.     ngx_http_fastcgi_split_part_t  *part;
  1006.     ngx_http_upstream_main_conf_t  *umcf;

  1007.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1008.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1009.     u = r->upstream;

  1010.     for ( ;; ) {

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

  1012.             f->pos = u->buffer.pos;
  1013.             f->last = u->buffer.last;

  1014.             rc = ngx_http_fastcgi_process_record(r, f);

  1015.             u->buffer.pos = f->pos;
  1016.             u->buffer.last = f->last;

  1017.             if (rc == NGX_AGAIN) {
  1018.                 return NGX_AGAIN;
  1019.             }

  1020.             if (rc == NGX_ERROR) {
  1021.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1022.             }

  1023.             if (f->type != NGX_HTTP_FASTCGI_STDOUT
  1024.                 && f->type != NGX_HTTP_FASTCGI_STDERR)
  1025.             {
  1026.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1027.                               "upstream sent unexpected FastCGI record: %d",
  1028.                               f->type);

  1029.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1030.             }

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

  1034.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1035.             }
  1036.         }

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

  1038.             if (u->buffer.pos + f->padding < u->buffer.last) {
  1039.                 f->state = ngx_http_fastcgi_st_version;
  1040.                 u->buffer.pos += f->padding;

  1041.                 continue;
  1042.             }

  1043.             if (u->buffer.pos + f->padding == u->buffer.last) {
  1044.                 f->state = ngx_http_fastcgi_st_version;
  1045.                 u->buffer.pos = u->buffer.last;

  1046.                 return NGX_AGAIN;
  1047.             }

  1048.             f->padding -= u->buffer.last - u->buffer.pos;
  1049.             u->buffer.pos = u->buffer.last;

  1050.             return NGX_AGAIN;
  1051.         }


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

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

  1054.             if (f->length) {
  1055.                 msg = u->buffer.pos;

  1056.                 if (u->buffer.pos + f->length <= u->buffer.last) {
  1057.                     u->buffer.pos += f->length;
  1058.                     f->length = 0;
  1059.                     f->state = ngx_http_fastcgi_st_padding;

  1060.                 } else {
  1061.                     f->length -= u->buffer.last - u->buffer.pos;
  1062.                     u->buffer.pos = u->buffer.last;
  1063.                 }

  1064.                 for (p = u->buffer.pos - 1; msg < p; p--) {
  1065.                     if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
  1066.                         break;
  1067.                     }
  1068.                 }

  1069.                 p++;

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

  1072.                 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1073.                 if (flcf->catch_stderr) {
  1074.                     pattern = flcf->catch_stderr->elts;

  1075.                     for (i = 0; i < flcf->catch_stderr->nelts; i++) {
  1076.                         if (ngx_strnstr(msg, (char *) pattern[i].data,
  1077.                                         p - msg)
  1078.                             != NULL)
  1079.                         {
  1080.                             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1081.                         }
  1082.                     }
  1083.                 }

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

  1085.                     if (!f->fastcgi_stdout) {

  1086.                         /*
  1087.                          * the special handling the large number
  1088.                          * of the PHP warnings to not allocate memory
  1089.                          */

  1090. #if (NGX_HTTP_CACHE)
  1091.                         if (r->cache) {
  1092.                             u->buffer.pos = u->buffer.start
  1093.                                                      + r->cache->header_start;
  1094.                         } else {
  1095.                             u->buffer.pos = u->buffer.start;
  1096.                         }
  1097. #else
  1098.                         u->buffer.pos = u->buffer.start;
  1099. #endif
  1100.                         u->buffer.last = u->buffer.pos;
  1101.                         f->large_stderr = 1;
  1102.                     }

  1103.                     return NGX_AGAIN;
  1104.                 }

  1105.             } else {
  1106.                 f->state = ngx_http_fastcgi_st_padding;
  1107.             }

  1108.             continue;
  1109.         }


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

  1111. #if (NGX_HTTP_CACHE)

  1112.         if (f->large_stderr && r->cache) {
  1113.             u_char                     *start;
  1114.             ssize_t                     len;
  1115.             ngx_http_fastcgi_header_t  *fh;

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

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

  1118.             /*
  1119.              * A tail of large stderr output before HTTP header is placed
  1120.              * in a cache file without a FastCGI record header.
  1121.              * To workaround it we put a dummy FastCGI record header at the
  1122.              * start of the stderr output or update r->cache_header_start,
  1123.              * if there is no enough place for the record header.
  1124.              */

  1125.             if (len >= 0) {
  1126.                 fh = (ngx_http_fastcgi_header_t *) start;
  1127.                 fh->version = 1;
  1128.                 fh->type = NGX_HTTP_FASTCGI_STDERR;
  1129.                 fh->request_id_hi = 0;
  1130.                 fh->request_id_lo = 1;
  1131.                 fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1132.                 fh->content_length_lo = (u_char) (len & 0xff);
  1133.                 fh->padding_length = 0;
  1134.                 fh->reserved = 0;

  1135.             } else {
  1136.                 r->cache->header_start += u->buffer.pos - start
  1137.                                            - sizeof(ngx_http_fastcgi_header_t);
  1138.             }

  1139.             f->large_stderr = 0;
  1140.         }

  1141. #endif

  1142.         f->fastcgi_stdout = 1;

  1143.         start = u->buffer.pos;

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

  1145.             /*
  1146.              * set u->buffer.last to the end of the FastCGI record data
  1147.              * for ngx_http_parse_header_line()
  1148.              */

  1149.             last = u->buffer.last;
  1150.             u->buffer.last = u->buffer.pos + f->length;

  1151.         } else {
  1152.             last = NULL;
  1153.         }

  1154.         for ( ;; ) {

  1155.             part_start = u->buffer.pos;
  1156.             part_end = u->buffer.last;

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

  1158.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1159.                            "http fastcgi parser: %d", rc);

  1160.             if (rc == NGX_AGAIN) {
  1161.                 break;
  1162.             }

  1163.             if (rc == NGX_OK) {

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

  1165.                 h = ngx_list_push(&u->headers_in.headers);
  1166.                 if (h == NULL) {
  1167.                     return NGX_ERROR;
  1168.                 }

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

  1170.                     part = f->split_parts->elts;
  1171.                     size = u->buffer.pos - part_start;

  1172.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1173.                         size += part[i].end - part[i].start;
  1174.                     }

  1175.                     p = ngx_pnalloc(r->pool, size);
  1176.                     if (p == NULL) {
  1177.                         return NGX_ERROR;
  1178.                     }

  1179.                     buf.pos = p;

  1180.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1181.                         p = ngx_cpymem(p, part[i].start,
  1182.                                        part[i].end - part[i].start);
  1183.                     }

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

  1185.                     buf.last = p;

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

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

  1188.                     if (rc != NGX_OK) {
  1189.                         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  1190.                                       "invalid header after joining "
  1191.                                       "FastCGI records");
  1192.                         return NGX_ERROR;
  1193.                     }

  1194.                     h->key.len = r->header_name_end - r->header_name_start;
  1195.                     h->key.data = r->header_name_start;
  1196.                     h->key.data[h->key.len] = '\0';

  1197.                     h->value.len = r->header_end - r->header_start;
  1198.                     h->value.data = r->header_start;
  1199.                     h->value.data[h->value.len] = '\0';

  1200.                     h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
  1201.                     if (h->lowcase_key == NULL) {
  1202.                         return NGX_ERROR;
  1203.                     }

  1204.                 } else {

  1205.                     h->key.len = r->header_name_end - r->header_name_start;
  1206.                     h->value.len = r->header_end - r->header_start;

  1207.                     h->key.data = ngx_pnalloc(r->pool,
  1208.                                               h->key.len + 1 + h->value.len + 1
  1209.                                               + h->key.len);
  1210.                     if (h->key.data == NULL) {
  1211.                         return NGX_ERROR;
  1212.                     }

  1213.                     h->value.data = h->key.data + h->key.len + 1;
  1214.                     h->lowcase_key = h->key.data + h->key.len + 1
  1215.                                      + h->value.len + 1;

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

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

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

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

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

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

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

  1235.                 if (u->buffer.pos < u->buffer.last) {
  1236.                     continue;
  1237.                 }

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

  1239.                 break;
  1240.             }

  1241.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1245.                 if (u->headers_in.status) {
  1246.                     status_line = &u->headers_in.status->value;

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

  1248.                     if (status == NGX_ERROR) {
  1249.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1250.                                       "upstream sent invalid status \"%V\"",
  1251.                                       status_line);
  1252.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1253.                     }

  1254.                     u->headers_in.status_n = status;
  1255.                     u->headers_in.status_line = *status_line;

  1256.                 } else if (u->headers_in.location) {
  1257.                     u->headers_in.status_n = 302;
  1258.                     ngx_str_set(&u->headers_in.status_line,
  1259.                                 "302 Moved Temporarily");

  1260.                 } else {
  1261.                     u->headers_in.status_n = 200;
  1262.                     ngx_str_set(&u->headers_in.status_line, "200 OK");
  1263.                 }

  1264.                 if (u->state && u->state->status == 0) {
  1265.                     u->state->status = u->headers_in.status_n;
  1266.                 }

  1267.                 break;
  1268.             }

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

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

  1272.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1273.         }

  1274.         if (last) {
  1275.             u->buffer.last = last;
  1276.         }

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

  1278.         if (f->length == 0) {
  1279.             f->state = ngx_http_fastcgi_st_padding;
  1280.         }

  1281.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1282.             return NGX_OK;
  1283.         }

  1284.         if (rc == NGX_OK) {
  1285.             continue;
  1286.         }

  1287.         /* rc == NGX_AGAIN */

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

  1290.         if (f->split_parts == NULL) {
  1291.             f->split_parts = ngx_array_create(r->pool, 1,
  1292.                                         sizeof(ngx_http_fastcgi_split_part_t));
  1293.             if (f->split_parts == NULL) {
  1294.                 return NGX_ERROR;
  1295.             }
  1296.         }

  1297.         part = ngx_array_push(f->split_parts);
  1298.         if (part == NULL) {
  1299.             return NGX_ERROR;
  1300.         }

  1301.         part->start = part_start;
  1302.         part->end = part_end;

  1303.         if (u->buffer.pos < u->buffer.last) {
  1304.             continue;
  1305.         }

  1306.         return NGX_AGAIN;
  1307.     }
  1308. }


  1309. static ngx_int_t
  1310. ngx_http_fastcgi_input_filter_init(void *data)
  1311. {
  1312.     ngx_http_request_t           *r = data;
  1313.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1314.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1315.     r->upstream->pipe->length = flcf->keep_conn ?
  1316.                                 (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;

  1317.     return NGX_OK;
  1318. }


  1319. static ngx_int_t
  1320. ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1321. {
  1322.     u_char                       *m, *msg;
  1323.     ngx_int_t                     rc;
  1324.     ngx_buf_t                    *b, **prev;
  1325.     ngx_chain_t                  *cl;
  1326.     ngx_http_request_t           *r;
  1327.     ngx_http_fastcgi_ctx_t       *f;
  1328.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1329.     if (buf->pos == buf->last) {
  1330.         return NGX_OK;
  1331.     }

  1332.     r = p->input_ctx;
  1333.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1334.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1335.     b = NULL;
  1336.     prev = &buf->shadow;

  1337.     f->pos = buf->pos;
  1338.     f->last = buf->last;

  1339.     for ( ;; ) {
  1340.         if (f->state < ngx_http_fastcgi_st_data) {

  1341.             rc = ngx_http_fastcgi_process_record(r, f);

  1342.             if (rc == NGX_AGAIN) {
  1343.                 break;
  1344.             }

  1345.             if (rc == NGX_ERROR) {
  1346.                 return NGX_ERROR;
  1347.             }

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

  1350.                 if (!flcf->keep_conn) {
  1351.                     p->upstream_done = 1;
  1352.                 }

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

  1355.                 continue;
  1356.             }

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

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

  1360.                 if (!flcf->keep_conn) {
  1361.                     p->upstream_done = 1;
  1362.                     break;
  1363.                 }

  1364.                 continue;
  1365.             }
  1366.         }


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

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

  1369.                 if (f->pos + f->padding < f->last) {
  1370.                     p->upstream_done = 1;
  1371.                     break;
  1372.                 }

  1373.                 if (f->pos + f->padding == f->last) {
  1374.                     p->upstream_done = 1;
  1375.                     r->upstream->keepalive = 1;
  1376.                     break;
  1377.                 }

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

  1379.                 break;
  1380.             }

  1381.             if (f->pos + f->padding < f->last) {
  1382.                 f->state = ngx_http_fastcgi_st_version;
  1383.                 f->pos += f->padding;

  1384.                 continue;
  1385.             }

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

  1388.                 break;
  1389.             }

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

  1391.             break;
  1392.         }


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

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

  1395.             if (f->length) {

  1396.                 if (f->pos == f->last) {
  1397.                     break;
  1398.                 }

  1399.                 msg = f->pos;

  1400.                 if (f->pos + f->length <= f->last) {
  1401.                     f->pos += f->length;
  1402.                     f->length = 0;
  1403.                     f->state = ngx_http_fastcgi_st_padding;

  1404.                 } else {
  1405.                     f->length -= f->last - f->pos;
  1406.                     f->pos = f->last;
  1407.                 }

  1408.                 for (m = f->pos - 1; msg < m; m--) {
  1409.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1410.                         break;
  1411.                     }
  1412.                 }

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

  1416.             } else {
  1417.                 f->state = ngx_http_fastcgi_st_padding;
  1418.             }

  1419.             continue;
  1420.         }

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

  1422.             if (f->pos + f->length <= f->last) {
  1423.                 f->state = ngx_http_fastcgi_st_padding;
  1424.                 f->pos += f->length;

  1425.                 continue;
  1426.             }

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

  1428.             break;
  1429.         }


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

  1431.         if (f->pos == f->last) {
  1432.             break;
  1433.         }

  1434.         cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1435.         if (cl == NULL) {
  1436.             return NGX_ERROR;
  1437.         }

  1438.         b = cl->buf;

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

  1440.         b->pos = f->pos;
  1441.         b->start = buf->start;
  1442.         b->end = buf->end;
  1443.         b->tag = p->tag;
  1444.         b->temporary = 1;
  1445.         b->recycled = 1;

  1446.         *prev = b;
  1447.         prev = &b->shadow;

  1448.         if (p->in) {
  1449.             *p->last_in = cl;
  1450.         } else {
  1451.             p->in = cl;
  1452.         }
  1453.         p->last_in = &cl->next;


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

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

  1457.         if (f->pos + f->length <= f->last) {
  1458.             f->state = ngx_http_fastcgi_st_padding;
  1459.             f->pos += f->length;
  1460.             b->last = f->pos;

  1461.             continue;
  1462.         }

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

  1464.         b->last = f->last;

  1465.         break;

  1466.     }

  1467.     if (flcf->keep_conn) {

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

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

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

  1473.         } else {
  1474.             /* ngx_http_fastcgi_st_data */

  1475.             p->length = f->length;
  1476.         }
  1477.     }

  1478.     if (b) {
  1479.         b->shadow = buf;
  1480.         b->last_shadow = 1;

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

  1483.         return NGX_OK;
  1484.     }

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

  1486.     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
  1487.         return NGX_ERROR;
  1488.     }

  1489.     return NGX_OK;
  1490. }


  1491. static ngx_int_t
  1492. ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
  1493. {
  1494.     u_char                  *m, *msg;
  1495.     ngx_int_t                rc;
  1496.     ngx_buf_t               *b, *buf;
  1497.     ngx_chain_t             *cl, **ll;
  1498.     ngx_http_request_t      *r;
  1499.     ngx_http_upstream_t     *u;
  1500.     ngx_http_fastcgi_ctx_t  *f;

  1501.     r = data;
  1502.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1503.     u = r->upstream;
  1504.     buf = &u->buffer;

  1505.     buf->pos = buf->last;
  1506.     buf->last += bytes;

  1507.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1508.         ll = &cl->next;
  1509.     }

  1510.     f->pos = buf->pos;
  1511.     f->last = buf->last;

  1512.     for ( ;; ) {
  1513.         if (f->state < ngx_http_fastcgi_st_data) {

  1514.             rc = ngx_http_fastcgi_process_record(r, f);

  1515.             if (rc == NGX_AGAIN) {
  1516.                 break;
  1517.             }

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

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

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

  1525.                 continue;
  1526.             }
  1527.         }

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

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

  1530.                 if (f->pos + f->padding < f->last) {
  1531.                     u->length = 0;
  1532.                     break;
  1533.                 }

  1534.                 if (f->pos + f->padding == f->last) {
  1535.                     u->length = 0;
  1536.                     u->keepalive = 1;
  1537.                     break;
  1538.                 }

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

  1540.                 break;
  1541.             }

  1542.             if (f->pos + f->padding < f->last) {
  1543.                 f->state = ngx_http_fastcgi_st_version;
  1544.                 f->pos += f->padding;

  1545.                 continue;
  1546.             }

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

  1549.                 break;
  1550.             }

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

  1552.             break;
  1553.         }


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

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

  1556.             if (f->length) {

  1557.                 if (f->pos == f->last) {
  1558.                     break;
  1559.                 }

  1560.                 msg = f->pos;

  1561.                 if (f->pos + f->length <= f->last) {
  1562.                     f->pos += f->length;
  1563.                     f->length = 0;
  1564.                     f->state = ngx_http_fastcgi_st_padding;

  1565.                 } else {
  1566.                     f->length -= f->last - f->pos;
  1567.                     f->pos = f->last;
  1568.                 }

  1569.                 for (m = f->pos - 1; msg < m; m--) {
  1570.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1571.                         break;
  1572.                     }
  1573.                 }

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

  1577.             } else {
  1578.                 f->state = ngx_http_fastcgi_st_padding;
  1579.             }

  1580.             continue;
  1581.         }

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

  1583.             if (f->pos + f->length <= f->last) {
  1584.                 f->state = ngx_http_fastcgi_st_padding;
  1585.                 f->pos += f->length;

  1586.                 continue;
  1587.             }

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

  1589.             break;
  1590.         }


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

  1592.         if (f->pos == f->last) {
  1593.             break;
  1594.         }

  1595.         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1596.         if (cl == NULL) {
  1597.             return NGX_ERROR;
  1598.         }

  1599.         *ll = cl;
  1600.         ll = &cl->next;

  1601.         b = cl->buf;

  1602.         b->flush = 1;
  1603.         b->memory = 1;

  1604.         b->pos = f->pos;
  1605.         b->tag = u->output.tag;

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

  1608.         if (f->pos + f->length <= f->last) {
  1609.             f->state = ngx_http_fastcgi_st_padding;
  1610.             f->pos += f->length;
  1611.             b->last = f->pos;

  1612.             continue;
  1613.         }

  1614.         f->length -= f->last - f->pos;
  1615.         b->last = f->last;

  1616.         break;
  1617.     }

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

  1619.     if (r->subrequest_in_memory) {

  1620.         cl = u->out_bufs;

  1621.         if (cl) {
  1622.             buf->pos = cl->buf->pos;
  1623.         }

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

  1625.         for (cl = u->out_bufs; cl; cl = cl->next) {
  1626.             ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1627.                            "http fastcgi in memory %p-%p %uz",
  1628.                            cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));

  1629.             if (buf->last == cl->buf->pos) {
  1630.                 buf->last = cl->buf->last;
  1631.                 continue;
  1632.             }

  1633.             buf->last = ngx_movemem(buf->last, cl->buf->pos,
  1634.                                     cl->buf->last - cl->buf->pos);

  1635.             cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
  1636.             cl->buf->last = buf->last;
  1637.         }
  1638.     }

  1639.     return NGX_OK;
  1640. }


  1641. static ngx_int_t
  1642. ngx_http_fastcgi_process_record(ngx_http_request_t *r,
  1643.     ngx_http_fastcgi_ctx_t *f)
  1644. {
  1645.     u_char                     ch, *p;
  1646.     ngx_http_fastcgi_state_e   state;

  1647.     state = f->state;

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

  1649.         ch = *p;

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

  1652.         switch (state) {

  1653.         case ngx_http_fastcgi_st_version:
  1654.             if (ch != 1) {
  1655.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1656.                               "upstream sent unsupported FastCGI "
  1657.                               "protocol version: %d", ch);
  1658.                 return NGX_ERROR;
  1659.             }
  1660.             state = ngx_http_fastcgi_st_type;
  1661.             break;

  1662.         case ngx_http_fastcgi_st_type:
  1663.             switch (ch) {
  1664.             case NGX_HTTP_FASTCGI_STDOUT:
  1665.             case NGX_HTTP_FASTCGI_STDERR:
  1666.             case NGX_HTTP_FASTCGI_END_REQUEST:
  1667.                  f->type = (ngx_uint_t) ch;
  1668.                  break;
  1669.             default:
  1670.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1671.                               "upstream sent invalid FastCGI "
  1672.                               "record type: %d", ch);
  1673.                 return NGX_ERROR;

  1674.             }
  1675.             state = ngx_http_fastcgi_st_request_id_hi;
  1676.             break;

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

  1678.         case ngx_http_fastcgi_st_request_id_hi:
  1679.             if (ch != 0) {
  1680.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1681.                               "upstream sent unexpected FastCGI "
  1682.                               "request id high byte: %d", ch);
  1683.                 return NGX_ERROR;
  1684.             }
  1685.             state = ngx_http_fastcgi_st_request_id_lo;
  1686.             break;

  1687.         case ngx_http_fastcgi_st_request_id_lo:
  1688.             if (ch != 1) {
  1689.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1690.                               "upstream sent unexpected FastCGI "
  1691.                               "request id low byte: %d", ch);
  1692.                 return NGX_ERROR;
  1693.             }
  1694.             state = ngx_http_fastcgi_st_content_length_hi;
  1695.             break;

  1696.         case ngx_http_fastcgi_st_content_length_hi:
  1697.             f->length = ch << 8;
  1698.             state = ngx_http_fastcgi_st_content_length_lo;
  1699.             break;

  1700.         case ngx_http_fastcgi_st_content_length_lo:
  1701.             f->length |= (size_t) ch;
  1702.             state = ngx_http_fastcgi_st_padding_length;
  1703.             break;

  1704.         case ngx_http_fastcgi_st_padding_length:
  1705.             f->padding = (size_t) ch;
  1706.             state = ngx_http_fastcgi_st_reserved;
  1707.             break;

  1708.         case ngx_http_fastcgi_st_reserved:
  1709.             state = ngx_http_fastcgi_st_data;

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

  1712.             f->pos = p + 1;
  1713.             f->state = state;

  1714.             return NGX_OK;

  1715.         /* suppress warning */
  1716.         case ngx_http_fastcgi_st_data:
  1717.         case ngx_http_fastcgi_st_padding:
  1718.             break;
  1719.         }
  1720.     }

  1721.     f->state = state;

  1722.     return NGX_AGAIN;
  1723. }


  1724. static void
  1725. ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
  1726. {
  1727.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1728.                    "abort http fastcgi request");

  1729.     return;
  1730. }


  1731. static void
  1732. ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  1733. {
  1734.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1735.                    "finalize http fastcgi request");

  1736.     return;
  1737. }


  1738. static ngx_int_t
  1739. ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
  1740. {
  1741.    ngx_http_variable_t  *var, *v;

  1742.     for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
  1743.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  1744.         if (var == NULL) {
  1745.             return NGX_ERROR;
  1746.         }

  1747.         var->get_handler = v->get_handler;
  1748.         var->data = v->data;
  1749.     }

  1750.     return NGX_OK;
  1751. }


  1752. static void *
  1753. ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
  1754. {
  1755.     ngx_http_fastcgi_main_conf_t  *conf;

  1756.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
  1757.     if (conf == NULL) {
  1758.         return NULL;
  1759.     }

  1760. #if (NGX_HTTP_CACHE)
  1761.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  1762.                        sizeof(ngx_http_file_cache_t *))
  1763.         != NGX_OK)
  1764.     {
  1765.         return NULL;
  1766.     }
  1767. #endif

  1768.     return conf;
  1769. }


  1770. static void *
  1771. ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
  1772. {
  1773.     ngx_http_fastcgi_loc_conf_t  *conf;

  1774.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
  1775.     if (conf == NULL) {
  1776.         return NULL;
  1777.     }

  1778.     /*
  1779.      * set by ngx_pcalloc():
  1780.      *
  1781.      *     conf->upstream.bufs.num = 0;
  1782.      *     conf->upstream.ignore_headers = 0;
  1783.      *     conf->upstream.next_upstream = 0;
  1784.      *     conf->upstream.cache_zone = NULL;
  1785.      *     conf->upstream.cache_use_stale = 0;
  1786.      *     conf->upstream.cache_methods = 0;
  1787.      *     conf->upstream.temp_path = NULL;
  1788.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  1789.      *     conf->upstream.uri = { 0, NULL };
  1790.      *     conf->upstream.location = NULL;
  1791.      *     conf->upstream.store_lengths = NULL;
  1792.      *     conf->upstream.store_values = NULL;
  1793.      *
  1794.      *     conf->index.len = { 0, NULL };
  1795.      */

  1796.     conf->upstream.store = NGX_CONF_UNSET;
  1797.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  1798.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  1799.     conf->upstream.buffering = NGX_CONF_UNSET;
  1800.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  1801.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  1802.     conf->upstream.local = NGX_CONF_UNSET_PTR;

  1803.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  1804.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  1805.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  1806.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  1807.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  1808.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  1809.     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;

  1810.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  1811.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  1812.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  1813.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  1814.     conf->upstream.pass_request_body = NGX_CONF_UNSET;

  1815. #if (NGX_HTTP_CACHE)
  1816.     conf->upstream.cache = NGX_CONF_UNSET;
  1817.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  1818.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  1819.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  1820.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  1821.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  1822.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  1823.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  1824.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  1825. #endif

  1826.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  1827.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  1828.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  1829.     /* "fastcgi_cyclic_temp_file" is disabled */
  1830.     conf->upstream.cyclic_temp_file = 0;

  1831.     conf->upstream.change_buffering = 1;

  1832.     conf->catch_stderr = NGX_CONF_UNSET_PTR;

  1833.     conf->keep_conn = NGX_CONF_UNSET;

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

  1835.     return conf;
  1836. }


  1837. static char *
  1838. ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  1839. {
  1840.     ngx_http_fastcgi_loc_conf_t *prev = parent;
  1841.     ngx_http_fastcgi_loc_conf_t *conf = child;

  1842.     size_t                        size;
  1843.     ngx_int_t                     rc;
  1844.     ngx_hash_init_t               hash;
  1845.     ngx_http_core_loc_conf_t     *clcf;

  1846. #if (NGX_HTTP_CACHE)

  1847.     if (conf->upstream.store > 0) {
  1848.         conf->upstream.cache = 0;
  1849.     }

  1850.     if (conf->upstream.cache > 0) {
  1851.         conf->upstream.store = 0;
  1852.     }

  1853. #endif

  1854.     if (conf->upstream.store == NGX_CONF_UNSET) {
  1855.         ngx_conf_merge_value(conf->upstream.store,
  1856.                               prev->upstream.store, 0);

  1857.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  1858.         conf->upstream.store_values = prev->upstream.store_values;
  1859.     }

  1860.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  1861.                               prev->upstream.store_access, 0600);

  1862.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  1863.                               prev->upstream.next_upstream_tries, 0);

  1864.     ngx_conf_merge_value(conf->upstream.buffering,
  1865.                               prev->upstream.buffering, 1);

  1866.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  1867.                               prev->upstream.ignore_client_abort, 0);

  1868.     ngx_conf_merge_value(conf->upstream.force_ranges,
  1869.                               prev->upstream.force_ranges, 0);

  1870.     ngx_conf_merge_ptr_value(conf->upstream.local,
  1871.                               prev->upstream.local, NULL);

  1872.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  1873.                               prev->upstream.connect_timeout, 60000);

  1874.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  1875.                               prev->upstream.send_timeout, 60000);

  1876.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  1877.                               prev->upstream.read_timeout, 60000);

  1878.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  1879.                               prev->upstream.next_upstream_timeout, 0);

  1880.     ngx_conf_merge_size_value(conf->upstream.send_lowat,
  1881.                               prev->upstream.send_lowat, 0);

  1882.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  1883.                               prev->upstream.buffer_size,
  1884.                               (size_t) ngx_pagesize);

  1885.     ngx_conf_merge_size_value(conf->upstream.limit_rate,
  1886.                               prev->upstream.limit_rate, 0);


  1887.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  1888.                               8, ngx_pagesize);

  1889.     if (conf->upstream.bufs.num < 2) {
  1890.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1891.                            "there must be at least 2 \"fastcgi_buffers\"");
  1892.         return NGX_CONF_ERROR;
  1893.     }


  1894.     size = conf->upstream.buffer_size;
  1895.     if (size < conf->upstream.bufs.size) {
  1896.         size = conf->upstream.bufs.size;
  1897.     }


  1898.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  1899.                               prev->upstream.busy_buffers_size_conf,
  1900.                               NGX_CONF_UNSET_SIZE);

  1901.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  1902.         conf->upstream.busy_buffers_size = 2 * size;
  1903.     } else {
  1904.         conf->upstream.busy_buffers_size =
  1905.                                          conf->upstream.busy_buffers_size_conf;
  1906.     }

  1907.     if (conf->upstream.busy_buffers_size < size) {
  1908.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1909.              "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
  1910.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  1911.              "one of the \"fastcgi_buffers\"");

  1912.         return NGX_CONF_ERROR;
  1913.     }

  1914.     if (conf->upstream.busy_buffers_size
  1915.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  1916.     {
  1917.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1918.              "\"fastcgi_busy_buffers_size\" must be less than "
  1919.              "the size of all \"fastcgi_buffers\" minus one buffer");

  1920.         return NGX_CONF_ERROR;
  1921.     }


  1922.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  1923.                               prev->upstream.temp_file_write_size_conf,
  1924.                               NGX_CONF_UNSET_SIZE);

  1925.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  1926.         conf->upstream.temp_file_write_size = 2 * size;
  1927.     } else {
  1928.         conf->upstream.temp_file_write_size =
  1929.                                       conf->upstream.temp_file_write_size_conf;
  1930.     }

  1931.     if (conf->upstream.temp_file_write_size < size) {
  1932.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1933.              "\"fastcgi_temp_file_write_size\" must be equal to or greater "
  1934.              "than the maximum of the value of \"fastcgi_buffer_size\" and "
  1935.              "one of the \"fastcgi_buffers\"");

  1936.         return NGX_CONF_ERROR;
  1937.     }


  1938.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  1939.                               prev->upstream.max_temp_file_size_conf,
  1940.                               NGX_CONF_UNSET_SIZE);

  1941.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  1942.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  1943.     } else {
  1944.         conf->upstream.max_temp_file_size =
  1945.                                         conf->upstream.max_temp_file_size_conf;
  1946.     }

  1947.     if (conf->upstream.max_temp_file_size != 0
  1948.         && conf->upstream.max_temp_file_size < size)
  1949.     {
  1950.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1951.              "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
  1952.              "temporary files usage or must be equal to or greater than "
  1953.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  1954.              "one of the \"fastcgi_buffers\"");

  1955.         return NGX_CONF_ERROR;
  1956.     }


  1957.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  1958.                               prev->upstream.ignore_headers,
  1959.                               NGX_CONF_BITMASK_SET);


  1960.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  1961.                               prev->upstream.next_upstream,
  1962.                               (NGX_CONF_BITMASK_SET
  1963.                                |NGX_HTTP_UPSTREAM_FT_ERROR
  1964.                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  1965.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  1966.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  1967.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  1968.     }

  1969.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  1970.                               prev->upstream.temp_path,
  1971.                               &ngx_http_fastcgi_temp_path)
  1972.         != NGX_OK)
  1973.     {
  1974.         return NGX_CONF_ERROR;
  1975.     }

  1976. #if (NGX_HTTP_CACHE)

  1977.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  1978.         ngx_conf_merge_value(conf->upstream.cache,
  1979.                               prev->upstream.cache, 0);

  1980.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  1981.         conf->upstream.cache_value = prev->upstream.cache_value;
  1982.     }

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

  1985.         shm_zone = conf->upstream.cache_zone;

  1986.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1987.                            "\"fastcgi_cache\" zone \"%V\" is unknown",
  1988.                            &shm_zone->shm.name);

  1989.         return NGX_CONF_ERROR;
  1990.     }

  1991.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  1992.                               prev->upstream.cache_min_uses, 1);

  1993.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  1994.                               prev->upstream.cache_use_stale,
  1995.                               (NGX_CONF_BITMASK_SET
  1996.                                |NGX_HTTP_UPSTREAM_FT_OFF));

  1997.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
  1998.         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
  1999.                                          |NGX_HTTP_UPSTREAM_FT_OFF;
  2000.     }

  2001.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  2002.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  2003.     }

  2004.     if (conf->upstream.cache_methods == 0) {
  2005.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  2006.     }

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

  2008.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  2009.                              prev->upstream.cache_bypass, NULL);

  2010.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  2011.                              prev->upstream.no_cache, NULL);

  2012.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  2013.                              prev->upstream.cache_valid, NULL);

  2014.     if (conf->cache_key.value.data == NULL) {
  2015.         conf->cache_key = prev->cache_key;
  2016.     }

  2017.     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
  2018.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  2019.                            "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
  2020.     }

  2021.     ngx_conf_merge_value(conf->upstream.cache_lock,
  2022.                               prev->upstream.cache_lock, 0);

  2023.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  2024.                               prev->upstream.cache_lock_timeout, 5000);

  2025.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  2026.                               prev->upstream.cache_lock_age, 5000);

  2027.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  2028.                               prev->upstream.cache_revalidate, 0);

  2029. #endif

  2030.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  2031.                               prev->upstream.pass_request_headers, 1);
  2032.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  2033.                               prev->upstream.pass_request_body, 1);

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

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

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


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

  2039.     hash.max_size = 512;
  2040.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  2041.     hash.name = "fastcgi_hide_headers_hash";

  2042.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  2043.              &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
  2044.         != NGX_OK)
  2045.     {
  2046.         return NGX_CONF_ERROR;
  2047.     }

  2048.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2049.     if (clcf->noname
  2050.         && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
  2051.     {
  2052.         conf->upstream.upstream = prev->upstream.upstream;
  2053.         conf->fastcgi_lengths = prev->fastcgi_lengths;
  2054.         conf->fastcgi_values = prev->fastcgi_values;
  2055.     }

  2056.     if (clcf->lmt_excpt && clcf->handler == NULL
  2057.         && (conf->upstream.upstream || conf->fastcgi_lengths))
  2058.     {
  2059.         clcf->handler = ngx_http_fastcgi_handler;
  2060.     }

  2061. #if (NGX_PCRE)
  2062.     if (conf->split_regex == NULL) {
  2063.         conf->split_regex = prev->split_regex;
  2064.         conf->split_name = prev->split_name;
  2065.     }
  2066. #endif

  2067.     if (conf->params_source == NULL) {
  2068.         conf->params = prev->params;
  2069. #if (NGX_HTTP_CACHE)
  2070.         conf->params_cache = prev->params_cache;
  2071. #endif
  2072.         conf->params_source = prev->params_source;
  2073.     }

  2074.     rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params, NULL);
  2075.     if (rc != NGX_OK) {
  2076.         return NGX_CONF_ERROR;
  2077.     }

  2078. #if (NGX_HTTP_CACHE)

  2079.     if (conf->upstream.cache) {
  2080.         rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
  2081.                                           ngx_http_fastcgi_cache_headers);
  2082.         if (rc != NGX_OK) {
  2083.             return NGX_CONF_ERROR;
  2084.         }
  2085.     }

  2086. #endif

  2087.     return NGX_CONF_OK;
  2088. }


  2089. static ngx_int_t
  2090. ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
  2091.     ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
  2092. {
  2093.     u_char                       *p;
  2094.     size_t                        size;
  2095.     uintptr_t                    *code;
  2096.     ngx_uint_t                    i, nsrc;
  2097.     ngx_array_t                   headers_names, params_merged;
  2098.     ngx_keyval_t                 *h;
  2099.     ngx_hash_key_t               *hk;
  2100.     ngx_hash_init_t               hash;
  2101.     ngx_http_upstream_param_t    *src, *s;
  2102.     ngx_http_script_compile_t     sc;
  2103.     ngx_http_script_copy_code_t  *copy;

  2104.     if (params->hash.buckets) {
  2105.         return NGX_OK;
  2106.     }

  2107.     if (conf->params_source == NULL && default_params == NULL) {
  2108.         params->hash.buckets = (void *) 1;
  2109.         return NGX_OK;
  2110.     }

  2111.     params->lengths = ngx_array_create(cf->pool, 64, 1);
  2112.     if (params->lengths == NULL) {
  2113.         return NGX_ERROR;
  2114.     }

  2115.     params->values = ngx_array_create(cf->pool, 512, 1);
  2116.     if (params->values == NULL) {
  2117.         return NGX_ERROR;
  2118.     }

  2119.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  2120.         != NGX_OK)
  2121.     {
  2122.         return NGX_ERROR;
  2123.     }

  2124.     if (conf->params_source) {
  2125.         src = conf->params_source->elts;
  2126.         nsrc = conf->params_source->nelts;

  2127.     } else {
  2128.         src = NULL;
  2129.         nsrc = 0;
  2130.     }

  2131.     if (default_params) {
  2132.         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
  2133.                            sizeof(ngx_http_upstream_param_t))
  2134.             != NGX_OK)
  2135.         {
  2136.             return NGX_ERROR;
  2137.         }

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

  2139.             s = ngx_array_push(&params_merged);
  2140.             if (s == NULL) {
  2141.                 return NGX_ERROR;
  2142.             }

  2143.             *s = src[i];
  2144.         }

  2145.         h = default_params;

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

  2147.             src = params_merged.elts;
  2148.             nsrc = params_merged.nelts;

  2149.             for (i = 0; i < nsrc; i++) {
  2150.                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  2151.                     goto next;
  2152.                 }
  2153.             }

  2154.             s = ngx_array_push(&params_merged);
  2155.             if (s == NULL) {
  2156.                 return NGX_ERROR;
  2157.             }

  2158.             s->key = h->key;
  2159.             s->value = h->value;
  2160.             s->skip_empty = 1;

  2161.         next:

  2162.             h++;
  2163.         }

  2164.         src = params_merged.elts;
  2165.         nsrc = params_merged.nelts;
  2166.     }

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

  2168.         if (src[i].key.len > sizeof("HTTP_") - 1
  2169.             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
  2170.         {
  2171.             hk = ngx_array_push(&headers_names);
  2172.             if (hk == NULL) {
  2173.                 return NGX_ERROR;
  2174.             }

  2175.             hk->key.len = src[i].key.len - 5;
  2176.             hk->key.data = src[i].key.data + 5;
  2177.             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
  2178.             hk->value = (void *) 1;

  2179.             if (src[i].value.len == 0) {
  2180.                 continue;
  2181.             }
  2182.         }

  2183.         copy = ngx_array_push_n(params->lengths,
  2184.                                 sizeof(ngx_http_script_copy_code_t));
  2185.         if (copy == NULL) {
  2186.             return NGX_ERROR;
  2187.         }

  2188.         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
  2189.         copy->len = src[i].key.len;

  2190.         copy = ngx_array_push_n(params->lengths,
  2191.                                 sizeof(ngx_http_script_copy_code_t));
  2192.         if (copy == NULL) {
  2193.             return NGX_ERROR;
  2194.         }

  2195.         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
  2196.         copy->len = src[i].skip_empty;


  2197.         size = (sizeof(ngx_http_script_copy_code_t)
  2198.                 + src[i].key.len + sizeof(uintptr_t) - 1)
  2199.                & ~(sizeof(uintptr_t) - 1);

  2200.         copy = ngx_array_push_n(params->values, size);
  2201.         if (copy == NULL) {
  2202.             return NGX_ERROR;
  2203.         }

  2204.         copy->code = ngx_http_script_copy_code;
  2205.         copy->len = src[i].key.len;

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


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

  2209.         sc.cf = cf;
  2210.         sc.source = &src[i].value;
  2211.         sc.flushes = &params->flushes;
  2212.         sc.lengths = &params->lengths;
  2213.         sc.values = &params->values;

  2214.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2215.             return NGX_ERROR;
  2216.         }

  2217.         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2218.         if (code == NULL) {
  2219.             return NGX_ERROR;
  2220.         }

  2221.         *code = (uintptr_t) NULL;


  2222.         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
  2223.         if (code == NULL) {
  2224.             return NGX_ERROR;
  2225.         }

  2226.         *code = (uintptr_t) NULL;
  2227.     }

  2228.     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2229.     if (code == NULL) {
  2230.         return NGX_ERROR;
  2231.     }

  2232.     *code = (uintptr_t) NULL;

  2233.     params->number = headers_names.nelts;

  2234.     hash.hash = &params->hash;
  2235.     hash.key = ngx_hash_key_lc;
  2236.     hash.max_size = 512;
  2237.     hash.bucket_size = 64;
  2238.     hash.name = "fastcgi_params_hash";
  2239.     hash.pool = cf->pool;
  2240.     hash.temp_pool = NULL;

  2241.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  2242. }


  2243. static ngx_int_t
  2244. ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
  2245.     ngx_http_variable_value_t *v, uintptr_t data)
  2246. {
  2247.     u_char                       *p;
  2248.     ngx_http_fastcgi_ctx_t       *f;
  2249.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2250.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2251.     f = ngx_http_fastcgi_split(r, flcf);

  2252.     if (f == NULL) {
  2253.         return NGX_ERROR;
  2254.     }

  2255.     if (f->script_name.len == 0
  2256.         || f->script_name.data[f->script_name.len - 1] != '/')
  2257.     {
  2258.         v->len = f->script_name.len;
  2259.         v->valid = 1;
  2260.         v->no_cacheable = 0;
  2261.         v->not_found = 0;
  2262.         v->data = f->script_name.data;

  2263.         return NGX_OK;
  2264.     }

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

  2266.     v->data = ngx_pnalloc(r->pool, v->len);
  2267.     if (v->data == NULL) {
  2268.         return NGX_ERROR;
  2269.     }

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

  2272.     return NGX_OK;
  2273. }


  2274. static ngx_int_t
  2275. ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
  2276.     ngx_http_variable_value_t *v, uintptr_t data)
  2277. {
  2278.     ngx_http_fastcgi_ctx_t       *f;
  2279.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2280.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2281.     f = ngx_http_fastcgi_split(r, flcf);

  2282.     if (f == NULL) {
  2283.         return NGX_ERROR;
  2284.     }

  2285.     v->len = f->path_info.len;
  2286.     v->valid = 1;
  2287.     v->no_cacheable = 0;
  2288.     v->not_found = 0;
  2289.     v->data = f->path_info.data;

  2290.     return NGX_OK;
  2291. }


  2292. static ngx_http_fastcgi_ctx_t *
  2293. ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  2294. {
  2295.     ngx_http_fastcgi_ctx_t       *f;
  2296. #if (NGX_PCRE)
  2297.     ngx_int_t                     n;
  2298.     int                           captures[(1 + 2) * 3];

  2299.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2300.     if (f == NULL) {
  2301.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2302.         if (f == NULL) {
  2303.             return NULL;
  2304.         }

  2305.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2306.     }

  2307.     if (f->script_name.len) {
  2308.         return f;
  2309.     }

  2310.     if (flcf->split_regex == NULL) {
  2311.         f->script_name = r->uri;
  2312.         return f;
  2313.     }

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

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

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

  2320.         return f;
  2321.     }

  2322.     if (n == NGX_REGEX_NO_MATCHED) {
  2323.         f->script_name = r->uri;
  2324.         return f;
  2325.     }

  2326.     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  2327.                   ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
  2328.                   n, &r->uri, &flcf->split_name);
  2329.     return NULL;

  2330. #else

  2331.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2332.     if (f == NULL) {
  2333.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2334.         if (f == NULL) {
  2335.             return NULL;
  2336.         }

  2337.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2338.     }

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

  2340.     return f;

  2341. #endif
  2342. }


  2343. static char *
  2344. ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2345. {
  2346.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2347.     ngx_url_t                   u;
  2348.     ngx_str_t                  *value, *url;
  2349.     ngx_uint_t                  n;
  2350.     ngx_http_core_loc_conf_t   *clcf;
  2351.     ngx_http_script_compile_t   sc;

  2352.     if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
  2353.         return "is duplicate";
  2354.     }

  2355.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2356.     clcf->handler = ngx_http_fastcgi_handler;

  2357.     if (clcf->name.data[clcf->name.len - 1] == '/') {
  2358.         clcf->auto_redirect = 1;
  2359.     }

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

  2361.     url = &value[1];

  2362.     n = ngx_http_script_variables_count(url);

  2363.     if (n) {

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

  2365.         sc.cf = cf;
  2366.         sc.source = url;
  2367.         sc.lengths = &flcf->fastcgi_lengths;
  2368.         sc.values = &flcf->fastcgi_values;
  2369.         sc.variables = n;
  2370.         sc.complete_lengths = 1;
  2371.         sc.complete_values = 1;

  2372.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2373.             return NGX_CONF_ERROR;
  2374.         }

  2375.         return NGX_CONF_OK;
  2376.     }

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

  2378.     u.url = value[1];
  2379.     u.no_resolve = 1;

  2380.     flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  2381.     if (flcf->upstream.upstream == NULL) {
  2382.         return NGX_CONF_ERROR;
  2383.     }

  2384.     return NGX_CONF_OK;
  2385. }


  2386. static char *
  2387. ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2388. {
  2389. #if (NGX_PCRE)
  2390.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2391.     ngx_str_t            *value;
  2392.     ngx_regex_compile_t   rc;
  2393.     u_char                errstr[NGX_MAX_CONF_ERRSTR];

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

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

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

  2397.     rc.pattern = value[1];
  2398.     rc.pool = cf->pool;
  2399.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  2400.     rc.err.data = errstr;

  2401.     if (ngx_regex_compile(&rc) != NGX_OK) {
  2402.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
  2403.         return NGX_CONF_ERROR;
  2404.     }

  2405.     if (rc.captures != 2) {
  2406.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2407.                            "pattern \"%V\" must have 2 captures", &value[1]);
  2408.         return NGX_CONF_ERROR;
  2409.     }

  2410.     flcf->split_regex = rc.regex;

  2411.     return NGX_CONF_OK;

  2412. #else

  2413.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2414.                        "\"%V\" requires PCRE library", &cmd->name);
  2415.     return NGX_CONF_ERROR;

  2416. #endif
  2417. }


  2418. static char *
  2419. ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2420. {
  2421.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2422.     ngx_str_t                  *value;
  2423.     ngx_http_script_compile_t   sc;

  2424.     if (flcf->upstream.store != NGX_CONF_UNSET) {
  2425.         return "is duplicate";
  2426.     }

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

  2428.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2429.         flcf->upstream.store = 0;
  2430.         return NGX_CONF_OK;
  2431.     }

  2432. #if (NGX_HTTP_CACHE)
  2433.     if (flcf->upstream.cache > 0) {
  2434.         return "is incompatible with \"fastcgi_cache\"";
  2435.     }
  2436. #endif

  2437.     flcf->upstream.store = 1;

  2438.     if (ngx_strcmp(value[1].data, "on") == 0) {
  2439.         return NGX_CONF_OK;
  2440.     }

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

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

  2444.     sc.cf = cf;
  2445.     sc.source = &value[1];
  2446.     sc.lengths = &flcf->upstream.store_lengths;
  2447.     sc.values = &flcf->upstream.store_values;
  2448.     sc.variables = ngx_http_script_variables_count(&value[1]);
  2449.     sc.complete_lengths = 1;
  2450.     sc.complete_values = 1;

  2451.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  2452.         return NGX_CONF_ERROR;
  2453.     }

  2454.     return NGX_CONF_OK;
  2455. }


  2456. #if (NGX_HTTP_CACHE)

  2457. static char *
  2458. ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2459. {
  2460.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2461.     ngx_str_t                         *value;
  2462.     ngx_http_complex_value_t           cv;
  2463.     ngx_http_compile_complex_value_t   ccv;

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

  2465.     if (flcf->upstream.cache != NGX_CONF_UNSET) {
  2466.         return "is duplicate";
  2467.     }

  2468.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2469.         flcf->upstream.cache = 0;
  2470.         return NGX_CONF_OK;
  2471.     }

  2472.     if (flcf->upstream.store > 0) {
  2473.         return "is incompatible with \"fastcgi_store\"";
  2474.     }

  2475.     flcf->upstream.cache = 1;

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

  2477.     ccv.cf = cf;
  2478.     ccv.value = &value[1];
  2479.     ccv.complex_value = &cv;

  2480.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2481.         return NGX_CONF_ERROR;
  2482.     }

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

  2484.         flcf->upstream.cache_value = ngx_palloc(cf->pool,
  2485.                                              sizeof(ngx_http_complex_value_t));
  2486.         if (flcf->upstream.cache_value == NULL) {
  2487.             return NGX_CONF_ERROR;
  2488.         }

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

  2490.         return NGX_CONF_OK;
  2491.     }

  2492.     flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  2493.                                                       &ngx_http_fastcgi_module);
  2494.     if (flcf->upstream.cache_zone == NULL) {
  2495.         return NGX_CONF_ERROR;
  2496.     }

  2497.     return NGX_CONF_OK;
  2498. }


  2499. static char *
  2500. ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2501. {
  2502.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2503.     ngx_str_t                         *value;
  2504.     ngx_http_compile_complex_value_t   ccv;

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

  2506.     if (flcf->cache_key.value.data) {
  2507.         return "is duplicate";
  2508.     }

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

  2510.     ccv.cf = cf;
  2511.     ccv.value = &value[1];
  2512.     ccv.complex_value = &flcf->cache_key;

  2513.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2514.         return NGX_CONF_ERROR;
  2515.     }

  2516.     return NGX_CONF_OK;
  2517. }

  2518. #endif


  2519. static char *
  2520. ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
  2521. {
  2522. #if (NGX_FREEBSD)
  2523.     ssize_t *np = data;

  2524.     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
  2525.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2526.                            "\"fastcgi_send_lowat\" must be less than %d "
  2527.                            "(sysctl net.inet.tcp.sendspace)",
  2528.                            ngx_freebsd_net_inet_tcp_sendspace);

  2529.         return NGX_CONF_ERROR;
  2530.     }

  2531. #elif !(NGX_HAVE_SO_SNDLOWAT)
  2532.     ssize_t *np = data;

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

  2535.     *np = 0;

  2536. #endif

  2537.     return NGX_CONF_OK;
  2538. }