📄 request.c
字号:
/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * http_request.c: functions to get and process requests * * Rob McCool 3/21/93 * * Thoroughly revamped by rst for Apache. NB this file reads * best from the bottom up. * */#include "apr_strings.h"#include "apr_file_io.h"#include "apr_fnmatch.h"#define APR_WANT_STRFUNC#include "apr_want.h"#define CORE_PRIVATE#include "ap_config.h"#include "httpd.h"#include "http_config.h"#include "http_request.h"#include "http_core.h"#include "http_protocol.h"#include "http_log.h"#include "http_main.h"#include "util_filter.h"#include "util_charset.h"#include "util_script.h"#include "mod_core.h"#if APR_HAVE_STDARG_H#include <stdarg.h>#endifAPR_HOOK_STRUCT( APR_HOOK_LINK(translate_name) APR_HOOK_LINK(map_to_storage) APR_HOOK_LINK(check_user_id) APR_HOOK_LINK(fixups) APR_HOOK_LINK(type_checker) APR_HOOK_LINK(access_checker) APR_HOOK_LINK(auth_checker) APR_HOOK_LINK(insert_filter) APR_HOOK_LINK(create_request))AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name, (request_rec *r), (r), DECLINED)AP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage, (request_rec *r), (r), DECLINED)AP_IMPLEMENT_HOOK_RUN_FIRST(int,check_user_id, (request_rec *r), (r), DECLINED)AP_IMPLEMENT_HOOK_RUN_ALL(int,fixups, (request_rec *r), (r), OK, DECLINED)AP_IMPLEMENT_HOOK_RUN_FIRST(int,type_checker, (request_rec *r), (r), DECLINED)AP_IMPLEMENT_HOOK_RUN_ALL(int,access_checker, (request_rec *r), (r), OK, DECLINED)AP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker, (request_rec *r), (r), DECLINED)AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))AP_IMPLEMENT_HOOK_RUN_ALL(int, create_request, (request_rec *r), (r), OK, DECLINED)static int decl_die(int status, char *phase, request_rec *r){ if (status == DECLINED) { ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, "configuration error: couldn't %s: %s", phase, r->uri); return HTTP_INTERNAL_SERVER_ERROR; } else { return status; }}/* This is the master logic for processing requests. Do NOT duplicate * this logic elsewhere, or the security model will be broken by future * API changes. Each phase must be individually optimized to pick up * redundant/duplicate calls by subrequests, and redirects. */AP_DECLARE(int) ap_process_request_internal(request_rec *r){ int file_req = (r->main && r->filename); int access_status; /* Ignore embedded %2F's in path for proxy requests */ if (!r->proxyreq && r->parsed_uri.path) { core_dir_config *d; d = ap_get_module_config(r->per_dir_config, &core_module); if (d->allow_encoded_slashes) { access_status = ap_unescape_url_keep2f(r->parsed_uri.path); } else { access_status = ap_unescape_url(r->parsed_uri.path); } if (access_status) { if (access_status == HTTP_NOT_FOUND) { if (! d->allow_encoded_slashes) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "found %%2f (encoded '/') in URI " "(decoded='%s'), returning 404", r->parsed_uri.path); } } return access_status; } } ap_getparents(r->uri); /* OK --- shrinking transformations... */ /* All file subrequests are a huge pain... they cannot bubble through the * next several steps. Only file subrequests are allowed an empty uri, * otherwise let translate_name kill the request. */ if (!file_req) { if ((access_status = ap_location_walk(r))) { return access_status; } if ((access_status = ap_run_translate_name(r))) { return decl_die(access_status, "translate", r); } } /* Reset to the server default config prior to running map_to_storage */ r->per_dir_config = r->server->lookup_defaults; if ((access_status = ap_run_map_to_storage(r))) { /* This request wasn't in storage (e.g. TRACE) */ return access_status; } /* Excluding file-specific requests with no 'true' URI... */ if (!file_req) { /* Rerun the location walk, which overrides any map_to_storage config. */ if ((access_status = ap_location_walk(r))) { return access_status; } } /* Only on the main request! */ if (r->main == NULL) { if ((access_status = ap_run_header_parser(r))) { return access_status; } } /* Skip authn/authz if the parent or prior request passed the authn/authz, * and that configuration didn't change (this requires optimized _walk() * functions in map_to_storage that use the same merge results given * identical input.) If the config changes, we must re-auth. */ if (r->main && (r->main->per_dir_config == r->per_dir_config)) { r->user = r->main->user; r->ap_auth_type = r->main->ap_auth_type; } else if (r->prev && (r->prev->per_dir_config == r->per_dir_config)) { r->user = r->prev->user; r->ap_auth_type = r->prev->ap_auth_type; } else { switch (ap_satisfies(r)) { case SATISFY_ALL: case SATISFY_NOSPEC: if ((access_status = ap_run_access_checker(r)) != 0) { return decl_die(access_status, "check access", r); } if (ap_some_auth_required(r)) { if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) { return decl_die(access_status, ap_auth_type(r) ? "check user. No user file?" : "perform authentication. AuthType not set!", r); } if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) { return decl_die(access_status, ap_auth_type(r) ? "check access. No groups file?" : "perform authentication. AuthType not set!", r); } } break; case SATISFY_ANY: if (((access_status = ap_run_access_checker(r)) != 0)) { if (!ap_some_auth_required(r)) { return decl_die(access_status, "check access", r); } if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) { return decl_die(access_status, ap_auth_type(r) ? "check user. No user file?" : "perform authentication. AuthType not set!", r); } if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) { return decl_die(access_status, ap_auth_type(r) ? "check access. No groups file?" : "perform authentication. AuthType not set!", r); } } break; } } /* XXX Must make certain the ap_run_type_checker short circuits mime * in mod-proxy for r->proxyreq && r->parsed_uri.scheme * && !strcmp(r->parsed_uri.scheme, "http") */ if ((access_status = ap_run_type_checker(r)) != 0) { return decl_die(access_status, "find types", r); } if ((access_status = ap_run_fixups(r)) != 0) { return access_status; } return OK;}/* Useful caching structures to repeat _walk/merge sequences as required * when a subrequest or redirect reuses substantially the same config. * * Directive order in the httpd.conf file and its Includes significantly * impact this optimization. Grouping common blocks at the front of the * config that are less likely to change between a request and * its subrequests, or between a request and its redirects reduced * the work of these functions significantly. */typedef struct walk_walked_t { ap_conf_vector_t *matched; /* A dir_conf sections we matched */ ap_conf_vector_t *merged; /* The dir_conf merged result */} walk_walked_t;typedef struct walk_cache_t { const char *cached; /* The identifier we matched */ ap_conf_vector_t **dir_conf_tested; /* The sections we matched against */ ap_conf_vector_t *dir_conf_merged; /* Base per_dir_config */ ap_conf_vector_t *per_dir_result; /* per_dir_config += walked result */ apr_array_header_t *walked; /* The list of walk_walked_t results */} walk_cache_t;static walk_cache_t *prep_walk_cache(apr_size_t t, request_rec *r){ walk_cache_t *cache; void **note; /* Find the most relevant, recent entry to work from. That would be * this request (on the second call), or the parent request of a * subrequest, or the prior request of an internal redirect. Provide * this _walk()er with a copy it is allowed to munge. If there is no * parent or prior cached request, then create a new walk cache. */ note = ap_get_request_note(r, t); if (!note) { return NULL; } if (!(cache = *note)) { void **inherit_note; if ((r->main && ((inherit_note = ap_get_request_note(r->main, t))) && *inherit_note) || (r->prev && ((inherit_note = ap_get_request_note(r->prev, t))) && *inherit_note)) { cache = apr_pmemdup(r->pool, *inherit_note, sizeof(*cache)); cache->walked = apr_array_copy(r->pool, cache->walked); } else { cache = apr_pcalloc(r->pool, sizeof(*cache)); cache->walked = apr_array_make(r->pool, 4, sizeof(walk_walked_t)); } *note = cache; } return cache;}/***************************************************************** * * Getting and checking directory configuration. Also checks the * FollowSymlinks and FollowSymOwner stuff, since this is really the * only place that can happen (barring a new mid_dir_walk callout). * * We can't do it as an access_checker module function which gets * called with the final per_dir_config, since we could have a directory * with FollowSymLinks disabled, which contains a symlink to another * with a .htaccess file which turns FollowSymLinks back on --- and * access in such a case must be denied. So, whatever it is that * checks FollowSymLinks needs to know the state of the options as * they change, all the way down. *//* * resolve_symlink must _always_ be called on an APR_LNK file type! * It will resolve the actual target file type, modification date, etc, * and provide any processing required for symlink evaluation. * Path must already be cleaned, no trailing slash, no multi-slashes, * and don't call this on the root! * * Simply, the number of times we deref a symlink are minimal compared * to the number of times we had an extra lstat() since we 'weren't sure'. * * To optimize, we stat() anything when given (opts & OPT_SYM_LINKS), otherwise * we start off with an lstat(). Every lstat() must be dereferenced in case * it points at a 'nasty' - we must always rerun check_safe_file (or similar.) */static int resolve_symlink(char *d, apr_finfo_t *lfi, int opts, apr_pool_t *p){ apr_finfo_t fi; int res; const char *savename; if (!(opts & (OPT_SYM_OWNER | OPT_SYM_LINKS))) { return HTTP_FORBIDDEN; } /* Save the name from the valid bits. */ savename = (lfi->valid & APR_FINFO_NAME) ? lfi->name : NULL; if (opts & OPT_SYM_LINKS) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -