static const char *set_trace_enable(cmd_parms *cmd, void *dummy,
                                    const char *arg1)
{
    core_server_config *conf =
        ap_get_core_module_config(cmd->server->module_config);

    if (ap_cstr_casecmp(arg1, "on") == 0) {
        conf->trace_enable = AP_TRACE_ENABLE;
    }
    else if (ap_cstr_casecmp(arg1, "off") == 0) {
        conf->trace_enable = AP_TRACE_DISABLE;
    }
    else if (ap_cstr_casecmp(arg1, "extended") == 0) {
        conf->trace_enable = AP_TRACE_EXTENDED;
    }
    else {
        return "TraceEnable must be one of 'on', 'off', or 'extended'";
    }

    return NULL;
}


core: Disallow Methods' registration at run time (.htaccess), they may be
used only if registered at init time (httpd.conf).

Calling ap_method_register() in children processes is not the right scope
since it won't be shared for all requests.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1807655 13f79535-47bb-0310-9956-ffa450edef68

static const char *set_error_document(cmd_parms *cmd, void *conf_,
                                      const char *errno_str, const char *msg)
{
    core_dir_config *conf = conf_;
    int error_number, index_number, idx500;
    enum { MSG, LOCAL_PATH, REMOTE_PATH } what = MSG;

    /* 1st parameter should be a 3 digit number, which we recognize;
     * convert it into an array index
     */
    error_number = atoi(errno_str);
    idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);

    if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
        index_number = idx500;
    }
    else if ((index_number = ap_index_of_response(error_number)) == idx500) {
        return apr_pstrcat(cmd->pool, "Unsupported HTTP response code ",
                           errno_str, NULL);
    }

    /* Heuristic to determine second argument. */
    if (ap_strchr_c(msg,' '))
        what = MSG;
    else if (msg[0] == '/')
        what = LOCAL_PATH;
    else if (ap_is_url(msg))
        what = REMOTE_PATH;
    else
        what = MSG;

    /* The entry should be ignored if it is a full URL for a 401 error */

    if (error_number == 401 && what == REMOTE_PATH) {
        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server, APLOGNO(00113)
                     "%s:%d cannot use a full URL in a 401 ErrorDocument "
                     "directive --- ignoring!", cmd->directive->filename, cmd->directive->line_num);
    }
    else { /* Store it... */
        if (conf->response_code_exprs == NULL) {
            conf->response_code_exprs = apr_hash_make(cmd->pool);
        }

        if (ap_cstr_casecmp(msg, "default") == 0) {
            /* special case: ErrorDocument 404 default restores the
             * canned server error response
             */
            apr_hash_set(conf->response_code_exprs,
                    apr_pmemdup(cmd->pool, &index_number, sizeof(index_number)),
                    sizeof(index_number), &errordocument_default);
        }
        else {
            ap_expr_info_t *expr;
            const char *expr_err = NULL;

            /* hack. Prefix a " if it is a msg; as that is what
             * http_protocol.c relies on to distinguish between
             * a msg and a (local) path.
             */
            const char *response =
                    (what == MSG) ? apr_pstrcat(cmd->pool, "\"", msg, NULL) :
                            apr_pstrdup(cmd->pool, msg);

            expr = ap_expr_parse_cmd(cmd, response, AP_EXPR_FLAG_STRING_RESULT,
                    &expr_err, NULL);

            if (expr_err) {
                return apr_pstrcat(cmd->temp_pool,
                                   "Cannot parse expression in ErrorDocument: ",
                                   expr_err, NULL);
            }

            apr_hash_set(conf->response_code_exprs,
                    apr_pmemdup(cmd->pool, &index_number, sizeof(index_number)),
                    sizeof(index_number), expr);

        }
    }

    return NULL;
}

Apache httpd allows remote attackers to read secret data from process memory if the Limit directive can be set in a user's .htaccess file, or if httpd.conf has certain misconfigurations, aka Optionsbleed. This affects the Apache HTTP Server through 2.2.34 and 2.4.x through 2.4.27. The attacker sends an unauthenticated OPTIONS HTTP request when attempting to read secret data. This is a use-after-free issue and thus secret data is not always sent, and the specific data depends on many factors including configuration. Exploitation with .htaccess can be blocked with a patch to the ap_limit_section function in server/core.c.


static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
{
    core_server_config *base = (core_server_config *)basev;
    core_server_config *virt = (core_server_config *)virtv;
    core_server_config *conf = (core_server_config *)
                               apr_pmemdup(p, base, sizeof(core_server_config));

    if (virt->ap_document_root)
        conf->ap_document_root = virt->ap_document_root;

    if (virt->access_name)
        conf->access_name = virt->access_name;

    /* XXX optimize to keep base->sec_ pointers if virt->sec_ array is empty */
    conf->sec_dir = apr_array_append(p, base->sec_dir, virt->sec_dir);
    conf->sec_url = apr_array_append(p, base->sec_url, virt->sec_url);

    if (virt->redirect_limit)
        conf->redirect_limit = virt->redirect_limit;

    if (virt->subreq_limit)
        conf->subreq_limit = virt->subreq_limit;

    if (virt->trace_enable != AP_TRACE_UNSET)
        conf->trace_enable = virt->trace_enable;

    if (virt->http09_enable != AP_HTTP09_UNSET)
        conf->http09_enable = virt->http09_enable;

    if (virt->http_conformance != AP_HTTP_CONFORMANCE_UNSET)
        conf->http_conformance = virt->http_conformance;

    if (virt->http_methods != AP_HTTP_METHODS_UNSET)
        conf->http_methods = virt->http_methods;

    if (virt->http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_UNSET)
        conf->http_cl_head_zero = virt->http_cl_head_zero;

    if (virt->http_expect_strict != AP_HTTP_EXPECT_STRICT_UNSET)
        conf->http_expect_strict = virt->http_expect_strict;

    /* no action for virt->accf_map, not allowed per-vhost */

    if (virt->protocol)
        conf->protocol = virt->protocol;

    if (virt->gprof_dir)
        conf->gprof_dir = virt->gprof_dir;

    if (virt->error_log_format)
        conf->error_log_format = virt->error_log_format;

    if (virt->error_log_conn)
        conf->error_log_conn = virt->error_log_conn;

    if (virt->error_log_req)
        conf->error_log_req = virt->error_log_req;

    if (virt->conn_log_level) {
        if (!conf->conn_log_level) {
            conf->conn_log_level = virt->conn_log_level;
        }
        else {
            /* apr_array_append actually creates a new array */
            conf->conn_log_level = apr_array_append(p, conf->conn_log_level,
                                                    virt->conn_log_level);
        }
    }

    conf->merge_trailers = (virt->merge_trailers != AP_MERGE_TRAILERS_UNSET)
                           ? virt->merge_trailers
                           : base->merge_trailers;

    conf->protocols = ((virt->protocols->nelts > 0) ?
                       virt->protocols : base->protocols);
    conf->protocols_honor_order = ((virt->protocols_honor_order < 0) ?
                                       base->protocols_honor_order :
                                       virt->protocols_honor_order);
    conf->async_filter = ((virt->async_filter_set) ?
                                       virt->async_filter :
                                       base->async_filter);
    conf->async_filter_set = base->async_filter_set || virt->async_filter_set;

    return conf;
}


static const char *start_cond_section(cmd_parms *cmd, void *mconfig, const char *arg)
{
    const char *endp = ap_strrchr_c(arg, '>');
    int result, not = (arg[0] == '!');
    test_cond_section_fn testfn = (test_cond_section_fn)cmd->info;
    const char *arg1;

    if (endp == NULL) {
        return unclosed_directive(cmd);
    }

    arg = apr_pstrmemdup(cmd->temp_pool, arg, endp - arg);

    if (not) {
        arg++;
    }

    arg1 = ap_getword_conf(cmd->temp_pool, &arg);

    if (!arg1[0]) {
        return missing_container_arg(cmd);
    }

    result = testfn(cmd, arg1);

    if ((!not && result) || (not && !result)) {
        ap_directive_t *parent = NULL;
        ap_directive_t *current = NULL;
        const char *retval;

        retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
                                      &current, &parent, cmd->cmd->name);
        *(ap_directive_t **)mconfig = current;
        return retval;
    }
    else {
        *(ap_directive_t **)mconfig = NULL;
        return ap_soak_end_container(cmd, cmd->cmd->name);
    }
}


static int check_errorlog_dir(apr_pool_t *p, server_rec *s)
{
    if (!s->error_fname || s->error_fname[0] == '|'
        || s->errorlog_provider != NULL) {
        return APR_SUCCESS;
    }
    else {
        char *abs = ap_server_root_relative(p, s->error_fname);
        char *dir = ap_make_dirstr_parent(p, abs);
        apr_finfo_t finfo;
        apr_status_t rv = apr_stat(&finfo, dir, APR_FINFO_TYPE, p);
        if (rv == APR_SUCCESS && finfo.filetype != APR_DIR)
            rv = APR_ENOTDIR;
        if (rv != APR_SUCCESS) {
            const char *desc = "main error log";
            if (s->defn_name)
                desc = apr_psprintf(p, "error log of vhost defined at %s:%d",
                                    s->defn_name, s->defn_line_number);
            ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, rv,
                          ap_server_conf, APLOGNO(02291)
                         "Cannot access directory '%s' for %s", dir, desc);
            return !OK;
        }
    }
    return OK;
}


AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
{
    core_server_config *sconf = ap_get_core_module_config(s->module_config);
    void **new_space = (void **)apr_array_push(sconf->sec_dir);

    *new_space = dir_config;
}


static void register_hooks(apr_pool_t *p)
{
    errorlog_hash = apr_hash_make(p);
    ap_register_log_hooks(p);
    ap_register_config_hooks(p);
    ap_expr_init(p);

    /* create_connection and pre_connection should always be hooked
     * APR_HOOK_REALLY_LAST by core to give other modules the opportunity
     * to install alternate network transports and stop other functions
     * from being run.
     */
    ap_hook_create_connection(core_create_conn, NULL, NULL,
                              APR_HOOK_REALLY_LAST);
    ap_hook_pre_connection(core_pre_connection, NULL, NULL,
                           APR_HOOK_REALLY_LAST);

    ap_hook_pre_config(core_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
    ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_check_config(core_check_config,NULL,NULL,APR_HOOK_FIRST);
    ap_hook_test_config(core_dump_config,NULL,NULL,APR_HOOK_FIRST);
    ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_map_to_storage(core_upgrade_storage,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_child_init(core_child_init,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE);
    ap_hook_handler(core_upgrade_handler,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
    /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
    ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
    APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
                      APR_HOOK_MIDDLE);
    ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_child_status(ap_core_child_status, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_insert_network_bucket(core_insert_network_bucket, NULL, NULL,
                                  APR_HOOK_REALLY_LAST);
    ap_hook_dirwalk_stat(core_dirwalk_stat, NULL, NULL, APR_HOOK_REALLY_LAST);
    ap_hook_open_htaccess(ap_open_htaccess, NULL, NULL, APR_HOOK_REALLY_LAST);
    ap_hook_optional_fn_retrieve(core_optional_fn_retrieve, NULL, NULL,
                                 APR_HOOK_MIDDLE);
    ap_hook_output_pending(ap_filter_output_pending, NULL, NULL,
            APR_HOOK_MIDDLE);

    /* register the core's insert_filter hook and register core-provided
     * filters
     */
    ap_hook_insert_filter(core_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);

    ap_core_input_filter_handle =
        ap_register_input_filter("CORE_IN", ap_core_input_filter,
                                 NULL, AP_FTYPE_NETWORK);
    ap_content_length_filter_handle =
        ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter,
                                  NULL, AP_FTYPE_PROTOCOL);
    ap_core_output_filter_handle =
        ap_register_output_filter("CORE", ap_core_output_filter,
                                  NULL, AP_FTYPE_NETWORK);
    ap_request_core_filter_handle =
        ap_register_output_filter("REQ_CORE", ap_request_core_filter,
                                  NULL, AP_FTYPE_TRANSCODE);
    ap_subreq_core_filter_handle =
        ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter,
                                  NULL, AP_FTYPE_CONTENT_SET);
    ap_old_write_func =
        ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
                                  NULL, AP_FTYPE_RESOURCE - 10);
}


static apr_status_t reset_request_notes(void *dummy)
{
    num_request_notes = AP_NUM_STD_NOTES;
    return APR_SUCCESS;
}


AP_DECLARE(void) ap_get_server_revision(ap_version_t *version)
{
    version->major = AP_SERVER_MAJORVERSION_NUMBER;
    version->minor = AP_SERVER_MINORVERSION_NUMBER;
    version->patch = AP_SERVER_PATCHLEVEL_NUMBER;
    version->add_string = AP_SERVER_ADD_STRING;
}


static const char *set_etag_bits(cmd_parms *cmd, void *mconfig,
                                 const char *args_p)
{
    core_dir_config *cfg;
    etag_components_t bit;
    char action;
    char *token;
    const char *args;
    int valid;
    int first;
    int explicit;

    cfg = (core_dir_config *)mconfig;

    args = args_p;
    first = 1;
    explicit = 0;
    while (args[0] != '\0') {
        action = '*';
        bit = ETAG_UNSET;
        valid = 1;
        token = ap_getword_conf(cmd->temp_pool, &args);
        if ((*token == '+') || (*token == '-')) {
            action = *token;
            token++;
        }
        else {
            /*
             * The occurrence of an absolute setting wipes
             * out any previous relative ones.  The first such
             * occurrence forgets any inherited ones, too.
             */
            if (first) {
                cfg->etag_bits = ETAG_UNSET;
                cfg->etag_add = ETAG_UNSET;
                cfg->etag_remove = ETAG_UNSET;
                first = 0;
            }
        }

        if (ap_cstr_casecmp(token, "None") == 0) {
            if (action != '*') {
                valid = 0;
            }
            else {
                cfg->etag_bits = bit = ETAG_NONE;
                explicit = 1;
            }
        }
        else if (ap_cstr_casecmp(token, "All") == 0) {
            if (action != '*') {
                valid = 0;
            }
            else {
                explicit = 1;
                cfg->etag_bits = bit = ETAG_ALL;
            }
        }
        else if (ap_cstr_casecmp(token, "Size") == 0) {
            bit = ETAG_SIZE;
        }
        else if ((ap_cstr_casecmp(token, "LMTime") == 0)
                 || (ap_cstr_casecmp(token, "MTime") == 0)
                 || (ap_cstr_casecmp(token, "LastModified") == 0)) {
            bit = ETAG_MTIME;
        }
        else if (ap_cstr_casecmp(token, "INode") == 0) {
            bit = ETAG_INODE;
        }
        else {
            return apr_pstrcat(cmd->pool, "Unknown keyword '",
                               token, "' for ", cmd->cmd->name,
                               " directive", NULL);
        }

        if (! valid) {
            return apr_pstrcat(cmd->pool, cmd->cmd->name, " keyword '",
                               token, "' cannot be used with '+' or '-'",
                               NULL);
        }

        if (action == '+') {
            /*
             * Make sure it's in the 'add' list and absent from the
             * 'subtract' list.
             */
            cfg->etag_add |= bit;
            cfg->etag_remove &= (~ bit);
        }
        else if (action == '-') {
            cfg->etag_remove |= bit;
            cfg->etag_add &= (~ bit);
        }
        else {
            /*
             * Non-relative values wipe out any + or - values
             * accumulated so far.
             */
            cfg->etag_bits |= bit;
            cfg->etag_add = ETAG_UNSET;
            cfg->etag_remove = ETAG_UNSET;
            explicit = 1;
        }
    }

    /*
     * Any setting at all will clear the 'None' and 'Unset' bits.
     */

    if (cfg->etag_add != ETAG_UNSET) {
        cfg->etag_add &= (~ ETAG_UNSET);
    }

    if (cfg->etag_remove != ETAG_UNSET) {
        cfg->etag_remove &= (~ ETAG_UNSET);
    }

    if (explicit) {
        cfg->etag_bits &= (~ ETAG_UNSET);

        if ((cfg->etag_bits & ETAG_NONE) != ETAG_NONE) {
            cfg->etag_bits &= (~ ETAG_NONE);
        }
    }

    return NULL;
}


static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
                                           const char *arg)
{
    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
    int lim;

    if (err != NULL) {
        return err;
    }

    lim = atoi(arg);
    if (lim < 0) {
        return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg,
                          "\" must be a non-negative integer",
                          NULL);
    }

    cmd->server->limit_req_fieldsize = lim;
    return NULL;
}


static const char *set_loglevel(cmd_parms *cmd, void *config_, const char *arg)
{
    struct ap_logconf *log;

    if (cmd->path) {
        core_dir_config *dconf = config_;
        if (!dconf->log) {
            dconf->log = ap_new_log_config(cmd->pool, NULL);
        }
        log = dconf->log;
    }
    else {
        log = &cmd->server->log;
    }

    if (arg == NULL)
        return "LogLevel requires level keyword or module loglevel specifier";

    return update_loglevel(cmd, log, arg);
}


static void log_backtrace(const request_rec *r)
{
    const request_rec *top = r;

    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00121)
                  "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");

    while (top && (top->prev || top->main)) {
        if (top->prev) {
            top = top->prev;
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00122)
                          "redirected from r->uri = %s",
                          top->uri ? top->uri : "(unexpectedly NULL)");
        }

        if (!top->prev && top->main) {
            top = top->main;
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00123)
                          "subrequested from r->uri = %s",
                          top->uri ? top->uri : "(unexpectedly NULL)");
        }
    }
}


AP_DECLARE(void) ap_random_insecure_bytes(void *buf, apr_size_t size)
{
#if APR_HAS_THREADS
    if (rng_mutex)
        apr_thread_mutex_lock(rng_mutex);
#endif
    /* apr_random_insecure_bytes can only fail with APR_ENOTENOUGHENTROPY,
     * and we have ruled that out during initialization. Therefore we don't
     * need to check the return code.
     */
    apr_random_insecure_bytes(rng, buf, size);
#if APR_HAS_THREADS
    if (rng_mutex)
        apr_thread_mutex_unlock(rng_mutex);
#endif
}


static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
                                   const char *arg, const char * arg2)
{
    core_dir_config *conf = conf_;

    ap_unixd_set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
    return NULL;
}


static const char *set_access_name(cmd_parms *cmd, void *dummy,
                                   const char *arg)
{
    void *sconf = cmd->server->module_config;
    core_server_config *conf = ap_get_core_module_config(sconf);

    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
    if (err != NULL) {
        return err;
    }

    conf->access_name = apr_pstrdup(cmd->pool, arg);
    return NULL;
}


static void core_optional_fn_retrieve(void)
{
    ap_init_scoreboard(NULL);
}


static const char *set_async_filter(cmd_parms *cmd, void *dummy,
                                             const char *arg)
{
    core_server_config *conf =
    ap_get_core_module_config(cmd->server->module_config);
    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);

    if (err) {
        return err;
    }

    if (ap_cstr_casecmp(arg, "network") == 0) {
        conf->async_filter = AP_FTYPE_NETWORK;
    }
    else if (ap_cstr_casecmp(arg, "connection") == 0) {
        conf->async_filter = AP_FTYPE_CONNECTION;
    }
    else if (ap_cstr_casecmp(arg, "request") == 0) {
        conf->async_filter = 0;
    }
    else {
        return "AsyncFilter must be 'network', 'connection' or 'request'";
    }
    conf->async_filter_set = 1;

    return NULL;
}


static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
{
    ap_mutex_init(pconf);

    if (!saved_server_config_defines)
        init_config_defines(pconf);
    apr_pool_cleanup_register(pconf, NULL, reset_config_defines,
                              apr_pool_cleanup_null);

    mpm_common_pre_config(pconf);

    return OK;
}


AP_CORE_DECLARE(conn_rec *) ap_create_slave_connection(conn_rec *c)
{
    apr_pool_t *pool;
    conn_slave_rec *new;
    conn_rec *sc = (conn_rec *) apr_palloc(c->pool, sizeof(conn_rec));

    apr_pool_create(&pool, c->pool);
    apr_pool_tag(pool, "slave_conn");
    memcpy(sc, c, sizeof(conn_rec));
    sc->slaves = NULL;
    sc->master = c;
    sc->input_filters = NULL;
    sc->output_filters = NULL;
    sc->pool = pool;
    new = apr_array_push(c->slaves);
    new->c = sc;
    return sc;
}


AP_DECLARE(void) ap_set_context_info(request_rec *r, const char *context_prefix,
                                     const char *context_document_root)
{
    core_request_config *conf = ap_get_core_module_config(r->request_config);
    if (context_prefix)
        conf->context_prefix = context_prefix;
    if (context_document_root)
        conf->context_document_root = context_document_root;
}


static const ap_directive_t * find_parent(const ap_directive_t *dirp,
                                          const char *what)
{
    while (dirp->parent != NULL) {
        dirp = dirp->parent;

        /* ### it would be nice to have atom-ized directives */
        if (ap_cstr_casecmp(dirp->directive, what) == 0)
            return dirp;
    }

    return NULL;
}


AP_CORE_DECLARE(void) ap_add_file_conf(apr_pool_t *p, core_dir_config *conf,
                                       void *url_config)
{
    void **new_space;

    if (!conf->sec_file)
        conf->sec_file = apr_array_make(p, 2, sizeof(ap_conf_vector_t *));

    new_space = (void **)apr_array_push(conf->sec_file);
    *new_space = url_config;
}


static const char *set_limit_req_line(cmd_parms *cmd, void *dummy,
                                      const char *arg)
{
    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
    int lim;

    if (err != NULL) {
        return err;
    }

    lim = atoi(arg);
    if (lim < 0) {
        return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg,
                           "\" must be a non-negative integer", NULL);
    }

    cmd->server->limit_req_line = lim;
    return NULL;
}


static const char *no_set_limit(cmd_parms *cmd, void *conf_,
                                const char *arg, const char *arg2)
{
    ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server, APLOGNO(00118)
                "%s not supported on this platform", cmd->cmd->name);

    return NULL;
}


static const char *server_hostname_port(cmd_parms *cmd, void *dummy, const char *arg)
{
    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
    const char *portstr, *part;
    char *scheme;
    int port;

    if (err != NULL) {
        return err;
    }

    if (apr_fnmatch_test(arg))
        return apr_pstrcat(cmd->temp_pool, "Invalid ServerName \"", arg,
                "\" use ServerAlias to set multiple server names.", NULL);

    part = ap_strstr_c(arg, "://");

    if (part) {
      scheme = apr_pstrndup(cmd->pool, arg, part - arg);
      ap_str_tolower(scheme);
      cmd->server->server_scheme = (const char *)scheme;
      part += 3;
    } else {
      part = arg;
    }

    portstr = ap_strchr_c(part, ':');
    if (portstr) {
        cmd->server->server_hostname = apr_pstrndup(cmd->pool, part,
                                                    portstr - part);
        portstr++;
        port = atoi(portstr);
        if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
            return apr_pstrcat(cmd->temp_pool, "The port number \"", arg,
                          "\" is outside the appropriate range "
                          "(i.e., 1..65535).", NULL);
        }
    }
    else {
        cmd->server->server_hostname = apr_pstrdup(cmd->pool, part);
        port = 0;
    }

    cmd->server->port = port;
    return NULL;
}


AP_DECLARE(void) ap_register_errorlog_handler(apr_pool_t *p, char *tag,
                                              ap_errorlog_handler_fn_t *handler,
                                              int flags)
{
    ap_errorlog_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
    log_struct->func = handler;
    log_struct->flags = flags;

    apr_hash_set(errorlog_hash, tag, 1, (const void *)log_struct);
}


AP_CORE_DECLARE(const char *) ap_add_if_conf(apr_pool_t *p,
                                             core_dir_config *conf,
                                             void *if_config)
{
    void **new_space;
    core_dir_config *new = ap_get_module_config(if_config, &core_module);

    if (!conf->sec_if) {
        conf->sec_if = apr_array_make(p, 2, sizeof(ap_conf_vector_t *));
    }
    if (new->condition_ifelse & AP_CONDITION_ELSE) {
        int have_if = 0;
        if (conf->sec_if->nelts > 0) {
            core_dir_config *last;
            ap_conf_vector_t *lastelt = APR_ARRAY_IDX(conf->sec_if,
                                                      conf->sec_if->nelts - 1,
                                                      ap_conf_vector_t *);
            last = ap_get_module_config(lastelt, &core_module);
            if (last->condition_ifelse & AP_CONDITION_IF)
                have_if = 1;
        }
        if (!have_if)
            return "<Else> or <ElseIf> section without previous <If> or "
                   "<ElseIf> section in same scope";
    }

    new_space = (void **)apr_array_push(conf->sec_if);
    *new_space = if_config;
    return NULL;
}


static void set_banner(apr_pool_t *pconf)
{
    if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
        ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT);
    }
    else if (ap_server_tokens == SrvTk_MINIMAL) {
        ap_add_version_component(pconf, AP_SERVER_BASEVERSION);
    }
    else if (ap_server_tokens == SrvTk_MINOR) {
        ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MINORREVISION);
    }
    else if (ap_server_tokens == SrvTk_MAJOR) {
        ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION);
    }
    else {
        ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
    }

    /*
     * Lock the server_banner string if we're not displaying
     * the full set of tokens
     */
    if (ap_server_tokens != SrvTk_FULL) {
        banner_locked++;
    }
    server_description = AP_SERVER_BASEVERSION " (" PLATFORM ")";
}


static const char *set_serverpath(cmd_parms *cmd, void *dummy,
                                  const char *arg)
{
    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);

    if (err != NULL) {
        return err;
    }

    cmd->server->path = arg;
    cmd->server->pathlen = (int)strlen(arg);
    return NULL;
}


AP_DECLARE(const char *) ap_context_document_root(request_rec *r)
{
    core_request_config *conf = ap_get_core_module_config(r->request_config);
    if (conf->context_document_root)
        return conf->context_document_root;
    else
        return ap_document_root(r);
}


AP_DECLARE(apr_size_t) ap_register_request_note(void)
{
    apr_pool_cleanup_register(apr_hook_global_pool, NULL, reset_request_notes,
                              apr_pool_cleanup_null);
    return num_request_notes++;
}


static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, const char *arg)
{
    void *sconf = cmd->server->module_config;
    core_server_config *conf = ap_get_core_module_config(sconf);

    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
    if (err != NULL) {
        return err;
    }

    conf->gprof_dir = arg;
    return NULL;
}


static const char *set_cgi_var(cmd_parms *cmd, void *d_,
                               const char *var, const char *rule_)
{
    core_dir_config *d = d_;
    char *rule = apr_pstrdup(cmd->pool, rule_);

    ap_str_tolower(rule);

    if (!strcmp(var, "REQUEST_URI")) {
        if (strcmp(rule, "current-uri") && strcmp(rule, "original-uri")) {
            return "Valid rules for REQUEST_URI are 'current-uri' and 'original-uri'";
        }
    }
    else {
        return apr_pstrcat(cmd->pool, "Unrecognized CGI variable: \"",
                           var, "\"", NULL);
    }

    if (!d->cgi_var_rules) {
        d->cgi_var_rules = apr_hash_make(cmd->pool);
    }
    apr_hash_set(d->cgi_var_rules, var, APR_HASH_KEY_STRING, rule);
    return NULL;
}


static const char *set_cl_head_zero(cmd_parms *cmd, void *dummy, int arg)
{
    core_server_config *conf =
        ap_get_core_module_config(cmd->server->module_config);

    if (arg) {
        conf->http_cl_head_zero = AP_HTTP_CL_HEAD_ZERO_ENABLE;
    } else {
        conf->http_cl_head_zero = AP_HTTP_CL_HEAD_ZERO_DISABLE;
    }
    return NULL;
}


static const char *set_accept_path_info(cmd_parms *cmd, void *d_, const char *arg)
{
    core_dir_config *d = d_;

    if (ap_cstr_casecmp(arg, "on") == 0) {
        d->accept_path_info = AP_REQ_ACCEPT_PATH_INFO;
    }
    else if (ap_cstr_casecmp(arg, "off") == 0) {
        d->accept_path_info = AP_REQ_REJECT_PATH_INFO;
    }
    else if (ap_cstr_casecmp(arg, "default") == 0) {
        d->accept_path_info = AP_REQ_DEFAULT_PATH_INFO;
    }
    else {
        return "AcceptPathInfo must be set to on, off or default";
    }

    return NULL;
}


static apr_status_t core_insert_network_bucket(conn_rec *c,
                                               apr_bucket_brigade *bb,
                                               apr_socket_t *socket)
{
    apr_bucket *e = apr_bucket_socket_create(socket, c->bucket_alloc);
    APR_BRIGADE_INSERT_TAIL(bb, e);
    return APR_SUCCESS;
}


static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
{
    const char *errmsg;
    const char *endp = ap_strrchr_c(arg, '>');
    int old_overrides = cmd->override;
    char *old_path = cmd->path;
    core_dir_config *conf;
    const command_rec *thiscmd = cmd->cmd;
    ap_conf_vector_t *new_if_conf = ap_create_per_dir_config(cmd->pool);
    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
    const char *condition;
    const char *expr_err;

    if (err != NULL) {
        return err;
    }

    if (endp == NULL) {
        return unclosed_directive(cmd);
    }

    arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);

    /*
     * Set a dummy value so that other directives notice that they are inside
     * a config section.
     */
    cmd->path = "*If";
    /* Only if not an .htaccess file */
    if (!old_path) {
        cmd->override = OR_ALL|ACCESS_CONF;
    }

    /* initialize our config and fetch it */
    conf = ap_set_config_vectors(cmd->server, new_if_conf, cmd->path,
                                 &core_module, cmd->pool);

    if (cmd->cmd->cmd_data == COND_IF)
        conf->condition_ifelse = AP_CONDITION_IF;
    else if (cmd->cmd->cmd_data == COND_ELSEIF)
        conf->condition_ifelse = AP_CONDITION_ELSEIF;
    else if (cmd->cmd->cmd_data == COND_ELSE)
        conf->condition_ifelse = AP_CONDITION_ELSE;
    else
        ap_assert(0);

    if (conf->condition_ifelse == AP_CONDITION_ELSE) {
        if (arg[0])
            return "<Else> does not take an argument";
    }
    else {
        if (!arg[0])
            return missing_container_arg(cmd);
        condition = ap_getword_conf(cmd->pool, &arg);
        conf->condition = ap_expr_parse_cmd(cmd, condition, 0, &expr_err, NULL);
        if (expr_err)
            return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s",
                                expr_err);
    }

    errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_if_conf);
    if (errmsg != NULL)
        return errmsg;

    conf->d = cmd->path;
    conf->d_is_fnmatch = 0;
    conf->r = NULL;

    errmsg = ap_add_if_conf(cmd->pool, (core_dir_config *)mconfig, new_if_conf);
    if (errmsg != NULL)
        return errmsg;

    if (*arg != '\0') {
        return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
                           "> arguments not supported.", NULL);
    }

    cmd->path = old_path;
    cmd->override = old_overrides;

    return NULL;
}


static module *find_module(server_rec *s, const char *name)
{
    module *found = ap_find_linked_module(name);

    /* search prelinked stuff */
    if (!found) {
        ap_module_symbol_t *current = ap_prelinked_module_symbols;

        for (; current->name; ++current) {
            if (!strcmp(current->name, name)) {
                found = current->modp;
                break;
            }
        }
    }

    /* search dynamic stuff */
    if (!found) {
        APR_OPTIONAL_FN_TYPE(ap_find_loaded_module_symbol) *check_symbol =
            APR_RETRIEVE_OPTIONAL_FN(ap_find_loaded_module_symbol);

        if (check_symbol) {
            /*
             * There are two phases where calling ap_find_loaded_module_symbol
             * is problematic:
             *
             * During reading of the config, ap_server_conf is invalid but s
             * points to the main server config, if passed from cmd->server
             * of an EXEC_ON_READ directive.
             *
             * During config parsing, s may be a virtual host that would cause
             * a segfault in mod_so if passed to ap_find_loaded_module_symbol,
             * because mod_so's server config for vhosts is initialized later.
             * But ap_server_conf is already set at this time.
             *
             * Therefore we use s if it is not virtual and ap_server_conf if
             * s is virtual.
             */
            found = check_symbol(s->is_virtual ? ap_server_conf : s, name);
        }
    }

    return found;
}


static const char *generate_message(cmd_parms *cmd, void *dummy,
                                    const char *arg)
{
    /* cast with 64-bit warning avoidance */
    int level = (cmd->info==(void*)APLOG_ERR)? APLOG_ERR: APLOG_WARNING;
    char * msg;

    /* get position information from wherever we can? */
    ap_configfile_t * cf = cmd->config_file;
    ap_directive_t const * ed1 = cmd->directive;
    ap_directive_t const * ed2 = cmd->err_directive;

    /* expect an argument */
    if (!arg || !*arg) {
        return "The Error or Warning directive was used with no message.";
    }

    /* set message, strip off quotes if necessary */
    msg = (char *)arg;
    if (*arg == '"' || *arg == '\'') {
        apr_size_t len = strlen(arg);
        char last = *(arg + len - 1);

        if (*arg == last) {
            msg = apr_pstrndup(cmd->pool, arg + 1, len - 2);
        }
    }

    /* generate error or warning with a configuration file position.
     * the log is displayed on the terminal as no log file is opened yet.
     */
    ap_log_error(APLOG_MARK, level, 0, NULL,
                 "%s on line %d of %s", msg,
                 cf? cf->line_number:
                   ed1? ed1->line_num:
                     ed2? ed2->line_num: -1,
                 cf? cf->name:
                   ed1? ed1->filename:
                     ed2? ed2->filename: "<UNKNOWN>");

    /* message displayed above, return will stop configuration processing */
    return level==APLOG_ERR?
        "Configuration processing stopped by Error directive": NULL;
}


static int test_ifdirective_section(cmd_parms *cmd, const char *arg)
{
    return ap_exists_directive(cmd->temp_pool, arg);
}


static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *s,
                                  apr_socket_t *csd, long id, void *sbh,
                                  apr_bucket_alloc_t *alloc)
{
    apr_status_t rv;
    apr_pool_t *pool;
    conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
    core_server_config *sconf = ap_get_core_module_config(s->module_config);

    c->sbh = sbh;
    ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL);

    /* Got a connection structure, so initialize what fields we can
     * (the rest are zeroed out by pcalloc).
     */
    apr_pool_create(&pool, ptrans);
    apr_pool_tag(pool, "master_conn");
    c->pool = pool;

    c->conn_config = ap_create_conn_config(c->pool);
    c->notes = apr_table_make(c->pool, 5);
    c->slaves = apr_array_make(c->pool, 20, sizeof(conn_slave_rec *));
    c->requests = apr_array_make(c->pool, 20, sizeof(request_rec *));

    if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
        != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(00137)
                     "apr_socket_addr_get(APR_LOCAL)");
        apr_socket_close(csd);
        return NULL;
    }

    apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
    if ((rv = apr_socket_addr_get(&c->client_addr, APR_REMOTE, csd))
        != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(00138)
                     "apr_socket_addr_get(APR_REMOTE)");
        apr_socket_close(csd);
        return NULL;
    }

    apr_sockaddr_ip_get(&c->client_ip, c->client_addr);
    c->base_server = s;

    c->id = id;
    c->bucket_alloc = alloc;
    c->empty = apr_brigade_create(c->pool, c->bucket_alloc);
    c->filters = apr_hash_make(c->pool);
    c->async_filter = sconf->async_filter;

    c->clogging_input_filters = 0;

    if (sconf->conn_log_level) {
        int i;
        conn_log_config *conf;
        const struct ap_logconf *log = NULL;
        struct ap_logconf *merged;

        for (i = 0; i < sconf->conn_log_level->nelts; i++) {
            conf = APR_ARRAY_IDX(sconf->conn_log_level, i, conn_log_config *);
            if (apr_ipsubnet_test(conf->subnet, c->client_addr))
                log = &conf->log;
        }
        if (log) {
            merged = ap_new_log_config(c->pool, log);
            ap_merge_log_config(&s->log, merged);
            c->log = merged;
        }
    }

    return c;
}


static const char *set_allow_opts(cmd_parms *cmd, allow_options_t *opts,
                                  const char *l)
{
    allow_options_t opt;
    int first = 1;

    char *w, *p = (char *) l;
    char *tok_state;

    while ((w = apr_strtok(p, ",", &tok_state)) != NULL) {

        if (first) {
            p = NULL;
            *opts = OPT_NONE;
            first = 0;
        }

        if (!ap_cstr_casecmp(w, "Indexes")) {
            opt = OPT_INDEXES;
        }
        else if (!ap_cstr_casecmp(w, "Includes")) {
            /* If Includes is permitted, both Includes and
             * IncludesNOEXEC may be changed. */
            opt = (OPT_INCLUDES | OPT_INC_WITH_EXEC);
        }
        else if (!ap_cstr_casecmp(w, "IncludesNOEXEC")) {
            opt = OPT_INCLUDES;
        }
        else if (!ap_cstr_casecmp(w, "FollowSymLinks")) {
            opt = OPT_SYM_LINKS;
        }
        else if (!ap_cstr_casecmp(w, "SymLinksIfOwnerMatch")) {
            opt = OPT_SYM_OWNER;
        }
        else if (!ap_cstr_casecmp(w, "ExecCGI")) {
            opt = OPT_EXECCGI;
        }
        else if (!ap_cstr_casecmp(w, "MultiViews")) {
            opt = OPT_MULTI;
        }
        else if (!ap_cstr_casecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
            opt = OPT_MULTI|OPT_EXECCGI;
        }
        else if (!ap_cstr_casecmp(w, "None")) {
            opt = OPT_NONE;
        }
        else if (!ap_cstr_casecmp(w, "All")) {
            opt = OPT_ALL;
        }
        else {
            return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
        }

        *opts |= opt;
    }

    (*opts) &= (~OPT_UNSET);

    return NULL;
}


static void core_child_init(apr_pool_t *pchild, server_rec *s)
{
    apr_proc_t proc;
#if APR_HAS_THREADS
    int threaded_mpm;
    if (ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm) == APR_SUCCESS
        && threaded_mpm)
    {
        apr_thread_mutex_create(&rng_mutex, APR_THREAD_MUTEX_DEFAULT, pchild);
    }
#endif
    /* The MPMs use plain fork() and not apr_proc_fork(), so we have to call
     * apr_random_after_fork() manually in the child
     */
    proc.pid = getpid();
    apr_random_after_fork(&proc);
}


static char *parse_errorlog_item(apr_pool_t *p, ap_errorlog_format_item *it,
                                 const char **sa)
{
    const char *s = *sa;
    ap_errorlog_handler *handler;
    int i;

    if (*s != '%') {
        if (*s == ' ') {
            it->flags |= AP_ERRORLOG_FLAG_FIELD_SEP;
        }
        return parse_errorlog_misc_string(p, it, sa);
    }

    ++s;

    if (*s == ' ') {
        /* percent-space (% ) is a field separator */
        it->flags |= AP_ERRORLOG_FLAG_FIELD_SEP;
        *sa = ++s;
        /* recurse */
        return parse_errorlog_item(p, it, sa);
    }
    else if (*s == '%') {
        it->arg = "%";
        it->func = log_constant_item;
        *sa = ++s;
        return NULL;
    }

    while (*s) {
        switch (*s) {
        case '{':
            ++s;
            it->arg = ap_getword(p, &s, '}');
            break;
        case '+':
            ++s;
            it->flags |= AP_ERRORLOG_FLAG_REQUIRED;
            break;
        case '-':
            ++s;
            it->flags |= AP_ERRORLOG_FLAG_NULL_AS_HYPHEN;
            break;
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            i = *s - '0';
            while (apr_isdigit(*++s))
                i = i * 10 + (*s) - '0';
            it->min_loglevel = i;
            break;
        case 'M':
            it->func = NULL;
            it->flags |= AP_ERRORLOG_FLAG_MESSAGE;
            *sa = ++s;
            return NULL;
        default:
            handler = (ap_errorlog_handler *)apr_hash_get(errorlog_hash, s, 1);
            if (!handler) {
                char dummy[2];

                dummy[0] = *s;
                dummy[1] = '\0';
                return apr_pstrcat(p, "Unrecognized error log format directive %",
                               dummy, NULL);
            }
            it->func = handler->func;
            *sa = ++s;
            return NULL;
        }
    }

    return "Ran off end of error log format parsing args to some directive";
}


static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
                                   const char *arg)
{
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);

    if (err != NULL) {
        return err;
    }

    if (!ap_cstr_casecmp(arg, "OS")) {
        ap_server_tokens = SrvTk_OS;
    }
    else if (!ap_cstr_casecmp(arg, "Min") || !ap_cstr_casecmp(arg, "Minimal")) {
        ap_server_tokens = SrvTk_MINIMAL;
    }
    else if (!ap_cstr_casecmp(arg, "Major")) {
        ap_server_tokens = SrvTk_MAJOR;
    }
    else if (!ap_cstr_casecmp(arg, "Minor") ) {
        ap_server_tokens = SrvTk_MINOR;
    }
    else if (!ap_cstr_casecmp(arg, "Prod") || !ap_cstr_casecmp(arg, "ProductOnly")) {
        ap_server_tokens = SrvTk_PRODUCT_ONLY;
    }
    else if (!ap_cstr_casecmp(arg, "Full")) {
        ap_server_tokens = SrvTk_FULL;
    }
    else {
        return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', or 'Full'";
    }

    return NULL;
}


static int default_handler(request_rec *r)
{
    conn_rec *c = r->connection;
    apr_bucket_brigade *bb;
    apr_bucket *e;
    core_dir_config *d;
    int errstatus;
    apr_file_t *fd = NULL;
    apr_status_t status;
    /* XXX if/when somebody writes a content-md5 filter we either need to
     *     remove this support or coordinate when to use the filter vs.
     *     when to use this code
     *     The current choice of when to compute the md5 here matches the 1.3
     *     support fairly closely (unlike 1.3, we don't handle computing md5
     *     when the charset is translated).
     */
    int bld_content_md5;

    d = (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
    bld_content_md5 = (d->content_md5 == AP_CONTENT_MD5_ON)
                      && r->output_filters->frec->ftype != AP_FTYPE_RESOURCE;

    ap_allow_standard_methods(r, MERGE_ALLOW, M_GET, M_OPTIONS, M_POST, -1);

    /* If filters intend to consume the request body, they must
     * register an InputFilter to slurp the contents of the POST
     * data from the POST input stream.  It no longer exists when
     * the output filters are invoked by the default handler.
     */
    if ((errstatus = ap_discard_request_body(r)) != OK) {
        return errstatus;
    }

    if (r->method_number == M_GET || r->method_number == M_POST) {
        if (r->finfo.filetype == APR_NOFILE) {
            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00128)
                          "File does not exist: %s",
                          apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
            return HTTP_NOT_FOUND;
        }

        /* Don't try to serve a dir.  Some OSs do weird things with
         * raw I/O on a dir.
         */
        if (r->finfo.filetype == APR_DIR) {
            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00129)
                          "Attempt to serve directory: %s", r->filename);
            return HTTP_NOT_FOUND;
        }

        if ((r->used_path_info != AP_REQ_ACCEPT_PATH_INFO) &&
            r->path_info && *r->path_info)
        {
            /* default to reject */
            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00130)
                          "File does not exist: %s",
                          apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
            return HTTP_NOT_FOUND;
        }

        /* We understood the (non-GET) method, but it might not be legal for
           this particular resource. Check to see if the 'deliver_script'
           flag is set. If so, then we go ahead and deliver the file since
           it isn't really content (only GET normally returns content).

           Note: based on logic further above, the only possible non-GET
           method at this point is POST. In the future, we should enable
           script delivery for all methods.  */
        if (r->method_number != M_GET) {
            core_request_config *req_cfg;

            req_cfg = ap_get_core_module_config(r->request_config);
            if (!req_cfg->deliver_script) {
                /* The flag hasn't been set for this request. Punt. */
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00131)
                              "This resource does not accept the %s method.",
                              r->method);
                return HTTP_METHOD_NOT_ALLOWED;
            }
        }

        if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
#if APR_HAS_SENDFILE
                            | AP_SENDFILE_ENABLED(d->enable_sendfile)
#endif
                                    , 0, r->pool)) != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00132)
                          "file permissions deny server access: %s", r->filename);
            return HTTP_FORBIDDEN;
        }

        ap_update_mtime(r, r->finfo.mtime);
        ap_set_last_modified(r);
        ap_set_etag(r);
        ap_set_accept_ranges(r);
        ap_set_content_length(r, r->finfo.size);
        if (bld_content_md5) {
            apr_table_setn(r->headers_out, "Content-MD5",
                           ap_md5digest(r->pool, fd));
        }

        bb = apr_brigade_create(r->pool, c->bucket_alloc);

        if ((errstatus = ap_meets_conditions(r)) != OK) {
            apr_file_close(fd);
            r->status = errstatus;
        }
        else {
            e = apr_brigade_insert_file(bb, fd, 0, r->finfo.size, r->pool);

#if APR_HAS_MMAP
            if (d->enable_mmap == ENABLE_MMAP_OFF) {
                (void)apr_bucket_file_enable_mmap(e, 0);
            }
#endif
        }

        e = apr_bucket_eos_create(c->bucket_alloc);
        APR_BRIGADE_INSERT_TAIL(bb, e);

        status = ap_pass_brigade(r->output_filters, bb);
        apr_brigade_cleanup(bb);

        if (status == APR_SUCCESS
            || r->status != HTTP_OK
            || c->aborted) {
            return OK;
        }
        else {
            /* no way to know what type of error occurred */
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00133)
                          "default_handler: ap_pass_brigade returned %i",
                          status);
            return AP_FILTER_ERROR;
        }
    }
    else {              /* unusual method (not GET or POST) */
        if (r->method_number == M_INVALID) {
            /* See if this looks like an undecrypted SSL handshake attempt.
             * It's safe to look a couple bytes into the_request if it exists, as it's
             * always allocated at least MIN_LINE_ALLOC (80) bytes.
             */
            if (r->the_request
                && r->the_request[0] == 0x16
                && (r->the_request[1] == 0x2 || r->the_request[1] == 0x3)) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00134)
                              "Invalid method in request %s - possible attempt to establish SSL connection on non-SSL port", r->the_request);
            } else {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00135)
                              "Invalid method in request %s", r->the_request);
            }
            return HTTP_NOT_IMPLEMENTED;
        }

        if (r->method_number == M_OPTIONS) {
            return ap_send_http_options(r);
        }
        return HTTP_METHOD_NOT_ALLOWED;
    }
}


static const char *set_enable_sendfile(cmd_parms *cmd, void *d_,
                                   const char *arg)
{
    core_dir_config *d = d_;

    if (ap_cstr_casecmp(arg, "on") == 0) {
        d->enable_sendfile = ENABLE_SENDFILE_ON;
    }
    else if (ap_cstr_casecmp(arg, "off") == 0) {
        d->enable_sendfile = ENABLE_SENDFILE_OFF;
    }
    else {
        return "parameter must be 'on' or 'off'";
    }

    return NULL;
}


AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd,
                                              unsigned forbidden)
{
    const char *gt = (cmd->cmd->name[0] == '<'
                      && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
                         ? ">" : "";
    const ap_directive_t *found;

    if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
        return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
                           " cannot occur within <VirtualHost> section", NULL);
    }

    if ((forbidden & (NOT_IN_LIMIT | NOT_IN_DIR_LOC_FILE))
        && cmd->limited != -1) {
        return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
                           " cannot occur within <Limit> or <LimitExcept> "
                           "section", NULL);
    }

    if ((forbidden & NOT_IN_HTACCESS) && (cmd->pool == cmd->temp_pool)) {
         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
                            " cannot occur within htaccess files", NULL);
    }

    if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE) {
        if (cmd->path != NULL) {
            return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
                            " cannot occur within <Directory/Location/Files> "
                            "section", NULL);
        }
        if (cmd->cmd->req_override & EXEC_ON_READ) {
            /* EXEC_ON_READ must be NOT_IN_DIR_LOC_FILE, if not, it will
             * (deliberately) segfault below in the individual tests...
             */
            return NULL;
        }
    }

    if (((forbidden & NOT_IN_DIRECTORY)
         && ((found = find_parent(cmd->directive, "<Directory"))
             || (found = find_parent(cmd->directive, "<DirectoryMatch"))))
        || ((forbidden & NOT_IN_LOCATION)
            && ((found = find_parent(cmd->directive, "<Location"))
                || (found = find_parent(cmd->directive, "<LocationMatch"))))
        || ((forbidden & NOT_IN_FILES)
            && ((found = find_parent(cmd->directive, "<Files"))
                || (found = find_parent(cmd->directive, "<FilesMatch"))
                || (found = find_parent(cmd->directive, "<If"))
                || (found = find_parent(cmd->directive, "<ElseIf"))
                || (found = find_parent(cmd->directive, "<Else"))))
        || ((forbidden & NOT_IN_PROXY)
            && ((found = find_parent(cmd->directive, "<Proxy"))
                || (found = find_parent(cmd->directive, "<ProxyMatch"))))) {
        return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
                           " cannot occur within ", found->directive,
                           "> section", NULL);
    }

    return NULL;
}


static const char *set_max_ranges(cmd_parms *cmd, void *conf_, const char *arg)
{
    core_dir_config *conf = conf_;
    int val = 0;

    if (!ap_cstr_casecmp(arg, "none")) {
        val = AP_MAXRANGES_NORANGES;
    }
    else if (!ap_cstr_casecmp(arg, "default")) {
        val = AP_MAXRANGES_DEFAULT;
    }
    else if (!ap_cstr_casecmp(arg, "unlimited")) {
        val = AP_MAXRANGES_UNLIMITED;
    }
    else {
        val = atoi(arg);
        if (val <= 0)
            return "MaxRanges requires 'none', 'default', 'unlimited' or "
                   "a positive integer";
    }

    conf->max_ranges = val;

    return NULL;
}


static const char *set_limit_mem(cmd_parms *cmd, void *conf_,
                                 const char *arg, const char * arg2)
{
    core_dir_config *conf = conf_;

#if defined(RLIMIT_AS)
    ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS);
#elif defined(RLIMIT_DATA)
    ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
#elif defined(RLIMIT_VMEM)
    ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM);
#endif

    return NULL;
}


AP_DECLARE(const char *) ap_get_server_name_for_url(request_rec *r)
{
    const char *plain_server_name = ap_get_server_name(r);

#if APR_HAVE_IPV6
    if (ap_strchr_c(plain_server_name, ':')) { /* IPv6 literal? */
        return apr_pstrcat(r->pool, "[", plain_server_name, "]", NULL);
    }
#endif
    return plain_server_name;
}


AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word)
{
# define SMALL_EXPANSION 5
    struct sll {
        struct sll *next;
        const char *string;
        apr_size_t len;
    } *result, *current, sresult[SMALL_EXPANSION];
    char *res_buf, *cp;
    const char *s, *e, *ep;
    unsigned spc;
    apr_size_t outlen;

    s = ap_strchr_c(word, '$');
    if (!s) {
        return word;
    }

    /* well, actually something to do */
    ep = word + strlen(word);
    spc = 0;
    result = current = &(sresult[spc++]);
    current->next = NULL;
    current->string = word;
    current->len = s - word;
    outlen = current->len;

    do {
        /* prepare next entry */
        if (current->len) {
            current->next = (spc < SMALL_EXPANSION)
                            ? &(sresult[spc++])
                            : (struct sll *)apr_palloc(p,
                                                       sizeof(*current->next));
            current = current->next;
            current->next = NULL;
            current->len = 0;
        }

        if (*s == '$') {
            if (s[1] == '{' && (e = ap_strchr_c(s+2, '}'))) {
                char *name = apr_pstrmemdup(p, s+2, e-s-2);
                word = NULL;
                if (server_config_defined_vars)
                    word = apr_table_get(server_config_defined_vars, name);
                if (!word)
                    word = getenv(name);
                if (word) {
                    current->string = word;
                    current->len = strlen(word);
                    outlen += current->len;
                }
                else {
                    if (ap_strchr(name, ':') == 0)
                        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(00111)
                                     "Config variable ${%s} is not defined",
                                     name);
                    current->string = s;
                    current->len = e - s + 1;
                    outlen += current->len;
                }
                s = e + 1;
            }
            else {
                current->string = s++;
                current->len = 1;
                ++outlen;
            }
        }
        else {
            word = s;
            s = ap_strchr_c(s, '$');
            current->string = word;
            current->len = s ? s - word : ep - word;
            outlen += current->len;
        }
    } while (s && *s);

    /* assemble result */
    res_buf = cp = apr_palloc(p, outlen + 1);
    do {
        if (result->len) {
            memcpy(cp, result->string, result->len);
            cp += result->len;
        }
        result = result->next;
    } while (result);
    res_buf[outlen] = '\0';

    return res_buf;
}


AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
                                            int type, int *str_is_ip)
{
    int hostname_lookups;
    int ignored_str_is_ip;

    if (!str_is_ip) { /* caller doesn't want to know */
        str_is_ip = &ignored_str_is_ip;
    }
    *str_is_ip = 0;

    /* If we haven't checked the host name, and we want to */
    if (dir_config) {
        hostname_lookups = ((core_dir_config *)ap_get_core_module_config(dir_config))
                           ->hostname_lookups;

        if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
            hostname_lookups = HOSTNAME_LOOKUP_OFF;
        }
    }
    else {
        /* the default */
        hostname_lookups = HOSTNAME_LOOKUP_OFF;
    }

    if (type != REMOTE_NOLOOKUP
        && conn->remote_host == NULL
        && (type == REMOTE_DOUBLE_REV
        || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {

        if (apr_getnameinfo(&conn->remote_host, conn->client_addr, 0)
            == APR_SUCCESS) {
            ap_str_tolower(conn->remote_host);

            if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
                conn->double_reverse = do_double_reverse(conn->double_reverse,
                                                         conn->remote_host,
                                                         conn->client_addr,
                                                         conn->pool);
                if (conn->double_reverse != 1) {
                    conn->remote_host = NULL;
                }
            }
        }

        /* if failed, set it to the NULL string to indicate error */
        if (conn->remote_host == NULL) {
            conn->remote_host = "";
        }
    }

    if (type == REMOTE_DOUBLE_REV) {
        conn->double_reverse = do_double_reverse(conn->double_reverse,
                                                 conn->remote_host,
                                                 conn->client_addr, conn->pool);
        if (conn->double_reverse == -1) {
            return NULL;
        }
    }

    /*
     * Return the desired information; either the remote DNS name, if found,
     * or either NULL (if the hostname was requested) or the IP address
     * (if any identifier was requested).
     */
    if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
        return conn->remote_host;
    }
    else {
        if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
            return NULL;
        }
        else {
            *str_is_ip = 1;
            return conn->client_ip;
        }
    }
}


static const char *set_signature_flag(cmd_parms *cmd, void *d_,
                                      const char *arg)
{
    core_dir_config *d = d_;

    if (ap_cstr_casecmp(arg, "On") == 0) {
        d->server_signature = srv_sig_on;
    }
    else if (ap_cstr_casecmp(arg, "Off") == 0) {
        d->server_signature = srv_sig_off;
    }
    else if (ap_cstr_casecmp(arg, "EMail") == 0) {
        d->server_signature = srv_sig_withmail;
    }
    else {
        return "ServerSignature: use one of: off | on | email";
    }

    return NULL;
}


AP_DECLARE(int) ap_allow_options(request_rec *r)
{
    core_dir_config *conf =
      (core_dir_config *)ap_get_core_module_config(r->per_dir_config);

    return conf->opts;
}


static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
                                       const char *arg1, const char *arg2)
{
    core_server_config *conf =
        ap_get_core_module_config(cmd->server->module_config);
    int limit = atoi(arg1);

    if (limit <= 0) {
        return "The recursion limit must be greater than zero.";
    }
    if (limit < 4) {
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00119)
                     "Limiting internal redirects to very low numbers may "
                     "cause normal requests to fail.");
    }

    conf->redirect_limit = limit;

    if (arg2) {
        limit = atoi(arg2);

        if (limit <= 0) {
            return "The recursion limit must be greater than zero.";
        }
        if (limit < 4) {
            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00120)
                         "Limiting the subrequest depth to a very low level may"
                         " cause normal requests to fail.");
        }
    }

    conf->subreq_limit = limit;

    return NULL;
}


static const char *set_document_root(cmd_parms *cmd, void *dummy,
                                     const char *arg)
{
    void *sconf = cmd->server->module_config;
    core_server_config *conf = ap_get_core_module_config(sconf);

    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
    if (err != NULL) {
        return err;
    }

    /* When ap_document_root_check is false; skip all the stuff below */
    if (!ap_document_root_check) {
       conf->ap_document_root = arg;
       return NULL;
    }

    /* Make it absolute, relative to ServerRoot */
    arg = ap_server_root_relative(cmd->pool, arg);
    if (arg == NULL) {
        return "DocumentRoot must be a directory";
    }

    if (apr_filepath_merge((char**)&conf->ap_document_root, NULL, arg,
                           APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS
        || !ap_is_directory(cmd->temp_pool, arg)) {
        if (cmd->server->is_virtual) {
            ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0,
                          cmd->pool, APLOGNO(00112)
                          "Warning: DocumentRoot [%s] does not exist",
                          arg);
            conf->ap_document_root = arg;
        }
        else {
            return apr_psprintf(cmd->pool,
                                "DocumentRoot '%s' is not a directory, or is not readable",
                                arg);
        }
    }
    return NULL;
}


static const char *set_max_reversals(cmd_parms *cmd, void *conf_, const char *arg)
{
    core_dir_config *conf = conf_;
    int val = 0;

    if (!ap_cstr_casecmp(arg, "none")) {
        val = AP_MAXRANGES_NORANGES;
    }
    else if (!ap_cstr_casecmp(arg, "default")) {
        val = AP_MAXRANGES_DEFAULT;
    }
    else if (!ap_cstr_casecmp(arg, "unlimited")) {
        val = AP_MAXRANGES_UNLIMITED;
    }
    else {
        val = atoi(arg);
        if (val <= 0)
            return "MaxRangeReversals requires 'none', 'default', 'unlimited' or "
            "a positive integer";
    }

    conf->max_reversals = val;

    return NULL;
}


static void *create_core_server_config(apr_pool_t *a, server_rec *s)
{
    core_server_config *conf;
    int is_virtual = s->is_virtual;

    conf = (core_server_config *)apr_pcalloc(a, sizeof(core_server_config));

    /* global-default / global-only settings */

    if (!is_virtual) {
        conf->ap_document_root = DOCUMENT_LOCATION;
        conf->access_name = DEFAULT_ACCESS_FNAME;

        /* A mapping only makes sense in the global context */
        conf->accf_map = apr_table_make(a, 5);
#if APR_HAS_SO_ACCEPTFILTER
        apr_table_setn(conf->accf_map, "http", ACCEPT_FILTER_NAME);
        apr_table_setn(conf->accf_map, "https", "dataready");
#elif defined(WIN32)
        /* 'data' is disabled on Windows due to a DoS vuln (PR 59970) */
        apr_table_setn(conf->accf_map, "http", "connect");
        apr_table_setn(conf->accf_map, "https", "connect");
#else
        apr_table_setn(conf->accf_map, "http", "data");
        apr_table_setn(conf->accf_map, "https", "data");
#endif
    }
    /* pcalloc'ed - we have NULL's/0's
    else ** is_virtual ** {
        conf->ap_document_root = NULL;
        conf->access_name = NULL;
        conf->accf_map = NULL;
    }
     */

    /* initialization, no special case for global context */

    conf->sec_dir = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
    conf->sec_url = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));

    /* pcalloc'ed - we have NULL's/0's
    conf->gprof_dir = NULL;

    ** recursion stopper; 0 == unset
    conf->redirect_limit = 0;
    conf->subreq_limit = 0;

    conf->protocol = NULL;
     */

    conf->trace_enable = AP_TRACE_UNSET;

    conf->protocols = apr_array_make(a, 5, sizeof(const char *));
    conf->protocols_honor_order = -1;
    conf->async_filter = 0;

    return (void *)conf;
}


static const char *set_use_canonical_phys_port(cmd_parms *cmd, void *d_,
                                          const char *arg)
{
    core_dir_config *d = d_;

    if (ap_cstr_casecmp(arg, "on") == 0) {
        d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_ON;
    }
    else if (ap_cstr_casecmp(arg, "off") == 0) {
        d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_OFF;
    }
    else {
        return "parameter must be 'on' or 'off'";
    }

    return NULL;
}


AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
{
    char sport[20];
    core_dir_config *conf;

    conf = (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
    if ((conf->server_signature == srv_sig_off)
            || (conf->server_signature == srv_sig_unset)) {
        return "";
    }

    apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));

    if (conf->server_signature == srv_sig_withmail) {
        return apr_pstrcat(r->pool, prefix, "<address>",
                           ap_get_server_banner(),
                           " Server at server->server_admin) ? "" : "mailto:",
                           ap_escape_html(r->pool, r->server->server_admin),
                           "\">",
                           ap_escape_html(r->pool, ap_get_server_name(r)),
                           " Port ", sport,
                           "</address>\n", NULL);
    }

    return apr_pstrcat(r->pool, prefix, "<address>", ap_get_server_banner(),
                       " Server at ",
                       ap_escape_html(r->pool, ap_get_server_name(r)),
                       " Port ", sport,
                       "</address>\n", NULL);
}


static const char *set_limit_cpu(cmd_parms *cmd, void *conf_,
                                 const char *arg, const char *arg2)
{
    core_dir_config *conf = conf_;

    ap_unixd_set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
    return NULL;
}


Add addition overflow check for stream buffer (#226)

size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )
{
    const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    size_t xReturn;

    configASSERT( pxStreamBuffer );

    xReturn = prvBytesInBuffer( pxStreamBuffer );
    return xReturn;
}

The kernel in Amazon Web Services FreeRTOS before 10.4.3 has an integer overflow in stream_buffer.c for a stream buffer.


size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
                                    void * pvRxData,
                                    size_t xBufferLengthBytes,
                                    BaseType_t * const pxHigherPriorityTaskWoken )
{
    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;

    configASSERT( pvRxData );
    configASSERT( pxStreamBuffer );

    /* This receive function is used by both message buffers, which store
     * discrete messages, and stream buffers, which store a continuous stream of
     * bytes.  Discrete messages include an additional
     * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
     * message. */
    if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
    {
        xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
    }
    else
    {
        xBytesToStoreMessageLength = 0;
    }

    xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );

    /* Whether receiving a discrete message (where xBytesToStoreMessageLength
     * holds the number of bytes used to store the message length) or a stream of
     * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
     * available must be greater than xBytesToStoreMessageLength to be able to
     * read bytes from the buffer. */
    if( xBytesAvailable > xBytesToStoreMessageLength )
    {
        xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );

        /* Was a task waiting for space in the buffer? */
        if( xReceivedLength != ( size_t ) 0 )
        {
            sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );

    return xReceivedLength;
}


    StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
                                                           size_t xTriggerLevelBytes,
                                                           BaseType_t xIsMessageBuffer,
                                                           uint8_t * const pucStreamBufferStorageArea,
                                                           StaticStreamBuffer_t * const pxStaticStreamBuffer )
    {
        StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */
        StreamBufferHandle_t xReturn;
        uint8_t ucFlags;

        configASSERT( pucStreamBufferStorageArea );
        configASSERT( pxStaticStreamBuffer );
        configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );

        /* A trigger level of 0 would cause a waiting task to unblock even when
         * the buffer was empty. */
        if( xTriggerLevelBytes == ( size_t ) 0 )
        {
            xTriggerLevelBytes = ( size_t ) 1;
        }

        if( xIsMessageBuffer != pdFALSE )
        {
            /* Statically allocated message buffer. */
            ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;
        }
        else
        {
            /* Statically allocated stream buffer. */
            ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;
        }

        /* In case the stream buffer is going to be used as a message buffer
         * (that is, it will hold discrete messages with a little meta data that
         * says how big the next message is) check the buffer will be large enough
         * to hold at least one message. */
        configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );

        #if ( configASSERT_DEFINED == 1 )
            {
                /* Sanity check that the size of the structure used to declare a
                 * variable of type StaticStreamBuffer_t equals the size of the real
                 * message buffer structure. */
                volatile size_t xSize = sizeof( StaticStreamBuffer_t );
                configASSERT( xSize == sizeof( StreamBuffer_t ) );
            } /*lint !e529 xSize is referenced is configASSERT() is defined. */
        #endif /* configASSERT_DEFINED */

        if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )
        {
            prvInitialiseNewStreamBuffer( pxStreamBuffer,
                                          pucStreamBufferStorageArea,
                                          xBufferSizeBytes,
                                          xTriggerLevelBytes,
                                          ucFlags );

            /* Remember this was statically allocated in case it is ever deleted
             * again. */
            pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;

            traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );

            xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */
        }
        else
        {
            xReturn = NULL;
            traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );
        }

        return xReturn;
    }


    void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer,
                                             UBaseType_t uxStreamBufferNumber )
    {
        xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
    }


static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
                                          uint8_t * const pucBuffer,
                                          size_t xBufferSizeBytes,
                                          size_t xTriggerLevelBytes,
                                          uint8_t ucFlags )
{
    /* Assert here is deliberately writing to the entire buffer to ensure it can
     * be written to without generating exceptions, and is setting the buffer to a
     * known value to assist in development/debugging. */
    #if ( configASSERT_DEFINED == 1 )
        {
            /* The value written just has to be identifiable when looking at the
             * memory.  Don't use 0xA5 as that is the stack fill value and could
             * result in confusion as to what is actually being observed. */
            const BaseType_t xWriteValue = 0x55;
            configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer );
        } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */
    #endif

    ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */
    pxStreamBuffer->pucBuffer = pucBuffer;
    pxStreamBuffer->xLength = xBufferSizeBytes;
    pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
    pxStreamBuffer->ucFlags = ucFlags;
}


BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
                                              BaseType_t * pxHigherPriorityTaskWoken )
{
    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    BaseType_t xReturn;
    UBaseType_t uxSavedInterruptStatus;

    configASSERT( pxStreamBuffer );

    uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
    {
        if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
        {
            ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
                                         ( uint32_t ) 0,
                                         eNoAction,
                                         pxHigherPriorityTaskWoken );
            ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;
            xReturn = pdTRUE;
        }
        else
        {
            xReturn = pdFALSE;
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

    return xReturn;
}


    uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )
    {
        return( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER );
    }


BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,
                                         size_t xTriggerLevel )
{
    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    BaseType_t xReturn;

    configASSERT( pxStreamBuffer );

    /* It is not valid for the trigger level to be 0. */
    if( xTriggerLevel == ( size_t ) 0 )
    {
        xTriggerLevel = ( size_t ) 1;
    }

    /* The trigger level is the number of bytes that must be in the stream
     * buffer before a task that is waiting for data is unblocked. */
    if( xTriggerLevel <= pxStreamBuffer->xLength )
    {
        pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
        xReturn = pdPASS;
    }
    else
    {
        xReturn = pdFALSE;
    }

    return xReturn;
}


static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,
                                        void * pvRxData,
                                        size_t xBufferLengthBytes,
                                        size_t xBytesAvailable,
                                        size_t xBytesToStoreMessageLength )
{
    size_t xOriginalTail, xReceivedLength, xNextMessageLength;
    configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;

    if( xBytesToStoreMessageLength != ( size_t ) 0 )
    {
        /* A discrete message is being received.  First receive the length
         * of the message.  A copy of the tail is stored so the buffer can be
         * returned to its prior state if the length of the message is too
         * large for the provided buffer. */
        xOriginalTail = pxStreamBuffer->xTail;
        ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable );
        xNextMessageLength = ( size_t ) xTempNextMessageLength;

        /* Reduce the number of bytes available by the number of bytes just
         * read out. */
        xBytesAvailable -= xBytesToStoreMessageLength;

        /* Check there is enough space in the buffer provided by the
         * user. */
        if( xNextMessageLength > xBufferLengthBytes )
        {
            /* The user has provided insufficient space to read the message
             * so return the buffer to its previous state (so the length of
             * the message is in the buffer again). */
            pxStreamBuffer->xTail = xOriginalTail;
            xNextMessageLength = 0;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        /* A stream of bytes is being received (as opposed to a discrete
         * message), so read as many bytes as possible. */
        xNextMessageLength = xBufferLengthBytes;
    }

    /* Read the actual data. */
    xReceivedLength = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xNextMessageLength, xBytesAvailable ); /*lint !e9079 Data storage area is implemented as uint8_t array for ease of sizing, indexing and alignment. */

    return xReceivedLength;
}


size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
                                 const void * pvTxData,
                                 size_t xDataLengthBytes,
                                 BaseType_t * const pxHigherPriorityTaskWoken )
{
    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    size_t xReturn, xSpace;
    size_t xRequiredSpace = xDataLengthBytes;

    configASSERT( pvTxData );
    configASSERT( pxStreamBuffer );

    /* This send function is used to write to both message buffers and stream
     * buffers.  If this is a message buffer then the space needed must be
     * increased by the amount of bytes needed to store the length of the
     * message. */
    if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
    {
        xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
    xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );

    if( xReturn > ( size_t ) 0 )
    {
        /* Was a task waiting for the data? */
        if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
        {
            sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );

    return xReturn;
}


BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )
{
    BaseType_t xReturn;
    size_t xBytesToStoreMessageLength;
    const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;

    configASSERT( pxStreamBuffer );

    /* This generic version of the receive function is used by both message
     * buffers, which store discrete messages, and stream buffers, which store a
     * continuous stream of bytes.  Discrete messages include an additional
     * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */
    if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
    {
        xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
    }
    else
    {
        xBytesToStoreMessageLength = 0;
    }

    /* True if the available space equals zero. */
    if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )
    {
        xReturn = pdTRUE;
    }
    else
    {
        xReturn = pdFALSE;
    }

    return xReturn;
}


static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
                                      uint8_t * pucData,
                                      size_t xMaxCount,
                                      size_t xBytesAvailable )
{
    size_t xCount, xFirstLength, xNextTail;

    /* Use the minimum of the wanted bytes and the available bytes. */
    xCount = configMIN( xBytesAvailable, xMaxCount );

    if( xCount > ( size_t ) 0 )
    {
        xNextTail = pxStreamBuffer->xTail;

        /* Calculate the number of bytes that can be read - which may be
         * less than the number wanted if the data wraps around to the start of
         * the buffer. */
        xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount );

        /* Obtain the number of bytes it is possible to obtain in the first
         * read.  Asserts check bounds of read and write. */
        configASSERT( xFirstLength <= xMaxCount );
        configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength );
        ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */

        /* If the total number of wanted bytes is greater than the number
         * that could be read in the first read... */
        if( xCount > xFirstLength )
        {
            /*...then read the remaining bytes from the start of the buffer. */
            configASSERT( xCount <= xMaxCount );
            ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* Move the tail pointer to effectively remove the data read from
         * the buffer. */
        xNextTail += xCount;

        if( xNextTail >= pxStreamBuffer->xLength )
        {
            xNextTail -= pxStreamBuffer->xLength;
        }

        pxStreamBuffer->xTail = xNextTail;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return xCount;
}


BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
{
    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    BaseType_t xReturn = pdFAIL;

    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxStreamBufferNumber;
    #endif

    configASSERT( pxStreamBuffer );

    #if ( configUSE_TRACE_FACILITY == 1 )
        {
            /* Store the stream buffer number so it can be restored after the
             * reset. */
            uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
        }
    #endif

    /* Can only reset a message buffer if there are no tasks blocked on it. */
    taskENTER_CRITICAL();
    {
        if( pxStreamBuffer->xTaskWaitingToReceive == NULL )
        {
            if( pxStreamBuffer->xTaskWaitingToSend == NULL )
            {
                prvInitialiseNewStreamBuffer( pxStreamBuffer,
                                              pxStreamBuffer->pucBuffer,
                                              pxStreamBuffer->xLength,
                                              pxStreamBuffer->xTriggerLevelBytes,
                                              pxStreamBuffer->ucFlags );
                xReturn = pdPASS;

                #if ( configUSE_TRACE_FACILITY == 1 )
                    {
                        pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
                    }
                #endif

                traceSTREAM_BUFFER_RESET( xStreamBuffer );
            }
        }
    }
    taskEXIT_CRITICAL();

    return xReturn;
}


static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )
{
/* Returns the distance between xTail and xHead. */
    size_t xCount;

    xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;
    xCount -= pxStreamBuffer->xTail;

    if( xCount >= pxStreamBuffer->xLength )
    {
        xCount -= pxStreamBuffer->xLength;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return xCount;
}


size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )
{
    const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    size_t xSpace;

    configASSERT( pxStreamBuffer );

    xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;
    xSpace -= pxStreamBuffer->xHead;
    xSpace -= ( size_t ) 1;

    if( xSpace >= pxStreamBuffer->xLength )
    {
        xSpace -= pxStreamBuffer->xLength;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return xSpace;
}


    StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
                                                     size_t xTriggerLevelBytes,
                                                     BaseType_t xIsMessageBuffer )
    {
        uint8_t * pucAllocatedMemory;
        uint8_t ucFlags;

        /* In case the stream buffer is going to be used as a message buffer
         * (that is, it will hold discrete messages with a little meta data that
         * says how big the next message is) check the buffer will be large enough
         * to hold at least one message. */
        if( xIsMessageBuffer == pdTRUE )
        {
            /* Is a message buffer but not statically allocated. */
            ucFlags = sbFLAGS_IS_MESSAGE_BUFFER;
            configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
        }
        else
        {
            /* Not a message buffer and not statically allocated. */
            ucFlags = 0;
            configASSERT( xBufferSizeBytes > 0 );
        }

        configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );

        /* A trigger level of 0 would cause a waiting task to unblock even when
         * the buffer was empty. */
        if( xTriggerLevelBytes == ( size_t ) 0 )
        {
            xTriggerLevelBytes = ( size_t ) 1;
        }

        /* A stream buffer requires a StreamBuffer_t structure and a buffer.
         * Both are allocated in a single call to pvPortMalloc().  The
         * StreamBuffer_t structure is placed at the start of the allocated memory
         * and the buffer follows immediately after.  The requested size is
         * incremented so the free space is returned as the user would expect -
         * this is a quirk of the implementation that means otherwise the free
         * space would be reported as one byte smaller than would be logically
         * expected. */
        if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) )
        {
            xBufferSizeBytes++;
            pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */
        }
        else
        {
            pucAllocatedMemory = NULL;
        }

        if( pucAllocatedMemory != NULL )
        {
            prvInitialiseNewStreamBuffer( ( StreamBuffer_t * ) pucAllocatedMemory,       /* Structure at the start of the allocated memory. */ /*lint !e9087 Safe cast as allocated memory is aligned. */ /*lint !e826 Area is not too small and alignment is guaranteed provided malloc() behaves as expected and returns aligned buffer. */
                                          pucAllocatedMemory + sizeof( StreamBuffer_t ), /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */
                                          xBufferSizeBytes,
                                          xTriggerLevelBytes,
                                          ucFlags );

            traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer );
        }
        else
        {
            traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );
        }

        return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */
    }


size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )
{
    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    size_t xReturn, xBytesAvailable, xOriginalTail;
    configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;

    configASSERT( pxStreamBuffer );

    /* Ensure the stream buffer is being used as a message buffer. */
    if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
    {
        xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );

        if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
        {
            /* The number of bytes available is greater than the number of bytes
             * required to hold the length of the next message, so another message
             * is available.  Return its length without removing the length bytes
             * from the buffer.  A copy of the tail is stored so the buffer can be
             * returned to its prior state as the message is not actually being
             * removed from the buffer. */
            xOriginalTail = pxStreamBuffer->xTail;
            ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable );
            xReturn = ( size_t ) xTempReturn;
            pxStreamBuffer->xTail = xOriginalTail;
        }
        else
        {
            /* The minimum amount of bytes in a message buffer is
             * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is
             * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid
             * value is 0. */
            configASSERT( xBytesAvailable == 0 );
            xReturn = 0;
        }
    }
    else
    {
        xReturn = 0;
    }

    return xReturn;
}


size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
                          const void * pvTxData,
                          size_t xDataLengthBytes,
                          TickType_t xTicksToWait )
{
    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    size_t xReturn, xSpace = 0;
    size_t xRequiredSpace = xDataLengthBytes;
    TimeOut_t xTimeOut;

    /* The maximum amount of space a stream buffer will ever report is its length
     * minus 1. */
    const size_t xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1;

    configASSERT( pvTxData );
    configASSERT( pxStreamBuffer );

    /* This send function is used to write to both message buffers and stream
     * buffers.  If this is a message buffer then the space needed must be
     * increased by the amount of bytes needed to store the length of the
     * message. */
    if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
    {
        xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;

        /* Overflow? */
        configASSERT( xRequiredSpace > xDataLengthBytes );

        /* If this is a message buffer then it must be possible to write the
         * whole message. */
        if( xRequiredSpace > xMaxReportedSpace )
        {
            /* The message would not fit even if the entire buffer was empty,
             * so don't wait for space. */
            xTicksToWait = ( TickType_t ) 0;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        /* If this is a stream buffer then it is acceptable to write only part
         * of the message to the buffer.  Cap the length to the total length of
         * the buffer. */
        if( xRequiredSpace > xMaxReportedSpace )
        {
            xRequiredSpace = xMaxReportedSpace;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

    if( xTicksToWait != ( TickType_t ) 0 )
    {
        vTaskSetTimeOutState( &xTimeOut );

        do
        {
            /* Wait until the required number of bytes are free in the message
             * buffer. */
            taskENTER_CRITICAL();
            {
                xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );

                if( xSpace < xRequiredSpace )
                {
                    /* Clear notification state as going to wait for space. */
                    ( void ) xTaskNotifyStateClear( NULL );

                    /* Should only be one writer. */
                    configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
                    pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();
                }
                else
                {
                    taskEXIT_CRITICAL();
                    break;
                }
            }
            taskEXIT_CRITICAL();

            traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
            ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
            pxStreamBuffer->xTaskWaitingToSend = NULL;
        } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    if( xSpace == ( size_t ) 0 )
    {
        xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );

    if( xReturn > ( size_t ) 0 )
    {
        traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );

        /* Was a task waiting for the data? */
        if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
        {
            sbSEND_COMPLETED( pxStreamBuffer );
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
        traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );
    }

    return xReturn;
}


void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )
{
    StreamBuffer_t * pxStreamBuffer = xStreamBuffer;

    configASSERT( pxStreamBuffer );

    traceSTREAM_BUFFER_DELETE( xStreamBuffer );

    if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )
    {
        #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
            {
                /* Both the structure and the buffer were allocated using a single call
                * to pvPortMalloc(), hence only one call to vPortFree() is required. */
                vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */
            }
        #else
            {
                /* Should not be possible to get here, ucFlags must be corrupt.
                 * Force an assert. */
                configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );
            }
        #endif
    }
    else
    {
        /* The structure and buffer were not allocated dynamically and cannot be
         * freed - just scrub the structure so future use will assert. */
        ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );
    }
}


    UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )
    {
        return xStreamBuffer->uxStreamBufferNumber;
    }


BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
                                                 BaseType_t * pxHigherPriorityTaskWoken )
{
    StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
    BaseType_t xReturn;
    UBaseType_t uxSavedInterruptStatus;

    configASSERT( pxStreamBuffer );

    uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
    {
        if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
        {
            ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
                                         ( uint32_t ) 0,
                                         eNoAction,
                                         pxHigherPriorityTaskWoken );
            ( pxStreamBuffer )->xTaskWaitingToSend = NULL;
            xReturn = pdTRUE;
        }
        else
        {
            xReturn = pdFALSE;
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

    return xReturn;
}