request.c

来自「Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相」· C语言 代码 · 共 1,783 行 · 第 1/5 页

C
1,783 行
字号
    /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,     * and note the end result to (potentially) skip this step next time.     */    if (now_merged) {        r->per_dir_config = ap_merge_per_dir_configs(r->pool,                                                     r->per_dir_config,                                                     now_merged);    }    cache->per_dir_result = r->per_dir_config;    return OK;}/***************************************************************** * * The sub_request mechanism. * * Fns to look up a relative URI from, e.g., a map file or SSI document. * These do all access checks, etc., but don't actually run the transaction * ... use run_sub_req below for that.  Also, be sure to use destroy_sub_req * as appropriate if you're likely to be creating more than a few of these. * (An early Apache version didn't destroy the sub_reqs used in directory * indexing.  The result, when indexing a directory with 800-odd files in * it, was massively excessive storage allocation). * * Note more manipulation of protocol-specific vars in the request * structure... */static request_rec *make_sub_request(const request_rec *r,                                     ap_filter_t *next_filter){    apr_pool_t *rrp;    request_rec *rnew;    apr_pool_create(&rrp, r->pool);    apr_pool_tag(rrp, "subrequest");    rnew = apr_pcalloc(rrp, sizeof(request_rec));    rnew->pool = rrp;    rnew->hostname       = r->hostname;    rnew->request_time   = r->request_time;    rnew->connection     = r->connection;    rnew->server         = r->server;    rnew->request_config = ap_create_request_config(rnew->pool);    /* Start a clean config from this subrequest's vhost.  Optimization in     * Location/File/Dir walks from the parent request assure that if the     * config blocks of the subrequest match the parent request, no merges     * will actually occur (and generally a minimal number of merges are     * required, even if the parent and subrequest aren't quite identical.)     */    rnew->per_dir_config = r->server->lookup_defaults;    rnew->htaccess = r->htaccess;    rnew->allowed_methods = ap_make_method_list(rnew->pool, 2);    /* make a copy of the allowed-methods list */    ap_copy_method_list(rnew->allowed_methods, r->allowed_methods);    /* start with the same set of output filters */    if (next_filter) {        /* while there are no input filters for a subrequest, we will         * try to insert some, so if we don't have valid data, the code         * will seg fault.         */        rnew->input_filters = r->input_filters;        rnew->proto_input_filters = r->proto_input_filters;        rnew->output_filters = next_filter;        rnew->proto_output_filters = r->proto_output_filters;        ap_add_output_filter_handle(ap_subreq_core_filter_handle,                                    NULL, rnew, rnew->connection);    }    else {        /* If NULL - we are expecting to be internal_fast_redirect'ed         * to this subrequest - or this request will never be invoked.         * Ignore the original request filter stack entirely, and         * drill the input and output stacks back to the connection.         */        rnew->proto_input_filters = r->proto_input_filters;        rnew->proto_output_filters = r->proto_output_filters;        rnew->input_filters = r->proto_input_filters;        rnew->output_filters = r->proto_output_filters;    }    /* no input filters for a subrequest */    ap_set_sub_req_protocol(rnew, r);    /* We have to run this after we fill in sub req vars,     * or the r->main pointer won't be setup     */    ap_run_create_request(rnew);    return rnew;}AP_CORE_DECLARE_NONSTD(apr_status_t) ap_sub_req_output_filter(ap_filter_t *f,                                                              apr_bucket_brigade *bb){    apr_bucket *e = APR_BRIGADE_LAST(bb);    if (APR_BUCKET_IS_EOS(e)) {        apr_bucket_delete(e);    }    if (!APR_BRIGADE_EMPTY(bb)) {        return ap_pass_brigade(f->next, bb);    }    return APR_SUCCESS;}AP_DECLARE(int) ap_some_auth_required(request_rec *r){    /* Is there a require line configured for the type of *this* req? */    const apr_array_header_t *reqs_arr = ap_requires(r);    require_line *reqs;    int i;    if (!reqs_arr) {        return 0;    }    reqs = (require_line *) reqs_arr->elts;    for (i = 0; i < reqs_arr->nelts; ++i) {        if (reqs[i].method_mask & (AP_METHOD_BIT << r->method_number)) {            return 1;        }    }    return 0;}AP_DECLARE(request_rec *) ap_sub_req_method_uri(const char *method,                                                const char *new_uri,                                                const request_rec *r,                                                ap_filter_t *next_filter){    request_rec *rnew;    int res;    char *udir;    rnew = make_sub_request(r, next_filter);    /* would be nicer to pass "method" to ap_set_sub_req_protocol */    rnew->method = method;    rnew->method_number = ap_method_number_of(method);    if (new_uri[0] == '/') {        ap_parse_uri(rnew, new_uri);    }    else {        udir = ap_make_dirstr_parent(rnew->pool, r->uri);        udir = ap_escape_uri(rnew->pool, udir);    /* re-escape it */        ap_parse_uri(rnew, ap_make_full_path(rnew->pool, udir, new_uri));    }    /* We cannot return NULL without violating the API. So just turn this     * subrequest into a 500 to indicate the failure. */    if (ap_is_recursion_limit_exceeded(r)) {        rnew->status = HTTP_INTERNAL_SERVER_ERROR;        return rnew;    }    /* lookup_uri      * If the content can be served by the quick_handler, we can     * safely bypass request_internal processing.     */    res = ap_run_quick_handler(rnew, 1);    if (res != OK) {        if ((res = ap_process_request_internal(rnew))) {            rnew->status = res;        }    }     return rnew;}AP_DECLARE(request_rec *) ap_sub_req_lookup_uri(const char *new_uri,                                                const request_rec *r,                                                ap_filter_t *next_filter){    return ap_sub_req_method_uri("GET", new_uri, r, next_filter);}AP_DECLARE(request_rec *) ap_sub_req_lookup_dirent(const apr_finfo_t *dirent,                                                   const request_rec *r,                                                   int subtype,                                                   ap_filter_t *next_filter){    request_rec *rnew;    int res;    char *fdir;    char *udir;    rnew = make_sub_request(r, next_filter);    /* Special case: we are looking at a relative lookup in the same directory.     * This is 100% safe, since dirent->name just came from the filesystem.     */    if (r->path_info && *r->path_info) {        /* strip path_info off the end of the uri to keep it in sync         * with r->filename, which has already been stripped by directory_walk,         * merge the dirent->name, and then, if the caller wants us to remerge         * the original path info, do so.  Note we never fix the path_info back         * to r->filename, since dir_walk would do so (but we don't expect it         * to happen in the usual cases)         */        udir = apr_pstrdup(rnew->pool, r->uri);        udir[ap_find_path_info(udir, r->path_info)] = '\0';        udir = ap_make_dirstr_parent(rnew->pool, udir);        rnew->uri = ap_make_full_path(rnew->pool, udir, dirent->name);        if (subtype == AP_SUBREQ_MERGE_ARGS) {            rnew->uri = ap_make_full_path(rnew->pool, rnew->uri, r->path_info + 1);            rnew->path_info = apr_pstrdup(rnew->pool, r->path_info);        }        rnew->uri = ap_escape_uri(rnew->pool, rnew->uri);    }    else {        udir = ap_make_dirstr_parent(rnew->pool, r->uri);        rnew->uri = ap_escape_uri(rnew->pool, ap_make_full_path(rnew->pool,                                                                udir,                                                                dirent->name));    }    fdir = ap_make_dirstr_parent(rnew->pool, r->filename);    rnew->filename = ap_make_full_path(rnew->pool, fdir, dirent->name);    if (r->canonical_filename == r->filename) {        rnew->canonical_filename = rnew->filename;    }    /* XXX This is now less relevant; we will do a full location walk     * these days for this case.  Preserve the apr_stat results, and     * perhaps we also tag that symlinks were tested and/or found for     * r->filename.     */    rnew->per_dir_config = r->server->lookup_defaults;    if ((dirent->valid & APR_FINFO_MIN) != APR_FINFO_MIN) {        /*         * apr_dir_read isn't very complete on this platform, so         * we need another apr_lstat (or simply apr_stat if we allow         * all symlinks here.)  If this is an APR_LNK that resolves         * to an APR_DIR, then we will rerun everything anyways...         * this should be safe.         */        apr_status_t rv;        if (ap_allow_options(rnew) & OPT_SYM_LINKS) {            if (((rv = apr_stat(&rnew->finfo, rnew->filename,                                APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)                && (rv != APR_INCOMPLETE)) {                rnew->finfo.filetype = 0;            }        }        else {            if (((rv = apr_lstat(&rnew->finfo, rnew->filename,                                 APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)                && (rv != APR_INCOMPLETE)) {                rnew->finfo.filetype = 0;            }        }    }    else {        memcpy(&rnew->finfo, dirent, sizeof(apr_finfo_t));    }    if (rnew->finfo.filetype == APR_LNK) {        /*         * Resolve this symlink.  We should tie this back to dir_walk's cache         */        if ((res = resolve_symlink(rnew->filename, &rnew->finfo,                                   ap_allow_options(rnew), rnew->pool))            != OK) {            rnew->status = res;            return rnew;        }    }    if (rnew->finfo.filetype == APR_DIR) {        /* ap_make_full_path overallocated the buffers         * by one character to help us out here.         */        strcpy(rnew->filename + strlen(rnew->filename), "/");        if (!rnew->path_info || !*rnew->path_info) {            strcpy(rnew->uri  + strlen(rnew->uri ), "/");        }    }    /* fill in parsed_uri values     */    if (r->args && *r->args && (subtype == AP_SUBREQ_MERGE_ARGS)) {        ap_parse_uri(rnew, apr_pstrcat(r->pool, rnew->uri, "?",                                       r->args, NULL));    }    else {        ap_parse_uri(rnew, rnew->uri);    }    /* We cannot return NULL without violating the API. So just turn this     * subrequest into a 500. */    if (ap_is_recursion_limit_exceeded(r)) {        rnew->status = HTTP_INTERNAL_SERVER_ERROR;        return rnew;    }    if ((res = ap_process_request_internal(rnew))) {        rnew->status = res;    }    return rnew;}AP_DECLARE(request_rec *) ap_sub_req_lookup_file(const char *new_file,                                                 const request_rec *r,                                                 ap_filter_t *next_filter){    request_rec *rnew;    int res;    char *fdir;    apr_size_t fdirlen;    rnew = make_sub_request(r, next_filter);    fdir = ap_make_dirstr_parent(rnew->pool, r->filename);    fdirlen = strlen(fdir);    /* Translate r->filename, if it was canonical, it stays canonical     */    if (r->canonical_filename == r->filename) {        rnew->canonical_filename = (char*)(1);    }    if (apr_filepath_merge(&rnew->filename, fdir, new_file,                           APR_FILEPATH_TRUENAME, rnew->pool) != APR_SUCCESS) {        rnew->status = HTTP_FORBIDDEN;        return rnew;    }    if (rnew->canonical_filename) {        rnew->canonical_filename = rnew->filename;    }    /*     * Check for a special case... if there are no '/' characters in new_file     * at all, and the path was the same, then we 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?