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

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 void ngx_http_scgi_abort_request(ngx_http_request_t *r);
  39. static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc);

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

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

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


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


  69. ngx_module_t  ngx_http_scgi_module;


  70. static ngx_command_t ngx_http_scgi_commands[] = {

  71.     { ngx_string("scgi_pass"),
  72.       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
  73.       ngx_http_scgi_pass,
  74.       NGX_HTTP_LOC_CONF_OFFSET,
  75.       0,
  76.       NULL },

  77.     { ngx_string("scgi_store"),
  78.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  79.       ngx_http_scgi_store,
  80.       NGX_HTTP_LOC_CONF_OFFSET,
  81.       0,
  82.       NULL },

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

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

  95.     { ngx_string("scgi_ignore_client_abort"),
  96.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  97.       ngx_conf_set_flag_slot,
  98.       NGX_HTTP_LOC_CONF_OFFSET,
  99.       offsetof(ngx_http_scgi_loc_conf_t, upstream.ignore_client_abort),
  100.       NULL },

  101.     { ngx_string("scgi_bind"),
  102.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  103.       ngx_http_upstream_bind_set_slot,
  104.       NGX_HTTP_LOC_CONF_OFFSET,
  105.       offsetof(ngx_http_scgi_loc_conf_t, upstream.local),
  106.       NULL },

  107.     { ngx_string("scgi_connect_timeout"),
  108.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  109.       ngx_conf_set_msec_slot,
  110.       NGX_HTTP_LOC_CONF_OFFSET,
  111.       offsetof(ngx_http_scgi_loc_conf_t, upstream.connect_timeout),
  112.       NULL },

  113.     { ngx_string("scgi_send_timeout"),
  114.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  115.       ngx_conf_set_msec_slot,
  116.       NGX_HTTP_LOC_CONF_OFFSET,
  117.       offsetof(ngx_http_scgi_loc_conf_t, upstream.send_timeout),
  118.       NULL },

  119.     { ngx_string("scgi_buffer_size"),
  120.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  121.       ngx_conf_set_size_slot,
  122.       NGX_HTTP_LOC_CONF_OFFSET,
  123.       offsetof(ngx_http_scgi_loc_conf_t, upstream.buffer_size),
  124.       NULL },

  125.     { ngx_string("scgi_pass_request_headers"),
  126.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  127.       ngx_conf_set_flag_slot,
  128.       NGX_HTTP_LOC_CONF_OFFSET,
  129.       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_request_headers),
  130.       NULL },

  131.     { ngx_string("scgi_pass_request_body"),
  132.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  133.       ngx_conf_set_flag_slot,
  134.       NGX_HTTP_LOC_CONF_OFFSET,
  135.       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_request_body),
  136.       NULL },

  137.     { ngx_string("scgi_intercept_errors"),
  138.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  139.       ngx_conf_set_flag_slot,
  140.       NGX_HTTP_LOC_CONF_OFFSET,
  141.       offsetof(ngx_http_scgi_loc_conf_t, upstream.intercept_errors),
  142.       NULL },

  143.     { ngx_string("scgi_read_timeout"),
  144.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  145.       ngx_conf_set_msec_slot,
  146.       NGX_HTTP_LOC_CONF_OFFSET,
  147.       offsetof(ngx_http_scgi_loc_conf_t, upstream.read_timeout),
  148.       NULL },

  149.     { ngx_string("scgi_buffers"),
  150.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  151.       ngx_conf_set_bufs_slot,
  152.       NGX_HTTP_LOC_CONF_OFFSET,
  153.       offsetof(ngx_http_scgi_loc_conf_t, upstream.bufs),
  154.       NULL },

  155.     { ngx_string("scgi_busy_buffers_size"),
  156.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  157.       ngx_conf_set_size_slot,
  158.       NGX_HTTP_LOC_CONF_OFFSET,
  159.       offsetof(ngx_http_scgi_loc_conf_t, upstream.busy_buffers_size_conf),
  160.       NULL },

  161.     { ngx_string("scgi_force_ranges"),
  162.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  163.       ngx_conf_set_flag_slot,
  164.       NGX_HTTP_LOC_CONF_OFFSET,
  165.       offsetof(ngx_http_scgi_loc_conf_t, upstream.force_ranges),
  166.       NULL },

  167.     { ngx_string("scgi_limit_rate"),
  168.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  169.       ngx_conf_set_size_slot,
  170.       NGX_HTTP_LOC_CONF_OFFSET,
  171.       offsetof(ngx_http_scgi_loc_conf_t, upstream.limit_rate),
  172.       NULL },

  173. #if (NGX_HTTP_CACHE)

  174.     { ngx_string("scgi_cache"),
  175.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  176.       ngx_http_scgi_cache,
  177.       NGX_HTTP_LOC_CONF_OFFSET,
  178.       0,
  179.       NULL },

  180.     { ngx_string("scgi_cache_key"),
  181.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  182.       ngx_http_scgi_cache_key,
  183.       NGX_HTTP_LOC_CONF_OFFSET,
  184.       0,
  185.       NULL },

  186.     { ngx_string("scgi_cache_path"),
  187.       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
  188.       ngx_http_file_cache_set_slot,
  189.       NGX_HTTP_MAIN_CONF_OFFSET,
  190.       offsetof(ngx_http_scgi_main_conf_t, caches),
  191.       &ngx_http_scgi_module },

  192.     { ngx_string("scgi_cache_bypass"),
  193.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  194.       ngx_http_set_predicate_slot,
  195.       NGX_HTTP_LOC_CONF_OFFSET,
  196.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_bypass),
  197.       NULL },

  198.     { ngx_string("scgi_no_cache"),
  199.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  200.       ngx_http_set_predicate_slot,
  201.       NGX_HTTP_LOC_CONF_OFFSET,
  202.       offsetof(ngx_http_scgi_loc_conf_t, upstream.no_cache),
  203.       NULL },

  204.     { ngx_string("scgi_cache_valid"),
  205.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  206.       ngx_http_file_cache_valid_set_slot,
  207.       NGX_HTTP_LOC_CONF_OFFSET,
  208.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_valid),
  209.       NULL },

  210.     { ngx_string("scgi_cache_min_uses"),
  211.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  212.       ngx_conf_set_num_slot,
  213.       NGX_HTTP_LOC_CONF_OFFSET,
  214.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_min_uses),
  215.       NULL },

  216.     { ngx_string("scgi_cache_use_stale"),
  217.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  218.       ngx_conf_set_bitmask_slot,
  219.       NGX_HTTP_LOC_CONF_OFFSET,
  220.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_use_stale),
  221.       &ngx_http_scgi_next_upstream_masks },

  222.     { ngx_string("scgi_cache_methods"),
  223.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  224.       ngx_conf_set_bitmask_slot,
  225.       NGX_HTTP_LOC_CONF_OFFSET,
  226.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_methods),
  227.       &ngx_http_upstream_cache_method_mask },

  228.     { ngx_string("scgi_cache_lock"),
  229.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  230.       ngx_conf_set_flag_slot,
  231.       NGX_HTTP_LOC_CONF_OFFSET,
  232.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock),
  233.       NULL },

  234.     { ngx_string("scgi_cache_lock_timeout"),
  235.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  236.       ngx_conf_set_msec_slot,
  237.       NGX_HTTP_LOC_CONF_OFFSET,
  238.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout),
  239.       NULL },

  240.     { ngx_string("scgi_cache_lock_age"),
  241.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  242.       ngx_conf_set_msec_slot,
  243.       NGX_HTTP_LOC_CONF_OFFSET,
  244.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_age),
  245.       NULL },

  246.     { ngx_string("scgi_cache_revalidate"),
  247.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  248.       ngx_conf_set_flag_slot,
  249.       NGX_HTTP_LOC_CONF_OFFSET,
  250.       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_revalidate),
  251.       NULL },

  252. #endif

  253.     { ngx_string("scgi_temp_path"),
  254.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
  255.       ngx_conf_set_path_slot,
  256.       NGX_HTTP_LOC_CONF_OFFSET,
  257.       offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_path),
  258.       NULL },

  259.     { ngx_string("scgi_max_temp_file_size"),
  260.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  261.       ngx_conf_set_size_slot,
  262.       NGX_HTTP_LOC_CONF_OFFSET,
  263.       offsetof(ngx_http_scgi_loc_conf_t, upstream.max_temp_file_size_conf),
  264.       NULL },

  265.     { ngx_string("scgi_temp_file_write_size"),
  266.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  267.       ngx_conf_set_size_slot,
  268.       NGX_HTTP_LOC_CONF_OFFSET,
  269.       offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_file_write_size_conf),
  270.       NULL },

  271.     { ngx_string("scgi_next_upstream"),
  272.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  273.       ngx_conf_set_bitmask_slot,
  274.       NGX_HTTP_LOC_CONF_OFFSET,
  275.       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream),
  276.       &ngx_http_scgi_next_upstream_masks },

  277.     { ngx_string("scgi_next_upstream_tries"),
  278.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  279.       ngx_conf_set_num_slot,
  280.       NGX_HTTP_LOC_CONF_OFFSET,
  281.       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_tries),
  282.       NULL },

  283.     { ngx_string("scgi_next_upstream_timeout"),
  284.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  285.       ngx_conf_set_msec_slot,
  286.       NGX_HTTP_LOC_CONF_OFFSET,
  287.       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_timeout),
  288.       NULL },

  289.     { ngx_string("scgi_param"),
  290.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
  291.       ngx_http_upstream_param_set_slot,
  292.       NGX_HTTP_LOC_CONF_OFFSET,
  293.       offsetof(ngx_http_scgi_loc_conf_t, params_source),
  294.       NULL },

  295.     { ngx_string("scgi_pass_header"),
  296.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  297.       ngx_conf_set_str_array_slot,
  298.       NGX_HTTP_LOC_CONF_OFFSET,
  299.       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_headers),
  300.       NULL },

  301.     { ngx_string("scgi_hide_header"),
  302.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  303.       ngx_conf_set_str_array_slot,
  304.       NGX_HTTP_LOC_CONF_OFFSET,
  305.       offsetof(ngx_http_scgi_loc_conf_t, upstream.hide_headers),
  306.       NULL },

  307.     { ngx_string("scgi_ignore_headers"),
  308.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  309.       ngx_conf_set_bitmask_slot,
  310.       NGX_HTTP_LOC_CONF_OFFSET,
  311.       offsetof(ngx_http_scgi_loc_conf_t, upstream.ignore_headers),
  312.       &ngx_http_upstream_ignore_headers_masks },

  313.       ngx_null_command
  314. };


  315. static ngx_http_module_t ngx_http_scgi_module_ctx = {
  316.     NULL,                                  /* preconfiguration */
  317.     NULL,                                  /* postconfiguration */

  318.     ngx_http_scgi_create_main_conf,        /* create main configuration */
  319.     NULL,                                  /* init main configuration */

  320.     NULL,                                  /* create server configuration */
  321.     NULL,                                  /* merge server configuration */

  322.     ngx_http_scgi_create_loc_conf,         /* create location configuration */
  323.     ngx_http_scgi_merge_loc_conf           /* merge location configuration */
  324. };


  325. ngx_module_t ngx_http_scgi_module = {
  326.     NGX_MODULE_V1,
  327.     &ngx_http_scgi_module_ctx,             /* module context */
  328.     ngx_http_scgi_commands,                /* module directives */
  329.     NGX_HTTP_MODULE,                       /* module type */
  330.     NULL,                                  /* init master */
  331.     NULL,                                  /* init module */
  332.     NULL,                                  /* init process */
  333.     NULL,                                  /* init thread */
  334.     NULL,                                  /* exit thread */
  335.     NULL,                                  /* exit process */
  336.     NULL,                                  /* exit master */
  337.     NGX_MODULE_V1_PADDING
  338. };


  339. static ngx_str_t ngx_http_scgi_hide_headers[] = {
  340.     ngx_string("Status"),
  341.     ngx_string("X-Accel-Expires"),
  342.     ngx_string("X-Accel-Redirect"),
  343.     ngx_string("X-Accel-Limit-Rate"),
  344.     ngx_string("X-Accel-Buffering"),
  345.     ngx_string("X-Accel-Charset"),
  346.     ngx_null_string
  347. };


  348. #if (NGX_HTTP_CACHE)

  349. static ngx_keyval_t  ngx_http_scgi_cache_headers[] = {
  350.     { ngx_string("HTTP_IF_MODIFIED_SINCE"),
  351.       ngx_string("$upstream_cache_last_modified") },
  352.     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
  353.     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
  354.     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
  355.     { ngx_string("HTTP_RANGE"), ngx_string("") },
  356.     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
  357.     { ngx_null_string, ngx_null_string }
  358. };

  359. #endif


  360. static ngx_path_init_t ngx_http_scgi_temp_path = {
  361.     ngx_string(NGX_HTTP_SCGI_TEMP_PATH), { 1, 2, 0 }
  362. };


  363. static ngx_int_t
  364. ngx_http_scgi_handler(ngx_http_request_t *r)
  365. {
  366.     ngx_int_t                   rc;
  367.     ngx_http_status_t          *status;
  368.     ngx_http_upstream_t        *u;
  369.     ngx_http_scgi_loc_conf_t   *scf;
  370. #if (NGX_HTTP_CACHE)
  371.     ngx_http_scgi_main_conf_t  *smcf;
  372. #endif

  373.     if (ngx_http_upstream_create(r) != NGX_OK) {
  374.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  375.     }

  376.     status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
  377.     if (status == NULL) {
  378.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  379.     }

  380.     ngx_http_set_ctx(r, status, ngx_http_scgi_module);

  381.     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);

  382.     if (scf->scgi_lengths) {
  383.         if (ngx_http_scgi_eval(r, scf) != NGX_OK) {
  384.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  385.         }
  386.     }

  387.     u = r->upstream;

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

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

  391. #if (NGX_HTTP_CACHE)
  392.     smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module);

  393.     u->caches = &smcf->caches;
  394.     u->create_key = ngx_http_scgi_create_key;
  395. #endif

  396.     u->create_request = ngx_http_scgi_create_request;
  397.     u->reinit_request = ngx_http_scgi_reinit_request;
  398.     u->process_header = ngx_http_scgi_process_status_line;
  399.     u->abort_request = ngx_http_scgi_abort_request;
  400.     u->finalize_request = ngx_http_scgi_finalize_request;
  401.     r->state = 0;

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

  403.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  404.     if (u->pipe == NULL) {
  405.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  406.     }

  407.     u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
  408.     u->pipe->input_ctx = r;

  409.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  410.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  411.         return rc;
  412.     }

  413.     return NGX_DONE;
  414. }


  415. static ngx_int_t
  416. ngx_http_scgi_eval(ngx_http_request_t *r, ngx_http_scgi_loc_conf_t * scf)
  417. {
  418.     ngx_url_t             url;
  419.     ngx_http_upstream_t  *u;

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

  421.     if (ngx_http_script_run(r, &url.url, scf->scgi_lengths->elts, 0,
  422.                             scf->scgi_values->elts)
  423.         == NULL)
  424.     {
  425.         return NGX_ERROR;
  426.     }

  427.     url.no_resolve = 1;

  428.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  429.         if (url.err) {
  430.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  431.                           "%s in upstream \"%V\"", url.err, &url.url);
  432.         }

  433.         return NGX_ERROR;
  434.     }

  435.     u = r->upstream;

  436.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  437.     if (u->resolved == NULL) {
  438.         return NGX_ERROR;
  439.     }

  440.     if (url.addrs && url.addrs[0].sockaddr) {
  441.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  442.         u->resolved->socklen = url.addrs[0].socklen;
  443.         u->resolved->naddrs = 1;
  444.         u->resolved->host = url.addrs[0].name;

  445.     } else {
  446.         u->resolved->host = url.host;
  447.         u->resolved->port = url.port;
  448.         u->resolved->no_port = url.no_port;
  449.     }

  450.     return NGX_OK;
  451. }


  452. #if (NGX_HTTP_CACHE)

  453. static ngx_int_t
  454. ngx_http_scgi_create_key(ngx_http_request_t *r)
  455. {
  456.     ngx_str_t                 *key;
  457.     ngx_http_scgi_loc_conf_t  *scf;

  458.     key = ngx_array_push(&r->cache->keys);
  459.     if (key == NULL) {
  460.         return NGX_ERROR;
  461.     }

  462.     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);

  463.     if (ngx_http_complex_value(r, &scf->cache_key, key) != NGX_OK) {
  464.         return NGX_ERROR;
  465.     }

  466.     return NGX_OK;
  467. }

  468. #endif


  469. static ngx_int_t
  470. ngx_http_scgi_create_request(ngx_http_request_t *r)
  471. {
  472.     off_t                         content_length_n;
  473.     u_char                        ch, *key, *val, *lowcase_key;
  474.     size_t                        len, key_len, val_len, allocated;
  475.     ngx_buf_t                    *b;
  476.     ngx_str_t                     content_length;
  477.     ngx_uint_t                    i, n, hash, skip_empty, header_params;
  478.     ngx_chain_t                  *cl, *body;
  479.     ngx_list_part_t              *part;
  480.     ngx_table_elt_t              *header, **ignored;
  481.     ngx_http_scgi_params_t       *params;
  482.     ngx_http_script_code_pt       code;
  483.     ngx_http_script_engine_t      e, le;
  484.     ngx_http_scgi_loc_conf_t     *scf;
  485.     ngx_http_script_len_code_pt   lcode;
  486.     u_char                        buffer[NGX_OFF_T_LEN];

  487.     content_length_n = 0;
  488.     body = r->upstream->request_bufs;

  489.     while (body) {
  490.         content_length_n += ngx_buf_size(body->buf);
  491.         body = body->next;
  492.     }

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

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

  496.     header_params = 0;
  497.     ignored = NULL;

  498.     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);

  499. #if (NGX_HTTP_CACHE)
  500.     params = r->upstream->cacheable ? &scf->params_cache : &scf->params;
  501. #else
  502.     params = &scf->params;
  503. #endif

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

  506.         ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
  507.         le.flushed = 1;

  508.         le.ip = params->lengths->elts;
  509.         le.request = r;

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

  511.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  512.             key_len = lcode(&le);

  513.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  514.             skip_empty = lcode(&le);

  515.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  516.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  517.             }
  518.             le.ip += sizeof(uintptr_t);

  519.             if (skip_empty && val_len == 0) {
  520.                 continue;
  521.             }

  522.             len += key_len + val_len + 1;
  523.         }
  524.     }

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

  526.         allocated = 0;
  527.         lowcase_key = NULL;

  528.         if (params->number) {
  529.             n = 0;
  530.             part = &r->headers_in.headers.part;

  531.             while (part) {
  532.                 n += part->nelts;
  533.                 part = part->next;
  534.             }

  535.             ignored = ngx_palloc(r->pool, n * sizeof(void *));
  536.             if (ignored == NULL) {
  537.                 return NGX_ERROR;
  538.             }
  539.         }

  540.         part = &r->headers_in.headers.part;
  541.         header = part->elts;

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

  543.             if (i >= part->nelts) {
  544.                 if (part->next == NULL) {
  545.                     break;
  546.                 }

  547.                 part = part->next;
  548.                 header = part->elts;
  549.                 i = 0;
  550.             }

  551.             if (params->number) {
  552.                 if (allocated < header[i].key.len) {
  553.                     allocated = header[i].key.len + 16;
  554.                     lowcase_key = ngx_pnalloc(r->pool, allocated);
  555.                     if (lowcase_key == NULL) {
  556.                         return NGX_ERROR;
  557.                     }
  558.                 }

  559.                 hash = 0;

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

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

  564.                     } else if (ch == '-') {
  565.                         ch = '_';
  566.                     }

  567.                     hash = ngx_hash(hash, ch);
  568.                     lowcase_key[n] = ch;
  569.                 }

  570.                 if (ngx_hash_find(&params->hash, hash, lowcase_key, n)) {
  571.                     ignored[header_params++] = &header[i];
  572.                     continue;
  573.                 }
  574.             }

  575.             len += sizeof("HTTP_") - 1 + header[i].key.len + 1
  576.                 + header[i].value.len + 1;
  577.         }
  578.     }

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

  580.     b = ngx_create_temp_buf(r->pool, NGX_SIZE_T_LEN + 1 + len + 1);
  581.     if (b == NULL) {
  582.         return NGX_ERROR;
  583.     }

  584.     cl = ngx_alloc_chain_link(r->pool);
  585.     if (cl == NULL) {
  586.         return NGX_ERROR;
  587.     }

  588.     cl->buf = b;

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

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

  593.         e.ip = params->values->elts;
  594.         e.pos = b->last;
  595.         e.request = r;
  596.         e.flushed = 1;

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

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

  599.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  600.             lcode(&le); /* key length */

  601.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  602.             skip_empty = lcode(&le);

  603.             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  604.                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
  605.             }
  606.             le.ip += sizeof(uintptr_t);

  607.             if (skip_empty && val_len == 0) {
  608.                 e.skip = 1;

  609.                 while (*(uintptr_t *) e.ip) {
  610.                     code = *(ngx_http_script_code_pt *) e.ip;
  611.                     code((ngx_http_script_engine_t *) &e);
  612.                 }
  613.                 e.ip += sizeof(uintptr_t);

  614.                 e.skip = 0;

  615.                 continue;
  616.             }

  617. #if (NGX_DEBUG)
  618.             key = e.pos;
  619. #endif
  620.             code = *(ngx_http_script_code_pt *) e.ip;
  621.             code((ngx_http_script_engine_t *) & e);

  622. #if (NGX_DEBUG)
  623.             val = e.pos;
  624. #endif
  625.             while (*(uintptr_t *) e.ip) {
  626.                 code = *(ngx_http_script_code_pt *) e.ip;
  627.                 code((ngx_http_script_engine_t *) &e);
  628.             }
  629.             *e.pos++ = '\0';
  630.             e.ip += sizeof(uintptr_t);

  631.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  632.                            "scgi param: \"%s: %s\"", key, val);
  633.         }

  634.         b->last = e.pos;
  635.     }

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

  637.         part = &r->headers_in.headers.part;
  638.         header = part->elts;

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

  640.             if (i >= part->nelts) {
  641.                 if (part->next == NULL) {
  642.                     break;
  643.                 }

  644.                 part = part->next;
  645.                 header = part->elts;
  646.                 i = 0;
  647.             }

  648.             for (n = 0; n < header_params; n++) {
  649.                 if (&header[i] == ignored[n]) {
  650.                     goto next;
  651.                 }
  652.             }

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

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

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

  659.                 } else if (ch == '-') {
  660.                     ch = '_';
  661.                 }

  662.                 *b->last++ = ch;
  663.             }

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

  665.             val = b->last;
  666.             b->last = ngx_copy(val, header[i].value.data, header[i].value.len);
  667.             *b->last++ = (u_char) 0;

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

  670.         next:

  671.             continue;
  672.          }
  673.     }

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

  675.     if (scf->upstream.pass_request_body) {
  676.         body = r->upstream->request_bufs;
  677.         r->upstream->request_bufs = cl;

  678.         while (body) {
  679.             b = ngx_alloc_buf(r->pool);
  680.             if (b == NULL) {
  681.                 return NGX_ERROR;
  682.             }

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

  684.             cl->next = ngx_alloc_chain_link(r->pool);
  685.             if (cl->next == NULL) {
  686.                 return NGX_ERROR;
  687.             }

  688.             cl = cl->next;
  689.             cl->buf = b;

  690.             body = body->next;
  691.         }

  692.     } else {
  693.         r->upstream->request_bufs = cl;
  694.     }

  695.     cl->next = NULL;

  696.     return NGX_OK;
  697. }


  698. static ngx_int_t
  699. ngx_http_scgi_reinit_request(ngx_http_request_t *r)
  700. {
  701.     ngx_http_status_t  *status;

  702.     status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);

  703.     if (status == NULL) {
  704.         return NGX_OK;
  705.     }

  706.     status->code = 0;
  707.     status->count = 0;
  708.     status->start = NULL;
  709.     status->end = NULL;

  710.     r->upstream->process_header = ngx_http_scgi_process_status_line;
  711.     r->state = 0;

  712.     return NGX_OK;
  713. }


  714. static ngx_int_t
  715. ngx_http_scgi_process_status_line(ngx_http_request_t *r)
  716. {
  717.     size_t                len;
  718.     ngx_int_t             rc;
  719.     ngx_http_status_t    *status;
  720.     ngx_http_upstream_t  *u;

  721.     status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);

  722.     if (status == NULL) {
  723.         return NGX_ERROR;
  724.     }

  725.     u = r->upstream;

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

  727.     if (rc == NGX_AGAIN) {
  728.         return rc;
  729.     }

  730.     if (rc == NGX_ERROR) {
  731.         u->process_header = ngx_http_scgi_process_header;
  732.         return ngx_http_scgi_process_header(r);
  733.     }

  734.     if (u->state && u->state->status == 0) {
  735.         u->state->status = status->code;
  736.     }

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

  738.     len = status->end - status->start;
  739.     u->headers_in.status_line.len = len;

  740.     u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
  741.     if (u->headers_in.status_line.data == NULL) {
  742.         return NGX_ERROR;
  743.     }

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

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

  748.     u->process_header = ngx_http_scgi_process_header;

  749.     return ngx_http_scgi_process_header(r);
  750. }


  751. static ngx_int_t
  752. ngx_http_scgi_process_header(ngx_http_request_t *r)
  753. {
  754.     ngx_str_t                      *status_line;
  755.     ngx_int_t                       rc, status;
  756.     ngx_table_elt_t                *h;
  757.     ngx_http_upstream_t            *u;
  758.     ngx_http_upstream_header_t     *hh;
  759.     ngx_http_upstream_main_conf_t  *umcf;

  760.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  761.     for ( ;; ) {

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

  763.         if (rc == NGX_OK) {

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

  765.             h = ngx_list_push(&r->upstream->headers_in.headers);
  766.             if (h == NULL) {
  767.                 return NGX_ERROR;
  768.             }

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

  770.             h->key.len = r->header_name_end - r->header_name_start;
  771.             h->value.len = r->header_end - r->header_start;

  772.             h->key.data = ngx_pnalloc(r->pool,
  773.                                       h->key.len + 1 + h->value.len + 1
  774.                                       + h->key.len);
  775.             if (h->key.data == NULL) {
  776.                 return NGX_ERROR;
  777.             }

  778.             h->value.data = h->key.data + h->key.len + 1;
  779.             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;

  780.             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
  781.             h->key.data[h->key.len] = '\0';
  782.             ngx_memcpy(h->value.data, r->header_start, h->value.len);
  783.             h->value.data[h->value.len] = '\0';

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

  786.             } else {
  787.                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
  788.             }

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

  791.             if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
  792.                 return NGX_ERROR;
  793.             }

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

  796.             continue;
  797.         }

  798.         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  802.             u = r->upstream;

  803.             if (u->headers_in.status_n) {
  804.                 goto done;
  805.             }

  806.             if (u->headers_in.status) {
  807.                 status_line = &u->headers_in.status->value;

  808.                 status = ngx_atoi(status_line->data, 3);
  809.                 if (status == NGX_ERROR) {
  810.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  811.                                   "upstream sent invalid status \"%V\"",
  812.                                   status_line);
  813.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  814.                 }

  815.                 u->headers_in.status_n = status;
  816.                 u->headers_in.status_line = *status_line;

  817.             } else if (u->headers_in.location) {
  818.                 u->headers_in.status_n = 302;
  819.                 ngx_str_set(&u->headers_in.status_line,
  820.                             "302 Moved Temporarily");

  821.             } else {
  822.                 u->headers_in.status_n = 200;
  823.                 ngx_str_set(&u->headers_in.status_line, "200 OK");
  824.             }

  825.             if (u->state && u->state->status == 0) {
  826.                 u->state->status = u->headers_in.status_n;
  827.             }

  828.         done:

  829.             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS
  830.                 && r->headers_in.upgrade)
  831.             {
  832.                 u->upgrade = 1;
  833.             }

  834.             return NGX_OK;
  835.         }

  836.         if (rc == NGX_AGAIN) {
  837.             return NGX_AGAIN;
  838.         }

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

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

  842.         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  843.     }
  844. }


  845. static void
  846. ngx_http_scgi_abort_request(ngx_http_request_t *r)
  847. {
  848.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  849.                    "abort http scgi request");

  850.     return;
  851. }


  852. static void
  853. ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  854. {
  855.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  856.                    "finalize http scgi request");

  857.     return;
  858. }


  859. static void *
  860. ngx_http_scgi_create_main_conf(ngx_conf_t *cf)
  861. {
  862.     ngx_http_scgi_main_conf_t  *conf;

  863.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_main_conf_t));
  864.     if (conf == NULL) {
  865.         return NULL;
  866.     }

  867. #if (NGX_HTTP_CACHE)
  868.     if (ngx_array_init(&conf->caches, cf->pool, 4,
  869.                        sizeof(ngx_http_file_cache_t *))
  870.         != NGX_OK)
  871.     {
  872.         return NULL;
  873.     }
  874. #endif

  875.     return conf;
  876. }


  877. static void *
  878. ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
  879. {
  880.     ngx_http_scgi_loc_conf_t  *conf;

  881.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_loc_conf_t));
  882.     if (conf == NULL) {
  883.         return NULL;
  884.     }

  885.     conf->upstream.store = NGX_CONF_UNSET;
  886.     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
  887.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  888.     conf->upstream.buffering = NGX_CONF_UNSET;
  889.     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
  890.     conf->upstream.force_ranges = NGX_CONF_UNSET;

  891.     conf->upstream.local = NGX_CONF_UNSET_PTR;

  892.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  893.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  894.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  895.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  896.     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
  897.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
  898.     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;

  899.     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
  900.     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
  901.     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;

  902.     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
  903.     conf->upstream.pass_request_body = NGX_CONF_UNSET;

  904. #if (NGX_HTTP_CACHE)
  905.     conf->upstream.cache = NGX_CONF_UNSET;
  906.     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
  907.     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
  908.     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
  909.     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
  910.     conf->upstream.cache_lock = NGX_CONF_UNSET;
  911.     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
  912.     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
  913.     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
  914. #endif

  915.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  916.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  917.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  918.     /* "scgi_cyclic_temp_file" is disabled */
  919.     conf->upstream.cyclic_temp_file = 0;

  920.     conf->upstream.change_buffering = 1;

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

  922.     return conf;
  923. }


  924. static char *
  925. ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  926. {
  927.     ngx_http_scgi_loc_conf_t *prev = parent;
  928.     ngx_http_scgi_loc_conf_t *conf = child;

  929.     size_t                        size;
  930.     ngx_int_t                     rc;
  931.     ngx_hash_init_t               hash;
  932.     ngx_http_core_loc_conf_t     *clcf;

  933. #if (NGX_HTTP_CACHE)

  934.     if (conf->upstream.store > 0) {
  935.         conf->upstream.cache = 0;
  936.     }

  937.     if (conf->upstream.cache > 0) {
  938.         conf->upstream.store = 0;
  939.     }

  940. #endif

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

  943.         conf->upstream.store_lengths = prev->upstream.store_lengths;
  944.         conf->upstream.store_values = prev->upstream.store_values;
  945.     }

  946.     ngx_conf_merge_uint_value(conf->upstream.store_access,
  947.                               prev->upstream.store_access, 0600);

  948.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  949.                               prev->upstream.next_upstream_tries, 0);

  950.     ngx_conf_merge_value(conf->upstream.buffering,
  951.                               prev->upstream.buffering, 1);

  952.     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
  953.                               prev->upstream.ignore_client_abort, 0);

  954.     ngx_conf_merge_value(conf->upstream.force_ranges,
  955.                               prev->upstream.force_ranges, 0);

  956.     ngx_conf_merge_ptr_value(conf->upstream.local,
  957.                               prev->upstream.local, NULL);

  958.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  959.                               prev->upstream.connect_timeout, 60000);

  960.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  961.                               prev->upstream.send_timeout, 60000);

  962.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  963.                               prev->upstream.read_timeout, 60000);

  964.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  965.                               prev->upstream.next_upstream_timeout, 0);

  966.     ngx_conf_merge_size_value(conf->upstream.send_lowat,
  967.                               prev->upstream.send_lowat, 0);

  968.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  969.                               prev->upstream.buffer_size,
  970.                               (size_t) ngx_pagesize);

  971.     ngx_conf_merge_size_value(conf->upstream.limit_rate,
  972.                               prev->upstream.limit_rate, 0);


  973.     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
  974.                               8, ngx_pagesize);

  975.     if (conf->upstream.bufs.num < 2) {
  976.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  977.                            "there must be at least 2 \"scgi_buffers\"");
  978.         return NGX_CONF_ERROR;
  979.     }


  980.     size = conf->upstream.buffer_size;
  981.     if (size < conf->upstream.bufs.size) {
  982.         size = conf->upstream.bufs.size;
  983.     }


  984.     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
  985.                               prev->upstream.busy_buffers_size_conf,
  986.                               NGX_CONF_UNSET_SIZE);

  987.     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
  988.         conf->upstream.busy_buffers_size = 2 * size;
  989.     } else {
  990.         conf->upstream.busy_buffers_size =
  991.             conf->upstream.busy_buffers_size_conf;
  992.     }

  993.     if (conf->upstream.busy_buffers_size < size) {
  994.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  995.             "\"scgi_busy_buffers_size\" must be equal to or greater "
  996.             "than the maximum of the value of \"scgi_buffer_size\" and "
  997.             "one of the \"scgi_buffers\"");

  998.         return NGX_CONF_ERROR;
  999.     }

  1000.     if (conf->upstream.busy_buffers_size
  1001.         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
  1002.     {
  1003.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1004.             "\"scgi_busy_buffers_size\" must be less than "
  1005.             "the size of all \"scgi_buffers\" minus one buffer");

  1006.         return NGX_CONF_ERROR;
  1007.     }


  1008.     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
  1009.                               prev->upstream.temp_file_write_size_conf,
  1010.                               NGX_CONF_UNSET_SIZE);

  1011.     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
  1012.         conf->upstream.temp_file_write_size = 2 * size;
  1013.     } else {
  1014.         conf->upstream.temp_file_write_size =
  1015.             conf->upstream.temp_file_write_size_conf;
  1016.     }

  1017.     if (conf->upstream.temp_file_write_size < size) {
  1018.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1019.             "\"scgi_temp_file_write_size\" must be equal to or greater than "
  1020.             "the maximum of the value of \"scgi_buffer_size\" and "
  1021.             "one of the \"scgi_buffers\"");

  1022.         return NGX_CONF_ERROR;
  1023.     }


  1024.     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
  1025.                               prev->upstream.max_temp_file_size_conf,
  1026.                               NGX_CONF_UNSET_SIZE);

  1027.     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
  1028.         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
  1029.     } else {
  1030.         conf->upstream.max_temp_file_size =
  1031.             conf->upstream.max_temp_file_size_conf;
  1032.     }

  1033.     if (conf->upstream.max_temp_file_size != 0
  1034.         && conf->upstream.max_temp_file_size < size)
  1035.     {
  1036.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1037.             "\"scgi_max_temp_file_size\" must be equal to zero to disable "
  1038.             "temporary files usage or must be equal to or greater than "
  1039.             "the maximum of the value of \"scgi_buffer_size\" and "
  1040.             "one of the \"scgi_buffers\"");

  1041.         return NGX_CONF_ERROR;
  1042.     }


  1043.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  1044.                                  prev->upstream.ignore_headers,
  1045.                                  NGX_CONF_BITMASK_SET);


  1046.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  1047.                                  prev->upstream.next_upstream,
  1048.                                  (NGX_CONF_BITMASK_SET
  1049.                                   |NGX_HTTP_UPSTREAM_FT_ERROR
  1050.                                   |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  1051.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  1052.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  1053.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  1054.     }

  1055.     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
  1056.                                   prev->upstream.temp_path,
  1057.                                   &ngx_http_scgi_temp_path)
  1058.         != NGX_OK)
  1059.     {
  1060.         return NGX_CONF_ERROR;
  1061.     }

  1062. #if (NGX_HTTP_CACHE)

  1063.     if (conf->upstream.cache == NGX_CONF_UNSET) {
  1064.         ngx_conf_merge_value(conf->upstream.cache,
  1065.                               prev->upstream.cache, 0);

  1066.         conf->upstream.cache_zone = prev->upstream.cache_zone;
  1067.         conf->upstream.cache_value = prev->upstream.cache_value;
  1068.     }

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

  1071.         shm_zone = conf->upstream.cache_zone;

  1072.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1073.                            "\"scgi_cache\" zone \"%V\" is unknown",
  1074.                            &shm_zone->shm.name);

  1075.         return NGX_CONF_ERROR;
  1076.     }

  1077.     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
  1078.                               prev->upstream.cache_min_uses, 1);

  1079.     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
  1080.                               prev->upstream.cache_use_stale,
  1081.                               (NGX_CONF_BITMASK_SET
  1082.                                |NGX_HTTP_UPSTREAM_FT_OFF));

  1083.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
  1084.         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
  1085.                                          |NGX_HTTP_UPSTREAM_FT_OFF;
  1086.     }

  1087.     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
  1088.         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
  1089.     }

  1090.     if (conf->upstream.cache_methods == 0) {
  1091.         conf->upstream.cache_methods = prev->upstream.cache_methods;
  1092.     }

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

  1094.     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
  1095.                              prev->upstream.cache_bypass, NULL);

  1096.     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
  1097.                              prev->upstream.no_cache, NULL);

  1098.     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
  1099.                              prev->upstream.cache_valid, NULL);

  1100.     if (conf->cache_key.value.data == NULL) {
  1101.         conf->cache_key = prev->cache_key;
  1102.     }

  1103.     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
  1104.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  1105.                            "no \"scgi_cache_key\" for \"scgi_cache\"");
  1106.     }

  1107.     ngx_conf_merge_value(conf->upstream.cache_lock,
  1108.                               prev->upstream.cache_lock, 0);

  1109.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
  1110.                               prev->upstream.cache_lock_timeout, 5000);

  1111.     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
  1112.                               prev->upstream.cache_lock_age, 5000);

  1113.     ngx_conf_merge_value(conf->upstream.cache_revalidate,
  1114.                               prev->upstream.cache_revalidate, 0);

  1115. #endif

  1116.     ngx_conf_merge_value(conf->upstream.pass_request_headers,
  1117.                          prev->upstream.pass_request_headers, 1);
  1118.     ngx_conf_merge_value(conf->upstream.pass_request_body,
  1119.                          prev->upstream.pass_request_body, 1);

  1120.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  1121.                          prev->upstream.intercept_errors, 0);

  1122.     hash.max_size = 512;
  1123.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  1124.     hash.name = "scgi_hide_headers_hash";

  1125.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  1126.             &prev->upstream, ngx_http_scgi_hide_headers, &hash)
  1127.         != NGX_OK)
  1128.     {
  1129.         return NGX_CONF_ERROR;
  1130.     }

  1131.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  1132.     if (clcf->noname
  1133.         && conf->upstream.upstream == NULL && conf->scgi_lengths == NULL)
  1134.     {
  1135.         conf->upstream.upstream = prev->upstream.upstream;
  1136.         conf->scgi_lengths = prev->scgi_lengths;
  1137.         conf->scgi_values = prev->scgi_values;
  1138.     }

  1139.     if (clcf->lmt_excpt && clcf->handler == NULL
  1140.         && (conf->upstream.upstream || conf->scgi_lengths))
  1141.     {
  1142.         clcf->handler = ngx_http_scgi_handler;
  1143.     }

  1144.     if (conf->params_source == NULL) {
  1145.         conf->params = prev->params;
  1146. #if (NGX_HTTP_CACHE)
  1147.         conf->params_cache = prev->params_cache;
  1148. #endif
  1149.         conf->params_source = prev->params_source;
  1150.     }

  1151.     rc = ngx_http_scgi_init_params(cf, conf, &conf->params, NULL);
  1152.     if (rc != NGX_OK) {
  1153.         return NGX_CONF_ERROR;
  1154.     }

  1155. #if (NGX_HTTP_CACHE)

  1156.     if (conf->upstream.cache) {
  1157.         rc = ngx_http_scgi_init_params(cf, conf, &conf->params_cache,
  1158.                                        ngx_http_scgi_cache_headers);
  1159.         if (rc != NGX_OK) {
  1160.             return NGX_CONF_ERROR;
  1161.         }
  1162.     }

  1163. #endif

  1164.     return NGX_CONF_OK;
  1165. }


  1166. static ngx_int_t
  1167. ngx_http_scgi_init_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
  1168.     ngx_http_scgi_params_t *params, ngx_keyval_t *default_params)
  1169. {
  1170.     u_char                       *p;
  1171.     size_t                        size;
  1172.     uintptr_t                    *code;
  1173.     ngx_uint_t                    i, nsrc;
  1174.     ngx_array_t                   headers_names, params_merged;
  1175.     ngx_keyval_t                 *h;
  1176.     ngx_hash_key_t               *hk;
  1177.     ngx_hash_init_t               hash;
  1178.     ngx_http_upstream_param_t    *src, *s;
  1179.     ngx_http_script_compile_t     sc;
  1180.     ngx_http_script_copy_code_t  *copy;

  1181.     if (params->hash.buckets) {
  1182.         return NGX_OK;
  1183.     }

  1184.     if (conf->params_source == NULL && default_params == NULL) {
  1185.         params->hash.buckets = (void *) 1;
  1186.         return NGX_OK;
  1187.     }

  1188.     params->lengths = ngx_array_create(cf->pool, 64, 1);
  1189.     if (params->lengths == NULL) {
  1190.         return NGX_ERROR;
  1191.     }

  1192.     params->values = ngx_array_create(cf->pool, 512, 1);
  1193.     if (params->values == NULL) {
  1194.         return NGX_ERROR;
  1195.     }

  1196.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  1197.         != NGX_OK)
  1198.     {
  1199.         return NGX_ERROR;
  1200.     }

  1201.     if (conf->params_source) {
  1202.         src = conf->params_source->elts;
  1203.         nsrc = conf->params_source->nelts;

  1204.     } else {
  1205.         src = NULL;
  1206.         nsrc = 0;
  1207.     }

  1208.     if (default_params) {
  1209.         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
  1210.                            sizeof(ngx_http_upstream_param_t))
  1211.             != NGX_OK)
  1212.         {
  1213.             return NGX_ERROR;
  1214.         }

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

  1216.             s = ngx_array_push(&params_merged);
  1217.             if (s == NULL) {
  1218.                 return NGX_ERROR;
  1219.             }

  1220.             *s = src[i];
  1221.         }

  1222.         h = default_params;

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

  1224.             src = params_merged.elts;
  1225.             nsrc = params_merged.nelts;

  1226.             for (i = 0; i < nsrc; i++) {
  1227.                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  1228.                     goto next;
  1229.                 }
  1230.             }

  1231.             s = ngx_array_push(&params_merged);
  1232.             if (s == NULL) {
  1233.                 return NGX_ERROR;
  1234.             }

  1235.             s->key = h->key;
  1236.             s->value = h->value;
  1237.             s->skip_empty = 1;

  1238.         next:

  1239.             h++;
  1240.         }

  1241.         src = params_merged.elts;
  1242.         nsrc = params_merged.nelts;
  1243.     }

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

  1245.         if (src[i].key.len > sizeof("HTTP_") - 1
  1246.             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
  1247.         {
  1248.             hk = ngx_array_push(&headers_names);
  1249.             if (hk == NULL) {
  1250.                 return NGX_ERROR;
  1251.             }

  1252.             hk->key.len = src[i].key.len - 5;
  1253.             hk->key.data = src[i].key.data + 5;
  1254.             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
  1255.             hk->value = (void *) 1;

  1256.             if (src[i].value.len == 0) {
  1257.                 continue;
  1258.             }
  1259.         }

  1260.         copy = ngx_array_push_n(params->lengths,
  1261.                                 sizeof(ngx_http_script_copy_code_t));
  1262.         if (copy == NULL) {
  1263.             return NGX_ERROR;
  1264.         }

  1265.         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
  1266.         copy->len = src[i].key.len + 1;

  1267.         copy = ngx_array_push_n(params->lengths,
  1268.                                 sizeof(ngx_http_script_copy_code_t));
  1269.         if (copy == NULL) {
  1270.             return NGX_ERROR;
  1271.         }

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


  1274.         size = (sizeof(ngx_http_script_copy_code_t)
  1275.                 + src[i].key.len + 1 + sizeof(uintptr_t) - 1)
  1276.                & ~(sizeof(uintptr_t) - 1);

  1277.         copy = ngx_array_push_n(params->values, size);
  1278.         if (copy == NULL) {
  1279.             return NGX_ERROR;
  1280.         }

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

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


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

  1286.         sc.cf = cf;
  1287.         sc.source = &src[i].value;
  1288.         sc.flushes = &params->flushes;
  1289.         sc.lengths = &params->lengths;
  1290.         sc.values = &params->values;

  1291.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  1292.             return NGX_ERROR;
  1293.         }

  1294.         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  1295.         if (code == NULL) {
  1296.             return NGX_ERROR;
  1297.         }

  1298.         *code = (uintptr_t) NULL;


  1299.         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
  1300.         if (code == NULL) {
  1301.             return NGX_ERROR;
  1302.         }

  1303.         *code = (uintptr_t) NULL;
  1304.     }

  1305.     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
  1306.     if (code == NULL) {
  1307.         return NGX_ERROR;
  1308.     }

  1309.     *code = (uintptr_t) NULL;

  1310.     params->number = headers_names.nelts;

  1311.     hash.hash = &params->hash;
  1312.     hash.key = ngx_hash_key_lc;
  1313.     hash.max_size = 512;
  1314.     hash.bucket_size = 64;
  1315.     hash.name = "scgi_params_hash";
  1316.     hash.pool = cf->pool;
  1317.     hash.temp_pool = NULL;

  1318.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  1319. }


  1320. static char *
  1321. ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1322. {
  1323.     ngx_http_scgi_loc_conf_t *scf = conf;

  1324.     ngx_url_t                   u;
  1325.     ngx_str_t                  *value, *url;
  1326.     ngx_uint_t                  n;
  1327.     ngx_http_core_loc_conf_t   *clcf;
  1328.     ngx_http_script_compile_t   sc;

  1329.     if (scf->upstream.upstream || scf->scgi_lengths) {
  1330.         return "is duplicate";
  1331.     }

  1332.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
  1333.     clcf->handler = ngx_http_scgi_handler;

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

  1335.     url = &value[1];

  1336.     n = ngx_http_script_variables_count(url);

  1337.     if (n) {

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

  1339.         sc.cf = cf;
  1340.         sc.source = url;
  1341.         sc.lengths = &scf->scgi_lengths;
  1342.         sc.values = &scf->scgi_values;
  1343.         sc.variables = n;
  1344.         sc.complete_lengths = 1;
  1345.         sc.complete_values = 1;

  1346.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  1347.             return NGX_CONF_ERROR;
  1348.         }

  1349.         return NGX_CONF_OK;
  1350.     }

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

  1352.     u.url = value[1];
  1353.     u.no_resolve = 1;

  1354.     scf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  1355.     if (scf->upstream.upstream == NULL) {
  1356.         return NGX_CONF_ERROR;
  1357.     }

  1358.     if (clcf->name.data[clcf->name.len - 1] == '/') {
  1359.         clcf->auto_redirect = 1;
  1360.     }

  1361.     return NGX_CONF_OK;
  1362. }


  1363. static char *
  1364. ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1365. {
  1366.     ngx_http_scgi_loc_conf_t *scf = conf;

  1367.     ngx_str_t                  *value;
  1368.     ngx_http_script_compile_t   sc;

  1369.     if (scf->upstream.store != NGX_CONF_UNSET) {
  1370.         return "is duplicate";
  1371.     }

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

  1373.     if (ngx_strcmp(value[1].data, "off") == 0) {
  1374.         scf->upstream.store = 0;
  1375.         return NGX_CONF_OK;
  1376.     }

  1377. #if (NGX_HTTP_CACHE)
  1378.     if (scf->upstream.cache > 0) {
  1379.         return "is incompatible with \"scgi_cache\"";
  1380.     }
  1381. #endif

  1382.     scf->upstream.store = 1;

  1383.     if (ngx_strcmp(value[1].data, "on") == 0) {
  1384.         return NGX_CONF_OK;
  1385.     }

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

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

  1389.     sc.cf = cf;
  1390.     sc.source = &value[1];
  1391.     sc.lengths = &scf->upstream.store_lengths;
  1392.     sc.values = &scf->upstream.store_values;
  1393.     sc.variables = ngx_http_script_variables_count(&value[1]);
  1394.     sc.complete_lengths = 1;
  1395.     sc.complete_values = 1;

  1396.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  1397.         return NGX_CONF_ERROR;
  1398.     }

  1399.     return NGX_CONF_OK;
  1400. }


  1401. #if (NGX_HTTP_CACHE)

  1402. static char *
  1403. ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1404. {
  1405.     ngx_http_scgi_loc_conf_t *scf = conf;

  1406.     ngx_str_t                         *value;
  1407.     ngx_http_complex_value_t           cv;
  1408.     ngx_http_compile_complex_value_t   ccv;

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

  1410.     if (scf->upstream.cache != NGX_CONF_UNSET) {
  1411.         return "is duplicate";
  1412.     }

  1413.     if (ngx_strcmp(value[1].data, "off") == 0) {
  1414.         scf->upstream.cache = 0;
  1415.         return NGX_CONF_OK;
  1416.     }

  1417.     if (scf->upstream.store > 0) {
  1418.         return "is incompatible with \"scgi_store\"";
  1419.     }

  1420.     scf->upstream.cache = 1;

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

  1422.     ccv.cf = cf;
  1423.     ccv.value = &value[1];
  1424.     ccv.complex_value = &cv;

  1425.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  1426.         return NGX_CONF_ERROR;
  1427.     }

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

  1429.         scf->upstream.cache_value = ngx_palloc(cf->pool,
  1430.                                              sizeof(ngx_http_complex_value_t));
  1431.         if (scf->upstream.cache_value == NULL) {
  1432.             return NGX_CONF_ERROR;
  1433.         }

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

  1435.         return NGX_CONF_OK;
  1436.     }

  1437.     scf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
  1438.                                                      &ngx_http_scgi_module);
  1439.     if (scf->upstream.cache_zone == NULL) {
  1440.         return NGX_CONF_ERROR;
  1441.     }

  1442.     return NGX_CONF_OK;
  1443. }


  1444. static char *
  1445. ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1446. {
  1447.     ngx_http_scgi_loc_conf_t *scf = conf;

  1448.     ngx_str_t                         *value;
  1449.     ngx_http_compile_complex_value_t   ccv;

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

  1451.     if (scf->cache_key.value.data) {
  1452.         return "is duplicate";
  1453.     }

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

  1455.     ccv.cf = cf;
  1456.     ccv.value = &value[1];
  1457.     ccv.complex_value = &scf->cache_key;

  1458.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  1459.         return NGX_CONF_ERROR;
  1460.     }

  1461.     return NGX_CONF_OK;
  1462. }

  1463. #endif