📄 request.c
字号:
* ordered by number of segments. See core_reorder_directories * startseg tells us how many segments describe the root path * e.g. the complete path "//host/foo/" to a UNC share (4) */ startseg = seg = ap_count_dirs(r->filename); sec_idx = 0; /* * Go down the directory hierarchy. Where we have to check for * symlinks, do so. Where a .htaccess file has permission to * override anything, try to find one. */ do { int res; char *seg_name; char *delim; int temp_slash=0; /* We have no trailing slash, but we sure would appreciate one. * However, we don't want to append a / our first time through. */ if ((seg > startseg) && r->filename[filename_len-1] != '/') { r->filename[filename_len++] = '/'; r->filename[filename_len] = 0; temp_slash=1; } /* Begin *this* level by looking for matching <Directory> sections * from the server config. */ for (; sec_idx < num_sec; ++sec_idx) { ap_conf_vector_t *entry_config = sec_ent[sec_idx]; core_dir_config *entry_core; entry_core = ap_get_module_config(entry_config, &core_module); /* No more possible matches for this many segments? * We are done when we find relative/regex/longer components. */ if (entry_core->r || entry_core->d_components > seg) { break; } /* We will never skip '0' element components, e.g. plain old * <Directory >, and <Directory "/"> are classified as zero * so that Win32/Netware/OS2 etc all pick them up. * Otherwise, skip over the mismatches. */ if (entry_core->d_components && ((entry_core->d_components < seg) || (entry_core->d_is_fnmatch ? (apr_fnmatch(entry_core->d, r->filename, FNM_PATHNAME) != APR_SUCCESS) : (strcmp(r->filename, entry_core->d) != 0)))) { continue; } /* If we haven't continue'd above, we have a match. * * Calculate our full-context core opts & override. */ core_opts_merge(sec_ent[sec_idx], &opts); /* If we merged this same section last time, reuse it */ if (matches) { if (last_walk->matched == sec_ent[sec_idx]) { now_merged = last_walk->merged; ++last_walk; --matches; continue; } /* We fell out of sync. This is our own copy of walked, * so truncate the remaining matches and reset remaining. */ cache->walked->nelts -= matches; matches = 0; } if (now_merged) { now_merged = ap_merge_per_dir_configs(r->pool, now_merged, sec_ent[sec_idx]); } else { now_merged = sec_ent[sec_idx]; } last_walk = (walk_walked_t*)apr_array_push(cache->walked); last_walk->matched = sec_ent[sec_idx]; last_walk->merged = now_merged; } /* If .htaccess files are enabled, check for one, provided we * have reached a real path. */ do { /* Not really a loop, just a break'able code block */ ap_conf_vector_t *htaccess_conf = NULL; /* No htaccess in an incomplete root path, * nor if it's disabled */ if (seg < startseg || !opts.override) { break; } res = ap_parse_htaccess(&htaccess_conf, r, opts.override, apr_pstrdup(r->pool, r->filename), sconf->access_name); if (res) { return res; } if (!htaccess_conf) { break; } /* If we are still here, we found our htaccess. * * Calculate our full-context core opts & override. */ core_opts_merge(htaccess_conf, &opts); /* If we merged this same htaccess last time, reuse it... * this wouldn't work except that we cache the htaccess * sections for the lifetime of the request, so we match * the same conf. Good planning (no, pure luck ;) */ if (matches) { if (last_walk->matched == htaccess_conf) { now_merged = last_walk->merged; ++last_walk; --matches; break; } /* We fell out of sync. This is our own copy of walked, * so truncate the remaining matches and reset * remaining. */ cache->walked->nelts -= matches; matches = 0; } if (now_merged) { now_merged = ap_merge_per_dir_configs(r->pool, now_merged, htaccess_conf); } else { now_merged = htaccess_conf; } last_walk = (walk_walked_t*)apr_array_push(cache->walked); last_walk->matched = htaccess_conf; last_walk->merged = now_merged; } while (0); /* Only one htaccess, not a real loop */ /* That temporary trailing slash was useful, now drop it. */ if (temp_slash) { r->filename[--filename_len] = '\0'; } /* Time for all good things to come to an end? */ if (!r->path_info || !*r->path_info) { break; } /* Now it's time for the next segment... * We will assume the next element is an end node, and fix it up * below as necessary... */ seg_name = r->filename + filename_len; delim = strchr(r->path_info + (*r->path_info == '/' ? 1 : 0), '/'); if (delim) { size_t path_info_len = delim - r->path_info; *delim = '\0'; memcpy(seg_name, r->path_info, path_info_len + 1); filename_len += path_info_len; r->path_info = delim; *delim = '/'; } else { size_t path_info_len = strlen(r->path_info); memcpy(seg_name, r->path_info, path_info_len + 1); filename_len += path_info_len; r->path_info += path_info_len; } if (*seg_name == '/') ++seg_name; /* If nothing remained but a '/' string, we are finished */ if (!*seg_name) { break; } /* First optimization; * If...we knew r->filename was a file, and * if...we have strict (case-sensitive) filenames, or * we know the canonical_filename matches to _this_ name, and * if...we have allowed symlinks * skip the lstat and dummy up an APR_DIR value for thisinfo. */ if (r->finfo.filetype#ifdef CASE_BLIND_FILESYSTEM && (filename_len <= canonical_len)#endif && ((opts.opts & (OPT_SYM_OWNER | OPT_SYM_LINKS)) == OPT_SYM_LINKS)) { thisinfo.filetype = APR_DIR; ++seg; continue; } /* We choose apr_lstat here, rather that apr_stat, so that we * capture this path object rather than its target. We will * replace the info with our target's info below. We especially * want the name of this 'link' object, not the name of its * target, if we are fixing the filename case/resolving aliases. */ rv = apr_lstat(&thisinfo, r->filename, APR_FINFO_MIN | APR_FINFO_NAME, r->pool); if (APR_STATUS_IS_ENOENT(rv)) { /* Nothing? That could be nice. But our directory * walk is done. */ thisinfo.filetype = APR_NOFILE; break; } else if (APR_STATUS_IS_EACCES(rv)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "access to %s denied", r->uri); return r->status = HTTP_FORBIDDEN; } else if ((rv != APR_SUCCESS && rv != APR_INCOMPLETE) || !(thisinfo.valid & APR_FINFO_TYPE)) { /* If we hit ENOTDIR, we must have over-optimized, deny * rather than assume not found. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "access to %s failed", r->uri); return r->status = HTTP_FORBIDDEN; } /* Fix up the path now if we have a name, and they don't agree */ if ((thisinfo.valid & APR_FINFO_NAME) && strcmp(seg_name, thisinfo.name)) { /* TODO: provide users an option that an internal/external * redirect is required here? We need to walk the URI and * filename in tandem to properly correlate these. */ strcpy(seg_name, thisinfo.name); filename_len = strlen(r->filename); } if (thisinfo.filetype == APR_LNK) { /* Is this a possibly acceptable symlink? */ if ((res = resolve_symlink(r->filename, &thisinfo, opts.opts, r->pool)) != OK) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Symbolic link not allowed: %s", r->filename); return r->status = res; } } /* Ok, we are done with the link's info, test the real target */ if (thisinfo.filetype == APR_REG || thisinfo.filetype == APR_NOFILE) { /* That was fun, nothing left for us here */ break; } else if (thisinfo.filetype != APR_DIR) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Forbidden: %s doesn't point to " "a file or directory", r->filename); return r->status = HTTP_FORBIDDEN; } ++seg; } while (thisinfo.filetype == APR_DIR); /* If we have _not_ optimized, this is the time to recover * the final stat result. */ if (!r->finfo.filetype || r->finfo.filetype == APR_LNK) { r->finfo = thisinfo; } /* Now splice the saved path_info back onto any new path_info */ if (save_path_info) { if (r->path_info && *r->path_info) { r->path_info = ap_make_full_path(r->pool, r->path_info, save_path_info); } else { r->path_info = save_path_info; } } /* * Now we'll deal with the regexes, note we pick up sec_idx * where we left off (we gave up after we hit entry_core->r) */ for (; sec_idx < num_sec; ++sec_idx) { core_dir_config *entry_core; entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module); if (!entry_core->r) { continue; } if (ap_regexec(entry_core->r, r->filename, 0, NULL, REG_NOTEOL)) { continue; } /* If we haven't already continue'd above, we have a match. * * Calculate our full-context core opts & override. */ core_opts_merge(sec_ent[sec_idx], &opts); /* If we merged this same section last time, reuse it */ if (matches) { if (last_walk->matched == sec_ent[sec_idx]) { now_merged = last_walk->merged; ++last_walk; --matches; continue; } /* We fell out of sync. This is our own copy of walked, * so truncate the remaining matches and reset remaining. */ cache->walked->nelts -= matches; matches = 0; } if (now_merged) { now_merged = ap_merge_per_dir_configs(r->pool,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -