static char *
ngx_http_xss_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_xss_loc_conf_t *prev = parent;
    ngx_http_xss_loc_conf_t *conf = child;

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

    ngx_conf_merge_value(conf->get_enabled, prev->get_enabled, 0);

    ngx_conf_merge_value(conf->check_status, prev->check_status, 1);

    ngx_conf_merge_value(conf->override_status, prev->override_status, 1);

#if defined(nginx_version) && nginx_version >= 8029
    if (ngx_http_merge_types(cf, &conf->input_types_keys, &conf->input_types,
                             &prev->input_types_keys, &prev->input_types,
                             ngx_http_xss_default_types)
        != NGX_OK)
#else /* 0.7.x or 0.8.x < 0.8.29 */
    if (ngx_http_merge_types(cf, conf->input_types_keys, &conf->input_types,
                             prev->input_types_keys, &prev->input_types,
                             ngx_http_xss_default_types)
        != NGX_OK)
#endif
    {
        return NGX_CONF_ERROR;
    }

    ngx_conf_merge_str_value(conf->output_type, prev->output_type,
                             ngx_http_xss_default_output_type);

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

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

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    ngx_conf_merge_size_value(conf->line_buffer_size,
                              prev->line_buffer_size, 8 * ngx_pagesize);

    /* Default total buffer size is 128k */
    ngx_conf_merge_bufs_value(conf->bufs, prev->bufs,
                              (128 * 1024) / ngx_pagesize, ngx_pagesize);

    return NGX_CONF_OK;
}
示例#3
0
static char *
ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_uint_t                i, n;
    ngx_http_sub_pair_t      *pairs;
    ngx_http_sub_match_t     *matches;
    ngx_http_sub_loc_conf_t  *prev = parent;
    ngx_http_sub_loc_conf_t  *conf = child;

    ngx_conf_merge_value(conf->once, prev->once, 1);
    ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0);

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
            != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    if (conf->pairs == NULL) {
        conf->dynamic = prev->dynamic;
        conf->pairs = prev->pairs;
        conf->matches = prev->matches;
        conf->tables = prev->tables;
    }

    if (conf->pairs && conf->dynamic == 0 && conf->tables == NULL) {
        pairs = conf->pairs->elts;
        n = conf->pairs->nelts;

        matches = ngx_palloc(cf->pool, sizeof(ngx_http_sub_match_t) * n);
        if (matches == NULL) {
            return NGX_CONF_ERROR;
        }

        for (i = 0; i < n; i++) {
            matches[i].match = pairs[i].match.value;
            matches[i].value = &pairs[i].value;
        }

        conf->matches = ngx_palloc(cf->pool, sizeof(ngx_array_t));
        if (conf->matches == NULL) {
            return NGX_CONF_ERROR;
        }

        conf->matches->elts = matches;
        conf->matches->nelts = n;

        conf->tables = ngx_palloc(cf->pool, sizeof(ngx_http_sub_tables_t));
        if (conf->tables == NULL) {
            return NGX_CONF_ERROR;
        }

        ngx_http_sub_init_tables(conf->tables, conf->matches->elts,
                                 conf->matches->nelts);
    }

    return NGX_CONF_OK;
}
// Merge a child configuration with a parent one
static char * ngx_http_jsonp_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_jsonp_conf_t *prev = parent;
    ngx_http_jsonp_conf_t *conf = child;

    // This is trivial, as we have only enable to merge
    // note the 0 default value
    ngx_conf_merge_value(conf->enable, prev->enable, 0);

    // Inherit the variable index from the parent
    // if not defined
    if (conf->variable_index == NGX_CONF_UNSET)
    {
        conf->variable_index = prev->variable_index;
    }

    // Merge the applicable mimetypes
    if (ngx_http_merge_types(cf, conf->mimetypes_keys, &conf->mimetypes,
                             prev->mimetypes_keys, &prev->mimetypes,
                             ngx_http_jsonp_default_mimetypes) != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_gzip_conf_t *prev = parent;
    ngx_http_gzip_conf_t *conf = child;
    ngx_conf_merge_value(conf->enable, prev->enable, 0);
    ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
    ngx_conf_merge_bufs_value(conf->bufs, prev->bufs,
                              (128 * 1024) / ngx_pagesize, ngx_pagesize);
    ngx_conf_merge_size_value(conf->postpone_gzipping, prev->postpone_gzipping,
                              0);
    ngx_conf_merge_value(conf->level, prev->level, 1);
    ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS);
    ngx_conf_merge_size_value(conf->memlevel, prev->memlevel,
                              MAX_MEM_LEVEL - 1);
    ngx_conf_merge_value(conf->min_length, prev->min_length, 20);
    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
            != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }
    return NGX_CONF_OK;
}
static char *
ngx_http_proxy_connect_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_proxy_connect_loc_conf_t *prev = parent;
    ngx_http_proxy_connect_loc_conf_t *conf = child;


    if (ngx_http_merge_types(cf, &conf->block_ports, &conf->ports,
                             &prev->block_ports, &prev->ports,
                             ngx_http_proxy_connect_block_ports)
            != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }
#if (NGX_PCRE)
    ngx_conf_merge_ptr_value(conf->black_hosts, prev->black_hosts, NGX_CONF_UNSET_PTR)
#endif

    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.buffer_size,
                              prev->upstream.buffer_size,
                              (size_t) ngx_pagesize);

    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 (conf->upstream.upstream == NULL) {
        conf->upstream.upstream = prev->upstream.upstream;
    }

    if (conf->index == NGX_CONF_UNSET) {
        conf->index = prev->index;
    }

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

    ngx_conf_merge_str_value(conf->before_body, prev->before_body, "");
    ngx_conf_merge_str_value(conf->after_body, prev->after_body, "");

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, &prev->types_keys, &prev->types, ngx_http_html_default_types) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

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

    ngx_conf_merge_value(conf->enable, prev->enable, 0);

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_minify_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_sub_loc_conf_t *prev = parent;
    ngx_http_sub_loc_conf_t *conf = child;
//    ngx_conf_merge_value(conf->once, prev->once, 1);

    ngx_http_sub_merge_wm_tables(cf, prev, NULL);
    ngx_http_sub_merge_wm_tables(cf, conf, prev);

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

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

    ngx_conf_merge_value(conf->enable, prev->enable,
                         NGX_HTTP_GUNZIP_OFF);

    ngx_conf_merge_bufs_value(conf->bufs, prev->bufs,
                              (128 * 1024) / ngx_pagesize, ngx_pagesize);

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

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

    ngx_conf_merge_value(conf->enable, prev->enable, 0);
    ngx_conf_merge_str_value(conf->delimiter, prev->delimiter, "");
    ngx_conf_merge_value(conf->ignore_file_error, prev->ignore_file_error, 0);
    ngx_conf_merge_uint_value(conf->max_files, prev->max_files, 10);
    ngx_conf_merge_value(conf->unique, prev->unique, 1);

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_concat_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

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

    ngx_conf_merge_value(conf->enable, prev->enable, 0);
    ngx_conf_merge_bufs_value(conf->bufs, prev->bufs,
                              (128 * 1024) / ngx_pagesize, ngx_pagesize);

    ngx_conf_merge_value(conf->level, prev->level, 6);
    ngx_conf_merge_value(conf->min_length, prev->min_length, 2048);

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

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

    ngx_conf_merge_value(conf->once, prev->once, 1);
    ngx_conf_merge_str_value(conf->match, prev->match, "");

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

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_replace_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    u_char         **value;
    sre_int_t        err_offset, err_regex_id;
    ngx_str_t        prefix, suffix;
    sre_pool_t      *ppool; /* parser pool */
    sre_regex_t     *re;
    sre_program_t   *prog;

    ngx_http_replace_main_conf_t    *rmcf;

    ngx_http_replace_loc_conf_t *prev = parent;
    ngx_http_replace_loc_conf_t *conf = child;

    ngx_conf_merge_size_value(conf->max_buffered_size,
                              prev->max_buffered_size,
                              8192);

    ngx_conf_merge_uint_value(conf->last_modified,
                              prev->last_modified,
                              NGX_HTTP_REPLACE_CLEAR_LAST_MODIFIED);

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_html_default_types)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

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

    if (conf->regexes.nelts > 0 && conf->program == NULL) {

        dd("parsing and compiling %d regexes", (int) conf->regexes.nelts);

        ppool = sre_create_pool(1024);
        if (ppool == NULL) {
            return NGX_CONF_ERROR;
        }

        value = conf->regexes.elts;

        re = sre_regex_parse_multi(ppool, value, conf->regexes.nelts,
                                   &conf->ncaps, conf->multi_flags.elts,
                                   &err_offset, &err_regex_id);

        if (re == NULL) {

            if (err_offset >= 0) {
                prefix.data = value[err_regex_id];
                prefix.len = err_offset;

                suffix.data = value[err_regex_id] + err_offset;
                suffix.len = ngx_strlen(value[err_regex_id]) - err_offset;

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "failed to parse regex at offset %i: "
                                   "syntax error; marked by <-- HERE in "
                                   "\"%V <-- HERE %V\"",
                                   (ngx_int_t) err_offset, &prefix, &suffix);

            } else {

                if (err_regex_id >= 0) {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "failed to parse regex \"%s\"",
                                       value[err_regex_id]);

                } else {
                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                       "failed to parse regex \"%s\" "
                                       "and its siblings",
                                       value[0]);
                }
            }

            sre_destroy_pool(ppool);
            return NGX_CONF_ERROR;
        }

        rmcf = ngx_http_conf_get_module_main_conf(cf,
                                              ngx_http_replace_filter_module);

        prog = sre_regex_compile(rmcf->compiler_pool, re);

        sre_destroy_pool(ppool);

        if (prog == NULL) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "failed to compile regex \"%s\" and its "
                               "siblings", value[0]);

            return NGX_CONF_ERROR;
        }

        conf->program = prog;
        conf->ovecsize = 2 * (conf->ncaps + 1) * sizeof(sre_int_t);

    } else {

        conf->regexes       = prev->regexes;
        conf->multi_once    = prev->multi_once;
        conf->multi_flags   = prev->multi_flags;
        conf->multi_replace = prev->multi_replace;
        conf->parse_buf     = prev->parse_buf;
        conf->verbatim      = prev->verbatim;
        conf->program       = prev->program;
        conf->ncaps         = prev->ncaps;
        conf->ovecsize      = prev->ovecsize;
        conf->seen_once     = prev->seen_once;
        conf->seen_global   = prev->seen_global;
    }

    return NGX_CONF_OK;
}
示例#15
0
static char *
ngx_http_vod_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_vod_loc_conf_t *prev = parent;
    ngx_http_vod_loc_conf_t *conf = child;
	const ngx_http_vod_submodule_t** cur_module;
	ngx_int_t rc;
	size_t proxy_header_len;
	u_char* p;
	char* err;

	// base params
	ngx_conf_merge_str_value(conf->child_request_location, prev->child_request_location, "");
	if (conf->submodule.parse_uri_file_name == NGX_CONF_UNSET_PTR) 
	{
		if (prev->submodule.parse_uri_file_name != NGX_CONF_UNSET_PTR)
		{
			conf->submodule = prev->submodule;
		}
		else
		{
			// zero module = serve files
			ngx_memzero(&conf->submodule, sizeof(conf->submodule));
		}
	}
	ngx_conf_merge_ptr_value(conf->request_handler, prev->request_handler, ngx_http_vod_local_request_handler);
	ngx_conf_merge_str_value(conf->multi_uri_suffix, prev->multi_uri_suffix, ".urlset");

	ngx_conf_merge_uint_value(conf->segmenter.segment_duration, prev->segmenter.segment_duration, 10000);
	ngx_conf_merge_ptr_value(conf->segmenter.bootstrap_segments, prev->segmenter.bootstrap_segments, NULL);
	ngx_conf_merge_value(conf->segmenter.align_to_key_frames, prev->segmenter.align_to_key_frames, 0);
	ngx_conf_merge_ptr_value(conf->segmenter.get_segment_count, prev->segmenter.get_segment_count, segmenter_get_segment_count_last_short);
	ngx_conf_merge_ptr_value(conf->segmenter.get_segment_durations, prev->segmenter.get_segment_durations, segmenter_get_segment_durations_estimate);

	if (conf->secret_key == NULL) 
	{
		conf->secret_key = prev->secret_key;
	}
	ngx_conf_merge_uint_value(conf->duplicate_bitrate_threshold, prev->duplicate_bitrate_threshold, 4096);
	ngx_conf_merge_str_value(conf->https_header_name, prev->https_header_name, "");
	ngx_conf_merge_str_value(conf->segments_base_url, prev->segments_base_url, "");
	conf->segments_base_url_has_scheme =
		(ngx_strncasecmp(conf->segments_base_url.data, (u_char *) "http://", 7) == 0 ||
		ngx_strncasecmp(conf->segments_base_url.data, (u_char *) "https://", 8) == 0);


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

	if (conf->response_cache_zone == NULL)
	{
		conf->response_cache_zone = prev->response_cache_zone;
	}
	
	ngx_conf_merge_size_value(conf->initial_read_size, prev->initial_read_size, 4096);
	ngx_conf_merge_size_value(conf->max_moov_size, prev->max_moov_size, 128 * 1024 * 1024);
	ngx_conf_merge_size_value(conf->cache_buffer_size, prev->cache_buffer_size, 256 * 1024);

	err = ngx_merge_upstream_conf(cf, &conf->upstream, &prev->upstream);
	if (err != NGX_CONF_OK)
	{
		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
			"ngx_http_vod_merge_loc_conf: ngx_merge_upstream_conf failed (1)");
		return err;
	}
	ngx_conf_merge_str_value(conf->upstream_host_header, prev->upstream_host_header, "");
	
	if (conf->upstream_extra_args == NULL) 
	{
		conf->upstream_extra_args = prev->upstream_extra_args;
	}

	if (conf->path_mapping_cache_zone == NULL)
	{
		conf->path_mapping_cache_zone = prev->path_mapping_cache_zone;
	}
	ngx_conf_merge_str_value(conf->path_response_prefix, prev->path_response_prefix, "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml><result>");
	ngx_conf_merge_str_value(conf->path_response_postfix, prev->path_response_postfix, "</result></xml>");
	ngx_conf_merge_size_value(conf->max_path_length, prev->max_path_length, 1024);

	err = ngx_merge_upstream_conf(cf, &conf->fallback_upstream, &prev->fallback_upstream);
	if (err != NGX_CONF_OK)
	{
		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
			"ngx_http_vod_merge_loc_conf: ngx_merge_upstream_conf failed (2)");
		return err;
	}
	ngx_conf_merge_str_value(conf->proxy_header_name, prev->proxy_header_name, "X-Kaltura-Proxy");
	ngx_conf_merge_str_value(conf->proxy_header_value, prev->proxy_header_value, "dumpApiRequest");

	ngx_conf_merge_value(conf->last_modified_time, prev->last_modified_time, -1);
	if (ngx_http_merge_types(
		cf, 
		&conf->last_modified_types_keys, 
		&conf->last_modified_types,
		&prev->last_modified_types_keys, 
		&prev->last_modified_types,
		ngx_http_vod_last_modified_default_types) != NGX_OK)
	{
		return NGX_CONF_ERROR;
	}

	ngx_conf_merge_value(conf->drm_enabled, prev->drm_enabled, 0);
	ngx_conf_merge_uint_value(conf->drm_clear_lead_segment_count, prev->drm_clear_lead_segment_count, 1);
	err = ngx_merge_upstream_conf(cf, &conf->drm_upstream, &prev->drm_upstream);
	if (err != NGX_CONF_OK)
	{
		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
			"ngx_http_vod_merge_loc_conf: ngx_merge_upstream_conf failed (3)");
		return err;
	}
	ngx_conf_merge_size_value(conf->drm_max_info_length, prev->drm_max_info_length, 4096);
	if (conf->drm_info_cache_zone == NULL)
	{
		conf->drm_info_cache_zone = prev->drm_info_cache_zone;
	}
	if (conf->drm_request_uri == NULL) 
	{
		conf->drm_request_uri = prev->drm_request_uri;
	}

	ngx_conf_merge_str_value(conf->clip_to_param_name, prev->clip_to_param_name, "clipTo");
	ngx_conf_merge_str_value(conf->clip_from_param_name, prev->clip_from_param_name, "clipFrom");
	ngx_conf_merge_str_value(conf->tracks_param_name, prev->tracks_param_name, "tracks");
	ngx_conf_merge_str_value(conf->speed_param_name, prev->speed_param_name, "speed");

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

#if (NGX_THREADS)
	ngx_conf_merge_ptr_value(conf->open_file_thread_pool, prev->open_file_thread_pool, NULL);
#endif

	// validate vod_upstream / vod_upstream_host_header used when needed
	if (conf->request_handler == ngx_http_vod_remote_request_handler || conf->request_handler == ngx_http_vod_mapped_request_handler)
	{
		if (conf->child_request_location.len == 0)
		{
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
				"\"vod_child_request_path\" is mandatory for remote/mapped modes");
			return NGX_CONF_ERROR;
		}

		if (conf->upstream.upstream == NULL)
		{
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
				"\"vod_upstream\" is mandatory for remote/mapped modes");
			return NGX_CONF_ERROR;
		}
	}
	else
	{
		if (conf->upstream.upstream != NULL)
		{
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
				"\"vod_upstream\" does not apply to local mode");
			return NGX_CONF_ERROR;
		}

		if (conf->upstream_host_header.len != 0)
		{
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
				"\"vod_upstream_host_header\" does not apply to local mode");
			return NGX_CONF_ERROR;
		}
	}
	
	if (conf->request_handler == ngx_http_vod_remote_request_handler)
	{
		if (conf->fallback_upstream.upstream != NULL)
		{
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
				"\"vod_fallback_upstream\" does not apply to remote mode");
			return NGX_CONF_ERROR;
		}
	}

	if (conf->segmenter.segment_duration <= 0)
	{
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
			"\"segment_duration\" must be positive");
		return NGX_CONF_ERROR;
	}

	rc = segmenter_init_config(&conf->segmenter, cf->pool);
	if (rc != VOD_OK)
	{
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
			"failed to initialize the segmenter %i", rc);
		return NGX_CONF_ERROR;
	}

	if (conf->drm_enabled && conf->drm_upstream.upstream == NULL)
	{
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
			"\"drm_upstream\" must be configured when drm is enabled");
		return NGX_CONF_ERROR;
	}

	// validate the lengths of uri parameters
	if (conf->clip_to_param_name.len > MAX_URI_PARAM_NAME_LEN)
	{
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
			"\"clip_to_param_name\" should not be more than %d characters", MAX_URI_PARAM_NAME_LEN);
		return NGX_CONF_ERROR;
	}

	if (conf->clip_from_param_name.len > MAX_URI_PARAM_NAME_LEN)
	{
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
			"\"clip_from_param_name\" should not be more than %d characters", MAX_URI_PARAM_NAME_LEN);
		return NGX_CONF_ERROR;
	}

	if (conf->tracks_param_name.len > MAX_URI_PARAM_NAME_LEN)
	{
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
			"\"tracks_param_name\" should not be more than %d characters", MAX_URI_PARAM_NAME_LEN);
		return NGX_CONF_ERROR;
	}

	if (conf->speed_param_name.len > MAX_URI_PARAM_NAME_LEN)
	{
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
			"\"speed_param_name\" should not be more than %d characters", MAX_URI_PARAM_NAME_LEN);
		return NGX_CONF_ERROR;
	}
	
	// combine the proxy header name and value to a single line
	proxy_header_len = conf->proxy_header_name.len + sizeof(": ") - 1 + conf->proxy_header_value.len + sizeof(CRLF);
	conf->proxy_header.data = ngx_palloc(cf->pool, proxy_header_len);
	if (conf->proxy_header.data == NULL)
	{
		return NGX_CONF_ERROR;
	}
	p = conf->proxy_header.data;
	p = ngx_copy(p, conf->proxy_header_name.data, conf->proxy_header_name.len);
	*p++ = ':';		*p++ = ' ';
	p = ngx_copy(p, conf->proxy_header_value.data, conf->proxy_header_value.len);
	*p++ = '\r';		*p++ = '\n';
	*p = '\0';

	conf->proxy_header.len = p - conf->proxy_header.data;

	// init the hash table of the uri params (clipTo, clipFrom etc.)
	rc = ngx_http_vod_init_uri_params_hash(cf, conf);
	if (rc != NGX_OK)
	{
		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
			"ngx_http_vod_merge_loc_conf: ngx_http_vod_init_uri_params_hash failed");
		return NGX_CONF_ERROR;
	}

	// merge the submodules configuration
	for (cur_module = submodules; *cur_module != NULL; cur_module++)
	{
		err = (*cur_module)->merge_loc_conf(
			cf, 
			conf, 
			(u_char*)conf + (*cur_module)->conf_offset, 
			(u_char*)prev + (*cur_module)->conf_offset);
		if (err != NGX_CONF_OK)
		{
			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
				"ngx_http_vod_merge_loc_conf: submodule merge_loc_conf failed");
			return err;
		}
	}

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

    if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                             &prev->types_keys, &prev->types,
                             ngx_http_headers_default_types)
                             != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    /* conf->enable_types default 0 */

    if (conf->default_expires.expires != NGX_HTTP_EXPIRES_OFF) {

        if (conf->default_expires.expires != NGX_HTTP_EXPIRES_UNSET
            || prev->default_expires.expires == NGX_HTTP_EXPIRES_UNSET){
            /* current &prev expires is not set off */
            if (conf->types_keys != NULL
                || conf->types.size > 1
                || conf->types.buckets[0] != NULL)
            {
                /* current or prev set expires_by_types */
                conf->enable_types = 1;
            }
        }

        if (conf->default_expires.expires == NGX_HTTP_EXPIRES_UNSET) {

            conf->default_expires.expires = prev->default_expires.expires;
            conf->default_expires.expires_time =
                prev->default_expires.expires_time;

            if (conf->default_expires.expires == NGX_HTTP_EXPIRES_OFF) {
                /* prev expires set to off */
                /* or prev expires off by inherited but enable types */
                if (conf->types_keys != NULL || prev->enable_types) {
                    /*
                     * current set expires_by_types
                     * ignored prev expires set to off
                     */
                    conf->enable_types = 1;
                }
            } else {
                /* prev expires not set to off */
                if (conf->types_keys != NULL
                    || conf->types.size > 1
                    || conf->types.buckets[0] != NULL)
                {
                    /* current or prev set expires_by_types */
                    conf->enable_types = 1;
                }
            }
        }
    }

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

    return NGX_CONF_OK;
}