src/http/modules/ngx_http_fastcgi_module.c - nginx

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


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


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


  8. typedef struct {
  9.     ngx_array_t                    caches;  /* ngx_http_file_cache_t * */
  10. } ngx_http_fastcgi_main_conf_t;


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


  18. typedef struct {
  19.     ngx_http_upstream_conf_t       upstream;

  20.     ngx_str_t                      index;

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

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

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

  29.     ngx_flag_t                     keep_conn;

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

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


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


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


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

  61.     off_t                          rest;

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

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

  68.     ngx_array_t                   *split_parts;

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


  72. #define NGX_HTTP_FASTCGI_RESPONDER      1

  73. #define NGX_HTTP_FASTCGI_KEEP_CONN      1

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


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


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


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


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


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

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

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

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

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


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


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


  173. ngx_module_t  ngx_http_fastcgi_module;


  174. static ngx_command_t  ngx_http_fastcgi_commands[] = {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  307. #if (NGX_HTTP_CACHE)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  398. #endif

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

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

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

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

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

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

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

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

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

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

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

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

  471.       ngx_null_command
  472. };


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

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

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

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


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


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

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

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

  514. };


  515. static ngx_http_variable_t  ngx_http_fastcgi_vars[] = {

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

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

  522.       ngx_http_null_variable
  523. };


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


  533. static ngx_keyval_t  ngx_http_fastcgi_headers[] = {
  534.     { ngx_string("HTTP_HOST"),
  535.       ngx_string("$host$is_request_port$request_port") },
  536.     { ngx_null_string, ngx_null_string }
  537. };


  538. #if (NGX_HTTP_CACHE)

  539. static ngx_keyval_t  ngx_http_fastcgi_cache_headers[] = {
  540.     { ngx_string("HTTP_HOST"),
  541.       ngx_string("$host$is_request_port$request_port") },
  542.     { ngx_string("HTTP_IF_MODIFIED_SINCE"),
  543.       ngx_string("$upstream_cache_last_modified") },
  544.     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
  545.     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
  546.     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
  547.     { ngx_string("HTTP_RANGE"), ngx_string("") },
  548.     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
  549.     { ngx_null_string, ngx_null_string }
  550. };

  551. #endif


  552. static ngx_path_init_t  ngx_http_fastcgi_temp_path = {
  553.     ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
  554. };


  555. static ngx_int_t
  556. ngx_http_fastcgi_handler(ngx_http_request_t *r)
  557. {
  558.     ngx_int_t                      rc;
  559.     ngx_http_upstream_t           *u;
  560.     ngx_http_fastcgi_ctx_t        *f;
  561.     ngx_http_fastcgi_loc_conf_t   *flcf;
  562. #if (NGX_HTTP_CACHE)
  563.     ngx_http_fastcgi_main_conf_t  *fmcf;
  564. #endif

  565.     if (ngx_http_upstream_create(r) != NGX_OK) {
  566.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  567.     }

  568.     f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  569.     if (f == NULL) {
  570.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  571.     }

  572.     ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);

  573.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  574.     if (flcf->fastcgi_lengths) {
  575.         if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {
  576.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  577.         }
  578.     }

  579.     u = r->upstream;

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

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

  583. #if (NGX_HTTP_CACHE)
  584.     fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module);

  585.     u->caches = &fmcf->caches;
  586.     u->create_key = ngx_http_fastcgi_create_key;
  587. #endif

  588.     u->create_request = ngx_http_fastcgi_create_request;
  589.     u->reinit_request = ngx_http_fastcgi_reinit_request;
  590.     u->process_header = ngx_http_fastcgi_process_header;
  591.     u->abort_request = ngx_http_fastcgi_abort_request;
  592.     u->finalize_request = ngx_http_fastcgi_finalize_request;
  593.     r->state = 0;

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

  595.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  596.     if (u->pipe == NULL) {
  597.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  598.     }

  599.     u->pipe->input_filter = ngx_http_fastcgi_input_filter;
  600.     u->pipe->input_ctx = r;

  601.     u->input_filter_init = ngx_http_fastcgi_input_filter_init;
  602.     u->input_filter = ngx_http_fastcgi_non_buffered_filter;
  603.     u->input_filter_ctx = r;

  604.     if (!flcf->upstream.request_buffering
  605.         && flcf->upstream.pass_request_body)
  606.     {
  607.         r->request_body_no_buffering = 1;
  608.     }

  609.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  610.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  611.         return rc;
  612.     }

  613.     return NGX_DONE;
  614. }


  615. static ngx_int_t
  616. ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  617. {
  618.     ngx_url_t             url;
  619.     ngx_http_upstream_t  *u;

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

  621.     if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
  622.                             flcf->fastcgi_values->elts)
  623.         == NULL)
  624.     {
  625.         return NGX_ERROR;
  626.     }

  627.     url.no_resolve = 1;

  628.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  629.         if (url.err) {
  630.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  631.                           "%s in upstream \"%V\"", url.err, &url.url);
  632.         }

  633.         return NGX_ERROR;
  634.     }

  635.     u = r->upstream;

  636.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  637.     if (u->resolved == NULL) {
  638.         return NGX_ERROR;
  639.     }

  640.     if (url.addrs) {
  641.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  642.         u->resolved->socklen = url.addrs[0].socklen;
  643.         u->resolved->name = url.addrs[0].name;
  644.         u->resolved->naddrs = 1;
  645.     }

  646.     u->resolved->host = url.host;
  647.     u->resolved->port = url.port;
  648.     u->resolved->no_port = url.no_port;

  649.     return NGX_OK;
  650. }


  651. #if (NGX_HTTP_CACHE)

  652. static ngx_int_t
  653. ngx_http_fastcgi_create_key(ngx_http_request_t *r)
  654. {
  655.     ngx_str_t                    *key;
  656.     ngx_http_fastcgi_loc_conf_t  *flcf;

  657.     key = ngx_array_push(&r->cache->keys);
  658.     if (key == NULL) {
  659.         return NGX_ERROR;
  660.     }

  661.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  662.     if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) {
  663.         return NGX_ERROR;
  664.     }

  665.     return NGX_OK;
  666. }

  667. #endif


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

  687.     len = 0;
  688.     header_params = 0;
  689.     ignored = NULL;

  690.     u = r->upstream;

  691.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  692. #if (NGX_HTTP_CACHE)
  693.     params = u->cacheable ? &flcf->params_cache : &flcf->params;
  694. #else
  695.     params = &flcf->params;
  696. #endif

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

  699.         ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
  700.         le.flushed = 1;

  701.         le.ip = params->lengths->elts;
  702.         le.request = r;

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

  704.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  705.             key_len = lcode(&le);

  706.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  707.             skip_empty = lcode(&le);

  708.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  709.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  710.             }
  711.             le.ip += sizeof(uintptr_t);

  712.             if (skip_empty && val_len == 0) {
  713.                 continue;
  714.             }

  715.             len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
  716.         }
  717.     }

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

  719.         allocated = 0;
  720.         lowcase_key = NULL;

  721.         if (ngx_http_link_multi_headers(r) != NGX_OK) {
  722.             return NGX_ERROR;
  723.         }

  724.         if (params->number || r->headers_in.multi) {
  725.             n = 0;
  726.             part = &r->headers_in.headers.part;

  727.             while (part) {
  728.                 n += part->nelts;
  729.                 part = part->next;
  730.             }

  731.             ignored = ngx_palloc(r->pool, n * sizeof(void *));
  732.             if (ignored == NULL) {
  733.                 return NGX_ERROR;
  734.             }
  735.         }

  736.         part = &r->headers_in.headers.part;
  737.         header = part->elts;

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

  739.             if (i >= part->nelts) {
  740.                 if (part->next == NULL) {
  741.                     break;
  742.                 }

  743.                 part = part->next;
  744.                 header = part->elts;
  745.                 i = 0;
  746.             }

  747.             for (n = 0; n < header_params; n++) {
  748.                 if (&header[i] == ignored[n]) {
  749.                     goto next_length;
  750.                 }
  751.             }

  752.             if (params->number) {
  753.                 if (allocated < header[i].key.len) {
  754.                     allocated = header[i].key.len + 16;
  755.                     lowcase_key = ngx_pnalloc(r->pool, allocated);
  756.                     if (lowcase_key == NULL) {
  757.                         return NGX_ERROR;
  758.                     }
  759.                 }

  760.                 hash = 0;

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

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

  765.                     } else if (ch == '-') {
  766.                         ch = '_';
  767.                     }

  768.                     hash = ngx_hash(hash, ch);
  769.                     lowcase_key[n] = ch;
  770.                 }

  771.                 if (ngx_hash_find(&params->hash, hash, lowcase_key, n)) {
  772.                     ignored[header_params++] = &header[i];
  773.                     continue;
  774.                 }
  775.             }

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

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

  778.             for (hn = header[i].next; hn; hn = hn->next) {
  779.                 val_len += hn->value.len + 2;
  780.                 ignored[header_params++] = hn;
  781.             }

  782.             len += ((key_len > 127) ? 4 : 1) + key_len
  783.                    + ((val_len > 127) ? 4 : 1) + val_len;

  784.         next_length:

  785.             continue;
  786.         }
  787.     }


  788.     if (len > 65535) {
  789.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  790.                       "fastcgi request record is too big: %uz", len);
  791.         return NGX_ERROR;
  792.     }


  793.     padding = 8 - len % 8;
  794.     padding = (padding == 8) ? 0 : padding;


  795.     size = sizeof(ngx_http_fastcgi_header_t)
  796.            + sizeof(ngx_http_fastcgi_begin_request_t)

  797.            + sizeof(ngx_http_fastcgi_header_t/* NGX_HTTP_FASTCGI_PARAMS */
  798.            + len + padding
  799.            + sizeof(ngx_http_fastcgi_header_t/* NGX_HTTP_FASTCGI_PARAMS */

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


  801.     b = ngx_create_temp_buf(r->pool, size);
  802.     if (b == NULL) {
  803.         return NGX_ERROR;
  804.     }

  805.     cl = ngx_alloc_chain_link(r->pool);
  806.     if (cl == NULL) {
  807.         return NGX_ERROR;
  808.     }

  809.     cl->buf = b;

  810.     ngx_http_fastcgi_request_start.br.flags =
  811.         flcf->keep_conn ? NGX_HTTP_FASTCGI_KEEP_CONN : 0;

  812.     ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
  813.                sizeof(ngx_http_fastcgi_request_start_t));

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

  817.     h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  818.     h->content_length_lo = (u_char) (len & 0xff);
  819.     h->padding_length = (u_char) padding;
  820.     h->reserved = 0;

  821.     b->last = b->pos + sizeof(ngx_http_fastcgi_header_t)
  822.                      + sizeof(ngx_http_fastcgi_begin_request_t)
  823.                      + sizeof(ngx_http_fastcgi_header_t);


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

  826.         e.ip = params->values->elts;
  827.         e.pos = b->last;
  828.         e.request = r;
  829.         e.flushed = 1;

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

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

  832.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  833.             key_len = (u_char) lcode(&le);

  834.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  835.             skip_empty = lcode(&le);

  836.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  837.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  838.             }
  839.             le.ip += sizeof(uintptr_t);

  840.             if (skip_empty && val_len == 0) {
  841.                 e.skip = 1;

  842.                 while (*(uintptr_t *) e.ip) {
  843.                     code = *(ngx_http_script_code_pt *) e.ip;
  844.                     code((ngx_http_script_engine_t *) &e);
  845.                 }
  846.                 e.ip += sizeof(uintptr_t);

  847.                 e.skip = 0;

  848.                 continue;
  849.             }

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

  851.             if (val_len > 127) {
  852.                 *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  853.                 *e.pos++ = (u_char) ((val_len >> 16) & 0xff);
  854.                 *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
  855.                 *e.pos++ = (u_char) (val_len & 0xff);

  856.             } else {
  857.                 *e.pos++ = (u_char) val_len;
  858.             }

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

  864.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  865.                            "fastcgi param: \"%*s: %*s\"",
  866.                            key_len, e.pos - (key_len + val_len),
  867.                            val_len, e.pos - val_len);
  868.         }

  869.         b->last = e.pos;
  870.     }


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

  872.         part = &r->headers_in.headers.part;
  873.         header = part->elts;

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

  875.             if (i >= part->nelts) {
  876.                 if (part->next == NULL) {
  877.                     break;
  878.                 }

  879.                 part = part->next;
  880.                 header = part->elts;
  881.                 i = 0;
  882.             }

  883.             for (n = 0; n < header_params; n++) {
  884.                 if (&header[i] == ignored[n]) {
  885.                     goto next_value;
  886.                 }
  887.             }

  888.             key_len = sizeof("HTTP_") - 1 + header[i].key.len;
  889.             if (key_len > 127) {
  890.                 *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
  891.                 *b->last++ = (u_char) ((key_len >> 16) & 0xff);
  892.                 *b->last++ = (u_char) ((key_len >> 8) & 0xff);
  893.                 *b->last++ = (u_char) (key_len & 0xff);

  894.             } else {
  895.                 *b->last++ = (u_char) key_len;
  896.             }

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

  898.             for (hn = header[i].next; hn; hn = hn->next) {
  899.                 val_len += hn->value.len + 2;
  900.             }

  901.             if (val_len > 127) {
  902.                 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
  903.                 *b->last++ = (u_char) ((val_len >> 16) & 0xff);
  904.                 *b->last++ = (u_char) ((val_len >> 8) & 0xff);
  905.                 *b->last++ = (u_char) (val_len & 0xff);

  906.             } else {
  907.                 *b->last++ = (u_char) val_len;
  908.             }

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

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

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

  914.                 } else if (ch == '-') {
  915.                     ch = '_';
  916.                 }

  917.                 *b->last++ = ch;
  918.             }

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

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

  922.                 if (header[i].key.len == sizeof("Cookie") - 1
  923.                     && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
  924.                                        sizeof("Cookie") - 1)
  925.                        == 0)
  926.                 {
  927.                     sep = ';';

  928.                 } else {
  929.                     sep = ',';
  930.                 }

  931.                 for (hn = header[i].next; hn; hn = hn->next) {
  932.                     *b->last++ = sep;
  933.                     *b->last++ = ' ';
  934.                     b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
  935.                 }
  936.             }

  937.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  938.                            "fastcgi param: \"%*s: %*s\"",
  939.                            key_len, b->last - (key_len + val_len),
  940.                            val_len, b->last - val_len);
  941.         next_value:

  942.             continue;
  943.         }
  944.     }


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


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

  951.     h->version = 1;
  952.     h->type = NGX_HTTP_FASTCGI_PARAMS;
  953.     h->request_id_hi = 0;
  954.     h->request_id_lo = 1;
  955.     h->content_length_hi = 0;
  956.     h->content_length_lo = 0;
  957.     h->padding_length = 0;
  958.     h->reserved = 0;

  959.     if (r->request_body_no_buffering) {

  960.         u->request_bufs = cl;

  961.         u->output.output_filter = ngx_http_fastcgi_body_output_filter;
  962.         u->output.filter_ctx = r;

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

  964.         body = u->request_bufs;
  965.         u->request_bufs = cl;

  966. #if (NGX_SUPPRESS_WARN)
  967.         file_pos = 0;
  968.         pos = NULL;
  969. #endif

  970.         while (body) {

  971.             if (ngx_buf_special(body->buf)) {
  972.                 body = body->next;
  973.                 continue;
  974.             }

  975.             if (body->buf->in_file) {
  976.                 file_pos = body->buf->file_pos;

  977.             } else {
  978.                 pos = body->buf->pos;
  979.             }

  980.             next = 0;

  981.             do {
  982.                 b = ngx_alloc_buf(r->pool);
  983.                 if (b == NULL) {
  984.                     return NGX_ERROR;
  985.                 }

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

  987.                 if (body->buf->in_file) {
  988.                     b->file_pos = file_pos;
  989.                     file_pos += 32 * 1024;

  990.                     if (file_pos >= body->buf->file_last) {
  991.                         file_pos = body->buf->file_last;
  992.                         next = 1;
  993.                     }

  994.                     b->file_last = file_pos;
  995.                     len = (ngx_uint_t) (file_pos - b->file_pos);

  996.                 } else {
  997.                     b->pos = pos;
  998.                     b->start = pos;
  999.                     pos += 32 * 1024;

  1000.                     if (pos >= body->buf->last) {
  1001.                         pos = body->buf->last;
  1002.                         next = 1;
  1003.                     }

  1004.                     b->last = pos;
  1005.                     len = (ngx_uint_t) (pos - b->pos);
  1006.                 }

  1007.                 padding = 8 - len % 8;
  1008.                 padding = (padding == 8) ? 0 : padding;

  1009.                 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1010.                 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1011.                 h->version = 1;
  1012.                 h->type = NGX_HTTP_FASTCGI_STDIN;
  1013.                 h->request_id_hi = 0;
  1014.                 h->request_id_lo = 1;
  1015.                 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1016.                 h->content_length_lo = (u_char) (len & 0xff);
  1017.                 h->padding_length = (u_char) padding;
  1018.                 h->reserved = 0;

  1019.                 cl->next = ngx_alloc_chain_link(r->pool);
  1020.                 if (cl->next == NULL) {
  1021.                     return NGX_ERROR;
  1022.                 }

  1023.                 cl = cl->next;
  1024.                 cl->buf = b;

  1025.                 b = ngx_create_temp_buf(r->pool,
  1026.                                         sizeof(ngx_http_fastcgi_header_t)
  1027.                                         + padding);
  1028.                 if (b == NULL) {
  1029.                     return NGX_ERROR;
  1030.                 }

  1031.                 if (padding) {
  1032.                     ngx_memzero(b->last, padding);
  1033.                     b->last += padding;
  1034.                 }

  1035.                 cl->next = ngx_alloc_chain_link(r->pool);
  1036.                 if (cl->next == NULL) {
  1037.                     return NGX_ERROR;
  1038.                 }

  1039.                 cl = cl->next;
  1040.                 cl->buf = b;

  1041.             } while (!next);

  1042.             body = body->next;
  1043.         }

  1044.     } else {
  1045.         u->request_bufs = cl;
  1046.     }

  1047.     if (!r->request_body_no_buffering) {
  1048.         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1049.         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1050.         h->version = 1;
  1051.         h->type = NGX_HTTP_FASTCGI_STDIN;
  1052.         h->request_id_hi = 0;
  1053.         h->request_id_lo = 1;
  1054.         h->content_length_hi = 0;
  1055.         h->content_length_lo = 0;
  1056.         h->padding_length = 0;
  1057.         h->reserved = 0;
  1058.     }

  1059.     cl->next = NULL;

  1060.     return NGX_OK;
  1061. }


  1062. static ngx_int_t
  1063. ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
  1064. {
  1065.     ngx_http_fastcgi_ctx_t  *f;

  1066.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1067.     if (f == NULL) {
  1068.         return NGX_OK;
  1069.     }

  1070.     f->state = ngx_http_fastcgi_st_version;
  1071.     f->fastcgi_stdout = 0;
  1072.     f->large_stderr = 0;

  1073.     if (f->split_parts) {
  1074.         f->split_parts->nelts = 0;
  1075.     }

  1076.     r->state = 0;

  1077.     return NGX_OK;
  1078. }


  1079. static ngx_int_t
  1080. ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in)
  1081. {
  1082.     ngx_http_request_t  *r = data;

  1083.     off_t                       file_pos;
  1084.     u_char                     *pos, *start;
  1085.     size_t                      len, padding;
  1086.     ngx_buf_t                  *b;
  1087.     ngx_int_t                   rc;
  1088.     ngx_uint_t                  next, last;
  1089.     ngx_chain_t                *cl, *tl, *out, **ll;
  1090.     ngx_http_fastcgi_ctx_t     *f;
  1091.     ngx_http_fastcgi_header_t  *h;

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

  1094.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1095.     if (in == NULL) {
  1096.         out = in;
  1097.         goto out;
  1098.     }

  1099.     out = NULL;
  1100.     ll = &out;

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

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

  1105.         f->header_sent = 1;

  1106.         tl = ngx_alloc_chain_link(r->pool);
  1107.         if (tl == NULL) {
  1108.             return NGX_ERROR;
  1109.         }

  1110.         tl->buf = in->buf;
  1111.         *ll = tl;
  1112.         ll = &tl->next;

  1113.         in = in->next;

  1114.         if (in == NULL) {
  1115.             tl->next = NULL;
  1116.             goto out;
  1117.         }
  1118.     }

  1119.     cl = ngx_chain_get_free_buf(r->pool, &f->free);
  1120.     if (cl == NULL) {
  1121.         return NGX_ERROR;
  1122.     }

  1123.     b = cl->buf;

  1124.     b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1125.     b->temporary = 1;

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

  1128.         b->start = ngx_palloc(r->pool,
  1129.                               sizeof(ngx_http_fastcgi_header_t) + 7);
  1130.         if (b->start == NULL) {
  1131.             return NGX_ERROR;
  1132.         }

  1133.         b->pos = b->start;
  1134.         b->last = b->start;

  1135.         b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
  1136.     }

  1137.     *ll = cl;

  1138.     last = 0;
  1139.     padding = 0;

  1140. #if (NGX_SUPPRESS_WARN)
  1141.     file_pos = 0;
  1142.     pos = NULL;
  1143. #endif

  1144.     while (in) {

  1145.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1146.                        "fastcgi output in  l:%d f:%d %p, pos %p, size: %z "
  1147.                        "file: %O, size: %O",
  1148.                        in->buf->last_buf,
  1149.                        in->buf->in_file,
  1150.                        in->buf->start, in->buf->pos,
  1151.                        in->buf->last - in->buf->pos,
  1152.                        in->buf->file_pos,
  1153.                        in->buf->file_last - in->buf->file_pos);

  1154.         if (in->buf->last_buf) {
  1155.             last = 1;
  1156.         }

  1157.         if (ngx_buf_special(in->buf)) {
  1158.             in = in->next;
  1159.             continue;
  1160.         }

  1161.         if (in->buf->in_file) {
  1162.             file_pos = in->buf->file_pos;

  1163.         } else {
  1164.             pos = in->buf->pos;
  1165.         }

  1166.         next = 0;

  1167.         do {
  1168.             tl = ngx_chain_get_free_buf(r->pool, &f->free);
  1169.             if (tl == NULL) {
  1170.                 return NGX_ERROR;
  1171.             }

  1172.             b = tl->buf;
  1173.             start = b->start;

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

  1175.             /*
  1176.              * restore b->start to preserve memory allocated in the buffer,
  1177.              * to reuse it later for headers and padding
  1178.              */

  1179.             b->start = start;

  1180.             if (in->buf->in_file) {
  1181.                 b->file_pos = file_pos;
  1182.                 file_pos += 32 * 1024;

  1183.                 if (file_pos >= in->buf->file_last) {
  1184.                     file_pos = in->buf->file_last;
  1185.                     next = 1;
  1186.                 }

  1187.                 b->file_last = file_pos;
  1188.                 len = (ngx_uint_t) (file_pos - b->file_pos);

  1189.             } else {
  1190.                 b->pos = pos;
  1191.                 pos += 32 * 1024;

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

  1196.                 b->last = pos;
  1197.                 len = (ngx_uint_t) (pos - b->pos);
  1198.             }

  1199.             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1200.             b->shadow = in->buf;
  1201.             b->last_shadow = next;

  1202.             b->last_buf = 0;
  1203.             b->last_in_chain = 0;

  1204.             padding = 8 - len % 8;
  1205.             padding = (padding == 8) ? 0 : padding;

  1206.             h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1207.             cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1208.             h->version = 1;
  1209.             h->type = NGX_HTTP_FASTCGI_STDIN;
  1210.             h->request_id_hi = 0;
  1211.             h->request_id_lo = 1;
  1212.             h->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1213.             h->content_length_lo = (u_char) (len & 0xff);
  1214.             h->padding_length = (u_char) padding;
  1215.             h->reserved = 0;

  1216.             cl->next = tl;
  1217.             cl = tl;

  1218.             tl = ngx_chain_get_free_buf(r->pool, &f->free);
  1219.             if (tl == NULL) {
  1220.                 return NGX_ERROR;
  1221.             }

  1222.             b = tl->buf;

  1223.             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
  1224.             b->temporary = 1;

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

  1227.                 b->start = ngx_palloc(r->pool,
  1228.                                       sizeof(ngx_http_fastcgi_header_t) + 7);
  1229.                 if (b->start == NULL) {
  1230.                     return NGX_ERROR;
  1231.                 }

  1232.                 b->pos = b->start;
  1233.                 b->last = b->start;

  1234.                 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
  1235.             }

  1236.             if (padding) {
  1237.                 ngx_memzero(b->last, padding);
  1238.                 b->last += padding;
  1239.             }

  1240.             cl->next = tl;
  1241.             cl = tl;

  1242.         } while (!next);

  1243.         in = in->next;
  1244.     }

  1245.     if (last) {
  1246.         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
  1247.         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);

  1248.         h->version = 1;
  1249.         h->type = NGX_HTTP_FASTCGI_STDIN;
  1250.         h->request_id_hi = 0;
  1251.         h->request_id_lo = 1;
  1252.         h->content_length_hi = 0;
  1253.         h->content_length_lo = 0;
  1254.         h->padding_length = 0;
  1255.         h->reserved = 0;

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

  1257.     } else if (padding == 0) {
  1258.         /* TODO: do not allocate buffers instead */
  1259.         cl->buf->temporary = 0;
  1260.         cl->buf->sync = 1;
  1261.     }

  1262.     cl->next = NULL;

  1263. out:

  1264. #if (NGX_DEBUG)

  1265.     for (cl = out; cl; cl = cl->next) {
  1266.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1267.                        "fastcgi output out l:%d f:%d %p, pos %p, size: %z "
  1268.                        "file: %O, size: %O",
  1269.                        cl->buf->last_buf,
  1270.                        cl->buf->in_file,
  1271.                        cl->buf->start, cl->buf->pos,
  1272.                        cl->buf->last - cl->buf->pos,
  1273.                        cl->buf->file_pos,
  1274.                        cl->buf->file_last - cl->buf->file_pos);
  1275.     }

  1276. #endif

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

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

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

  1281.         /* mark original buffers as sent */

  1282.         if (cl->buf->shadow) {
  1283.             if (cl->buf->last_shadow) {
  1284.                 b = cl->buf->shadow;
  1285.                 b->pos = b->last;
  1286.             }

  1287.             cl->buf->shadow = NULL;
  1288.         }
  1289.     }

  1290.     return rc;
  1291. }


  1292. static ngx_int_t
  1293. ngx_http_fastcgi_process_header(ngx_http_request_t *r)
  1294. {
  1295.     u_char                         *p, *msg, *start, *last,
  1296.                                    *part_start, *part_end;
  1297.     size_t                          size;
  1298.     ngx_str_t                      *status_line, *pattern;
  1299.     ngx_int_t                       rc, status;
  1300.     ngx_buf_t                       buf;
  1301.     ngx_uint_t                      i;
  1302.     ngx_table_elt_t                *h;
  1303.     ngx_http_upstream_t            *u;
  1304.     ngx_http_fastcgi_ctx_t         *f;
  1305.     ngx_http_upstream_header_t     *hh;
  1306.     ngx_http_fastcgi_loc_conf_t    *flcf;
  1307.     ngx_http_fastcgi_split_part_t  *part;
  1308.     ngx_http_upstream_main_conf_t  *umcf;

  1309.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1310.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1311.     u = r->upstream;

  1312.     for ( ;; ) {

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

  1314.             f->pos = u->buffer.pos;
  1315.             f->last = u->buffer.last;

  1316.             rc = ngx_http_fastcgi_process_record(r, f);

  1317.             u->buffer.pos = f->pos;
  1318.             u->buffer.last = f->last;

  1319.             if (rc == NGX_AGAIN) {
  1320.                 return NGX_AGAIN;
  1321.             }

  1322.             if (rc == NGX_ERROR) {
  1323.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1324.             }

  1325.             if (f->type != NGX_HTTP_FASTCGI_STDOUT
  1326.                 && f->type != NGX_HTTP_FASTCGI_STDERR)
  1327.             {
  1328.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1329.                               "upstream sent unexpected FastCGI record: %ui",
  1330.                               f->type);

  1331.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1332.             }

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

  1336.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1337.             }
  1338.         }

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

  1340.             if (u->buffer.pos + f->padding < u->buffer.last) {
  1341.                 f->state = ngx_http_fastcgi_st_version;
  1342.                 u->buffer.pos += f->padding;

  1343.                 continue;
  1344.             }

  1345.             if (u->buffer.pos + f->padding == u->buffer.last) {
  1346.                 f->state = ngx_http_fastcgi_st_version;
  1347.                 u->buffer.pos = u->buffer.last;

  1348.                 return NGX_AGAIN;
  1349.             }

  1350.             f->padding -= u->buffer.last - u->buffer.pos;
  1351.             u->buffer.pos = u->buffer.last;

  1352.             return NGX_AGAIN;
  1353.         }


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

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

  1356.             if (f->length) {
  1357.                 msg = u->buffer.pos;

  1358.                 if (u->buffer.pos + f->length <= u->buffer.last) {
  1359.                     u->buffer.pos += f->length;
  1360.                     f->length = 0;
  1361.                     f->state = ngx_http_fastcgi_st_padding;

  1362.                 } else {
  1363.                     f->length -= u->buffer.last - u->buffer.pos;
  1364.                     u->buffer.pos = u->buffer.last;
  1365.                 }

  1366.                 for (p = u->buffer.pos - 1; msg < p; p--) {
  1367.                     if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
  1368.                         break;
  1369.                     }
  1370.                 }

  1371.                 p++;

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

  1374.                 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  1375.                 if (flcf->catch_stderr) {
  1376.                     pattern = flcf->catch_stderr->elts;

  1377.                     for (i = 0; i < flcf->catch_stderr->nelts; i++) {
  1378.                         if (ngx_strnstr(msg, (char *) pattern[i].data,
  1379.                                         p - msg)
  1380.                             != NULL)
  1381.                         {
  1382.                             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1383.                         }
  1384.                     }
  1385.                 }

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

  1387.                     if (!f->fastcgi_stdout) {

  1388.                         /*
  1389.                          * the special handling the large number
  1390.                          * of the PHP warnings to not allocate memory
  1391.                          */

  1392. #if (NGX_HTTP_CACHE)
  1393.                         if (r->cache) {
  1394.                             u->buffer.pos = u->buffer.start
  1395.                                                      + r->cache->header_start;
  1396.                         } else {
  1397.                             u->buffer.pos = u->buffer.start;
  1398.                         }
  1399. #else
  1400.                         u->buffer.pos = u->buffer.start;
  1401. #endif
  1402.                         u->buffer.last = u->buffer.pos;
  1403.                         f->large_stderr = 1;
  1404.                     }

  1405.                     return NGX_AGAIN;
  1406.                 }

  1407.             } else {
  1408.                 f->state = ngx_http_fastcgi_st_padding;
  1409.             }

  1410.             continue;
  1411.         }


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

  1413. #if (NGX_HTTP_CACHE)

  1414.         if (f->large_stderr && r->cache) {
  1415.             ssize_t                     len;
  1416.             ngx_http_fastcgi_header_t  *fh;

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

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

  1419.             /*
  1420.              * A tail of large stderr output before HTTP header is placed
  1421.              * in a cache file without a FastCGI record header.
  1422.              * To workaround it we put a dummy FastCGI record header at the
  1423.              * start of the stderr output or update r->cache_header_start,
  1424.              * if there is no enough place for the record header.
  1425.              */

  1426.             if (len >= 0) {
  1427.                 fh = (ngx_http_fastcgi_header_t *) start;
  1428.                 fh->version = 1;
  1429.                 fh->type = NGX_HTTP_FASTCGI_STDERR;
  1430.                 fh->request_id_hi = 0;
  1431.                 fh->request_id_lo = 1;
  1432.                 fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
  1433.                 fh->content_length_lo = (u_char) (len & 0xff);
  1434.                 fh->padding_length = 0;
  1435.                 fh->reserved = 0;

  1436.             } else {
  1437.                 r->cache->header_start += u->buffer.pos - start
  1438.                                           - sizeof(ngx_http_fastcgi_header_t);
  1439.             }

  1440.             f->large_stderr = 0;
  1441.         }

  1442. #endif

  1443.         f->fastcgi_stdout = 1;

  1444.         start = u->buffer.pos;

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

  1446.             /*
  1447.              * set u->buffer.last to the end of the FastCGI record data
  1448.              * for ngx_http_parse_header_line()
  1449.              */

  1450.             last = u->buffer.last;
  1451.             u->buffer.last = u->buffer.pos + f->length;

  1452.         } else {
  1453.             last = NULL;
  1454.         }

  1455.         for ( ;; ) {

  1456.             part_start = u->buffer.pos;
  1457.             part_end = u->buffer.last;

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

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

  1461.             if (rc == NGX_AGAIN) {
  1462.                 break;
  1463.             }

  1464.             if (rc == NGX_OK) {

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

  1466.                 h = ngx_list_push(&u->headers_in.headers);
  1467.                 if (h == NULL) {
  1468.                     return NGX_ERROR;
  1469.                 }

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

  1471.                     part = f->split_parts->elts;
  1472.                     size = u->buffer.pos - part_start;

  1473.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1474.                         size += part[i].end - part[i].start;
  1475.                     }

  1476.                     p = ngx_pnalloc(r->pool, size);
  1477.                     if (p == NULL) {
  1478.                         h->hash = 0;
  1479.                         return NGX_ERROR;
  1480.                     }

  1481.                     buf.pos = p;

  1482.                     for (i = 0; i < f->split_parts->nelts; i++) {
  1483.                         p = ngx_cpymem(p, part[i].start,
  1484.                                        part[i].end - part[i].start);
  1485.                     }

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

  1487.                     buf.last = p;

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

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

  1490.                     if (rc != NGX_OK) {
  1491.                         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  1492.                                       "invalid header after joining "
  1493.                                       "FastCGI records");
  1494.                         h->hash = 0;
  1495.                         return NGX_ERROR;
  1496.                     }

  1497.                     h->key.len = r->header_name_end - r->header_name_start;
  1498.                     h->key.data = r->header_name_start;
  1499.                     h->key.data[h->key.len] = '\0';

  1500.                     h->value.len = r->header_end - r->header_start;
  1501.                     h->value.data = r->header_start;
  1502.                     h->value.data[h->value.len] = '\0';

  1503.                     h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
  1504.                     if (h->lowcase_key == NULL) {
  1505.                         return NGX_ERROR;
  1506.                     }

  1507.                 } else {

  1508.                     h->key.len = r->header_name_end - r->header_name_start;
  1509.                     h->value.len = r->header_end - r->header_start;

  1510.                     h->key.data = ngx_pnalloc(r->pool,
  1511.                                               h->key.len + 1 + h->value.len + 1
  1512.                                               + h->key.len);
  1513.                     if (h->key.data == NULL) {
  1514.                         h->hash = 0;
  1515.                         return NGX_ERROR;
  1516.                     }

  1517.                     h->value.data = h->key.data + h->key.len + 1;
  1518.                     h->lowcase_key = h->key.data + h->key.len + 1
  1519.                                      + h->value.len + 1;

  1520.                     ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  1521.                     h->key.data[h->key.len] = '\0';
  1522.                     ngx_memcpy(h->value.data, r->header_start, h->value.len);
  1523.                     h->value.data[h->value.len] = '\0';
  1524.                 }

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

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

  1528.                 } else {
  1529.                     ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  1530.                 }

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

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

  1535.                     if (rc != NGX_OK) {
  1536.                         return rc;
  1537.                     }
  1538.                 }

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

  1542.                 if (u->buffer.pos < u->buffer.last) {
  1543.                     continue;
  1544.                 }

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

  1546.                 break;
  1547.             }

  1548.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1552.                 if (u->headers_in.status) {
  1553.                     status_line = &u->headers_in.status->value;

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

  1555.                     if (status == NGX_ERROR) {
  1556.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1557.                                       "upstream sent invalid status \"%V\"",
  1558.                                       status_line);
  1559.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1560.                     }

  1561.                     u->headers_in.status_n = status;

  1562.                     if (status_line->len > 3) {
  1563.                         u->headers_in.status_line = *status_line;
  1564.                     }

  1565.                 } else if (u->headers_in.location) {
  1566.                     u->headers_in.status_n = 302;
  1567.                     ngx_str_set(&u->headers_in.status_line,
  1568.                                 "302 Moved Temporarily");

  1569.                 } else {
  1570.                     u->headers_in.status_n = 200;
  1571.                     ngx_str_set(&u->headers_in.status_line, "200 OK");
  1572.                 }

  1573.                 if (u->state && u->state->status == 0) {
  1574.                     u->state->status = u->headers_in.status_n;
  1575.                 }

  1576.                 break;
  1577.             }

  1578.             /* rc == NGX_HTTP_PARSE_INVALID_HEADER */

  1579.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1580.                           "upstream sent invalid header: \"%*s\\x%02xd...\"",
  1581.                           r->header_end - r->header_name_start,
  1582.                           r->header_name_start, *r->header_end);

  1583.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1584.         }

  1585.         if (last) {
  1586.             u->buffer.last = last;
  1587.         }

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

  1589.         if (f->length == 0) {
  1590.             f->state = ngx_http_fastcgi_st_padding;
  1591.         }

  1592.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1593.             return NGX_OK;
  1594.         }

  1595.         if (rc == NGX_OK) {
  1596.             continue;
  1597.         }

  1598.         /* rc == NGX_AGAIN */

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

  1601.         if (f->split_parts == NULL) {
  1602.             f->split_parts = ngx_array_create(r->pool, 1,
  1603.                                         sizeof(ngx_http_fastcgi_split_part_t));
  1604.             if (f->split_parts == NULL) {
  1605.                 return NGX_ERROR;
  1606.             }
  1607.         }

  1608.         part = ngx_array_push(f->split_parts);
  1609.         if (part == NULL) {
  1610.             return NGX_ERROR;
  1611.         }

  1612.         part->start = part_start;
  1613.         part->end = part_end;

  1614.         if (u->buffer.pos < u->buffer.last) {
  1615.             continue;
  1616.         }

  1617.         return NGX_AGAIN;
  1618.     }
  1619. }


  1620. static ngx_int_t
  1621. ngx_http_fastcgi_input_filter_init(void *data)
  1622. {
  1623.     ngx_http_request_t  *r = data;

  1624.     ngx_http_upstream_t          *u;
  1625.     ngx_http_fastcgi_ctx_t       *f;
  1626.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1627.     u = r->upstream;

  1628.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1629.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

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

  1632.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1633.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
  1634.     {
  1635.         f->rest = 0;

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

  1638.     } else {
  1639.         f->rest = u->headers_in.content_length_n;
  1640.     }

  1641.     return NGX_OK;
  1642. }


  1643. static ngx_int_t
  1644. ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
  1645. {
  1646.     u_char                       *m, *msg;
  1647.     ngx_int_t                     rc;
  1648.     ngx_buf_t                    *b, **prev;
  1649.     ngx_chain_t                  *cl;
  1650.     ngx_http_request_t           *r;
  1651.     ngx_http_fastcgi_ctx_t       *f;
  1652.     ngx_http_fastcgi_loc_conf_t  *flcf;

  1653.     if (buf->pos == buf->last) {
  1654.         return NGX_OK;
  1655.     }

  1656.     r = p->input_ctx;
  1657.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
  1658.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

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

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

  1663.         return NGX_OK;
  1664.     }

  1665.     b = NULL;
  1666.     prev = &buf->shadow;

  1667.     f->pos = buf->pos;
  1668.     f->last = buf->last;

  1669.     for ( ;; ) {
  1670.         if (f->state < ngx_http_fastcgi_st_data) {

  1671.             rc = ngx_http_fastcgi_process_record(r, f);

  1672.             if (rc == NGX_AGAIN) {
  1673.                 break;
  1674.             }

  1675.             if (rc == NGX_ERROR) {
  1676.                 return NGX_ERROR;
  1677.             }

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

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

  1682.                 if (f->rest > 0) {
  1683.                     ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1684.                                   "upstream prematurely closed "
  1685.                                   "FastCGI stdout");

  1686.                     p->upstream_error = 1;
  1687.                     p->upstream_eof = 0;
  1688.                     f->closed = 1;

  1689.                     break;
  1690.                 }

  1691.                 if (!flcf->keep_conn) {
  1692.                     p->upstream_done = 1;
  1693.                 }

  1694.                 continue;
  1695.             }

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

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

  1699.                 if (f->rest > 0) {
  1700.                     ngx_log_error(NGX_LOG_ERR, p->log, 0,
  1701.                                   "upstream prematurely closed "
  1702.                                   "FastCGI request");

  1703.                     p->upstream_error = 1;
  1704.                     p->upstream_eof = 0;
  1705.                     f->closed = 1;

  1706.                     break;
  1707.                 }

  1708.                 if (!flcf->keep_conn) {
  1709.                     p->upstream_done = 1;
  1710.                     break;
  1711.                 }

  1712.                 continue;
  1713.             }
  1714.         }


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

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

  1717.                 if (f->pos + f->padding < f->last) {
  1718.                     p->upstream_done = 1;
  1719.                     break;
  1720.                 }

  1721.                 if (f->pos + f->padding == f->last) {
  1722.                     p->upstream_done = 1;
  1723.                     r->upstream->keepalive = 1;
  1724.                     break;
  1725.                 }

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

  1727.                 break;
  1728.             }

  1729.             if (f->pos + f->padding < f->last) {
  1730.                 f->state = ngx_http_fastcgi_st_version;
  1731.                 f->pos += f->padding;

  1732.                 continue;
  1733.             }

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

  1736.                 break;
  1737.             }

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

  1739.             break;
  1740.         }


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

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

  1743.             if (f->length) {

  1744.                 if (f->pos == f->last) {
  1745.                     break;
  1746.                 }

  1747.                 msg = f->pos;

  1748.                 if (f->pos + f->length <= f->last) {
  1749.                     f->pos += f->length;
  1750.                     f->length = 0;
  1751.                     f->state = ngx_http_fastcgi_st_padding;

  1752.                 } else {
  1753.                     f->length -= f->last - f->pos;
  1754.                     f->pos = f->last;
  1755.                 }

  1756.                 for (m = f->pos - 1; msg < m; m--) {
  1757.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1758.                         break;
  1759.                     }
  1760.                 }

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

  1764.             } else {
  1765.                 f->state = ngx_http_fastcgi_st_padding;
  1766.             }

  1767.             continue;
  1768.         }

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

  1770.             if (f->pos + f->length <= f->last) {
  1771.                 f->state = ngx_http_fastcgi_st_padding;
  1772.                 f->pos += f->length;

  1773.                 continue;
  1774.             }

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

  1776.             break;
  1777.         }


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

  1779.         if (f->pos == f->last) {
  1780.             break;
  1781.         }

  1782.         if (f->rest == -2) {
  1783.             f->rest = r->upstream->headers_in.content_length_n;
  1784.         }

  1785.         if (f->rest == 0) {
  1786.             ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1787.                           "upstream sent more data than specified in "
  1788.                           "\"Content-Length\" header");
  1789.             p->upstream_done = 1;
  1790.             break;
  1791.         }

  1792.         cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1793.         if (cl == NULL) {
  1794.             return NGX_ERROR;
  1795.         }

  1796.         b = cl->buf;

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

  1798.         b->pos = f->pos;
  1799.         b->start = buf->start;
  1800.         b->end = buf->end;
  1801.         b->tag = p->tag;
  1802.         b->temporary = 1;
  1803.         b->recycled = 1;

  1804.         *prev = b;
  1805.         prev = &b->shadow;

  1806.         if (p->in) {
  1807.             *p->last_in = cl;
  1808.         } else {
  1809.             p->in = cl;
  1810.         }
  1811.         p->last_in = &cl->next;


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

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

  1815.         if (f->pos + f->length <= f->last) {
  1816.             f->state = ngx_http_fastcgi_st_padding;
  1817.             f->pos += f->length;
  1818.             b->last = f->pos;

  1819.         } else {
  1820.             f->length -= f->last - f->pos;
  1821.             f->pos = f->last;
  1822.             b->last = f->last;
  1823.         }

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

  1825.             if (b->last - b->pos > f->rest) {
  1826.                 ngx_log_error(NGX_LOG_WARN, p->log, 0,
  1827.                               "upstream sent more data than specified in "
  1828.                               "\"Content-Length\" header");

  1829.                 b->last = b->pos + f->rest;
  1830.                 p->upstream_done = 1;

  1831.                 break;
  1832.             }

  1833.             f->rest -= b->last - b->pos;
  1834.         }
  1835.     }

  1836.     if (flcf->keep_conn) {

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

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

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

  1842.         } else {
  1843.             /* ngx_http_fastcgi_st_data */

  1844.             p->length = f->length;
  1845.         }
  1846.     }

  1847.     if (b) {
  1848.         b->shadow = buf;
  1849.         b->last_shadow = 1;

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

  1852.         return NGX_OK;
  1853.     }

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

  1855.     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
  1856.         return NGX_ERROR;
  1857.     }

  1858.     return NGX_OK;
  1859. }


  1860. static ngx_int_t
  1861. ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
  1862. {
  1863.     u_char                  *m, *msg;
  1864.     ngx_int_t                rc;
  1865.     ngx_buf_t               *b, *buf;
  1866.     ngx_chain_t             *cl, **ll;
  1867.     ngx_http_request_t      *r;
  1868.     ngx_http_upstream_t     *u;
  1869.     ngx_http_fastcgi_ctx_t  *f;

  1870.     r = data;
  1871.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  1872.     u = r->upstream;
  1873.     buf = &u->buffer;

  1874.     buf->pos = buf->last;
  1875.     buf->last += bytes;

  1876.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1877.         ll = &cl->next;
  1878.     }

  1879.     f->pos = buf->pos;
  1880.     f->last = buf->last;

  1881.     for ( ;; ) {
  1882.         if (f->state < ngx_http_fastcgi_st_data) {

  1883.             rc = ngx_http_fastcgi_process_record(r, f);

  1884.             if (rc == NGX_AGAIN) {
  1885.                 break;
  1886.             }

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

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

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

  1894.                 continue;
  1895.             }
  1896.         }

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

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

  1899.                 if (f->rest > 0) {
  1900.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1901.                                   "upstream prematurely closed "
  1902.                                   "FastCGI request");
  1903.                     u->error = 1;
  1904.                     break;
  1905.                 }

  1906.                 if (f->pos + f->padding < f->last) {
  1907.                     u->length = 0;
  1908.                     break;
  1909.                 }

  1910.                 if (f->pos + f->padding == f->last) {
  1911.                     u->length = 0;
  1912.                     u->keepalive = 1;
  1913.                     break;
  1914.                 }

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

  1916.                 break;
  1917.             }

  1918.             if (f->pos + f->padding < f->last) {
  1919.                 f->state = ngx_http_fastcgi_st_version;
  1920.                 f->pos += f->padding;

  1921.                 continue;
  1922.             }

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

  1925.                 break;
  1926.             }

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

  1928.             break;
  1929.         }


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

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

  1932.             if (f->length) {

  1933.                 if (f->pos == f->last) {
  1934.                     break;
  1935.                 }

  1936.                 msg = f->pos;

  1937.                 if (f->pos + f->length <= f->last) {
  1938.                     f->pos += f->length;
  1939.                     f->length = 0;
  1940.                     f->state = ngx_http_fastcgi_st_padding;

  1941.                 } else {
  1942.                     f->length -= f->last - f->pos;
  1943.                     f->pos = f->last;
  1944.                 }

  1945.                 for (m = f->pos - 1; msg < m; m--) {
  1946.                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
  1947.                         break;
  1948.                     }
  1949.                 }

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

  1953.             } else {
  1954.                 f->state = ngx_http_fastcgi_st_padding;
  1955.             }

  1956.             continue;
  1957.         }

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

  1959.             if (f->pos + f->length <= f->last) {
  1960.                 f->state = ngx_http_fastcgi_st_padding;
  1961.                 f->pos += f->length;

  1962.                 continue;
  1963.             }

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

  1965.             break;
  1966.         }


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

  1968.         if (f->pos == f->last) {
  1969.             break;
  1970.         }

  1971.         if (f->rest == 0) {
  1972.             ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  1973.                           "upstream sent more data than specified in "
  1974.                           "\"Content-Length\" header");
  1975.             u->length = 0;
  1976.             break;
  1977.         }

  1978.         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1979.         if (cl == NULL) {
  1980.             return NGX_ERROR;
  1981.         }

  1982.         *ll = cl;
  1983.         ll = &cl->next;

  1984.         b = cl->buf;

  1985.         b->flush = 1;
  1986.         b->memory = 1;

  1987.         b->pos = f->pos;
  1988.         b->tag = u->output.tag;

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

  1991.         if (f->pos + f->length <= f->last) {
  1992.             f->state = ngx_http_fastcgi_st_padding;
  1993.             f->pos += f->length;
  1994.             b->last = f->pos;

  1995.         } else {
  1996.             f->length -= f->last - f->pos;
  1997.             f->pos = f->last;
  1998.             b->last = f->last;
  1999.         }

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

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

  2005.                 b->last = b->pos + f->rest;
  2006.                 u->length = 0;

  2007.                 break;
  2008.             }

  2009.             f->rest -= b->last - b->pos;
  2010.         }
  2011.     }

  2012.     return NGX_OK;
  2013. }


  2014. static ngx_int_t
  2015. ngx_http_fastcgi_process_record(ngx_http_request_t *r,
  2016.     ngx_http_fastcgi_ctx_t *f)
  2017. {
  2018.     u_char                     ch, *p;
  2019.     ngx_http_fastcgi_state_e   state;

  2020.     state = f->state;

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

  2022.         ch = *p;

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

  2025.         switch (state) {

  2026.         case ngx_http_fastcgi_st_version:
  2027.             if (ch != 1) {
  2028.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2029.                               "upstream sent unsupported FastCGI "
  2030.                               "protocol version: %d", ch);
  2031.                 return NGX_ERROR;
  2032.             }
  2033.             state = ngx_http_fastcgi_st_type;
  2034.             break;

  2035.         case ngx_http_fastcgi_st_type:
  2036.             switch (ch) {
  2037.             case NGX_HTTP_FASTCGI_STDOUT:
  2038.             case NGX_HTTP_FASTCGI_STDERR:
  2039.             case NGX_HTTP_FASTCGI_END_REQUEST:
  2040.                 f->type = (ngx_uint_t) ch;
  2041.                 break;
  2042.             default:
  2043.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2044.                               "upstream sent invalid FastCGI "
  2045.                               "record type: %d", ch);
  2046.                 return NGX_ERROR;

  2047.             }
  2048.             state = ngx_http_fastcgi_st_request_id_hi;
  2049.             break;

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

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

  2060.         case ngx_http_fastcgi_st_request_id_lo:
  2061.             if (ch != 1) {
  2062.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2063.                               "upstream sent unexpected FastCGI "
  2064.                               "request id low byte: %d", ch);
  2065.                 return NGX_ERROR;
  2066.             }
  2067.             state = ngx_http_fastcgi_st_content_length_hi;
  2068.             break;

  2069.         case ngx_http_fastcgi_st_content_length_hi:
  2070.             f->length = ch << 8;
  2071.             state = ngx_http_fastcgi_st_content_length_lo;
  2072.             break;

  2073.         case ngx_http_fastcgi_st_content_length_lo:
  2074.             f->length |= (size_t) ch;
  2075.             state = ngx_http_fastcgi_st_padding_length;
  2076.             break;

  2077.         case ngx_http_fastcgi_st_padding_length:
  2078.             f->padding = (size_t) ch;
  2079.             state = ngx_http_fastcgi_st_reserved;
  2080.             break;

  2081.         case ngx_http_fastcgi_st_reserved:
  2082.             state = ngx_http_fastcgi_st_data;

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

  2085.             f->pos = p + 1;
  2086.             f->state = state;

  2087.             return NGX_OK;

  2088.         /* suppress warning */
  2089.         case ngx_http_fastcgi_st_data:
  2090.         case ngx_http_fastcgi_st_padding:
  2091.             break;
  2092.         }
  2093.     }

  2094.     f->pos = p;
  2095.     f->state = state;

  2096.     return NGX_AGAIN;
  2097. }


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

  2103.     return;
  2104. }


  2105. static void
  2106. ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  2107. {
  2108.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2109.                    "finalize http fastcgi request");

  2110.     return;
  2111. }


  2112. static ngx_int_t
  2113. ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
  2114. {
  2115.     ngx_http_variable_t  *var, *v;

  2116.     for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
  2117.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  2118.         if (var == NULL) {
  2119.             return NGX_ERROR;
  2120.         }

  2121.         var->get_handler = v->get_handler;
  2122.         var->data = v->data;
  2123.     }

  2124.     return NGX_OK;
  2125. }


  2126. static void *
  2127. ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
  2128. {
  2129.     ngx_http_fastcgi_main_conf_t  *conf;

  2130.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
  2131.     if (conf == NULL) {
  2132.         return NULL;
  2133.     }

  2134. #if (NGX_HTTP_CACHE)
  2135.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  2136.                        sizeof(ngx_http_file_cache_t *))
  2137.         != NGX_OK)
  2138.     {
  2139.         return NULL;
  2140.     }
  2141. #endif

  2142.     return conf;
  2143. }


  2144. static void *
  2145. ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
  2146. {
  2147.     ngx_http_fastcgi_loc_conf_t  *conf;

  2148.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
  2149.     if (conf == NULL) {
  2150.         return NULL;
  2151.     }

  2152.     /*
  2153.      * set by ngx_pcalloc():
  2154.      *
  2155.      *     conf->upstream.bufs.num = 0;
  2156.      *     conf->upstream.ignore_headers = 0;
  2157.      *     conf->upstream.next_upstream = 0;
  2158.      *     conf->upstream.cache_zone = NULL;
  2159.      *     conf->upstream.cache_use_stale = 0;
  2160.      *     conf->upstream.cache_methods = 0;
  2161.      *     conf->upstream.temp_path = NULL;
  2162.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  2163.      *     conf->upstream.store_lengths = NULL;
  2164.      *     conf->upstream.store_values = NULL;
  2165.      *
  2166.      *     conf->index = { 0, NULL };
  2167.      */

  2168.     conf->upstream.store = NGX_CONF_UNSET;
  2169.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  2170.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  2171.     conf->upstream.buffering = NGX_CONF_UNSET;
  2172.     conf->upstream.request_buffering = NGX_CONF_UNSET;
  2173.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  2174.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  2175.     conf->upstream.local = NGX_CONF_UNSET_PTR;
  2176.     conf->upstream.socket_keepalive = NGX_CONF_UNSET;

  2177.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  2178.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  2179.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  2180.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  2181.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  2182.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  2183.     conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;

  2184.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  2185.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  2186.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  2187.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  2188.     conf->upstream.pass_request_body = NGX_CONF_UNSET;

  2189. #if (NGX_HTTP_CACHE)
  2190.     conf->upstream.cache = NGX_CONF_UNSET;
  2191.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  2192.     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
  2193.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  2194.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  2195.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  2196.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  2197.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  2198.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  2199.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  2200.     conf->upstream.cache_background_update = NGX_CONF_UNSET;
  2201. #endif

  2202.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  2203.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  2204.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  2205.     /* "fastcgi_cyclic_temp_file" is disabled */
  2206.     conf->upstream.cyclic_temp_file = 0;

  2207.     conf->upstream.change_buffering = 1;

  2208.     conf->catch_stderr = NGX_CONF_UNSET_PTR;

  2209.     conf->keep_conn = NGX_CONF_UNSET;

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

  2211.     return conf;
  2212. }


  2213. static char *
  2214. ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  2215. {
  2216.     ngx_http_fastcgi_loc_conf_t *prev = parent;
  2217.     ngx_http_fastcgi_loc_conf_t *conf = child;

  2218.     size_t                        size;
  2219.     ngx_int_t                     rc;
  2220.     ngx_hash_init_t               hash;
  2221.     ngx_http_core_loc_conf_t     *clcf;

  2222. #if (NGX_HTTP_CACHE)

  2223.     if (conf->upstream.store > 0) {
  2224.         conf->upstream.cache = 0;
  2225.     }

  2226.     if (conf->upstream.cache > 0) {
  2227.         conf->upstream.store = 0;
  2228.     }

  2229. #endif

  2230.     if (conf->upstream.store == NGX_CONF_UNSET) {
  2231.         ngx_conf_merge_value(conf->upstream.store,
  2232.                               prev->upstream.store, 0);

  2233.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  2234.         conf->upstream.store_values = prev->upstream.store_values;
  2235.     }

  2236.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  2237.                               prev->upstream.store_access, 0600);

  2238.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  2239.                               prev->upstream.next_upstream_tries, 0);

  2240.     ngx_conf_merge_value(conf->upstream.buffering,
  2241.                               prev->upstream.buffering, 1);

  2242.     ngx_conf_merge_value(conf->upstream.request_buffering,
  2243.                               prev->upstream.request_buffering, 1);

  2244.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  2245.                               prev->upstream.ignore_client_abort, 0);

  2246.     ngx_conf_merge_value(conf->upstream.force_ranges,
  2247.                               prev->upstream.force_ranges, 0);

  2248.     ngx_conf_merge_ptr_value(conf->upstream.local,
  2249.                               prev->upstream.local, NULL);

  2250.     ngx_conf_merge_value(conf->upstream.socket_keepalive,
  2251.                               prev->upstream.socket_keepalive, 0);

  2252.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  2253.                               prev->upstream.connect_timeout, 60000);

  2254.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  2255.                               prev->upstream.send_timeout, 60000);

  2256.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  2257.                               prev->upstream.read_timeout, 60000);

  2258.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  2259.                               prev->upstream.next_upstream_timeout, 0);

  2260.     ngx_conf_merge_size_value(conf->upstream.send_lowat,
  2261.                               prev->upstream.send_lowat, 0);

  2262.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  2263.                               prev->upstream.buffer_size,
  2264.                               (size_t) ngx_pagesize);

  2265.     ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
  2266.                               prev->upstream.limit_rate, NULL);


  2267.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  2268.                               8, ngx_pagesize);

  2269.     if (conf->upstream.bufs.num < 2) {
  2270.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2271.                            "there must be at least 2 \"fastcgi_buffers\"");
  2272.         return NGX_CONF_ERROR;
  2273.     }


  2274.     size = conf->upstream.buffer_size;
  2275.     if (size < conf->upstream.bufs.size) {
  2276.         size = conf->upstream.bufs.size;
  2277.     }


  2278.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  2279.                               prev->upstream.busy_buffers_size_conf,
  2280.                               NGX_CONF_UNSET_SIZE);

  2281.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  2282.         conf->upstream.busy_buffers_size = 2 * size;
  2283.     } else {
  2284.         conf->upstream.busy_buffers_size =
  2285.                                          conf->upstream.busy_buffers_size_conf;
  2286.     }

  2287.     if (conf->upstream.busy_buffers_size < size) {
  2288.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2289.              "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
  2290.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  2291.              "one of the \"fastcgi_buffers\"");

  2292.         return NGX_CONF_ERROR;
  2293.     }

  2294.     if (conf->upstream.busy_buffers_size
  2295.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  2296.     {
  2297.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2298.              "\"fastcgi_busy_buffers_size\" must be less than "
  2299.              "the size of all \"fastcgi_buffers\" minus one buffer");

  2300.         return NGX_CONF_ERROR;
  2301.     }


  2302.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  2303.                               prev->upstream.temp_file_write_size_conf,
  2304.                               NGX_CONF_UNSET_SIZE);

  2305.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  2306.         conf->upstream.temp_file_write_size = 2 * size;
  2307.     } else {
  2308.         conf->upstream.temp_file_write_size =
  2309.                                       conf->upstream.temp_file_write_size_conf;
  2310.     }

  2311.     if (conf->upstream.temp_file_write_size < size) {
  2312.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2313.              "\"fastcgi_temp_file_write_size\" must be equal to or greater "
  2314.              "than the maximum of the value of \"fastcgi_buffer_size\" and "
  2315.              "one of the \"fastcgi_buffers\"");

  2316.         return NGX_CONF_ERROR;
  2317.     }


  2318.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  2319.                               prev->upstream.max_temp_file_size_conf,
  2320.                               NGX_CONF_UNSET_SIZE);

  2321.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  2322.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  2323.     } else {
  2324.         conf->upstream.max_temp_file_size =
  2325.                                         conf->upstream.max_temp_file_size_conf;
  2326.     }

  2327.     if (conf->upstream.max_temp_file_size != 0
  2328.         && conf->upstream.max_temp_file_size < size)
  2329.     {
  2330.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2331.              "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
  2332.              "temporary files usage or must be equal to or greater than "
  2333.              "the maximum of the value of \"fastcgi_buffer_size\" and "
  2334.              "one of the \"fastcgi_buffers\"");

  2335.         return NGX_CONF_ERROR;
  2336.     }


  2337.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  2338.                               prev->upstream.ignore_headers,
  2339.                               NGX_CONF_BITMASK_SET);


  2340.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  2341.                               prev->upstream.next_upstream,
  2342.                               (NGX_CONF_BITMASK_SET
  2343.                                |NGX_HTTP_UPSTREAM_FT_ERROR
  2344.                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  2345.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  2346.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  2347.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  2348.     }

  2349.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  2350.                               prev->upstream.temp_path,
  2351.                               &ngx_http_fastcgi_temp_path)
  2352.         != NGX_CONF_OK)
  2353.     {
  2354.         return NGX_CONF_ERROR;
  2355.     }

  2356. #if (NGX_HTTP_CACHE)

  2357.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  2358.         ngx_conf_merge_value(conf->upstream.cache,
  2359.                               prev->upstream.cache, 0);

  2360.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  2361.         conf->upstream.cache_value = prev->upstream.cache_value;
  2362.     }

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

  2365.         shm_zone = conf->upstream.cache_zone;

  2366.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2367.                            "\"fastcgi_cache\" zone \"%V\" is unknown",
  2368.                            &shm_zone->shm.name);

  2369.         return NGX_CONF_ERROR;
  2370.     }

  2371.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  2372.                               prev->upstream.cache_min_uses, 1);

  2373.     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
  2374.                               prev->upstream.cache_max_range_offset,
  2375.                               NGX_MAX_OFF_T_VALUE);

  2376.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  2377.                               prev->upstream.cache_use_stale,
  2378.                               (NGX_CONF_BITMASK_SET
  2379.                                |NGX_HTTP_UPSTREAM_FT_OFF));

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

  2384.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  2385.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  2386.     }

  2387.     if (conf->upstream.cache_methods == 0) {
  2388.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  2389.     }

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

  2391.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  2392.                              prev->upstream.cache_bypass, NULL);

  2393.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  2394.                              prev->upstream.no_cache, NULL);

  2395.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  2396.                              prev->upstream.cache_valid, NULL);

  2397.     if (conf->cache_key.value.data == NULL) {
  2398.         conf->cache_key = prev->cache_key;
  2399.     }

  2400.     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
  2401.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  2402.                            "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
  2403.     }

  2404.     ngx_conf_merge_value(conf->upstream.cache_lock,
  2405.                               prev->upstream.cache_lock, 0);

  2406.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  2407.                               prev->upstream.cache_lock_timeout, 5000);

  2408.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  2409.                               prev->upstream.cache_lock_age, 5000);

  2410.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  2411.                               prev->upstream.cache_revalidate, 0);

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

  2414. #endif

  2415.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  2416.                               prev->upstream.pass_request_headers, 1);
  2417.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  2418.                               prev->upstream.pass_request_body, 1);

  2419.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  2420.                               prev->upstream.intercept_errors, 0);

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

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


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

  2424.     hash.max_size = 512;
  2425.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  2426.     hash.name = "fastcgi_hide_headers_hash";

  2427.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  2428.              &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
  2429.         != NGX_OK)
  2430.     {
  2431.         return NGX_CONF_ERROR;
  2432.     }

  2433.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2434.     if (clcf->noname
  2435.         && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
  2436.     {
  2437.         conf->upstream.upstream = prev->upstream.upstream;
  2438.         conf->fastcgi_lengths = prev->fastcgi_lengths;
  2439.         conf->fastcgi_values = prev->fastcgi_values;
  2440.     }

  2441.     if (clcf->lmt_excpt && clcf->handler == NULL
  2442.         && (conf->upstream.upstream || conf->fastcgi_lengths))
  2443.     {
  2444.         clcf->handler = ngx_http_fastcgi_handler;
  2445.     }

  2446. #if (NGX_PCRE)
  2447.     if (conf->split_regex == NULL) {
  2448.         conf->split_regex = prev->split_regex;
  2449.         conf->split_name = prev->split_name;
  2450.     }
  2451. #endif

  2452.     if (conf->params_source == NULL) {
  2453.         conf->params = prev->params;
  2454. #if (NGX_HTTP_CACHE)
  2455.         conf->params_cache = prev->params_cache;
  2456. #endif
  2457.         conf->params_source = prev->params_source;
  2458.     }

  2459.     rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params,
  2460.                                       ngx_http_fastcgi_headers);
  2461.     if (rc != NGX_OK) {
  2462.         return NGX_CONF_ERROR;
  2463.     }

  2464. #if (NGX_HTTP_CACHE)

  2465.     if (conf->upstream.cache) {
  2466.         rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
  2467.                                           ngx_http_fastcgi_cache_headers);
  2468.         if (rc != NGX_OK) {
  2469.             return NGX_CONF_ERROR;
  2470.         }
  2471.     }

  2472. #endif

  2473.     /*
  2474.      * special handling to preserve conf->params in the "http" section
  2475.      * to inherit it to all servers
  2476.      */

  2477.     if (prev->params.hash.buckets == NULL
  2478.         && conf->params_source == prev->params_source)
  2479.     {
  2480.         prev->params = conf->params;
  2481. #if (NGX_HTTP_CACHE)
  2482.         prev->params_cache = conf->params_cache;
  2483. #endif
  2484.     }

  2485.     return NGX_CONF_OK;
  2486. }


  2487. static ngx_int_t
  2488. ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
  2489.     ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
  2490. {
  2491.     u_char                       *p;
  2492.     size_t                        size;
  2493.     uintptr_t                    *code;
  2494.     ngx_uint_t                    i, nsrc;
  2495.     ngx_array_t                   headers_names, params_merged;
  2496.     ngx_keyval_t                 *h;
  2497.     ngx_hash_key_t               *hk;
  2498.     ngx_hash_init_t               hash;
  2499.     ngx_http_upstream_param_t    *src, *s;
  2500.     ngx_http_script_compile_t     sc;
  2501.     ngx_http_script_copy_code_t  *copy;

  2502.     if (params->hash.buckets) {
  2503.         return NGX_OK;
  2504.     }

  2505.     if (conf->params_source == NULL && default_params == NULL) {
  2506.         params->hash.buckets = (void *) 1;
  2507.         return NGX_OK;
  2508.     }

  2509.     params->lengths = ngx_array_create(cf->pool, 64, 1);
  2510.     if (params->lengths == NULL) {
  2511.         return NGX_ERROR;
  2512.     }

  2513.     params->values = ngx_array_create(cf->pool, 512, 1);
  2514.     if (params->values == NULL) {
  2515.         return NGX_ERROR;
  2516.     }

  2517.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  2518.         != NGX_OK)
  2519.     {
  2520.         return NGX_ERROR;
  2521.     }

  2522.     if (conf->params_source) {
  2523.         src = conf->params_source->elts;
  2524.         nsrc = conf->params_source->nelts;

  2525.     } else {
  2526.         src = NULL;
  2527.         nsrc = 0;
  2528.     }

  2529.     if (default_params) {
  2530.         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
  2531.                            sizeof(ngx_http_upstream_param_t))
  2532.             != NGX_OK)
  2533.         {
  2534.             return NGX_ERROR;
  2535.         }

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

  2537.             s = ngx_array_push(&params_merged);
  2538.             if (s == NULL) {
  2539.                 return NGX_ERROR;
  2540.             }

  2541.             *s = src[i];
  2542.         }

  2543.         h = default_params;

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

  2545.             src = params_merged.elts;
  2546.             nsrc = params_merged.nelts;

  2547.             for (i = 0; i < nsrc; i++) {
  2548.                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  2549.                     goto next;
  2550.                 }
  2551.             }

  2552.             s = ngx_array_push(&params_merged);
  2553.             if (s == NULL) {
  2554.                 return NGX_ERROR;
  2555.             }

  2556.             s->key = h->key;
  2557.             s->value = h->value;
  2558.             s->skip_empty = 1;

  2559.         next:

  2560.             h++;
  2561.         }

  2562.         src = params_merged.elts;
  2563.         nsrc = params_merged.nelts;
  2564.     }

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

  2566.         if (src[i].key.len > sizeof("HTTP_") - 1
  2567.             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
  2568.         {
  2569.             hk = ngx_array_push(&headers_names);
  2570.             if (hk == NULL) {
  2571.                 return NGX_ERROR;
  2572.             }

  2573.             hk->key.len = src[i].key.len - 5;
  2574.             hk->key.data = src[i].key.data + 5;
  2575.             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
  2576.             hk->value = (void *) 1;

  2577.             if (src[i].value.len == 0) {
  2578.                 continue;
  2579.             }
  2580.         }

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

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

  2589.         copy = ngx_array_push_n(params->lengths,
  2590.                                 sizeof(ngx_http_script_copy_code_t));
  2591.         if (copy == NULL) {
  2592.             return NGX_ERROR;
  2593.         }

  2594.         copy->code = (ngx_http_script_code_pt) (void *)
  2595.                                                  ngx_http_script_copy_len_code;
  2596.         copy->len = src[i].skip_empty;


  2597.         size = (sizeof(ngx_http_script_copy_code_t)
  2598.                 + src[i].key.len + sizeof(uintptr_t) - 1)
  2599.                & ~(sizeof(uintptr_t) - 1);

  2600.         copy = ngx_array_push_n(params->values, size);
  2601.         if (copy == NULL) {
  2602.             return NGX_ERROR;
  2603.         }

  2604.         copy->code = ngx_http_script_copy_code;
  2605.         copy->len = src[i].key.len;

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


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

  2609.         sc.cf = cf;
  2610.         sc.source = &src[i].value;
  2611.         sc.flushes = &params->flushes;
  2612.         sc.lengths = &params->lengths;
  2613.         sc.values = &params->values;

  2614.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2615.             return NGX_ERROR;
  2616.         }

  2617.         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2618.         if (code == NULL) {
  2619.             return NGX_ERROR;
  2620.         }

  2621.         *code = (uintptr_t) NULL;


  2622.         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
  2623.         if (code == NULL) {
  2624.             return NGX_ERROR;
  2625.         }

  2626.         *code = (uintptr_t) NULL;
  2627.     }

  2628.     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  2629.     if (code == NULL) {
  2630.         return NGX_ERROR;
  2631.     }

  2632.     *code = (uintptr_t) NULL;

  2633.     params->number = headers_names.nelts;

  2634.     hash.hash = &params->hash;
  2635.     hash.key = ngx_hash_key_lc;
  2636.     hash.max_size = 512;
  2637.     hash.bucket_size = 64;
  2638.     hash.name = "fastcgi_params_hash";
  2639.     hash.pool = cf->pool;
  2640.     hash.temp_pool = NULL;

  2641.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  2642. }


  2643. static ngx_int_t
  2644. ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
  2645.     ngx_http_variable_value_t *v, uintptr_t data)
  2646. {
  2647.     u_char                       *p;
  2648.     ngx_http_fastcgi_ctx_t       *f;
  2649.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2650.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2651.     f = ngx_http_fastcgi_split(r, flcf);

  2652.     if (f == NULL) {
  2653.         return NGX_ERROR;
  2654.     }

  2655.     if (f->script_name.len == 0
  2656.         || f->script_name.data[f->script_name.len - 1] != '/')
  2657.     {
  2658.         v->len = f->script_name.len;
  2659.         v->valid = 1;
  2660.         v->no_cacheable = 0;
  2661.         v->not_found = 0;
  2662.         v->data = f->script_name.data;

  2663.         return NGX_OK;
  2664.     }

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

  2666.     v->data = ngx_pnalloc(r->pool, v->len);
  2667.     if (v->data == NULL) {
  2668.         return NGX_ERROR;
  2669.     }

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

  2672.     return NGX_OK;
  2673. }


  2674. static ngx_int_t
  2675. ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
  2676.     ngx_http_variable_value_t *v, uintptr_t data)
  2677. {
  2678.     ngx_http_fastcgi_ctx_t       *f;
  2679.     ngx_http_fastcgi_loc_conf_t  *flcf;

  2680.     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);

  2681.     f = ngx_http_fastcgi_split(r, flcf);

  2682.     if (f == NULL) {
  2683.         return NGX_ERROR;
  2684.     }

  2685.     v->len = f->path_info.len;
  2686.     v->valid = 1;
  2687.     v->no_cacheable = 0;
  2688.     v->not_found = 0;
  2689.     v->data = f->path_info.data;

  2690.     return NGX_OK;
  2691. }


  2692. static ngx_http_fastcgi_ctx_t *
  2693. ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
  2694. {
  2695.     ngx_http_fastcgi_ctx_t       *f;
  2696. #if (NGX_PCRE)
  2697.     ngx_int_t                     n;
  2698.     int                           captures[(1 + 2) * 3];

  2699.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

  2700.     if (f == NULL) {
  2701.         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
  2702.         if (f == NULL) {
  2703.             return NULL;
  2704.         }

  2705.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2706.     }

  2707.     if (f->script_name.len) {
  2708.         return f;
  2709.     }

  2710.     if (flcf->split_regex == NULL) {
  2711.         f->script_name = r->uri;
  2712.         return f;
  2713.     }

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

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

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

  2720.         return f;
  2721.     }

  2722.     if (n == NGX_REGEX_NO_MATCHED) {
  2723.         f->script_name = r->uri;
  2724.         return f;
  2725.     }

  2726.     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  2727.                   ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
  2728.                   n, &r->uri, &flcf->split_name);
  2729.     return NULL;

  2730. #else

  2731.     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);

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

  2737.         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
  2738.     }

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

  2740.     return f;

  2741. #endif
  2742. }


  2743. static char *
  2744. ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2745. {
  2746.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2747.     ngx_url_t                   u;
  2748.     ngx_str_t                  *value, *url;
  2749.     ngx_uint_t                  n;
  2750.     ngx_http_core_loc_conf_t   *clcf;
  2751.     ngx_http_script_compile_t   sc;

  2752.     if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
  2753.         return "is duplicate";
  2754.     }

  2755.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  2756.     clcf->handler = ngx_http_fastcgi_handler;

  2757.     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
  2758.         clcf->auto_redirect = 1;
  2759.     }

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

  2761.     url = &value[1];

  2762.     n = ngx_http_script_variables_count(url);

  2763.     if (n) {

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

  2765.         sc.cf = cf;
  2766.         sc.source = url;
  2767.         sc.lengths = &flcf->fastcgi_lengths;
  2768.         sc.values = &flcf->fastcgi_values;
  2769.         sc.variables = n;
  2770.         sc.complete_lengths = 1;
  2771.         sc.complete_values = 1;

  2772.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  2773.             return NGX_CONF_ERROR;
  2774.         }

  2775.         return NGX_CONF_OK;
  2776.     }

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

  2778.     u.url = value[1];
  2779.     u.no_resolve = 1;

  2780.     flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  2781.     if (flcf->upstream.upstream == NULL) {
  2782.         return NGX_CONF_ERROR;
  2783.     }

  2784.     return NGX_CONF_OK;
  2785. }


  2786. static char *
  2787. ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2788. {
  2789. #if (NGX_PCRE)
  2790.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2791.     ngx_str_t            *value;
  2792.     ngx_regex_compile_t   rc;
  2793.     u_char                errstr[NGX_MAX_CONF_ERRSTR];

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

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

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

  2797.     rc.pattern = value[1];
  2798.     rc.pool = cf->pool;
  2799.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  2800.     rc.err.data = errstr;

  2801.     if (ngx_regex_compile(&rc) != NGX_OK) {
  2802.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
  2803.         return NGX_CONF_ERROR;
  2804.     }

  2805.     if (rc.captures != 2) {
  2806.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2807.                            "pattern \"%V\" must have 2 captures", &value[1]);
  2808.         return NGX_CONF_ERROR;
  2809.     }

  2810.     flcf->split_regex = rc.regex;

  2811.     return NGX_CONF_OK;

  2812. #else

  2813.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2814.                        "\"%V\" requires PCRE library", &cmd->name);
  2815.     return NGX_CONF_ERROR;

  2816. #endif
  2817. }


  2818. static char *
  2819. ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2820. {
  2821.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2822.     ngx_str_t                  *value;
  2823.     ngx_http_script_compile_t   sc;

  2824.     if (flcf->upstream.store != NGX_CONF_UNSET) {
  2825.         return "is duplicate";
  2826.     }

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

  2828.     if (ngx_strcmp(value[1].data, "off") == 0) {
  2829.         flcf->upstream.store = 0;
  2830.         return NGX_CONF_OK;
  2831.     }

  2832.     if (value[1].len == 0) {
  2833.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
  2834.         return NGX_CONF_ERROR;
  2835.     }

  2836. #if (NGX_HTTP_CACHE)
  2837.     if (flcf->upstream.cache > 0) {
  2838.         return "is incompatible with \"fastcgi_cache\"";
  2839.     }
  2840. #endif

  2841.     flcf->upstream.store = 1;

  2842.     if (ngx_strcmp(value[1].data, "on") == 0) {
  2843.         return NGX_CONF_OK;
  2844.     }

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

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

  2848.     sc.cf = cf;
  2849.     sc.source = &value[1];
  2850.     sc.lengths = &flcf->upstream.store_lengths;
  2851.     sc.values = &flcf->upstream.store_values;
  2852.     sc.variables = ngx_http_script_variables_count(&value[1]);
  2853.     sc.complete_lengths = 1;
  2854.     sc.complete_values = 1;

  2855.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  2856.         return NGX_CONF_ERROR;
  2857.     }

  2858.     return NGX_CONF_OK;
  2859. }


  2860. #if (NGX_HTTP_CACHE)

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

  2865.     ngx_str_t                         *value;
  2866.     ngx_http_complex_value_t           cv;
  2867.     ngx_http_compile_complex_value_t   ccv;

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

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

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

  2876.     if (flcf->upstream.store > 0) {
  2877.         return "is incompatible with \"fastcgi_store\"";
  2878.     }

  2879.     flcf->upstream.cache = 1;

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

  2881.     ccv.cf = cf;
  2882.     ccv.value = &value[1];
  2883.     ccv.complex_value = &cv;

  2884.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  2885.         return NGX_CONF_ERROR;
  2886.     }

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

  2888.         flcf->upstream.cache_value = ngx_palloc(cf->pool,
  2889.                                              sizeof(ngx_http_complex_value_t));
  2890.         if (flcf->upstream.cache_value == NULL) {
  2891.             return NGX_CONF_ERROR;
  2892.         }

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

  2894.         return NGX_CONF_OK;
  2895.     }

  2896.     flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  2897.                                                       &ngx_http_fastcgi_module);
  2898.     if (flcf->upstream.cache_zone == NULL) {
  2899.         return NGX_CONF_ERROR;
  2900.     }

  2901.     return NGX_CONF_OK;
  2902. }


  2903. static char *
  2904. ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  2905. {
  2906.     ngx_http_fastcgi_loc_conf_t *flcf = conf;

  2907.     ngx_str_t                         *value;
  2908.     ngx_http_compile_complex_value_t   ccv;

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

  2910.     if (flcf->cache_key.value.data) {
  2911.         return "is duplicate";
  2912.     }

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

  2914.     ccv.cf = cf;
  2915.     ccv.value = &value[1];
  2916.     ccv.complex_value = &flcf->cache_key;

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

  2920.     return NGX_CONF_OK;
  2921. }

  2922. #endif


  2923. static char *
  2924. ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
  2925. {
  2926. #if (NGX_FREEBSD)
  2927.     ssize_t *np = data;

  2928.     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
  2929.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  2930.                            "\"fastcgi_send_lowat\" must be less than %d "
  2931.                            "(sysctl net.inet.tcp.sendspace)",
  2932.                            ngx_freebsd_net_inet_tcp_sendspace);

  2933.         return NGX_CONF_ERROR;
  2934.     }

  2935. #elif !(NGX_HAVE_SO_SNDLOWAT)
  2936.     ssize_t *np = data;

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

  2939.     *np = 0;

  2940. #endif

  2941.     return NGX_CONF_OK;
  2942. }