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

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. * Copyright (C) Manlio Perillo (manlio.perillo@gmail.com)
  5. */


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


  9. typedef struct {
  10.     ngx_array_t                caches;  /* ngx_http_file_cache_t * */
  11. } ngx_http_scgi_main_conf_t;


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


  19. typedef struct {
  20.     ngx_http_upstream_conf_t   upstream;

  21.     ngx_http_scgi_params_t     params;
  22. #if (NGX_HTTP_CACHE)
  23.     ngx_http_scgi_params_t     params_cache;
  24. #endif
  25.     ngx_array_t               *params_source;

  26.     ngx_array_t               *scgi_lengths;
  27.     ngx_array_t               *scgi_values;

  28. #if (NGX_HTTP_CACHE)
  29.     ngx_http_complex_value_t   cache_key;
  30. #endif
  31. } ngx_http_scgi_loc_conf_t;


  32. static ngx_int_t ngx_http_scgi_eval(ngx_http_request_t *r,
  33.     ngx_http_scgi_loc_conf_t *scf);
  34. static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r);
  35. static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r);
  36. static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r);
  37. static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
  38. static ngx_int_t ngx_http_scgi_input_filter_init(void *data);
  39. static void ngx_http_scgi_abort_request(ngx_http_request_t *r);
  40. static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc);

  41. static void *ngx_http_scgi_create_main_conf(ngx_conf_t *cf);
  42. static void *ngx_http_scgi_create_loc_conf(ngx_conf_t *cf);
  43. static char *ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
  44.     void *child);
  45. static ngx_int_t ngx_http_scgi_init_params(ngx_conf_t *cf,
  46.     ngx_http_scgi_loc_conf_t *conf, ngx_http_scgi_params_t *params,
  47.     ngx_keyval_t *default_params);

  48. static char *ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
  49. static char *ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
  50.     void *conf);

  51. #if (NGX_HTTP_CACHE)
  52. static ngx_int_t ngx_http_scgi_create_key(ngx_http_request_t *r);
  53. static char *ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  54.     void *conf);
  55. static char *ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
  56.     void *conf);
  57. #endif


  58. static ngx_conf_bitmask_t ngx_http_scgi_next_upstream_masks[] = {
  59.     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
  60.     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
  61.     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
  62.     { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
  63.     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
  64.     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
  65.     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
  66.     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
  67.     { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
  68.     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
  69.     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
  70.     { ngx_null_string, 0 }
  71. };


  72. ngx_module_t  ngx_http_scgi_module;


  73. static ngx_command_t ngx_http_scgi_commands[] = {

  74.     { ngx_string("scgi_pass"),
  75.       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
  76.       ngx_http_scgi_pass,
  77.       NGX_HTTP_LOC_CONF_OFFSET,
  78.       0,
  79.       NULL },

  80.     { ngx_string("scgi_store"),
  81.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  82.       ngx_http_scgi_store,
  83.       NGX_HTTP_LOC_CONF_OFFSET,
  84.       0,
  85.       NULL },

  86.     { ngx_string("scgi_store_access"),
  87.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
  88.       ngx_conf_set_access_slot,
  89.       NGX_HTTP_LOC_CONF_OFFSET,
  90.       offsetof(ngx_http_scgi_loc_conf_t, upstream.store_access),
  91.       NULL },

  92.     { ngx_string("scgi_buffering"),
  93.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  94.       ngx_conf_set_flag_slot,
  95.       NGX_HTTP_LOC_CONF_OFFSET,
  96.       offsetof(ngx_http_scgi_loc_conf_t, upstream.buffering),
  97.       NULL },

  98.     { ngx_string("scgi_request_buffering"),
  99.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  100.       ngx_conf_set_flag_slot,
  101.       NGX_HTTP_LOC_CONF_OFFSET,
  102.       offsetof(ngx_http_scgi_loc_conf_t, upstream.request_buffering),
  103.       NULL },

  104.     { ngx_string("scgi_ignore_client_abort"),
  105.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  106.       ngx_conf_set_flag_slot,
  107.       NGX_HTTP_LOC_CONF_OFFSET,
  108.       offsetof(ngx_http_scgi_loc_conf_t, upstream.ignore_client_abort),
  109.       NULL },

  110.     { ngx_string("scgi_bind"),
  111.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  112.       ngx_http_upstream_bind_set_slot,
  113.       NGX_HTTP_LOC_CONF_OFFSET,
  114.       offsetof(ngx_http_scgi_loc_conf_t, upstream.local),
  115.       NULL },

  116.     { ngx_string("scgi_socket_keepalive"),
  117.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  118.       ngx_conf_set_flag_slot,
  119.       NGX_HTTP_LOC_CONF_OFFSET,
  120.       offsetof(ngx_http_scgi_loc_conf_t, upstream.socket_keepalive),
  121.       NULL },

  122.     { ngx_string("scgi_socket_rcvbuf"),
  123.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  124.       ngx_conf_set_size_slot,
  125.       NGX_HTTP_LOC_CONF_OFFSET,
  126.       offsetof(ngx_http_scgi_loc_conf_t, upstream.socket_rcvbuf),
  127.       NULL },

  128.     { ngx_string("scgi_socket_sndbuf"),
  129.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  130.       ngx_conf_set_size_slot,
  131.       NGX_HTTP_LOC_CONF_OFFSET,
  132.       offsetof(ngx_http_scgi_loc_conf_t, upstream.socket_sndbuf),
  133.       NULL },

  134.     { ngx_string("scgi_connect_timeout"),
  135.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  136.       ngx_conf_set_msec_slot,
  137.       NGX_HTTP_LOC_CONF_OFFSET,
  138.       offsetof(ngx_http_scgi_loc_conf_t, upstream.connect_timeout),
  139.       NULL },

  140.     { ngx_string("scgi_send_timeout"),
  141.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  142.       ngx_conf_set_msec_slot,
  143.       NGX_HTTP_LOC_CONF_OFFSET,
  144.       offsetof(ngx_http_scgi_loc_conf_t, upstream.send_timeout),
  145.       NULL },

  146.     { ngx_string("scgi_buffer_size"),
  147.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  148.       ngx_conf_set_size_slot,
  149.       NGX_HTTP_LOC_CONF_OFFSET,
  150.       offsetof(ngx_http_scgi_loc_conf_t, upstream.buffer_size),
  151.       NULL },

  152.     { ngx_string("scgi_pass_request_headers"),
  153.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  154.       ngx_conf_set_flag_slot,
  155.       NGX_HTTP_LOC_CONF_OFFSET,
  156.       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_request_headers),
  157.       NULL },

  158.     { ngx_string("scgi_pass_request_body"),
  159.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  160.       ngx_conf_set_flag_slot,
  161.       NGX_HTTP_LOC_CONF_OFFSET,
  162.       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_request_body),
  163.       NULL },

  164.     { ngx_string("scgi_intercept_errors"),
  165.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  166.       ngx_conf_set_flag_slot,
  167.       NGX_HTTP_LOC_CONF_OFFSET,
  168.       offsetof(ngx_http_scgi_loc_conf_t, upstream.intercept_errors),
  169.       NULL },

  170.     { ngx_string("scgi_read_timeout"),
  171.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  172.       ngx_conf_set_msec_slot,
  173.       NGX_HTTP_LOC_CONF_OFFSET,
  174.       offsetof(ngx_http_scgi_loc_conf_t, upstream.read_timeout),
  175.       NULL },

  176.     { ngx_string("scgi_buffers"),
  177.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  178.       ngx_conf_set_bufs_slot,
  179.       NGX_HTTP_LOC_CONF_OFFSET,
  180.       offsetof(ngx_http_scgi_loc_conf_t, upstream.bufs),
  181.       NULL },

  182.     { ngx_string("scgi_busy_buffers_size"),
  183.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  184.       ngx_conf_set_size_slot,
  185.       NGX_HTTP_LOC_CONF_OFFSET,
  186.       offsetof(ngx_http_scgi_loc_conf_t, upstream.busy_buffers_size_conf),
  187.       NULL },

  188.     { ngx_string("scgi_force_ranges"),
  189.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  190.       ngx_conf_set_flag_slot,
  191.       NGX_HTTP_LOC_CONF_OFFSET,
  192.       offsetof(ngx_http_scgi_loc_conf_t, upstream.force_ranges),
  193.       NULL },

  194.     { ngx_string("scgi_limit_rate"),
  195.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  196.       ngx_http_set_complex_value_size_slot,
  197.       NGX_HTTP_LOC_CONF_OFFSET,
  198.       offsetof(ngx_http_scgi_loc_conf_t, upstream.limit_rate),
  199.       NULL },

  200. #if (NGX_HTTP_CACHE)

  201.     { ngx_string("scgi_cache"),
  202.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  203.       ngx_http_scgi_cache,
  204.       NGX_HTTP_LOC_CONF_OFFSET,
  205.       0,
  206.       NULL },

  207.     { ngx_string("scgi_cache_key"),
  208.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  209.       ngx_http_scgi_cache_key,
  210.       NGX_HTTP_LOC_CONF_OFFSET,
  211.       0,
  212.       NULL },

  213.     { ngx_string("scgi_cache_path"),
  214.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  215.       ngx_http_file_cache_set_slot,
  216.       NGX_HTTP_MAIN_CONF_OFFSET,
  217.       offsetof(ngx_http_scgi_main_conf_t, caches),
  218.       &ngx_http_scgi_module },

  219.     { ngx_string("scgi_cache_bypass"),
  220.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  221.       ngx_http_set_predicate_slot,
  222.       NGX_HTTP_LOC_CONF_OFFSET,
  223.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_bypass),
  224.       NULL },

  225.     { ngx_string("scgi_no_cache"),
  226.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  227.       ngx_http_set_predicate_slot,
  228.       NGX_HTTP_LOC_CONF_OFFSET,
  229.       offsetof(ngx_http_scgi_loc_conf_t, upstream.no_cache),
  230.       NULL },

  231.     { ngx_string("scgi_cache_valid"),
  232.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  233.       ngx_http_file_cache_valid_set_slot,
  234.       NGX_HTTP_LOC_CONF_OFFSET,
  235.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_valid),
  236.       NULL },

  237.     { ngx_string("scgi_cache_min_uses"),
  238.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  239.       ngx_conf_set_num_slot,
  240.       NGX_HTTP_LOC_CONF_OFFSET,
  241.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_min_uses),
  242.       NULL },

  243.     { ngx_string("scgi_cache_max_range_offset"),
  244.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  245.       ngx_conf_set_off_slot,
  246.       NGX_HTTP_LOC_CONF_OFFSET,
  247.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_max_range_offset),
  248.       NULL },

  249.     { ngx_string("scgi_cache_use_stale"),
  250.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  251.       ngx_conf_set_bitmask_slot,
  252.       NGX_HTTP_LOC_CONF_OFFSET,
  253.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_use_stale),
  254.       &ngx_http_scgi_next_upstream_masks },

  255.     { ngx_string("scgi_cache_methods"),
  256.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  257.       ngx_conf_set_bitmask_slot,
  258.       NGX_HTTP_LOC_CONF_OFFSET,
  259.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_methods),
  260.       &ngx_http_upstream_cache_method_mask },

  261.     { ngx_string("scgi_cache_lock"),
  262.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  263.       ngx_conf_set_flag_slot,
  264.       NGX_HTTP_LOC_CONF_OFFSET,
  265.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock),
  266.       NULL },

  267.     { ngx_string("scgi_cache_lock_timeout"),
  268.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  269.       ngx_conf_set_msec_slot,
  270.       NGX_HTTP_LOC_CONF_OFFSET,
  271.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout),
  272.       NULL },

  273.     { ngx_string("scgi_cache_lock_age"),
  274.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  275.       ngx_conf_set_msec_slot,
  276.       NGX_HTTP_LOC_CONF_OFFSET,
  277.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_age),
  278.       NULL },

  279.     { ngx_string("scgi_cache_revalidate"),
  280.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  281.       ngx_conf_set_flag_slot,
  282.       NGX_HTTP_LOC_CONF_OFFSET,
  283.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_revalidate),
  284.       NULL },

  285.     { ngx_string("scgi_cache_background_update"),
  286.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  287.       ngx_conf_set_flag_slot,
  288.       NGX_HTTP_LOC_CONF_OFFSET,
  289.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_background_update),
  290.       NULL },

  291. #endif

  292.     { ngx_string("scgi_temp_path"),
  293.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  294.       ngx_conf_set_path_slot,
  295.       NGX_HTTP_LOC_CONF_OFFSET,
  296.       offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_path),
  297.       NULL },

  298.     { ngx_string("scgi_max_temp_file_size"),
  299.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  300.       ngx_conf_set_size_slot,
  301.       NGX_HTTP_LOC_CONF_OFFSET,
  302.       offsetof(ngx_http_scgi_loc_conf_t, upstream.max_temp_file_size_conf),
  303.       NULL },

  304.     { ngx_string("scgi_temp_file_write_size"),
  305.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  306.       ngx_conf_set_size_slot,
  307.       NGX_HTTP_LOC_CONF_OFFSET,
  308.       offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_file_write_size_conf),
  309.       NULL },

  310.     { ngx_string("scgi_next_upstream"),
  311.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  312.       ngx_conf_set_bitmask_slot,
  313.       NGX_HTTP_LOC_CONF_OFFSET,
  314.       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream),
  315.       &ngx_http_scgi_next_upstream_masks },

  316.     { ngx_string("scgi_next_upstream_tries"),
  317.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  318.       ngx_conf_set_num_slot,
  319.       NGX_HTTP_LOC_CONF_OFFSET,
  320.       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_tries),
  321.       NULL },

  322.     { ngx_string("scgi_next_upstream_timeout"),
  323.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  324.       ngx_conf_set_msec_slot,
  325.       NGX_HTTP_LOC_CONF_OFFSET,
  326.       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_timeout),
  327.       NULL },

  328.     { ngx_string("scgi_param"),
  329.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
  330.       ngx_http_upstream_param_set_slot,
  331.       NGX_HTTP_LOC_CONF_OFFSET,
  332.       offsetof(ngx_http_scgi_loc_conf_t, params_source),
  333.       NULL },

  334.     { ngx_string("scgi_pass_header"),
  335.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  336.       ngx_conf_set_str_array_slot,
  337.       NGX_HTTP_LOC_CONF_OFFSET,
  338.       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_headers),
  339.       NULL },

  340.     { ngx_string("scgi_hide_header"),
  341.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  342.       ngx_conf_set_str_array_slot,
  343.       NGX_HTTP_LOC_CONF_OFFSET,
  344.       offsetof(ngx_http_scgi_loc_conf_t, upstream.hide_headers),
  345.       NULL },

  346.     { ngx_string("scgi_ignore_headers"),
  347.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  348.       ngx_conf_set_bitmask_slot,
  349.       NGX_HTTP_LOC_CONF_OFFSET,
  350.       offsetof(ngx_http_scgi_loc_conf_t, upstream.ignore_headers),
  351.       &ngx_http_upstream_ignore_headers_masks },

  352.       ngx_null_command
  353. };


  354. static ngx_http_module_t ngx_http_scgi_module_ctx = {
  355.     NULL,                                  /* preconfiguration */
  356.     NULL,                                  /* postconfiguration */

  357.     ngx_http_scgi_create_main_conf,        /* create main configuration */
  358.     NULL,                                  /* init main configuration */

  359.     NULL,                                  /* create server configuration */
  360.     NULL,                                  /* merge server configuration */

  361.     ngx_http_scgi_create_loc_conf,         /* create location configuration */
  362.     ngx_http_scgi_merge_loc_conf           /* merge location configuration */
  363. };


  364. ngx_module_t ngx_http_scgi_module = {
  365.     NGX_MODULE_V1,
  366.     &ngx_http_scgi_module_ctx,             /* module context */
  367.     ngx_http_scgi_commands,                /* module directives */
  368.     NGX_HTTP_MODULE,                       /* module type */
  369.     NULL,                                  /* init master */
  370.     NULL,                                  /* init module */
  371.     NULL,                                  /* init process */
  372.     NULL,                                  /* init thread */
  373.     NULL,                                  /* exit thread */
  374.     NULL,                                  /* exit process */
  375.     NULL,                                  /* exit master */
  376.     NGX_MODULE_V1_PADDING
  377. };


  378. static ngx_str_t ngx_http_scgi_hide_headers[] = {
  379.     ngx_string("Status"),
  380.     ngx_string("X-Accel-Expires"),
  381.     ngx_string("X-Accel-Redirect"),
  382.     ngx_string("X-Accel-Limit-Rate"),
  383.     ngx_string("X-Accel-Buffering"),
  384.     ngx_string("X-Accel-Charset"),
  385.     ngx_null_string
  386. };


  387. static ngx_keyval_t  ngx_http_scgi_headers[] = {
  388.     { ngx_string("HTTP_HOST"),
  389.       ngx_string("$host$is_request_port$request_port") },
  390.     { ngx_null_string, ngx_null_string }
  391. };


  392. #if (NGX_HTTP_CACHE)

  393. static ngx_keyval_t  ngx_http_scgi_cache_headers[] = {
  394.     { ngx_string("HTTP_HOST"),
  395.       ngx_string("$host$is_request_port$request_port") },
  396.     { ngx_string("HTTP_IF_MODIFIED_SINCE"),
  397.       ngx_string("$upstream_cache_last_modified") },
  398.     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
  399.     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
  400.     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
  401.     { ngx_string("HTTP_RANGE"), ngx_string("") },
  402.     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
  403.     { ngx_null_string, ngx_null_string }
  404. };

  405. #endif


  406. static ngx_path_init_t ngx_http_scgi_temp_path = {
  407.     ngx_string(NGX_HTTP_SCGI_TEMP_PATH), { 1, 2, 0 }
  408. };


  409. static ngx_int_t
  410. ngx_http_scgi_handler(ngx_http_request_t *r)
  411. {
  412.     ngx_int_t                   rc;
  413.     ngx_http_status_t          *status;
  414.     ngx_http_upstream_t        *u;
  415.     ngx_http_scgi_loc_conf_t   *scf;
  416. #if (NGX_HTTP_CACHE)
  417.     ngx_http_scgi_main_conf_t  *smcf;
  418. #endif

  419.     if (ngx_http_upstream_create(r) != NGX_OK) {
  420.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  421.     }

  422.     status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
  423.     if (status == NULL) {
  424.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  425.     }

  426.     ngx_http_set_ctx(r, status, ngx_http_scgi_module);

  427.     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);

  428.     if (scf->scgi_lengths) {
  429.         if (ngx_http_scgi_eval(r, scf) != NGX_OK) {
  430.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  431.         }
  432.     }

  433.     u = r->upstream;

  434.     ngx_str_set(&u->schema, "scgi://");
  435.     u->output.tag = (ngx_buf_tag_t) &ngx_http_scgi_module;

  436.     u->conf = &scf->upstream;

  437. #if (NGX_HTTP_CACHE)
  438.     smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module);

  439.     u->caches = &smcf->caches;
  440.     u->create_key = ngx_http_scgi_create_key;
  441. #endif

  442.     u->create_request = ngx_http_scgi_create_request;
  443.     u->reinit_request = ngx_http_scgi_reinit_request;
  444.     u->process_header = ngx_http_scgi_process_status_line;
  445.     u->abort_request = ngx_http_scgi_abort_request;
  446.     u->finalize_request = ngx_http_scgi_finalize_request;
  447.     r->state = 0;

  448.     u->buffering = scf->upstream.buffering;

  449.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  450.     if (u->pipe == NULL) {
  451.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  452.     }

  453.     u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
  454.     u->pipe->input_ctx = r;

  455.     u->input_filter_init = ngx_http_scgi_input_filter_init;
  456.     u->input_filter = ngx_http_upstream_non_buffered_filter;
  457.     u->input_filter_ctx = r;

  458.     if (!scf->upstream.request_buffering
  459.         && scf->upstream.pass_request_body
  460.         && !r->headers_in.chunked)
  461.     {
  462.         r->request_body_no_buffering = 1;
  463.     }

  464.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  465.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  466.         return rc;
  467.     }

  468.     return NGX_DONE;
  469. }


  470. static ngx_int_t
  471. ngx_http_scgi_eval(ngx_http_request_t *r, ngx_http_scgi_loc_conf_t * scf)
  472. {
  473.     ngx_url_t             url;
  474.     ngx_http_upstream_t  *u;

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

  476.     if (ngx_http_script_run(r, &url.url, scf->scgi_lengths->elts, 0,
  477.                             scf->scgi_values->elts)
  478.         == NULL)
  479.     {
  480.         return NGX_ERROR;
  481.     }

  482.     url.no_resolve = 1;

  483.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  484.         if (url.err) {
  485.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  486.                           "%s in upstream \"%V\"", url.err, &url.url);
  487.         }

  488.         return NGX_ERROR;
  489.     }

  490.     u = r->upstream;

  491.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  492.     if (u->resolved == NULL) {
  493.         return NGX_ERROR;
  494.     }

  495.     if (url.addrs) {
  496.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  497.         u->resolved->socklen = url.addrs[0].socklen;
  498.         u->resolved->name = url.addrs[0].name;
  499.         u->resolved->naddrs = 1;
  500.     }

  501.     u->resolved->host = url.host;
  502.     u->resolved->port = url.port;
  503.     u->resolved->no_port = url.no_port;

  504.     return NGX_OK;
  505. }


  506. #if (NGX_HTTP_CACHE)

  507. static ngx_int_t
  508. ngx_http_scgi_create_key(ngx_http_request_t *r)
  509. {
  510.     ngx_str_t                 *key;
  511.     ngx_http_scgi_loc_conf_t  *scf;

  512.     key = ngx_array_push(&r->cache->keys);
  513.     if (key == NULL) {
  514.         return NGX_ERROR;
  515.     }

  516.     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);

  517.     if (ngx_http_complex_value(r, &scf->cache_key, key) != NGX_OK) {
  518.         return NGX_ERROR;
  519.     }

  520.     return NGX_OK;
  521. }

  522. #endif


  523. static ngx_int_t
  524. ngx_http_scgi_create_request(ngx_http_request_t *r)
  525. {
  526.     off_t                         content_length_n;
  527.     u_char                        ch, sep, *key, *val, *lowcase_key;
  528.     size_t                        len, params_len, key_len, val_len, allocated;
  529.     ngx_buf_t                    *b;
  530.     ngx_str_t                     content_length;
  531.     ngx_uint_t                    i, n, hash, skip_empty, header_params;
  532.     ngx_chain_t                  *cl, *body;
  533.     ngx_list_part_t              *part;
  534.     ngx_table_elt_t              *header, *hn, **ignored;
  535.     ngx_http_scgi_params_t       *params;
  536.     ngx_http_script_code_pt       code;
  537.     ngx_http_script_engine_t      e, le;
  538.     ngx_http_scgi_loc_conf_t     *scf;
  539.     ngx_http_script_len_code_pt   lcode;
  540.     u_char                        buffer[NGX_OFF_T_LEN];

  541.     content_length_n = 0;

  542.     if (r->headers_in.content_length_n > 0) {
  543.         content_length_n = r->headers_in.content_length_n;
  544.     }

  545.     content_length.data = buffer;
  546.     content_length.len = ngx_sprintf(buffer, "%O", content_length_n) - buffer;

  547.     len = sizeof("CONTENT_LENGTH") + content_length.len + 1;

  548.     params_len = 0;
  549.     header_params = 0;
  550.     ignored = NULL;

  551.     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);

  552. #if (NGX_HTTP_CACHE)
  553.     params = r->upstream->cacheable ? &scf->params_cache : &scf->params;
  554. #else
  555.     params = &scf->params;
  556. #endif

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

  559.         ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
  560.         le.flushed = 1;

  561.         le.ip = params->lengths->elts;
  562.         le.request = r;

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

  564.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  565.             key_len = lcode(&le);

  566.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  567.             skip_empty = lcode(&le);

  568.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  569.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  570.             }
  571.             le.ip += sizeof(uintptr_t);

  572.             if (skip_empty && val_len == 0) {
  573.                 continue;
  574.             }

  575.             params_len += key_len + val_len + 1;
  576.         }

  577.         len += params_len;
  578.     }

  579.     if (scf->upstream.pass_request_headers) {

  580.         allocated = 0;
  581.         lowcase_key = NULL;

  582.         if (ngx_http_link_multi_headers(r) != NGX_OK) {
  583.             return NGX_ERROR;
  584.         }

  585.         if (params->number || r->headers_in.multi) {
  586.             n = 0;
  587.             part = &r->headers_in.headers.part;

  588.             while (part) {
  589.                 n += part->nelts;
  590.                 part = part->next;
  591.             }

  592.             ignored = ngx_palloc(r->pool, n * sizeof(void *));
  593.             if (ignored == NULL) {
  594.                 return NGX_ERROR;
  595.             }
  596.         }

  597.         part = &r->headers_in.headers.part;
  598.         header = part->elts;

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

  600.             if (i >= part->nelts) {
  601.                 if (part->next == NULL) {
  602.                     break;
  603.                 }

  604.                 part = part->next;
  605.                 header = part->elts;
  606.                 i = 0;
  607.             }

  608.             for (n = 0; n < header_params; n++) {
  609.                 if (&header[i] == ignored[n]) {
  610.                     goto next_length;
  611.                 }
  612.             }

  613.             if (params->number) {
  614.                 if (allocated < header[i].key.len) {
  615.                     allocated = header[i].key.len + 16;
  616.                     lowcase_key = ngx_pnalloc(r->pool, allocated);
  617.                     if (lowcase_key == NULL) {
  618.                         return NGX_ERROR;
  619.                     }
  620.                 }

  621.                 hash = 0;

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

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

  626.                     } else if (ch == '-') {
  627.                         ch = '_';
  628.                     }

  629.                     hash = ngx_hash(hash, ch);
  630.                     lowcase_key[n] = ch;
  631.                 }

  632.                 if (ngx_hash_find(&params->hash, hash, lowcase_key, n)) {
  633.                     ignored[header_params++] = &header[i];
  634.                     continue;
  635.                 }
  636.             }

  637.             len += sizeof("HTTP_") - 1 + header[i].key.len + 1
  638.                 + header[i].value.len + 1;

  639.             for (hn = header[i].next; hn; hn = hn->next) {
  640.                 len += hn->value.len + 2;
  641.                 ignored[header_params++] = hn;
  642.             }

  643.         next_length:

  644.             continue;
  645.         }
  646.     }

  647.     /* netstring: "length:" + packet + "," */

  648.     b = ngx_create_temp_buf(r->pool, NGX_SIZE_T_LEN + 1 + len + 1);
  649.     if (b == NULL) {
  650.         return NGX_ERROR;
  651.     }

  652.     cl = ngx_alloc_chain_link(r->pool);
  653.     if (cl == NULL) {
  654.         return NGX_ERROR;
  655.     }

  656.     cl->buf = b;

  657.     b->last = ngx_sprintf(b->last, "%ui:CONTENT_LENGTH%Z%V%Z",
  658.                           len, &content_length);

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

  661.         e.ip = params->values->elts;
  662.         e.pos = b->last;
  663.         e.end = b->last + params_len;
  664.         e.request = r;
  665.         e.flushed = 1;

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

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

  668.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  669.             lcode(&le); /* key length */

  670.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  671.             skip_empty = lcode(&le);

  672.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  673.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  674.             }
  675.             le.ip += sizeof(uintptr_t);

  676.             if (skip_empty && val_len == 0) {
  677.                 e.skip = 1;

  678.                 while (*(uintptr_t *) e.ip) {
  679.                     code = *(ngx_http_script_code_pt *) e.ip;
  680.                     code((ngx_http_script_engine_t *) &e);
  681.                 }
  682.                 e.ip += sizeof(uintptr_t);

  683.                 e.skip = 0;

  684.                 continue;
  685.             }

  686. #if (NGX_DEBUG)
  687.             key = e.pos;
  688. #endif
  689.             code = *(ngx_http_script_code_pt *) e.ip;
  690.             code((ngx_http_script_engine_t *) &e);

  691.             if (e.status) {
  692.                 return NGX_ERROR;
  693.             }

  694. #if (NGX_DEBUG)
  695.             val = e.pos;
  696. #endif
  697.             while (*(uintptr_t *) e.ip) {
  698.                 code = *(ngx_http_script_code_pt *) e.ip;
  699.                 code((ngx_http_script_engine_t *) &e);
  700.             }

  701.             if (e.status) {
  702.                 return NGX_ERROR;
  703.             }

  704.             if (ngx_http_script_check_length(&e, 1) != NGX_OK) {
  705.                 return NGX_ERROR;
  706.             }

  707.             *e.pos++ = '\0';
  708.             e.ip += sizeof(uintptr_t);

  709.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  710.                            "scgi param: \"%s: %s\"", key, val);
  711.         }

  712.         if (e.pos != e.end) {
  713.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  714.                           "scgi request length mismatch");
  715.             return NGX_ERROR;
  716.         }

  717.         b->last = e.pos;
  718.     }

  719.     if (scf->upstream.pass_request_headers) {

  720.         part = &r->headers_in.headers.part;
  721.         header = part->elts;

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

  723.             if (i >= part->nelts) {
  724.                 if (part->next == NULL) {
  725.                     break;
  726.                 }

  727.                 part = part->next;
  728.                 header = part->elts;
  729.                 i = 0;
  730.             }

  731.             for (n = 0; n < header_params; n++) {
  732.                 if (&header[i] == ignored[n]) {
  733.                     goto next_value;
  734.                 }
  735.             }

  736.             key = b->last;
  737.             b->last = ngx_cpymem(key, "HTTP_", sizeof("HTTP_") - 1);

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

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

  742.                 } else if (ch == '-') {
  743.                     ch = '_';
  744.                 }

  745.                 *b->last++ = ch;
  746.             }

  747.             *b->last++ = (u_char) 0;

  748.             val = b->last;
  749.             b->last = ngx_copy(val, header[i].value.data, header[i].value.len);

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

  751.                 if (header[i].key.len == sizeof("Cookie") - 1
  752.                     && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
  753.                                        sizeof("Cookie") - 1)
  754.                        == 0)
  755.                 {
  756.                     sep = ';';

  757.                 } else {
  758.                     sep = ',';
  759.                 }

  760.                 for (hn = header[i].next; hn; hn = hn->next) {
  761.                     *b->last++ = sep;
  762.                     *b->last++ = ' ';
  763.                     b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
  764.                 }
  765.             }

  766.             *b->last++ = (u_char) 0;

  767.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  768.                            "scgi param: \"%s: %s\"", key, val);

  769.         next_value:

  770.             continue;
  771.         }
  772.     }

  773.     *b->last++ = (u_char) ',';

  774.     if (r->request_body_no_buffering) {
  775.         r->upstream->request_bufs = cl;

  776.     } else if (scf->upstream.pass_request_body) {
  777.         body = r->upstream->request_bufs;
  778.         r->upstream->request_bufs = cl;

  779.         while (body) {
  780.             b = ngx_alloc_buf(r->pool);
  781.             if (b == NULL) {
  782.                 return NGX_ERROR;
  783.             }

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

  785.             cl->next = ngx_alloc_chain_link(r->pool);
  786.             if (cl->next == NULL) {
  787.                 return NGX_ERROR;
  788.             }

  789.             cl = cl->next;
  790.             cl->buf = b;

  791.             body = body->next;
  792.         }

  793.     } else {
  794.         r->upstream->request_bufs = cl;
  795.     }

  796.     cl->next = NULL;

  797.     return NGX_OK;
  798. }


  799. static ngx_int_t
  800. ngx_http_scgi_reinit_request(ngx_http_request_t *r)
  801. {
  802.     ngx_http_status_t  *status;

  803.     status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);

  804.     if (status == NULL) {
  805.         return NGX_OK;
  806.     }

  807.     status->code = 0;
  808.     status->count = 0;
  809.     status->start = NULL;
  810.     status->end = NULL;

  811.     r->upstream->process_header = ngx_http_scgi_process_status_line;
  812.     r->state = 0;

  813.     return NGX_OK;
  814. }


  815. static ngx_int_t
  816. ngx_http_scgi_process_status_line(ngx_http_request_t *r)
  817. {
  818.     size_t                len;
  819.     ngx_int_t             rc;
  820.     ngx_http_status_t    *status;
  821.     ngx_http_upstream_t  *u;

  822.     status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);

  823.     if (status == NULL) {
  824.         return NGX_ERROR;
  825.     }

  826.     u = r->upstream;

  827.     rc = ngx_http_parse_status_line(r, &u->buffer, status);

  828.     if (rc == NGX_AGAIN) {
  829.         return rc;
  830.     }

  831.     if (rc == NGX_ERROR) {
  832.         u->process_header = ngx_http_scgi_process_header;
  833.         u->buffer.pos = status->line_start;
  834.         r->state = 0;
  835.         return ngx_http_scgi_process_header(r);
  836.     }

  837.     if (u->state && u->state->status == 0) {
  838.         u->state->status = status->code;
  839.     }

  840.     u->headers_in.status_n = status->code;

  841.     len = status->end - status->start;
  842.     u->headers_in.status_line.len = len;

  843.     u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
  844.     if (u->headers_in.status_line.data == NULL) {
  845.         return NGX_ERROR;
  846.     }

  847.     ngx_memcpy(u->headers_in.status_line.data, status->start, len);

  848.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  849.                    "http scgi status %ui \"%V\"",
  850.                    u->headers_in.status_n, &u->headers_in.status_line);

  851.     u->process_header = ngx_http_scgi_process_header;

  852.     return ngx_http_scgi_process_header(r);
  853. }


  854. static ngx_int_t
  855. ngx_http_scgi_process_header(ngx_http_request_t *r)
  856. {
  857.     ngx_str_t                      *status_line;
  858.     ngx_int_t                       rc, status;
  859.     ngx_table_elt_t                *h;
  860.     ngx_http_upstream_t            *u;
  861.     ngx_http_upstream_header_t     *hh;
  862.     ngx_http_upstream_main_conf_t  *umcf;

  863.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  864.     for ( ;; ) {

  865.         rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);

  866.         if (rc == NGX_OK) {

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

  868.             h = ngx_list_push(&r->upstream->headers_in.headers);
  869.             if (h == NULL) {
  870.                 return NGX_ERROR;
  871.             }

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

  873.             h->key.len = r->header_name_end - r->header_name_start;
  874.             h->value.len = r->header_end - r->header_start;

  875.             h->key.data = ngx_pnalloc(r->pool,
  876.                                       h->key.len + 1 + h->value.len + 1
  877.                                       + h->key.len);
  878.             if (h->key.data == NULL) {
  879.                 h->hash = 0;
  880.                 return NGX_ERROR;
  881.             }

  882.             h->value.data = h->key.data + h->key.len + 1;
  883.             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;

  884.             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  885.             h->key.data[h->key.len] = '\0';
  886.             ngx_memcpy(h->value.data, r->header_start, h->value.len);
  887.             h->value.data[h->value.len] = '\0';

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

  890.             } else {
  891.                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  892.             }

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

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

  897.                 if (rc != NGX_OK) {
  898.                     return rc;
  899.                 }
  900.             }

  901.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  902.                            "http scgi header: \"%V: %V\"", &h->key, &h->value);

  903.             continue;
  904.         }

  905.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

  907.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  908.                            "http scgi header done");

  909.             u = r->upstream;

  910.             if (u->headers_in.status_n) {
  911.                 goto done;
  912.             }

  913.             if (u->headers_in.status) {
  914.                 status_line = &u->headers_in.status->value;

  915.                 status = ngx_atoi(status_line->data, 3);
  916.                 if (status == NGX_ERROR) {
  917.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  918.                                   "upstream sent invalid status \"%V\"",
  919.                                   status_line);
  920.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  921.                 }

  922.                 u->headers_in.status_n = status;

  923.                 if (status_line->len > 3) {
  924.                     u->headers_in.status_line = *status_line;
  925.                 }

  926.             } else if (u->headers_in.location) {
  927.                 u->headers_in.status_n = 302;
  928.                 ngx_str_set(&u->headers_in.status_line,
  929.                             "302 Moved Temporarily");

  930.             } else {
  931.                 u->headers_in.status_n = 200;
  932.                 ngx_str_set(&u->headers_in.status_line, "200 OK");
  933.             }

  934.             if (u->state && u->state->status == 0) {
  935.                 u->state->status = u->headers_in.status_n;
  936.             }

  937.         done:

  938.             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS
  939.                 && r->headers_in.upgrade)
  940.             {
  941.                 u->upgrade = 1;
  942.             }

  943.             return NGX_OK;
  944.         }

  945.         if (rc == NGX_AGAIN) {
  946.             return NGX_AGAIN;
  947.         }

  948.         /* rc == NGX_HTTP_PARSE_INVALID_HEADER */

  949.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  950.                       "upstream sent invalid header: \"%*s\\x%02xd...\"",
  951.                       r->header_end - r->header_name_start,
  952.                       r->header_name_start, *r->header_end);

  953.         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  954.     }
  955. }


  956. static ngx_int_t
  957. ngx_http_scgi_input_filter_init(void *data)
  958. {
  959.     ngx_http_request_t   *r = data;
  960.     ngx_http_upstream_t  *u;

  961.     u = r->upstream;

  962.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  963.                    "http scgi filter init s:%ui l:%O",
  964.                    u->headers_in.status_n, u->headers_in.content_length_n);

  965.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  966.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
  967.     {
  968.         u->pipe->length = 0;
  969.         u->length = 0;

  970.     } else if (r->method == NGX_HTTP_HEAD) {
  971.         u->pipe->length = -1;
  972.         u->length = -1;

  973.     } else {
  974.         u->pipe->length = u->headers_in.content_length_n;
  975.         u->length = u->headers_in.content_length_n;
  976.     }

  977.     return NGX_OK;
  978. }


  979. static void
  980. ngx_http_scgi_abort_request(ngx_http_request_t *r)
  981. {
  982.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  983.                    "abort http scgi request");

  984.     return;
  985. }


  986. static void
  987. ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  988. {
  989.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  990.                    "finalize http scgi request");

  991.     return;
  992. }


  993. static void *
  994. ngx_http_scgi_create_main_conf(ngx_conf_t *cf)
  995. {
  996.     ngx_http_scgi_main_conf_t  *conf;

  997.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_main_conf_t));
  998.     if (conf == NULL) {
  999.         return NULL;
  1000.     }

  1001. #if (NGX_HTTP_CACHE)
  1002.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  1003.                        sizeof(ngx_http_file_cache_t *))
  1004.         != NGX_OK)
  1005.     {
  1006.         return NULL;
  1007.     }
  1008. #endif

  1009.     return conf;
  1010. }


  1011. static void *
  1012. ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
  1013. {
  1014.     ngx_http_scgi_loc_conf_t  *conf;

  1015.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_loc_conf_t));
  1016.     if (conf == NULL) {
  1017.         return NULL;
  1018.     }

  1019.     /*
  1020.      * set by ngx_pcalloc():
  1021.      *
  1022.      *     conf->upstream.bufs.num = 0;
  1023.      *     conf->upstream.ignore_headers = 0;
  1024.      *     conf->upstream.next_upstream = 0;
  1025.      *     conf->upstream.cache_zone = NULL;
  1026.      *     conf->upstream.cache_use_stale = 0;
  1027.      *     conf->upstream.cache_methods = 0;
  1028.      *     conf->upstream.temp_path = NULL;
  1029.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  1030.      *     conf->upstream.store_lengths = NULL;
  1031.      *     conf->upstream.store_values = NULL;
  1032.      */

  1033.     conf->upstream.store = NGX_CONF_UNSET;
  1034.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  1035.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  1036.     conf->upstream.buffering = NGX_CONF_UNSET;
  1037.     conf->upstream.request_buffering = NGX_CONF_UNSET;
  1038.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  1039.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  1040.     conf->upstream.local = NGX_CONF_UNSET_PTR;
  1041.     conf->upstream.socket_keepalive = NGX_CONF_UNSET;
  1042.     conf->upstream.socket_rcvbuf = NGX_CONF_UNSET_SIZE;
  1043.     conf->upstream.socket_sndbuf = NGX_CONF_UNSET_SIZE;

  1044.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  1045.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  1046.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  1047.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  1048.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  1049.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  1050.     conf->upstream.limit_rate = NGX_CONF_UNSET_PTR;

  1051.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  1052.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  1053.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  1054.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  1055.     conf->upstream.pass_request_body = NGX_CONF_UNSET;

  1056. #if (NGX_HTTP_CACHE)
  1057.     conf->upstream.cache = NGX_CONF_UNSET;
  1058.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  1059.     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
  1060.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  1061.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  1062.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  1063.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  1064.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  1065.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  1066.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  1067.     conf->upstream.cache_background_update = NGX_CONF_UNSET;
  1068. #endif

  1069.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  1070.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  1071.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  1072.     /* "scgi_cyclic_temp_file" is disabled */
  1073.     conf->upstream.cyclic_temp_file = 0;

  1074.     conf->upstream.change_buffering = 1;

  1075.     ngx_str_set(&conf->upstream.module, "scgi");

  1076.     return conf;
  1077. }


  1078. static char *
  1079. ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  1080. {
  1081.     ngx_http_scgi_loc_conf_t *prev = parent;
  1082.     ngx_http_scgi_loc_conf_t *conf = child;

  1083.     size_t                        size;
  1084.     ngx_int_t                     rc;
  1085.     ngx_hash_init_t               hash;
  1086.     ngx_http_core_loc_conf_t     *clcf;

  1087. #if (NGX_HTTP_CACHE)

  1088.     if (conf->upstream.store > 0) {
  1089.         conf->upstream.cache = 0;
  1090.     }

  1091.     if (conf->upstream.cache > 0) {
  1092.         conf->upstream.store = 0;
  1093.     }

  1094. #endif

  1095.     if (conf->upstream.store == NGX_CONF_UNSET) {
  1096.         ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);

  1097.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  1098.         conf->upstream.store_values = prev->upstream.store_values;
  1099.     }

  1100.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  1101.                               prev->upstream.store_access, 0600);

  1102.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  1103.                               prev->upstream.next_upstream_tries, 0);

  1104.     ngx_conf_merge_value(conf->upstream.buffering,
  1105.                               prev->upstream.buffering, 1);

  1106.     ngx_conf_merge_value(conf->upstream.request_buffering,
  1107.                               prev->upstream.request_buffering, 1);

  1108.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  1109.                               prev->upstream.ignore_client_abort, 0);

  1110.     ngx_conf_merge_value(conf->upstream.force_ranges,
  1111.                               prev->upstream.force_ranges, 0);

  1112.     ngx_conf_merge_ptr_value(conf->upstream.local,
  1113.                               prev->upstream.local, NULL);

  1114.     ngx_conf_merge_value(conf->upstream.socket_keepalive,
  1115.                               prev->upstream.socket_keepalive, 0);

  1116.     ngx_conf_merge_size_value(conf->upstream.socket_rcvbuf,
  1117.                               prev->upstream.socket_rcvbuf, 0);

  1118.     ngx_conf_merge_size_value(conf->upstream.socket_sndbuf,
  1119.                               prev->upstream.socket_sndbuf, 0);

  1120.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  1121.                               prev->upstream.connect_timeout, 60000);

  1122.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  1123.                               prev->upstream.send_timeout, 60000);

  1124.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  1125.                               prev->upstream.read_timeout, 60000);

  1126.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  1127.                               prev->upstream.next_upstream_timeout, 0);

  1128.     ngx_conf_merge_size_value(conf->upstream.send_lowat,
  1129.                               prev->upstream.send_lowat, 0);

  1130.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  1131.                               prev->upstream.buffer_size,
  1132.                               (size_t) ngx_pagesize);

  1133.     ngx_conf_merge_ptr_value(conf->upstream.limit_rate,
  1134.                               prev->upstream.limit_rate, NULL);


  1135.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  1136.                               8, ngx_pagesize);

  1137.     if (conf->upstream.bufs.num < 2) {
  1138.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1139.                            "there must be at least 2 \"scgi_buffers\"");
  1140.         return NGX_CONF_ERROR;
  1141.     }


  1142.     size = conf->upstream.buffer_size;
  1143.     if (size < conf->upstream.bufs.size) {
  1144.         size = conf->upstream.bufs.size;
  1145.     }


  1146.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  1147.                               prev->upstream.busy_buffers_size_conf,
  1148.                               NGX_CONF_UNSET_SIZE);

  1149.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  1150.         conf->upstream.busy_buffers_size = 2 * size;
  1151.     } else {
  1152.         conf->upstream.busy_buffers_size =
  1153.             conf->upstream.busy_buffers_size_conf;
  1154.     }

  1155.     if (conf->upstream.busy_buffers_size < size) {
  1156.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1157.             "\"scgi_busy_buffers_size\" must be equal to or greater "
  1158.             "than the maximum of the value of \"scgi_buffer_size\" and "
  1159.             "one of the \"scgi_buffers\"");

  1160.         return NGX_CONF_ERROR;
  1161.     }

  1162.     if (conf->upstream.busy_buffers_size
  1163.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  1164.     {
  1165.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1166.             "\"scgi_busy_buffers_size\" must be less than "
  1167.             "the size of all \"scgi_buffers\" minus one buffer");

  1168.         return NGX_CONF_ERROR;
  1169.     }


  1170.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  1171.                               prev->upstream.temp_file_write_size_conf,
  1172.                               NGX_CONF_UNSET_SIZE);

  1173.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  1174.         conf->upstream.temp_file_write_size = 2 * size;
  1175.     } else {
  1176.         conf->upstream.temp_file_write_size =
  1177.             conf->upstream.temp_file_write_size_conf;
  1178.     }

  1179.     if (conf->upstream.temp_file_write_size < size) {
  1180.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1181.             "\"scgi_temp_file_write_size\" must be equal to or greater than "
  1182.             "the maximum of the value of \"scgi_buffer_size\" and "
  1183.             "one of the \"scgi_buffers\"");

  1184.         return NGX_CONF_ERROR;
  1185.     }


  1186.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  1187.                               prev->upstream.max_temp_file_size_conf,
  1188.                               NGX_CONF_UNSET_SIZE);

  1189.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  1190.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  1191.     } else {
  1192.         conf->upstream.max_temp_file_size =
  1193.             conf->upstream.max_temp_file_size_conf;
  1194.     }

  1195.     if (conf->upstream.max_temp_file_size != 0
  1196.         && conf->upstream.max_temp_file_size < size)
  1197.     {
  1198.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1199.             "\"scgi_max_temp_file_size\" must be equal to zero to disable "
  1200.             "temporary files usage or must be equal to or greater than "
  1201.             "the maximum of the value of \"scgi_buffer_size\" and "
  1202.             "one of the \"scgi_buffers\"");

  1203.         return NGX_CONF_ERROR;
  1204.     }


  1205.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  1206.                                  prev->upstream.ignore_headers,
  1207.                                  NGX_CONF_BITMASK_SET);


  1208.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  1209.                                  prev->upstream.next_upstream,
  1210.                                  (NGX_CONF_BITMASK_SET
  1211.                                   |NGX_HTTP_UPSTREAM_FT_ERROR
  1212.                                   |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  1213.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  1214.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  1215.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  1216.     }

  1217.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  1218.                                   prev->upstream.temp_path,
  1219.                                   &ngx_http_scgi_temp_path)
  1220.         != NGX_CONF_OK)
  1221.     {
  1222.         return NGX_CONF_ERROR;
  1223.     }

  1224. #if (NGX_HTTP_CACHE)

  1225.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  1226.         ngx_conf_merge_value(conf->upstream.cache,
  1227.                               prev->upstream.cache, 0);

  1228.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  1229.         conf->upstream.cache_value = prev->upstream.cache_value;
  1230.     }

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

  1233.         shm_zone = conf->upstream.cache_zone;

  1234.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1235.                            "\"scgi_cache\" zone \"%V\" is unknown",
  1236.                            &shm_zone->shm.name);

  1237.         return NGX_CONF_ERROR;
  1238.     }

  1239.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  1240.                               prev->upstream.cache_min_uses, 1);

  1241.     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
  1242.                               prev->upstream.cache_max_range_offset,
  1243.                               NGX_MAX_OFF_T_VALUE);

  1244.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  1245.                               prev->upstream.cache_use_stale,
  1246.                               (NGX_CONF_BITMASK_SET
  1247.                                |NGX_HTTP_UPSTREAM_FT_OFF));

  1248.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
  1249.         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
  1250.                                          |NGX_HTTP_UPSTREAM_FT_OFF;
  1251.     }

  1252.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  1253.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  1254.     }

  1255.     if (conf->upstream.cache_methods == 0) {
  1256.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  1257.     }

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

  1259.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  1260.                              prev->upstream.cache_bypass, NULL);

  1261.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  1262.                              prev->upstream.no_cache, NULL);

  1263.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  1264.                              prev->upstream.cache_valid, NULL);

  1265.     if (conf->cache_key.value.data == NULL) {
  1266.         conf->cache_key = prev->cache_key;
  1267.     }

  1268.     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
  1269.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  1270.                            "no \"scgi_cache_key\" for \"scgi_cache\"");
  1271.     }

  1272.     ngx_conf_merge_value(conf->upstream.cache_lock,
  1273.                               prev->upstream.cache_lock, 0);

  1274.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  1275.                               prev->upstream.cache_lock_timeout, 5000);

  1276.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  1277.                               prev->upstream.cache_lock_age, 5000);

  1278.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  1279.                               prev->upstream.cache_revalidate, 0);

  1280.     ngx_conf_merge_value(conf->upstream.cache_background_update,
  1281.                               prev->upstream.cache_background_update, 0);

  1282. #endif

  1283.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  1284.                          prev->upstream.pass_request_headers, 1);
  1285.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  1286.                          prev->upstream.pass_request_body, 1);

  1287.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  1288.                          prev->upstream.intercept_errors, 0);

  1289.     hash.max_size = 512;
  1290.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  1291.     hash.name = "scgi_hide_headers_hash";

  1292.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  1293.             &prev->upstream, ngx_http_scgi_hide_headers, &hash)
  1294.         != NGX_OK)
  1295.     {
  1296.         return NGX_CONF_ERROR;
  1297.     }

  1298.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  1299.     if (clcf->noname
  1300.         && conf->upstream.upstream == NULL && conf->scgi_lengths == NULL)
  1301.     {
  1302.         conf->upstream.upstream = prev->upstream.upstream;
  1303.         conf->scgi_lengths = prev->scgi_lengths;
  1304.         conf->scgi_values = prev->scgi_values;
  1305.     }

  1306.     if (clcf->lmt_excpt && clcf->handler == NULL
  1307.         && (conf->upstream.upstream || conf->scgi_lengths))
  1308.     {
  1309.         clcf->handler = ngx_http_scgi_handler;
  1310.     }

  1311.     if (conf->params_source == NULL) {
  1312.         conf->params = prev->params;
  1313. #if (NGX_HTTP_CACHE)
  1314.         conf->params_cache = prev->params_cache;
  1315. #endif
  1316.         conf->params_source = prev->params_source;
  1317.     }

  1318.     rc = ngx_http_scgi_init_params(cf, conf, &conf->params,
  1319.                                    ngx_http_scgi_headers);
  1320.     if (rc != NGX_OK) {
  1321.         return NGX_CONF_ERROR;
  1322.     }

  1323. #if (NGX_HTTP_CACHE)

  1324.     if (conf->upstream.cache) {
  1325.         rc = ngx_http_scgi_init_params(cf, conf, &conf->params_cache,
  1326.                                        ngx_http_scgi_cache_headers);
  1327.         if (rc != NGX_OK) {
  1328.             return NGX_CONF_ERROR;
  1329.         }
  1330.     }

  1331. #endif

  1332.     /*
  1333.      * special handling to preserve conf->params in the "http" section
  1334.      * to inherit it to all servers
  1335.      */

  1336.     if (prev->params.hash.buckets == NULL
  1337.         && conf->params_source == prev->params_source)
  1338.     {
  1339.         prev->params = conf->params;
  1340. #if (NGX_HTTP_CACHE)
  1341.         prev->params_cache = conf->params_cache;
  1342. #endif
  1343.     }

  1344.     return NGX_CONF_OK;
  1345. }


  1346. static ngx_int_t
  1347. ngx_http_scgi_init_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
  1348.     ngx_http_scgi_params_t *params, ngx_keyval_t *default_params)
  1349. {
  1350.     u_char                       *p;
  1351.     size_t                        size;
  1352.     uintptr_t                    *code;
  1353.     ngx_uint_t                    i, nsrc;
  1354.     ngx_array_t                   headers_names, params_merged;
  1355.     ngx_keyval_t                 *h;
  1356.     ngx_hash_key_t               *hk;
  1357.     ngx_hash_init_t               hash;
  1358.     ngx_http_upstream_param_t    *src, *s;
  1359.     ngx_http_script_compile_t     sc;
  1360.     ngx_http_script_copy_code_t  *copy;

  1361.     if (params->hash.buckets) {
  1362.         return NGX_OK;
  1363.     }

  1364.     if (conf->params_source == NULL && default_params == NULL) {
  1365.         params->hash.buckets = (void *) 1;
  1366.         return NGX_OK;
  1367.     }

  1368.     params->lengths = ngx_array_create(cf->pool, 64, 1);
  1369.     if (params->lengths == NULL) {
  1370.         return NGX_ERROR;
  1371.     }

  1372.     params->values = ngx_array_create(cf->pool, 512, 1);
  1373.     if (params->values == NULL) {
  1374.         return NGX_ERROR;
  1375.     }

  1376.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  1377.         != NGX_OK)
  1378.     {
  1379.         return NGX_ERROR;
  1380.     }

  1381.     if (conf->params_source) {
  1382.         src = conf->params_source->elts;
  1383.         nsrc = conf->params_source->nelts;

  1384.     } else {
  1385.         src = NULL;
  1386.         nsrc = 0;
  1387.     }

  1388.     if (default_params) {
  1389.         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
  1390.                            sizeof(ngx_http_upstream_param_t))
  1391.             != NGX_OK)
  1392.         {
  1393.             return NGX_ERROR;
  1394.         }

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

  1396.             s = ngx_array_push(&params_merged);
  1397.             if (s == NULL) {
  1398.                 return NGX_ERROR;
  1399.             }

  1400.             *s = src[i];
  1401.         }

  1402.         h = default_params;

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

  1404.             src = params_merged.elts;
  1405.             nsrc = params_merged.nelts;

  1406.             for (i = 0; i < nsrc; i++) {
  1407.                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  1408.                     goto next;
  1409.                 }
  1410.             }

  1411.             s = ngx_array_push(&params_merged);
  1412.             if (s == NULL) {
  1413.                 return NGX_ERROR;
  1414.             }

  1415.             s->key = h->key;
  1416.             s->value = h->value;
  1417.             s->skip_empty = 1;

  1418.         next:

  1419.             h++;
  1420.         }

  1421.         src = params_merged.elts;
  1422.         nsrc = params_merged.nelts;
  1423.     }

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

  1425.         if (src[i].key.len > sizeof("HTTP_") - 1
  1426.             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
  1427.         {
  1428.             hk = ngx_array_push(&headers_names);
  1429.             if (hk == NULL) {
  1430.                 return NGX_ERROR;
  1431.             }

  1432.             hk->key.len = src[i].key.len - 5;
  1433.             hk->key.data = src[i].key.data + 5;
  1434.             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
  1435.             hk->value = (void *) 1;

  1436.             if (src[i].value.len == 0) {
  1437.                 continue;
  1438.             }
  1439.         }

  1440.         copy = ngx_array_push_n(params->lengths,
  1441.                                 sizeof(ngx_http_script_copy_code_t));
  1442.         if (copy == NULL) {
  1443.             return NGX_ERROR;
  1444.         }

  1445.         copy->code = (ngx_http_script_code_pt) (void *)
  1446.                                                  ngx_http_script_copy_len_code;
  1447.         copy->len = src[i].key.len + 1;

  1448.         copy = ngx_array_push_n(params->lengths,
  1449.                                 sizeof(ngx_http_script_copy_code_t));
  1450.         if (copy == NULL) {
  1451.             return NGX_ERROR;
  1452.         }

  1453.         copy->code = (ngx_http_script_code_pt) (void *)
  1454.                                                  ngx_http_script_copy_len_code;
  1455.         copy->len = src[i].skip_empty;


  1456.         size = (sizeof(ngx_http_script_copy_code_t)
  1457.                 + src[i].key.len + 1 + sizeof(uintptr_t) - 1)
  1458.                & ~(sizeof(uintptr_t) - 1);

  1459.         copy = ngx_array_push_n(params->values, size);
  1460.         if (copy == NULL) {
  1461.             return NGX_ERROR;
  1462.         }

  1463.         copy->code = ngx_http_script_copy_code;
  1464.         copy->len = src[i].key.len + 1;

  1465.         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
  1466.         (void) ngx_cpystrn(p, src[i].key.data, src[i].key.len + 1);


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

  1468.         sc.cf = cf;
  1469.         sc.source = &src[i].value;
  1470.         sc.flushes = &params->flushes;
  1471.         sc.lengths = &params->lengths;
  1472.         sc.values = &params->values;

  1473.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  1474.             return NGX_ERROR;
  1475.         }

  1476.         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  1477.         if (code == NULL) {
  1478.             return NGX_ERROR;
  1479.         }

  1480.         *code = (uintptr_t) NULL;


  1481.         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
  1482.         if (code == NULL) {
  1483.             return NGX_ERROR;
  1484.         }

  1485.         *code = (uintptr_t) NULL;
  1486.     }

  1487.     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  1488.     if (code == NULL) {
  1489.         return NGX_ERROR;
  1490.     }

  1491.     *code = (uintptr_t) NULL;

  1492.     params->number = headers_names.nelts;

  1493.     hash.hash = &params->hash;
  1494.     hash.key = ngx_hash_key_lc;
  1495.     hash.max_size = 512;
  1496.     hash.bucket_size = 64;
  1497.     hash.name = "scgi_params_hash";
  1498.     hash.pool = cf->pool;
  1499.     hash.temp_pool = NULL;

  1500.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  1501. }


  1502. static char *
  1503. ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1504. {
  1505.     ngx_http_scgi_loc_conf_t *scf = conf;

  1506.     ngx_url_t                   u;
  1507.     ngx_str_t                  *value, *url;
  1508.     ngx_uint_t                  n;
  1509.     ngx_http_core_loc_conf_t   *clcf;
  1510.     ngx_http_script_compile_t   sc;

  1511.     if (scf->upstream.upstream || scf->scgi_lengths) {
  1512.         return "is duplicate";
  1513.     }

  1514.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
  1515.     clcf->handler = ngx_http_scgi_handler;

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

  1517.     url = &value[1];

  1518.     n = ngx_http_script_variables_count(url);

  1519.     if (n) {

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

  1521.         sc.cf = cf;
  1522.         sc.source = url;
  1523.         sc.lengths = &scf->scgi_lengths;
  1524.         sc.values = &scf->scgi_values;
  1525.         sc.variables = n;
  1526.         sc.complete_lengths = 1;
  1527.         sc.complete_values = 1;

  1528.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  1529.             return NGX_CONF_ERROR;
  1530.         }

  1531.         return NGX_CONF_OK;
  1532.     }

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

  1534.     u.url = value[1];
  1535.     u.no_resolve = 1;

  1536.     scf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  1537.     if (scf->upstream.upstream == NULL) {
  1538.         return NGX_CONF_ERROR;
  1539.     }

  1540.     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
  1541.         clcf->auto_redirect = 1;
  1542.     }

  1543.     return NGX_CONF_OK;
  1544. }


  1545. static char *
  1546. ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1547. {
  1548.     ngx_http_scgi_loc_conf_t *scf = conf;

  1549.     ngx_str_t                  *value;
  1550.     ngx_http_script_compile_t   sc;

  1551.     if (scf->upstream.store != NGX_CONF_UNSET) {
  1552.         return "is duplicate";
  1553.     }

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

  1555.     if (ngx_strcmp(value[1].data, "off") == 0) {
  1556.         scf->upstream.store = 0;
  1557.         return NGX_CONF_OK;
  1558.     }

  1559.     if (value[1].len == 0) {
  1560.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty path");
  1561.         return NGX_CONF_ERROR;
  1562.     }

  1563. #if (NGX_HTTP_CACHE)
  1564.     if (scf->upstream.cache > 0) {
  1565.         return "is incompatible with \"scgi_cache\"";
  1566.     }
  1567. #endif

  1568.     scf->upstream.store = 1;

  1569.     if (ngx_strcmp(value[1].data, "on") == 0) {
  1570.         return NGX_CONF_OK;
  1571.     }

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

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

  1575.     sc.cf = cf;
  1576.     sc.source = &value[1];
  1577.     sc.lengths = &scf->upstream.store_lengths;
  1578.     sc.values = &scf->upstream.store_values;
  1579.     sc.variables = ngx_http_script_variables_count(&value[1]);
  1580.     sc.complete_lengths = 1;
  1581.     sc.complete_values = 1;

  1582.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  1583.         return NGX_CONF_ERROR;
  1584.     }

  1585.     return NGX_CONF_OK;
  1586. }


  1587. #if (NGX_HTTP_CACHE)

  1588. static char *
  1589. ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1590. {
  1591.     ngx_http_scgi_loc_conf_t *scf = conf;

  1592.     ngx_str_t                         *value;
  1593.     ngx_http_complex_value_t           cv;
  1594.     ngx_http_compile_complex_value_t   ccv;

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

  1596.     if (scf->upstream.cache != NGX_CONF_UNSET) {
  1597.         return "is duplicate";
  1598.     }

  1599.     if (ngx_strcmp(value[1].data, "off") == 0) {
  1600.         scf->upstream.cache = 0;
  1601.         return NGX_CONF_OK;
  1602.     }

  1603.     if (scf->upstream.store > 0) {
  1604.         return "is incompatible with \"scgi_store\"";
  1605.     }

  1606.     scf->upstream.cache = 1;

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

  1608.     ccv.cf = cf;
  1609.     ccv.value = &value[1];
  1610.     ccv.complex_value = &cv;

  1611.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  1612.         return NGX_CONF_ERROR;
  1613.     }

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

  1615.         scf->upstream.cache_value = ngx_palloc(cf->pool,
  1616.                                              sizeof(ngx_http_complex_value_t));
  1617.         if (scf->upstream.cache_value == NULL) {
  1618.             return NGX_CONF_ERROR;
  1619.         }

  1620.         *scf->upstream.cache_value = cv;

  1621.         return NGX_CONF_OK;
  1622.     }

  1623.     scf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  1624.                                                      &ngx_http_scgi_module);
  1625.     if (scf->upstream.cache_zone == NULL) {
  1626.         return NGX_CONF_ERROR;
  1627.     }

  1628.     return NGX_CONF_OK;
  1629. }


  1630. static char *
  1631. ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1632. {
  1633.     ngx_http_scgi_loc_conf_t *scf = conf;

  1634.     ngx_str_t                         *value;
  1635.     ngx_http_compile_complex_value_t   ccv;

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

  1637.     if (scf->cache_key.value.data) {
  1638.         return "is duplicate";
  1639.     }

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

  1641.     ccv.cf = cf;
  1642.     ccv.value = &value[1];
  1643.     ccv.complex_value = &scf->cache_key;

  1644.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  1645.         return NGX_CONF_ERROR;
  1646.     }

  1647.     return NGX_CONF_OK;
  1648. }

  1649. #endif