static char *ngx_http_upstream_q_chash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_upstream_srv_conf_t            *uscf;
    ngx_http_upstream_q_chash_srv_conf_t    *uchscf;
    ngx_str_t                               *value;
    ngx_http_script_compile_t               sc;

    uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
    uchscf = ngx_http_conf_upstream_srv_conf(uscf, ngx_http_upstream_q_chash_module);

    value = cf->args->elts;

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = &value[1];
    sc.lengths = &uchscf->lengths;
    sc.values = &uchscf->values;
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    uscf->peer.init_upstream = ngx_http_upstream_init_q_chash;
    uscf->flags = NGX_HTTP_UPSTREAM_CREATE
        | NGX_HTTP_UPSTREAM_WEIGHT
        | NGX_HTTP_UPSTREAM_MAX_FAILS
        | NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
        | NGX_HTTP_UPSTREAM_DOWN
        | NGX_HTTP_UPSTREAM_BACKUP;

    return NGX_CONF_OK;
}
static char *
ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_scgi_loc_conf_t *scf = conf;

    ngx_url_t                   u;
    ngx_str_t                  *value, *url;
    ngx_uint_t                  n;
    ngx_http_core_loc_conf_t   *clcf;
    ngx_http_script_compile_t   sc;

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

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

    value = cf->args->elts;

    url = &value[1];

    n = ngx_http_script_variables_count(url);

    if (n) {

        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = url;
        sc.lengths = &scf->scgi_lengths;
        sc.values = &scf->scgi_values;
        sc.variables = n;
        sc.complete_lengths = 1;
        sc.complete_values = 1;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_CONF_ERROR;
        }

        return NGX_CONF_OK;
    }

    ngx_memzero(&u, sizeof(ngx_url_t));

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

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

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

    return NGX_CONF_OK;
}
static char *
ngx_http_aclog_bypass_condition_value(ngx_conf_t *cf,
    ngx_http_aclog_bypass_condition_t *abc, ngx_str_t *value)
{
    ngx_int_t                              n;
    ngx_http_script_compile_t              sc;
    ngx_http_script_value_code_t          *val;
    ngx_http_script_complex_value_code_t  *complex;

    n = ngx_http_script_variables_count(value);

    if (n == 0) {
        val = ngx_http_script_start_code(cf->pool, &abc->codes,
                                         sizeof(ngx_http_script_value_code_t));
        if (val == NULL) {
            return NGX_CONF_ERROR;
        }

        n = ngx_atoi(value->data, value->len);

        if (n == NGX_ERROR) {
            n = 0;
        }

        val->code = ngx_http_script_value_code;
        val->value = (uintptr_t) n;
        val->text_len = (uintptr_t) value->len;
        val->text_data = (uintptr_t) value->data;

        return NGX_CONF_OK;
    }

    complex = ngx_http_script_start_code(cf->pool, &abc->codes,
                                 sizeof(ngx_http_script_complex_value_code_t));
    if (complex == NULL) {
        return NGX_CONF_ERROR;
    }

    complex->code = ngx_http_script_complex_value_code;
    complex->lengths = NULL;

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = value;
    sc.lengths = &complex->lengths;
    sc.values = &abc->codes;
    sc.variables = n;
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_scgi_loc_conf_t *scf = conf;

    ngx_str_t                  *value;
    ngx_http_script_compile_t   sc;

    if (scf->upstream.store != NGX_CONF_UNSET || scf->upstream.store_lengths) {
        return "is duplicate";
    }

    value = cf->args->elts;

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

#if (NGX_HTTP_CACHE)

    if (scf->upstream.cache != NGX_CONF_UNSET_PTR
        && scf->upstream.cache != NULL)
    {
        return "is incompatible with \"scgi_cache\"";
    }

#endif

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

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

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = &value[1];
    sc.lengths = &scf->upstream.store_lengths;
    sc.values = &scf->upstream.store_values;
    sc.variables = ngx_http_script_variables_count(&value[1]);;
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_fluentd_set_tag(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_int_t                   n;
    ngx_str_t                  *value;
    ngx_http_script_compile_t   sc;
    ngx_http_log_tag_template_t **field, *h;

    field = (ngx_http_log_tag_template_t**) (((u_char*)conf) + cmd->offset);

    value = cf->args->elts;

    if (*field == NULL) {
        *field = ngx_palloc(cf->pool, sizeof(ngx_http_log_tag_template_t));
        if (*field == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    h = *field;

    h->value = value[1];
    h->lengths = NULL;
    h->values = NULL;

    /*
     * Compile field name
     */
    n = ngx_http_script_variables_count(&value[1]);

    if (n > 0) {
        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = &value[1];
        sc.lengths = &h->lengths;
        sc.values = &h->values;
        sc.variables = n;
        sc.complete_lengths = 1;
        sc.complete_values = 1;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }

    return NGX_CONF_OK;
}
Beispiel #6
0
static char *
ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    passenger_loc_conf_t       *slcf = conf;

    ngx_str_t                  *value;
    ngx_http_script_compile_t   sc;

    if (slcf->upstream.store != NGX_CONF_UNSET || slcf->upstream.store_lengths)
    {
        return "is duplicate";
    }

    value = cf->args->elts;

    if (ngx_strcmp(value[1].data, "on") == 0) {
        slcf->upstream.store = 1;
        return NGX_CONF_OK;
    }

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

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

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = &value[1];
    sc.lengths = &slcf->upstream.store_lengths;
    sc.values = &slcf->upstream.store_values;
    sc.variables = ngx_http_script_variables_count(&value[1]);
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_proxy_connect_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_proxy_connect_loc_conf_t *plcf = conf;

    ngx_str_t                  *value, *url;
    ngx_uint_t                  n;
    ngx_http_core_loc_conf_t   *clcf;
    ngx_http_script_compile_t   sc;

    if (plcf->upstream.upstream || plcf->proxy_lengths) {
        return "is duplicate";
    }

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

    clcf->handler = ngx_http_proxy_connect_handler;

    value = cf->args->elts;

    url = &value[1];

    n = ngx_http_script_variables_count(url);

    if (n) {

        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = url;
        sc.lengths = &plcf->proxy_lengths;
        sc.values = &plcf->proxy_values;
        sc.variables = n;
        sc.complete_lengths = 1;
        sc.complete_values = 1;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }
    return NGX_CONF_OK;
}
static char *
ngx_http_data_dome_auth(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_data_dome_auth_conf_t *acf = conf;

    ngx_str_t        *value;
    ngx_str_t         uri;
    ngx_uint_t        n;

    ngx_http_script_compile_t   sc;

    if (acf->uri_lengths != NULL) {
	return "is duplicate";
    }

    value = cf->args->elts;

    if (ngx_strcmp(value[1].data, "learning") && cf->args->nelts == 3) {
	acf->learning = 1;
	uri = value[2];
    } else {
	uri = value[1];
    }

    n = ngx_http_script_variables_count(&uri);

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = &uri;
    sc.lengths = &acf->uri_lengths;
    sc.values = &acf->uri_values;
    sc.variables = n;
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_accesskey_compile_signature(ngx_conf_t *cf, ngx_http_accesskey_loc_conf_t *alcf)
{

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

    sc.cf = cf;
    sc.source = &alcf->signature;
    sc.lengths = &alcf->signature_lengths;
    sc.values = &alcf->signature_values;
    sc.variables = ngx_http_script_variables_count(&alcf->signature);;
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_secure_download_compile_secret(ngx_conf_t *cf, ngx_http_secure_download_loc_conf_t *sdc)
{

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

    sc.cf = cf;
    sc.source = &sdc->secret;
    sc.lengths = &sdc->secret_lengths;
    sc.values = &sdc->secret_values;
    sc.variables = ngx_http_script_variables_count(&sdc->secret);
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
/**
 * @brief nginx module's set endpoint
 *
 * Like ngx_http_log_zmq_set_format this function is pre-compiled. This is the endpoint
 * for the zmq message. To receive messages we have to be listening this topic. By nature
 * this endpoint can be dynamic in the same way we have variables in the configuration file.
 *
 * @code{.conf}
 * log_zmq_endpoint definition "/servers/nginx/$domain"
 * @endcode
 *
 * @param cf A ngx_conf_t pointer to the main nginx configurion
 * @param cmd A pointer to ngx_commant_t that defines the configuration line
 * @param conf A pointer to the configuration received
 * @return A char pointer which represents the status NGX_CONF_ERROR | NGX_CONF_OK
 * @note XXX it can be refactor (similar to the set_format)
 */
static char *
ngx_http_log_zmq_set_endpoint(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_log_zmq_main_conf_t        *bkmc;
    ngx_http_log_zmq_loc_conf_t         *llcf = conf;
    ngx_http_log_zmq_element_conf_t     *lecf;
    ngx_http_log_zmq_loc_element_conf_t *lelcf;
    ngx_str_t                           *value;
    ngx_http_script_compile_t           sc;

    bkmc = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_zmq_module);

    if (cf->cmd_type != NGX_HTTP_MAIN_CONF) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"log_zmq_endpoint\" directive can only used in \"http\" context");
        return NGX_CONF_ERROR;
    }

    if (bkmc == NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no \"log_zmq\" main configuration defined");
        return NGX_CONF_ERROR;
    }

    /* value[0] variable name
     * value[1] definition name
     * value[2] endpoint
     */

    value = cf->args->elts;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): definition \"%V\"", &value[1]);
    lecf = ngx_http_log_zmq_create_definition(cf, bkmc, &value[1]);

    if (NULL == lecf) {
        return NGX_CONF_ERROR;
    }

    /* set the location logs to main configuration logs */
    llcf->logs_definition = (ngx_array_t *) bkmc->logs;

    if (lecf->eset == 1) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_endpoint\" %V was initializated before", &value[1]);
        return NGX_CONF_ERROR;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): loc definition \"%V\"", &value[1]);
    lelcf = ngx_http_log_zmq_create_location_element(cf, llcf, &value[1]);

    if (NULL == lelcf) {
        return NGX_CONF_ERROR;
    }

    if (lecf->endpoint_lengths != NULL) {
        ngx_pfree(cf->pool, lecf->endpoint_lengths);
        lecf->endpoint_lengths = NULL;
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): clean endpoint lengths");
    }
    if (lecf->endpoint_values != NULL) {
        ngx_pfree(cf->pool, lecf->endpoint_values);
        lecf->endpoint_values = NULL;
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): clean endpoint values");
    }

    /* the endpoint is a string where we can place some nginx environment variables which are compiled
     * each time we process them. here we evaluate this set of data and prepare them to be used */
    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
    sc.cf = cf;
    sc.source = &value[2];
    sc.lengths = &(lecf->endpoint_lengths);
    sc.values = &(lecf->endpoint_values);
    sc.variables = ngx_http_script_variables_count(&value[2]);
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): compile");

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_endpoint\": error compiling format \"%V\"", &value[1]);
        return NGX_CONF_ERROR;
    }

    /* mark the endpoint as setted */
    lecf->eset = 1;

    lelcf->element = (ngx_http_log_zmq_element_conf_t *) lecf;
    lelcf->off = 0;
    llcf->off = 0;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint() return OK \"%V\"", &value[1]);

    return NGX_CONF_OK;
}
/**
 * @brief nginx module's set format
 *
 * This function evaluate the format string introducted in the configuration file.
 * The string is allocated and parsed to evaluate if it has any variables to
 * expand. This is the message sent to the log_zmq.
 *
 * @code{.conf}
 * log_zmq_format definition "put your stuff in here like vars $status"
 * @endcode
 *
 * @param cf A ngx_conf_t pointer to the main nginx configurion
 * @param cmd A pointer to ngx_commant_t that defines the configuration line
 * @param conf A pointer to the configuration received
 * @return A char pointer which represents the status NGX_CONF_ERROR | NGX_CONF_OK
 */
static char *
ngx_http_log_zmq_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_log_zmq_main_conf_t        *bkmc;
    ngx_http_log_zmq_loc_conf_t         *llcf = conf;
    ngx_http_log_zmq_element_conf_t     *lecf;
    ngx_http_log_zmq_loc_element_conf_t *lelcf;
    ngx_str_t                           *log_format, *value;
    ngx_http_script_compile_t           sc;
    size_t                              i, len, log_len;
    u_char                              *p;

    bkmc = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_zmq_module);

    if (cf->cmd_type != NGX_HTTP_MAIN_CONF) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"log_zmq_format\" directive can only be used in \"http\" context");
        return NGX_CONF_ERROR;
    }

    if (bkmc == NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no \"log_zmq\" main configuration defined");
        return NGX_CONF_ERROR;
    }

    len = 0;
    log_len = 0;

    /* value[0] variable name
     * value[1] definition name
     * value[2] format
     */
    value = cf->args->elts;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): definition \"%V\"", &value[1]);
    lecf = ngx_http_log_zmq_create_definition(cf, bkmc, &value[1]);

    if (NULL == lecf) {
        return NGX_CONF_ERROR;
    }

    /* set the location logs to main configuration logs */
    llcf->logs_definition = (ngx_array_t *) bkmc->logs;

    if (lecf->fset == 1) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_format\" %V was initializated before", &value[1]);
        return NGX_CONF_ERROR;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): loc definition \"%V\"", &value[1]);
    lelcf = ngx_http_log_zmq_create_location_element(cf, llcf, &value[1]);

    if (NULL == lelcf) {
        return NGX_CONF_ERROR;
    }

    /* this shoulnd get into this */
    if (lecf->data_lengths != NULL) {
        ngx_pfree(cf->pool, lecf->data_lengths);
        lecf->data_lengths = NULL;
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): clean data lengths");
    }
    if (lecf->data_values != NULL) {
        ngx_pfree(cf->pool, lecf->data_values);
        lecf->data_values = NULL;
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): clean data values");
    }

    /* we support multiline logs format */

    /* get the size of the log len (because multiline formats) */
    for (i = 2; i < cf->args->nelts; i++) {
        log_len = log_len + value[i].len;
    }

    log_format = ngx_palloc(cf->pool, sizeof(ngx_str_t));
    log_format->len = log_len;
    log_format->data = ngx_palloc(cf->pool, log_len + 1);

    p = &(log_format->data[0]);

    for (i = 2; i < cf->args->nelts; i++) {
        len = value[i].len;
        ngx_memcpy(p, value[i].data, len);
        p = p + len;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): value \"%V\"", &value[2]);

    /* recompile all together */
    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
    sc.cf = cf;
    sc.source = log_format;
    sc.lengths = &(lecf->data_lengths);
    sc.values = &(lecf->data_values);
    sc.variables = ngx_http_script_variables_count(log_format);
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): compile");

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_format\": error compiling format \"%V\"", &value[1]);
        return NGX_CONF_ERROR;
    }

    /* set the format as done */
    lecf->fset = 1;

    /* by default, this location have all configuration elements unmuted */
    lelcf->element = (ngx_http_log_zmq_element_conf_t *) lecf;
    lelcf->off = 0;

    /* by default, this location is unmuted */
    llcf->off = 0;

    ngx_pfree(cf->pool, log_format);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format() return OK \"%V\"", &value[1]);

    return NGX_CONF_OK;
}
static char *
ngx_http_echo_helper(ngx_http_echo_opcode_t opcode,
    ngx_http_echo_cmd_category_t cat,
    ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_str_t                       *raw_args;
    ngx_uint_t                       i, n;
    ngx_array_t                    **args_ptr;
    ngx_array_t                    **cmds_ptr;
    ngx_http_echo_cmd_t             *echo_cmd;
    ngx_http_core_loc_conf_t        *clcf;
    ngx_http_script_compile_t        sc;
    ngx_http_echo_main_conf_t       *emcf;
    ngx_http_echo_arg_template_t    *arg;

    emcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_echo_module);

    /* cmds_ptr points to ngx_http_echo_loc_conf_t's
     * handler_cmds, before_body_cmds, or after_body_cmds
     * array, depending on the actual offset */
    cmds_ptr = (ngx_array_t**)(((u_char*)conf) + cmd->offset);

    if (*cmds_ptr == NULL) {
        *cmds_ptr = ngx_array_create(cf->pool, 1,
                                     sizeof(ngx_http_echo_cmd_t));

        if (*cmds_ptr == NULL) {
            return NGX_CONF_ERROR;
        }

        if (cat == echo_handler_cmd) {
            LXTLOG("registering the content handler");
            /* register the content handler */
            clcf = ngx_http_conf_get_module_loc_conf(cf,
                                                     ngx_http_core_module);

            LXTLOG("registering the content handler (2)");
            clcf->handler = ngx_http_echo_handler;

        } else {
            LXTLOG("filter used = 1");
            emcf->requires_filter = 1;
        }
    }

    echo_cmd = ngx_array_push(*cmds_ptr);

    if (echo_cmd == NULL) {
        return NGX_CONF_ERROR;
    }

    echo_cmd->opcode = opcode;

    args_ptr = &echo_cmd->args;
    *args_ptr = ngx_array_create(cf->pool, 1,
            sizeof(ngx_http_echo_arg_template_t));

    if (*args_ptr == NULL) {
        return NGX_CONF_ERROR;
    }

    raw_args = cf->args->elts;

    /* we skip the first arg and start from the second */

    for (i = 1 ; i < cf->args->nelts; i++) {
        arg = ngx_array_push(*args_ptr);

        if (arg == NULL) {
            return NGX_CONF_ERROR;
        }

        arg->raw_value = raw_args[i];

        LXTLOG("found raw arg %s", raw_args[i].data);

        arg->lengths = NULL;
        arg->values  = NULL;

        n = ngx_http_script_variables_count(&arg->raw_value);

        if (n > 0) {
            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

            sc.cf = cf;
            sc.source = &arg->raw_value;
            sc.lengths = &arg->lengths;
            sc.values = &arg->values;
            sc.variables = n;
            sc.complete_lengths = 1;
            sc.complete_values = 1;

            if (ngx_http_script_compile(&sc) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    } /* end for */

    return NGX_CONF_OK;
}
static char *
ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_rewrite_loc_conf_t  *lcf = conf;

    ngx_str_t                         *value;
    ngx_uint_t                         last;
    ngx_regex_compile_t                rc;
    ngx_http_script_code_pt           *code;
    ngx_http_script_compile_t          sc;
    ngx_http_script_regex_code_t      *regex;
    ngx_http_script_regex_end_code_t  *regex_end;
    u_char                             errstr[NGX_MAX_CONF_ERRSTR];

    regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
                                       sizeof(ngx_http_script_regex_code_t));
    if (regex == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));

    value = cf->args->elts;

    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

    rc.pattern = value[1];
    rc.err.len = NGX_MAX_CONF_ERRSTR;
    rc.err.data = errstr;

    /* TODO: NGX_REGEX_CASELESS */

    regex->regex = ngx_http_regex_compile(cf, &rc);
    if (regex->regex == NULL) {
        return NGX_CONF_ERROR;
    }

    regex->code = ngx_http_script_regex_start_code;
    regex->uri = 1;
    regex->name = value[1];

    if (value[2].data[value[2].len - 1] == '?') {

        /* the last "?" drops the original arguments */
        value[2].len--;

    } else {
        regex->add_args = 1;
    }

    last = 0;

    if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
        || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
        || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
    {
        regex->status = NGX_HTTP_MOVED_TEMPORARILY;
        regex->redirect = 1;
        last = 1;
    }

    if (cf->args->nelts == 4) {
        if (ngx_strcmp(value[3].data, "last") == 0) {
            last = 1;

        } else if (ngx_strcmp(value[3].data, "break") == 0) {
            regex->break_cycle = 1;
            last = 1;

        } else if (ngx_strcmp(value[3].data, "redirect") == 0) {
            regex->status = NGX_HTTP_MOVED_TEMPORARILY;
            regex->redirect = 1;
            last = 1;

        } else if (ngx_strcmp(value[3].data, "permanent") == 0) {
            regex->status = NGX_HTTP_MOVED_PERMANENTLY;
            regex->redirect = 1;
            last = 1;

        } else {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid parameter \"%V\"", &value[3]);
            return NGX_CONF_ERROR;
        }
    }

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = &value[2];
    sc.lengths = &regex->lengths;
    sc.values = &lcf->codes;
    sc.variables = ngx_http_script_variables_count(&value[2]);
    sc.main = regex;
    sc.complete_lengths = 1;
    sc.compile_args = !regex->redirect;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    regex = sc.main;

    regex->size = sc.size;
    regex->args = sc.args;

    if (sc.variables == 0 && !sc.dup_capture) {
        regex->lengths = NULL;
    }

    regex_end = ngx_http_script_add_code(lcf->codes,
                                      sizeof(ngx_http_script_regex_end_code_t),
                                      &regex);
    if (regex_end == NULL) {
        return NGX_CONF_ERROR;
    }

    regex_end->code = ngx_http_script_regex_end_code;
    regex_end->uri = regex->uri;
    regex_end->args = regex->args;
    regex_end->add_args = regex->add_args;
    regex_end->redirect = regex->redirect;

    if (last) {
        code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), &regex);
        if (code == NULL) {
            return NGX_CONF_ERROR;
        }

        *code = NULL;
    }

    regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
                                              - (u_char *) regex;

    return NGX_CONF_OK;
}
static char *
ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_index_loc_conf_t *ilcf = conf;

    ngx_str_t                  *value;
    ngx_uint_t                  i, n;
    ngx_http_index_t           *index;
    ngx_http_script_compile_t   sc;

    if (ilcf->indices == NULL) {
        ilcf->indices = ngx_array_create(cf->pool, 2, sizeof(ngx_http_index_t));
        if (ilcf->indices == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {

        if (value[i].data[0] == '/' && i != cf->args->nelts - 1) {		//	index指令可以允许多个参数,但是最后一个参数是完整路径
            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                               "only the last index in \"index\" directive "
                               "should be absolute");
        }

        if (value[i].len == 0) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "index \"%V\" in \"index\" directive is invalid",
                               &value[1]);
            return NGX_CONF_ERROR;
        }

        index = ngx_array_push(ilcf->indices);
        if (index == NULL) {
            return NGX_CONF_ERROR;
        }

        index->name.len = value[i].len;
        index->name.data = value[i].data;
        index->lengths = NULL;
        index->values = NULL;

        n = ngx_http_script_variables_count(&value[i]);

		//	index指令使用的是字符串常量
        if (n == 0) {
            if (ilcf->max_index_len < index->name.len) {			//	保存指令index参数的字符最大长度
                ilcf->max_index_len = index->name.len;
            }

            if (index->name.data[0] == '/') {						//	???为什么直接返回???
                continue;
            }

            /* include the terminating '\0' to the length to use ngx_memcpy() */
            index->name.len++;

            continue;
        }


		//	index指令中使用内部变量
        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = &value[i];
        sc.lengths = &index->lengths;
        sc.values = &index->values;
        sc.variables = n;
        sc.complete_lengths = 1;
        sc.complete_values = 1;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_tcp_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{

	ngx_uint_t				   			n = 0;
    ngx_str_t                 			*value = NULL, *url = NULL;
	ngx_str_t				   			upstream_name;
    ngx_url_t                  			u;
	ngx_http_script_compile_t	   		sc;
    ngx_http_tcp_proxy_loc_conf_t 		*tlcf = conf;

    if (tlcf->upstream.upstream || tlcf->proxy_lengths) {
        return "is duplicate";
    }

	if (cf->args->nelts > 2){
		return "input param format wrong";
	}

	ngx_str_set(&upstream_name, "tcp");
	if (ngx_http_proxy_switch_set_upstream_instance(cf, 
			&tlcf->upstream, &upstream_name) != NGX_OK){

		return "upstream not support";
	}

	if (cf->args->nelts == 1){

		if (!ngx_http_conf_dyconfig_enabled(cf)){
			return "dyconfig not configured yet.";
		}

		if(ngx_http_proxy_switch_set_proxy_instance(cf, 
					&ngx_http_tcp_proxy) != NGX_OK){

			return NGX_CONF_ERROR;
		}
    	return NGX_CONF_OK;
	}

	value = cf->args->elts;
	url = &value[1];

	n = ngx_http_script_variables_count(url);

	if (n) {

		ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

		sc.cf = cf;
		sc.source = url;
		sc.lengths = &tlcf->proxy_lengths;
		sc.values = &tlcf->proxy_values;
		sc.variables = n;
		sc.complete_lengths = 1;
		sc.complete_values = 1;

		if (ngx_http_script_compile(&sc) != NGX_OK) {
			return NGX_CONF_ERROR;
		}

	}else{

		ngx_memzero(&u, sizeof(ngx_url_t));

		u.url = *url;
		u.no_resolve = 1;

		tlcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
		if (tlcf->upstream.upstream == NULL) {
			return NGX_CONF_ERROR;
		}
	}

	if(ngx_http_proxy_switch_set_proxy_instance(cf, 
			&ngx_http_tcp_proxy) != NGX_OK){
		
		return NGX_CONF_ERROR;
	}

    return NGX_CONF_OK;
}
Beispiel #17
0
static ngx_int_t
merge_headers(ngx_conf_t *cf, passenger_loc_conf_t *conf, passenger_loc_conf_t *prev)
{
    u_char                       *p;
    size_t                        size;
    uintptr_t                    *code;
    ngx_uint_t                    i;
    ngx_array_t                   headers_names, headers_merged;
    ngx_keyval_t                 *src, *s;
    ngx_hash_key_t               *hk;
    ngx_hash_init_t               hash;
    ngx_http_script_compile_t     sc;
    ngx_http_script_copy_code_t  *copy;

    if (conf->headers_source == NULL) {
        conf->flushes = prev->flushes;
        conf->headers_set_len = prev->headers_set_len;
        conf->headers_set = prev->headers_set;
        conf->headers_set_hash = prev->headers_set_hash;
        conf->headers_source = prev->headers_source;
    }

    if (conf->headers_set_hash.buckets
#if (NGX_HTTP_CACHE)
    #if NGINX_VERSION_NUM >= 1007009
        && ((conf->upstream_config.cache == NGX_CONF_UNSET) == (prev->upstream_config.cache == NGX_CONF_UNSET))
    #else
        && ((conf->upstream_config.cache == NGX_CONF_UNSET_PTR) == (prev->upstream_config.cache == NGX_CONF_UNSET_PTR))
    #endif
#endif
       )
    {
        return NGX_OK;
    }


    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (conf->headers_source == NULL) {
        conf->headers_source = ngx_array_create(cf->pool, 4,
                                                sizeof(ngx_keyval_t));
        if (conf->headers_source == NULL) {
            return NGX_ERROR;
        }
    }

    conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
    if (conf->headers_set_len == NULL) {
        return NGX_ERROR;
    }

    conf->headers_set = ngx_array_create(cf->pool, 512, 1);
    if (conf->headers_set == NULL) {
        return NGX_ERROR;
    }


    src = conf->headers_source->elts;
    for (i = 0; i < conf->headers_source->nelts; i++) {

        s = ngx_array_push(&headers_merged);
        if (s == NULL) {
            return NGX_ERROR;
        }

        *s = src[i];
    }


    src = headers_merged.elts;
    for (i = 0; i < headers_merged.nelts; i++) {

        hk = ngx_array_push(&headers_names);
        if (hk == NULL) {
            return NGX_ERROR;
        }

        hk->key = src[i].key;
        hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
        hk->value = (void *) 1;

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

        if (ngx_http_script_variables_count(&src[i].value) == 0) {
            copy = ngx_array_push_n(conf->headers_set_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_ERROR;
            }

            copy->code = (ngx_http_script_code_pt)
                                                 ngx_http_script_copy_len_code;
            copy->len = src[i].key.len + sizeof(": ") - 1
                        + src[i].value.len + sizeof(CRLF) - 1;


            size = (sizeof(ngx_http_script_copy_code_t)
                       + src[i].key.len + sizeof(": ") - 1
                       + src[i].value.len + sizeof(CRLF) - 1
                       + sizeof(uintptr_t) - 1)
                    & ~(sizeof(uintptr_t) - 1);

            copy = ngx_array_push_n(conf->headers_set, size);
            if (copy == NULL) {
                return NGX_ERROR;
            }

            copy->code = ngx_http_script_copy_code;
            copy->len = src[i].key.len + sizeof(": ") - 1
                        + src[i].value.len + sizeof(CRLF) - 1;

            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);

            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
            *p++ = ':'; *p++ = ' ';
            p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
            *p++ = CR; *p = LF;

        } else {
            copy = ngx_array_push_n(conf->headers_set_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_ERROR;
            }

            copy->code = (ngx_http_script_code_pt)
                                                 ngx_http_script_copy_len_code;
            copy->len = src[i].key.len + sizeof(": ") - 1;


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

            copy = ngx_array_push_n(conf->headers_set, size);
            if (copy == NULL) {
                return NGX_ERROR;
            }

            copy->code = ngx_http_script_copy_code;
            copy->len = src[i].key.len + sizeof(": ") - 1;

            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
            *p++ = ':'; *p = ' ';


            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

            sc.cf = cf;
            sc.source = &src[i].value;
            sc.flushes = &conf->flushes;
            sc.lengths = &conf->headers_set_len;
            sc.values = &conf->headers_set;

            if (ngx_http_script_compile(&sc) != NGX_OK) {
                return NGX_ERROR;
            }


            copy = ngx_array_push_n(conf->headers_set_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_ERROR;
            }

            copy->code = (ngx_http_script_code_pt)
                                                 ngx_http_script_copy_len_code;
            copy->len = sizeof(CRLF) - 1;


            size = (sizeof(ngx_http_script_copy_code_t)
                    + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
                    & ~(sizeof(uintptr_t) - 1);

            copy = ngx_array_push_n(conf->headers_set, size);
            if (copy == NULL) {
                return NGX_ERROR;
            }

            copy->code = ngx_http_script_copy_code;
            copy->len = sizeof(CRLF) - 1;

            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
            *p++ = CR; *p = LF;
        }

        code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_ERROR;
        }

        *code = (uintptr_t) NULL;

        code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_ERROR;
        }

        *code = (uintptr_t) NULL;
    }

    code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
    if (code == NULL) {
        return NGX_ERROR;
    }

    *code = (uintptr_t) NULL;


    hash.hash = &conf->headers_set_hash;
    hash.key = ngx_hash_key_lc;
    hash.max_size = conf->headers_hash_max_size;
    hash.bucket_size = conf->headers_hash_bucket_size;
    hash.name = "passenger_headers_hash";
    hash.pool = cf->pool;
    hash.temp_pool = NULL;

    return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
}
static char *
ngx_http_qrcode_cmder(ngx_http_qrcode_cfg_t cfg_code,
		ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	ngx_http_qrcode_loc_conf_t	*qlcf;
    ngx_http_qrcode_cmd_t 		*qr_cmd;
	ngx_str_t	*raw_args;
	ngx_array_t **cmds_ptr;
	ngx_array_t **args_ptr;
	ngx_http_qrcode_arg_template_t	*arg;
	ngx_http_script_compile_t 		sc;
	ngx_uint_t i, n;

	qlcf = (ngx_http_qrcode_loc_conf_t *)conf;
	cmds_ptr = &qlcf->cmds;

	if (*cmds_ptr == NULL)
	{
		*cmds_ptr = ngx_array_create(cf->pool, 1, sizeof(ngx_http_qrcode_cmd_t));

		if (*cmds_ptr == NULL) {
			return NGX_CONF_ERROR;
		}
	}

	qr_cmd = ngx_array_push(*cmds_ptr);

	if (qr_cmd == NULL) {
		return NGX_CONF_ERROR;
	}

	qr_cmd->cfg_code = cfg_code;

	args_ptr = &qr_cmd->args;
	*args_ptr = ngx_array_create(cf->pool, 1, sizeof(ngx_http_qrcode_arg_template_t));

	if (*args_ptr == NULL) {
		return NGX_CONF_ERROR;
	}

	raw_args = cf->args->elts;

	// we skip the first arg and start from the second
	for (i = 1 ; i < cf->args->nelts; i++)
	{
		arg = ngx_array_push(*args_ptr);

		if (arg == NULL)
			return NGX_CONF_ERROR;

		arg->raw_value 	= raw_args[i];
		arg->lengths 	= NULL;
		arg->values 	= NULL;

		n = ngx_http_script_variables_count(&arg->raw_value);

		if (n > 0) {
			ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

			sc.cf = cf;
			sc.source  = &arg->raw_value;
			sc.lengths = &arg->lengths;
			sc.values  = &arg->values;
			sc.variables = n;
			sc.complete_lengths = 1;
			sc.complete_values  = 1;

			if (ngx_http_script_compile(&sc) != NGX_OK) {
				return NGX_CONF_ERROR;
			}
		}
	} /* end for */

	return NGX_CONF_OK;
}
static char *
ngx_http_subs_filter( ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_int_t                   n;
    ngx_uint_t                  i;
    ngx_str_t                  *value;
    ngx_str_t                  *option;
    sub_pair_t                 *pair;
    ngx_http_subs_loc_conf_t   *slcf = conf;
    ngx_http_script_compile_t   sc;

    value = cf->args->elts;

    if (slcf->sub_pairs == NULL) {
        slcf->sub_pairs = ngx_array_create(cf->pool, 4, sizeof(sub_pair_t));
        if (slcf->sub_pairs == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    pair = ngx_array_push(slcf->sub_pairs);
    if (pair == NULL) {
        return NGX_CONF_ERROR;
    }
    ngx_memzero(pair, sizeof(sub_pair_t));

    pair->match = value[1];

    n = ngx_http_script_variables_count(&value[2]);
    if (n != 0) {
        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = &value[2];
        sc.lengths = &pair->sub_lengths;
        sc.values = &pair->sub_values;
        sc.variables = n;
        sc.complete_lengths = 1;
        sc.complete_values = 1;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_CONF_ERROR;
        }

        /* Dirty hack, if it has captured variables */
        if (sc.captures_mask) {
            pair->has_captured = 1;
        }

    } else {
        pair->sub = value[2];
    }

    if (cf->args->nelts > 3) {
        option = &value[3];
        for(i = 0; i < option->len; i++) {

            switch (option->data[i]){
            case 'i':
                pair->insensitive = 1;
                break;

            case 'o':
                pair->once = 1;
                break;

            case 'r':
                pair->regex = 1;
                break;

            case 'g':
            default:
                continue;
            }
        }
    }

    if (pair->regex || pair->insensitive) {
        if (ngx_http_subs_filter_regex_compile(pair, &sc, cf) == NGX_ERROR) {
            return NGX_CONF_ERROR;
        }
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_auth_ldap_require(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {

    ngx_http_script_compile_t   sc;
    ngx_http_auth_ldap_loc_conf_t *alcf = conf;
    ngx_str_t *value;

    value = cf->args->elts;

    if (alcf->require_user == NULL) {
	alcf->require_user = ngx_array_create(cf->pool, 4, sizeof(ngx_ldap_require_t));
	if (alcf->require_user == NULL) {
	    return NGX_CONF_ERROR;
	}
    }

    if (alcf->require_group == NULL) {
	alcf->require_group = ngx_array_create(cf->pool, 4, sizeof(ngx_ldap_require_t));
	if (alcf->require_group == NULL) {
	    return NGX_CONF_ERROR;
	}
    }

    if (ngx_strcmp(value[1].data, "valid_user") == 0) {
	alcf->require_valid_user = 1;
    }

    if (ngx_strcmp(value[1].data, "user") == 0 || ngx_strcmp(value[1].data, "group") == 0)
    {
	ngx_int_t n;
	ngx_ldap_require_t *rule = NULL;

	if (ngx_strcmp(value[1].data, "user") == 0) {
	    rule = ngx_array_push(alcf->require_user);
	}

	if (ngx_strcmp(value[1].data, "group") == 0) {
	    rule = ngx_array_push(alcf->require_group);
	}

	if (rule == NULL) {
	    return NGX_CONF_ERROR;
	}

	rule->value.data = value[2].data;
	rule->value.len = value[2].len;
	rule->values = NULL;
	rule->lengths = NULL;

	n = ngx_http_script_variables_count(&value[2]);
	if(n > 0) {
	    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
	    sc.cf = cf;
	    sc.source = &value[2];
	    sc.lengths = &rule->lengths;
	    sc.values = &rule->values;
	    sc.complete_lengths = 1;
	    sc.complete_values = 1;

	    if (ngx_http_script_compile(&sc) != NGX_OK) {
		return NGX_CONF_ERROR;
	    }
	}
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_scgi_loc_conf_t *prev = parent;
    ngx_http_scgi_loc_conf_t *conf = child;

    u_char                       *p;
    size_t                        size;
    uintptr_t                    *code;
    ngx_uint_t                    i;
    ngx_array_t                   headers_names;
    ngx_keyval_t                 *src;
    ngx_hash_key_t               *hk;
    ngx_hash_init_t               hash;
    ngx_http_core_loc_conf_t     *clcf;
    ngx_http_script_compile_t     sc;
    ngx_http_script_copy_code_t  *copy;

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

        if (conf->upstream.store_lengths == NULL) {
            conf->upstream.store_lengths = prev->upstream.store_lengths;
            conf->upstream.store_values = prev->upstream.store_values;
        }
    }

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

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

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

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

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

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

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

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


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

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


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


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

    if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream.busy_buffers_size = 2 * size;
    } else {
        conf->upstream.busy_buffers_size =
            conf->upstream.busy_buffers_size_conf;
    }

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

        return NGX_CONF_ERROR;
    }

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

        return NGX_CONF_ERROR;
    }


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

    if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream.temp_file_write_size = 2 * size;
    } else {
        conf->upstream.temp_file_write_size =
            conf->upstream.temp_file_write_size_conf;
    }

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

        return NGX_CONF_ERROR;
    }


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

    if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
    } else {
        conf->upstream.max_temp_file_size =
            conf->upstream.max_temp_file_size_conf;
    }

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

        return NGX_CONF_ERROR;
    }


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


    ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
                                 prev->upstream.next_upstream,
                                 (NGX_CONF_BITMASK_SET
                                  |NGX_HTTP_UPSTREAM_FT_ERROR
                                  |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

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

    if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
                                  prev->upstream.temp_path,
                                  &ngx_http_scgi_temp_path)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

#if (NGX_HTTP_CACHE)

    ngx_conf_merge_ptr_value(conf->upstream.cache,
                              prev->upstream.cache, NULL);

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

        shm_zone = conf->upstream.cache;

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

        return NGX_CONF_ERROR;
    }

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

    ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
                              prev->upstream.cache_use_stale,
                              (NGX_CONF_BITMASK_SET
                               |NGX_HTTP_UPSTREAM_FT_OFF));

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

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

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

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

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

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

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

#endif

    ngx_conf_merge_value(conf->upstream.pass_request_headers,
                         prev->upstream.pass_request_headers, 1);
    ngx_conf_merge_value(conf->upstream.pass_request_body,
                         prev->upstream.pass_request_body, 1);

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

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

    if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
            &prev->upstream, ngx_http_scgi_hide_headers, &hash)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    if (conf->upstream.upstream == NULL) {
        conf->upstream.upstream = prev->upstream.upstream;
    }

    if (conf->scgi_lengths == NULL) {
        conf->scgi_lengths = prev->scgi_lengths;
        conf->scgi_values = prev->scgi_values;
    }

    if (conf->upstream.upstream || conf->scgi_lengths) {
        clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
        if (clcf->handler == NULL && clcf->lmt_excpt) {
            clcf->handler = ngx_http_scgi_handler;
        }
    }

    if (conf->params_source == NULL) {
        conf->flushes = prev->flushes;
        conf->params_len = prev->params_len;
        conf->params = prev->params;
        conf->params_source = prev->params_source;
        conf->headers_hash = prev->headers_hash;

#if (NGX_HTTP_CACHE)

        if (conf->params_source == NULL) {

            if ((conf->upstream.cache == NULL)
                == (prev->upstream.cache == NULL))
            {
                return NGX_CONF_OK;
            }

            /* 6 is a number of ngx_http_scgi_cache_headers entries */
            conf->params_source = ngx_array_create(cf->pool, 6,
                                                   sizeof(ngx_keyval_t));
            if (conf->params_source == NULL) {
                return NGX_CONF_ERROR;
            }
        }
#else

        if (conf->params_source == NULL) {
            return NGX_CONF_OK;
        }

#endif
    }

    conf->params_len = ngx_array_create(cf->pool, 64, 1);
    if (conf->params_len == NULL) {
        return NGX_CONF_ERROR;
    }

    conf->params = ngx_array_create(cf->pool, 512, 1);
    if (conf->params == NULL) {
        return NGX_CONF_ERROR;
    }

    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    src = conf->params_source->elts;

#if (NGX_HTTP_CACHE)

    if (conf->upstream.cache) {
        ngx_keyval_t  *h, *s;

        for (h = ngx_http_scgi_cache_headers; h->key.len; h++) {

            for (i = 0; i < conf->params_source->nelts; i++) {
                if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
                    goto next;
                }
            }

            s = ngx_array_push(conf->params_source);
            if (s == NULL) {
                return NGX_CONF_ERROR;
            }

            *s = *h;

            src = conf->params_source->elts;

        next:

            h++;
        }
    }

#endif

    for (i = 0; i < conf->params_source->nelts; i++) {

        if (src[i].key.len > sizeof("HTTP_") - 1
            && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
        {
            hk = ngx_array_push(&headers_names);
            if (hk == NULL) {
                return NGX_CONF_ERROR;
            }

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

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

        copy = ngx_array_push_n(conf->params_len,
                                sizeof(ngx_http_script_copy_code_t));
        if (copy == NULL) {
            return NGX_CONF_ERROR;
        }

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


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

        copy = ngx_array_push_n(conf->params, size);
        if (copy == NULL) {
            return NGX_CONF_ERROR;
        }

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

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


        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = &src[i].value;
        sc.flushes = &conf->flushes;
        sc.lengths = &conf->params_len;
        sc.values = &conf->params;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_CONF_ERROR;
        }

        code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_CONF_ERROR;
        }

        *code = (uintptr_t) NULL;


        code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_CONF_ERROR;
        }

        *code = (uintptr_t) NULL;
    }

    code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
    if (code == NULL) {
        return NGX_CONF_ERROR;
    }

    *code = (uintptr_t) NULL;

    code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
    if (code == NULL) {
        return NGX_CONF_ERROR;
    }

    *code = (uintptr_t) NULL;

    conf->header_params = headers_names.nelts;

    hash.hash = &conf->headers_hash;
    hash.key = ngx_hash_key_lc;
    hash.max_size = 512;
    hash.bucket_size = 64;
    hash.name = "scgi_params_hash";
    hash.pool = cf->pool;
    hash.temp_pool = NULL;

    if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *ngx_http_alog_write_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
        ngx_http_alog_loc_conf_t *llcf = conf;
        ngx_http_alog_main_conf_t *lmcf;

        ngx_str_t *value;
        ngx_http_alog_t *log;

        int log_level;
        unsigned flush;

        ngx_http_script_compile_t sc;
        ngx_uint_t n;

        lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_alog_module);

        if (cf->cmd_type != NGX_HTTP_LOC_CONF) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"alog\" directive can be used only on \"location\" level");
                return NGX_CONF_ERROR;
        }

        if (cf->args->nelts > 4) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid alog setting, usage: alog [log_level] [log_msg] [flush]");
                return NGX_CONF_ERROR;
        }

        if (lmcf->log_level == NGX_CONF_UNSET || alog_log_thread_ctx.log_file == NULL) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"alog_set\" directive is missing. You should set it in \"http\" before using alog");
                return NGX_CONF_ERROR;
        }

        value = cf->args->elts;

        log_level = alog_parse_log_level(&value[1]);

        if (log_level == NGX_CONF_UNSET) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid alog level \"%s\"", value[1].data);
                return NGX_CONF_ERROR;
        }

        flush = 0;

        if (cf->args->nelts == 4) {
                if (ngx_strncasecmp(value[3].data, (u_char *) "FLUSH", 4) == 0) {
                        flush = 1;
                } else {
                        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid alog flush flag value, use \"flush\" only");
                        return NGX_CONF_ERROR;
                }
        }

        if (log_level < lmcf->log_level) {
                return NGX_CONF_OK;
        }

        if (llcf->logs == NULL) {
                llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_alog_t));

                if (llcf->logs == NULL) {
                        return NGX_CONF_ERROR;
                }
        }

        log = ngx_array_push(llcf->logs);

        if (log == NULL) {
                return NGX_CONF_ERROR;
        }

        log->level = log_level;
        log->flush = flush;

        log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_alog_script_t));

        if (log->script == NULL) {
                return NGX_CONF_ERROR;
        }
        
        /* store raw str value of arg */
        log->script->raw_value = value[2];

        n = ngx_http_script_variables_count(&value[2]);

        if (n > 0) {
                ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

                sc.cf = cf;
                sc.source = &(log->script->raw_value);
                sc.lengths = &(log->script->lengths);
                sc.values = &(log->script->values);
                sc.variables = n;
                sc.complete_lengths = 1;
                sc.complete_values = 1;

                if (ngx_http_script_compile(&sc) != NGX_OK) {
                        return NGX_CONF_ERROR;
                }
        }

        return NGX_CONF_OK;
}
Beispiel #23
0
char *
passenger_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    passenger_loc_conf_t         *prev = parent;
    passenger_loc_conf_t         *conf = child;

    u_char                       *p;
    size_t                        size;
    uintptr_t                    *code;
    ngx_uint_t                    i;
    ngx_str_t                    *prev_base_uris, *base_uri;
    ngx_str_t                    *prev_union_station_filters, *union_station_filter;
    ngx_keyval_t                 *src;
    ngx_hash_init_t               hash;
    ngx_http_script_compile_t     sc;
    ngx_http_script_copy_code_t  *copy;

    #include "MergeLocationConfig.c"
    if (prev->options_cache.data == NULL) {
        cache_loc_conf_options(cf, prev);
    }
    cache_loc_conf_options(cf, conf);
    
    if (prev->base_uris != NGX_CONF_UNSET_PTR) {
        if (conf->base_uris == NGX_CONF_UNSET_PTR) {
            conf->base_uris = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
            if (conf->base_uris == NULL) {
                return NGX_CONF_ERROR;
            }
        }
        
        prev_base_uris = (ngx_str_t *) prev->base_uris->elts;
        for (i = 0; i < prev->base_uris->nelts; i++) {
            base_uri = (ngx_str_t *) ngx_array_push(conf->base_uris);
            if (base_uri == NULL) {
                return NGX_CONF_ERROR;
            }
            *base_uri = prev_base_uris[i];
        }
    }
    
    if (prev->union_station_filters != NGX_CONF_UNSET_PTR) {
        if (conf->union_station_filters == NGX_CONF_UNSET_PTR) {
            conf->union_station_filters = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
            if (conf->union_station_filters == NULL) {
                return NGX_CONF_ERROR;
            }
        }
        
        prev_union_station_filters = (ngx_str_t *) prev->union_station_filters->elts;
        for (i = 0; i < prev->union_station_filters->nelts; i++) {
            union_station_filter = (ngx_str_t *) ngx_array_push(conf->union_station_filters);
            if (union_station_filter == NULL) {
                return NGX_CONF_ERROR;
            }
            *union_station_filter = prev_union_station_filters[i];
        }
    }

    /******************************/
    /******************************/

    if (conf->upstream_config.store != 0) {
        ngx_conf_merge_value(conf->upstream_config.store,
                                  prev->upstream_config.store, 0);

        if (conf->upstream_config.store_lengths == NULL) {
            conf->upstream_config.store_lengths = prev->upstream_config.store_lengths;
            conf->upstream_config.store_values = prev->upstream_config.store_values;
        }
    }

    ngx_conf_merge_uint_value(conf->upstream_config.store_access,
                              prev->upstream_config.store_access, 0600);

    ngx_conf_merge_value(conf->upstream_config.buffering,
                         prev->upstream_config.buffering, 0);

    ngx_conf_merge_value(conf->upstream_config.ignore_client_abort,
                         prev->upstream_config.ignore_client_abort, 0);

    ngx_conf_merge_ptr_value(conf->upstream_config.local,
                             prev->upstream_config.local, NULL);

    ngx_conf_merge_msec_value(conf->upstream_config.connect_timeout,
                              prev->upstream_config.connect_timeout, 12000000);

    ngx_conf_merge_msec_value(conf->upstream_config.send_timeout,
                              prev->upstream_config.send_timeout, 12000000);

    ngx_conf_merge_msec_value(conf->upstream_config.read_timeout,
                              prev->upstream_config.read_timeout, 12000000);

    ngx_conf_merge_size_value(conf->upstream_config.send_lowat,
                              prev->upstream_config.send_lowat, 0);

    ngx_conf_merge_size_value(conf->upstream_config.buffer_size,
                              prev->upstream_config.buffer_size,
                              16 * 1024);


    ngx_conf_merge_bufs_value(conf->upstream_config.bufs, prev->upstream_config.bufs,
                              8, 16 * 1024);

    if (conf->upstream_config.bufs.num < 2) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "there must be at least 2 \"passenger_buffers\"");
        return NGX_CONF_ERROR;
    }


    size = conf->upstream_config.buffer_size;
    if (size < conf->upstream_config.bufs.size) {
        size = conf->upstream_config.bufs.size;
    }


    ngx_conf_merge_size_value(conf->upstream_config.busy_buffers_size_conf,
                              prev->upstream_config.busy_buffers_size_conf,
                              NGX_CONF_UNSET_SIZE);

    if (conf->upstream_config.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream_config.busy_buffers_size = 2 * size;
    } else {
        conf->upstream_config.busy_buffers_size =
                                         conf->upstream_config.busy_buffers_size_conf;
    }

    if (conf->upstream_config.busy_buffers_size < size) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
             "\"passenger_busy_buffers_size\" must be equal to or greater "
             "than the maximum of the value of \"passenger_buffer_size\" and "
             "one of the \"passenger_buffers\"");

        return NGX_CONF_ERROR;
    }

    if (conf->upstream_config.busy_buffers_size
        > (conf->upstream_config.bufs.num - 1) * conf->upstream_config.bufs.size)
    {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
             "\"passenger_busy_buffers_size\" must be less than "
             "the size of all \"passenger_buffers\" minus one buffer");

        return NGX_CONF_ERROR;
    }


    ngx_conf_merge_size_value(conf->upstream_config.temp_file_write_size_conf,
                              prev->upstream_config.temp_file_write_size_conf,
                              NGX_CONF_UNSET_SIZE);

    if (conf->upstream_config.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream_config.temp_file_write_size = 2 * size;
    } else {
        conf->upstream_config.temp_file_write_size =
                                      conf->upstream_config.temp_file_write_size_conf;
    }

    if (conf->upstream_config.temp_file_write_size < size) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
             "\"passenger_temp_file_write_size\" must be equal to or greater than "
             "the maximum of the value of \"passenger_buffer_size\" and "
             "one of the \"passenger_buffers\"");

        return NGX_CONF_ERROR;
    }


    ngx_conf_merge_size_value(conf->upstream_config.max_temp_file_size_conf,
                              prev->upstream_config.max_temp_file_size_conf,
                              NGX_CONF_UNSET_SIZE);

    if (conf->upstream_config.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream_config.max_temp_file_size = 1024 * 1024 * 1024;
    } else {
        conf->upstream_config.max_temp_file_size =
                                        conf->upstream_config.max_temp_file_size_conf;
    }

    if (conf->upstream_config.max_temp_file_size != 0
        && conf->upstream_config.max_temp_file_size < size)
    {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
             "\"passenger_max_temp_file_size\" must be equal to zero to disable "
             "temporary files usage or must be equal to or greater than "
             "the maximum of the value of \"passenger_buffer_size\" and "
             "one of the \"passenger_buffers\"");

        return NGX_CONF_ERROR;
    }

    ngx_conf_merge_bitmask_value(conf->upstream_config.ignore_headers,
                                 prev->upstream_config.ignore_headers,
                                 NGX_CONF_BITMASK_SET);

    ngx_conf_merge_bitmask_value(conf->upstream_config.next_upstream,
                              prev->upstream_config.next_upstream,
                              (NGX_CONF_BITMASK_SET
                               |NGX_HTTP_UPSTREAM_FT_ERROR
                               |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

    if (conf->upstream_config.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
        conf->upstream_config.next_upstream = NGX_CONF_BITMASK_SET
                                       |NGX_HTTP_UPSTREAM_FT_OFF;
    }

    ngx_conf_merge_path_value(cf,
                              &conf->upstream_config.temp_path,
                              prev->upstream_config.temp_path,
                              &ngx_http_proxy_temp_path);

#if (NGX_HTTP_CACHE)

    ngx_conf_merge_ptr_value(conf->upstream_config.cache,
                             prev->upstream_config.cache, NULL);

    if (conf->upstream_config.cache && conf->upstream_config.cache->data == NULL) {
        ngx_shm_zone_t  *shm_zone;

        shm_zone = conf->upstream_config.cache;

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

        return NGX_CONF_ERROR;
    }

    ngx_conf_merge_uint_value(conf->upstream_config.cache_min_uses,
                              prev->upstream_config.cache_min_uses, 1);

    ngx_conf_merge_bitmask_value(conf->upstream_config.cache_use_stale,
                              prev->upstream_config.cache_use_stale,
                              (NGX_CONF_BITMASK_SET
                               | NGX_HTTP_UPSTREAM_FT_OFF));

    if (conf->upstream_config.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
        conf->upstream_config.cache_use_stale = NGX_CONF_BITMASK_SET
                                                | NGX_HTTP_UPSTREAM_FT_OFF;
    }

    if (conf->upstream_config.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
        conf->upstream_config.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
    }

    if (conf->upstream_config.cache_methods == 0) {
        conf->upstream_config.cache_methods = prev->upstream_config.cache_methods;
    }

    conf->upstream_config.cache_methods |= NGX_HTTP_GET | NGX_HTTP_HEAD;

    ngx_conf_merge_ptr_value(conf->upstream_config.cache_bypass,
                             prev->upstream_config.cache_bypass, NULL);

    ngx_conf_merge_ptr_value(conf->upstream_config.no_cache,
                             prev->upstream_config.no_cache, NULL);

    ngx_conf_merge_ptr_value(conf->upstream_config.cache_valid,
                             prev->upstream_config.cache_valid, NULL);

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

    #if NGINX_VERSION_NUM >= 1002000
    ngx_conf_merge_value(conf->upstream_config.cache_lock,
                         prev->upstream_config.cache_lock, 0);

    ngx_conf_merge_msec_value(conf->upstream_config.cache_lock_timeout,
                              prev->upstream_config.cache_lock_timeout, 5000);
    #endif

#endif

    ngx_conf_merge_value(conf->upstream_config.pass_request_headers,
                         prev->upstream_config.pass_request_headers, 1);
    ngx_conf_merge_value(conf->upstream_config.pass_request_body,
                         prev->upstream_config.pass_request_body, 1);

    ngx_conf_merge_value(conf->upstream_config.intercept_errors,
                         prev->upstream_config.intercept_errors, 0);


    hash.max_size = 512;
    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
    hash.name = "passenger_hide_headers_hash";

    if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream_config,
            &prev->upstream_config, headers_to_hide, &hash)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    if (conf->upstream_config.upstream == NULL) {
        conf->upstream_config.upstream = prev->upstream_config.upstream;
    }

    if (conf->vars_source == NULL) {
        conf->flushes = prev->flushes;
        conf->vars_len = prev->vars_len;
        conf->vars = prev->vars;
        conf->vars_source = prev->vars_source;

        if (conf->vars_source == NULL) {
            return NGX_CONF_OK;
        }
    }

    conf->vars_len = ngx_array_create(cf->pool, 64, 1);
    if (conf->vars_len == NULL) {
        return NGX_CONF_ERROR;
    }

    conf->vars = ngx_array_create(cf->pool, 512, 1);
    if (conf->vars == NULL) {
        return NGX_CONF_ERROR;
    }

    src = conf->vars_source->elts;
    for (i = 0; i < conf->vars_source->nelts; i++) {

        if (ngx_http_script_variables_count(&src[i].value) == 0) {
            copy = ngx_array_push_n(conf->vars_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

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


            copy = ngx_array_push_n(conf->vars_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

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


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

            copy = ngx_array_push_n(conf->vars, size);
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

            copy->code = ngx_http_script_copy_code;
            copy->len = src[i].key.len + src[i].value.len;

            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);

            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
            ngx_memcpy(p, src[i].value.data, src[i].value.len);

        } else {
            copy = ngx_array_push_n(conf->vars_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

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


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

            copy = ngx_array_push_n(conf->vars, size);
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

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

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


            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

            sc.cf = cf;
            sc.source = &src[i].value;
            sc.flushes = &conf->flushes;
            sc.lengths = &conf->vars_len;
            sc.values = &conf->vars;

            if (ngx_http_script_compile(&sc) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }

        code = ngx_array_push_n(conf->vars_len, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_CONF_ERROR;
        }

        *code = (uintptr_t) NULL;


        code = ngx_array_push_n(conf->vars, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_CONF_ERROR;
        }

        *code = (uintptr_t) NULL;
    }

    code = ngx_array_push_n(conf->vars_len, sizeof(uintptr_t));
    if (code == NULL) {
        return NGX_CONF_ERROR;
    }

    *code = (uintptr_t) NULL;

    return NGX_CONF_OK;
}
static char *
ngx_http_internal_redirect_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_str_t                               *value;
    ngx_int_t                                code;
    ngx_uint_t                               n;
    ngx_http_script_compile_t                sc;
    ngx_http_internal_redirect_entry_t      *redirect;
    ngx_http_internal_redirect_main_conf_t  *imcf;
    ngx_http_internal_redirect_loc_conf_t   *ilcf = conf;

    if (ilcf->redirects == NULL) {
        ilcf->redirects = ngx_array_create(cf->pool, 4,
                                    sizeof(ngx_http_internal_redirect_entry_t));
        if (ilcf->redirects == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    redirect = ngx_array_push(ilcf->redirects);
    if (redirect == NULL) {
        return NGX_CONF_ERROR;
    }
    ngx_memzero(redirect, sizeof(ngx_http_internal_redirect_entry_t));

    value = cf->args->elts;
    redirect->name = value[cf->args->nelts - 1];

    n = ngx_http_script_variables_count(&redirect->name);

    if (n) {
        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = &redirect->name;
        sc.lengths = &redirect->lengths;
        sc.values = &redirect->values;
        sc.variables = n;
        sc.complete_lengths = 1;
        sc.complete_values = 1;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }

    if (redirect->name.data[0] == '=') {
        code = ngx_atoi(redirect->name.data + 1, redirect->name.len - 1);
        if (code == NGX_ERROR || code > 999) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid code \"%V\"",
                               &redirect->name);
            return NGX_CONF_ERROR;
        }

        redirect->code = code;
    }

    cf->args->nelts--;

    if (ngx_http_internal_redirect_if_condition(cf, redirect) != NGX_CONF_OK) {
        return NGX_CONF_ERROR;
    }

    imcf = ngx_http_conf_get_module_main_conf(cf,
                                             ngx_http_internal_redirect_module);
    imcf->required = 1;

    return NGX_CONF_OK;
}
static char *
ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_headers_conf_t *hcf = conf;

    ngx_int_t                   n;
    ngx_str_t                  *value;
    ngx_uint_t                  i;
    ngx_http_header_val_t      *h;
    ngx_http_set_header_t      *sh;
    ngx_http_script_compile_t   sc;

    value = cf->args->elts;

    if (hcf->headers == NULL) {
        hcf->headers = ngx_array_create(cf->pool, 1,
                                        sizeof(ngx_http_header_val_t));
        if (hcf->headers == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    h = ngx_array_push(hcf->headers);
    if (h == NULL) {
        return NGX_CONF_ERROR;
    }

    h->value.hash = 1;
    h->value.key = value[1];
    h->value.value = value[2];
    h->offset = 0;
    h->handler = ngx_http_add_header;
    h->lengths = NULL;
    h->values = NULL;

    sh = ngx_http_set_headers;
    for (i = 0; sh[i].name.len; i++) {
        if (ngx_strcasecmp(value[1].data, sh[i].name.data) != 0) {
            continue;
        }

        h->offset = sh[i].offset;
        h->handler = sh[i].handler;
        break;
    }

    n = ngx_http_script_variables_count(&value[2]);

    if (n == 0) {
        return NGX_CONF_OK;
    }

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = &value[2];
    sc.lengths = &h->lengths;
    sc.values = &h->values;
    sc.variables = n;
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
Beispiel #26
0
char *
passenger_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    passenger_loc_conf_t         *prev = parent;
    passenger_loc_conf_t         *conf = child;

    u_char                       *p;
    size_t                        size;
    uintptr_t                    *code;
    ngx_str_t                    *header;
    ngx_uint_t                    i, j;
    ngx_array_t                   hide_headers;
    ngx_str_t                    *prev_base_uris, *base_uri;
    ngx_keyval_t                 *src;
    ngx_hash_key_t               *hk;
    ngx_hash_init_t               hash;
    ngx_http_script_compile_t     sc;
    ngx_http_script_copy_code_t  *copy;
#if NGINX_VERSION_NUM < 7000
    u_char                       *temp_path;
#endif

    ngx_conf_merge_value(conf->enabled, prev->enabled, 0);
    ngx_conf_merge_value(conf->use_global_queue, prev->use_global_queue, 0);
    ngx_conf_merge_str_value(conf->environment, prev->environment, "production");
    ngx_conf_merge_str_value(conf->spawn_method, prev->spawn_method, "smart-lv2");
    if (conf->framework_spawner_idle_time == -1 && prev->framework_spawner_idle_time != -1) {
        conf->framework_spawner_idle_time = prev->framework_spawner_idle_time;
    }
    if (conf->app_spawner_idle_time == -1 && prev->app_spawner_idle_time != -1) {
        conf->app_spawner_idle_time = prev->app_spawner_idle_time;
    }

    if (prev->base_uris != NGX_CONF_UNSET_PTR) {
        if (conf->base_uris == NGX_CONF_UNSET_PTR) {
            conf->base_uris = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
            if (conf->base_uris == NULL) {
                return NGX_CONF_ERROR;
            }
        }

        prev_base_uris = (ngx_str_t *) prev->base_uris->elts;
        for (i = 0; i < prev->base_uris->nelts; i++) {
            base_uri = (ngx_str_t *) ngx_array_push(conf->base_uris);
            if (base_uri == NULL) {
                return NGX_CONF_ERROR;
            }
            *base_uri = prev_base_uris[i];
        }
    }


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

        if (conf->upstream.store_lengths == NULL) {
            conf->upstream.store_lengths = prev->upstream.store_lengths;
            conf->upstream.store_values = prev->upstream.store_values;
        }
    }

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

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

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

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

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

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

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

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


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

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


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


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

    if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream.busy_buffers_size = 2 * size;
    } else {
        conf->upstream.busy_buffers_size =
            conf->upstream.busy_buffers_size_conf;
    }

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

        return NGX_CONF_ERROR;
    }

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

        return NGX_CONF_ERROR;
    }


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

    if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream.temp_file_write_size = 2 * size;
    } else {
        conf->upstream.temp_file_write_size =
            conf->upstream.temp_file_write_size_conf;
    }

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

        return NGX_CONF_ERROR;
    }


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

    if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
        conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
    } else {
        conf->upstream.max_temp_file_size =
            conf->upstream.max_temp_file_size_conf;
    }

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

        return NGX_CONF_ERROR;
    }


    ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
                                 prev->upstream.next_upstream,
                                 (NGX_CONF_BITMASK_SET
                                  |NGX_HTTP_UPSTREAM_FT_ERROR
                                  |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

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

#if NGINX_VERSION_NUM < 7000
    temp_path = ngx_palloc(cf->pool, NGX_MAX_PATH);
    ngx_memzero(temp_path, NGX_MAX_PATH);
    ngx_snprintf(temp_path, NGX_MAX_PATH, "%s/webserver_private", passenger_temp_dir);
    ngx_conf_merge_path_value(conf->upstream.temp_path,
                              prev->upstream.temp_path,
                              temp_path, 1, 2, 0,
                              ngx_garbage_collector_temp_handler, cf);
    conf->upstream.temp_path->name.len = ngx_strlen(conf->upstream.temp_path->name.data);
#else
    ngx_conf_merge_path_value(cf,
                              &conf->upstream.temp_path,
                              prev->upstream.temp_path,
                              &ngx_http_proxy_temp_path);
#endif

    ngx_conf_merge_value(conf->upstream.pass_request_headers,
                         prev->upstream.pass_request_headers, 1);
    ngx_conf_merge_value(conf->upstream.pass_request_body,
                         prev->upstream.pass_request_body, 1);

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



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

    if (conf->upstream.hide_headers == NULL
            && conf->upstream.pass_headers == NULL)
    {
        conf->upstream.hide_headers = prev->upstream.hide_headers;
        conf->upstream.pass_headers = prev->upstream.pass_headers;
        conf->upstream.hide_headers_hash = prev->upstream.hide_headers_hash;

        if (conf->upstream.hide_headers_hash.buckets) {
            goto peers;
        }

    } else {
        if (conf->upstream.hide_headers == NULL) {
            conf->upstream.hide_headers = prev->upstream.hide_headers;
        }

        if (conf->upstream.pass_headers == NULL) {
            conf->upstream.pass_headers = prev->upstream.pass_headers;
        }
    }

    if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
            != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    for (header = headers_to_hide; header->len; header++) {
        hk = ngx_array_push(&hide_headers);
        if (hk == NULL) {
            return NGX_CONF_ERROR;
        }

        hk->key = *header;
        hk->key_hash = ngx_hash_key_lc(header->data, header->len);
        hk->value = (void *) 1;
    }

    if (conf->upstream.hide_headers) {

        header = conf->upstream.hide_headers->elts;

        for (i = 0; i < conf->upstream.hide_headers->nelts; i++) {

            hk = hide_headers.elts;

            for (j = 0; j < hide_headers.nelts; j++) {
                if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) {
                    goto exist;
                }
            }

            hk = ngx_array_push(&hide_headers);
            if (hk == NULL) {
                return NGX_CONF_ERROR;
            }

            hk->key = header[i];
            hk->key_hash = ngx_hash_key_lc(header[i].data, header[i].len);
            hk->value = (void *) 1;

exist:

            continue;
        }
    }

    if (conf->upstream.pass_headers) {

        hk = hide_headers.elts;
        header = conf->upstream.pass_headers->elts;

        for (i = 0; i < conf->upstream.pass_headers->nelts; i++) {

            for (j = 0; j < hide_headers.nelts; j++) {

                if (hk[j].key.data == NULL) {
                    continue;
                }

                if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) {
                    hk[j].key.data = NULL;
                    break;
                }
            }
        }
    }

    hash.hash = &conf->upstream.hide_headers_hash;
    hash.key = ngx_hash_key_lc;
    hash.max_size = 512;
    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
    hash.name = "passenger_hide_headers_hash";
    hash.pool = cf->pool;
    hash.temp_pool = NULL;

    if (ngx_hash_init(&hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

peers:

    if (conf->upstream.upstream == NULL) {
        conf->upstream.upstream = prev->upstream.upstream;
#if NGINX_VERSION_NUM < 7000
        conf->upstream.schema = prev->upstream.schema;
#endif
    }

    if (conf->vars_source == NULL) {
        conf->flushes = prev->flushes;
        conf->vars_len = prev->vars_len;
        conf->vars = prev->vars;
        conf->vars_source = prev->vars_source;

        if (conf->vars_source == NULL) {
            return NGX_CONF_OK;
        }
    }

    conf->vars_len = ngx_array_create(cf->pool, 64, 1);
    if (conf->vars_len == NULL) {
        return NGX_CONF_ERROR;
    }

    conf->vars = ngx_array_create(cf->pool, 512, 1);
    if (conf->vars == NULL) {
        return NGX_CONF_ERROR;
    }

    src = conf->vars_source->elts;
    for (i = 0; i < conf->vars_source->nelts; i++) {

        if (ngx_http_script_variables_count(&src[i].value) == 0) {
            copy = ngx_array_push_n(conf->vars_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

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


            copy = ngx_array_push_n(conf->vars_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

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


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

            copy = ngx_array_push_n(conf->vars, size);
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

            copy->code = ngx_http_script_copy_code;
            copy->len = src[i].key.len + src[i].value.len;

            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);

            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
            ngx_memcpy(p, src[i].value.data, src[i].value.len);

        } else {
            copy = ngx_array_push_n(conf->vars_len,
                                    sizeof(ngx_http_script_copy_code_t));
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

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


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

            copy = ngx_array_push_n(conf->vars, size);
            if (copy == NULL) {
                return NGX_CONF_ERROR;
            }

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

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


            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

            sc.cf = cf;
            sc.source = &src[i].value;
            sc.flushes = &conf->flushes;
            sc.lengths = &conf->vars_len;
            sc.values = &conf->vars;

            if (ngx_http_script_compile(&sc) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }

        code = ngx_array_push_n(conf->vars_len, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_CONF_ERROR;
        }

        *code = (uintptr_t) NULL;


        code = ngx_array_push_n(conf->vars, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_CONF_ERROR;
        }

        *code = (uintptr_t) NULL;
    }

    code = ngx_array_push_n(conf->vars_len, sizeof(uintptr_t));
    if (code == NULL) {
        return NGX_CONF_ERROR;
    }

    *code = (uintptr_t) NULL;

    return NGX_CONF_OK;
}