📄 mod_rewrite.c
字号:
} } else { rewritelog(r, 1, "[per-dir %s] pass through %s", dconf->directory, r->filename); return DECLINED; }}/***** Content-Handlers**** [used for redirect support]***/static int handler_redirect(request_rec *r){ /* just make sure that we are really meant! */ if (strncmp(r->filename, "redirect:", 9) != 0) { return DECLINED; } /* now do the internal redirect */ ap_internal_redirect(ap_pstrcat(r->pool, r->filename+9, r->args ? "?" : NULL, r->args, NULL), r); /* and return gracefully */ return OK;}/*** +-------------------------------------------------------+** | |** | the rewriting engine** | |** +-------------------------------------------------------+*//* * Apply a complete rule set, * i.e. a list of rewrite rules */static int apply_rewrite_list(request_rec *r, array_header *rewriterules, char *perdir){ rewriterule_entry *entries; rewriterule_entry *p; int i; int changed; int rc; int s; /* * Iterate over all existing rules */ entries = (rewriterule_entry *)rewriterules->elts; changed = 0; loop: for (i = 0; i < rewriterules->nelts; i++) { p = &entries[i]; /* * Ignore this rule on subrequests if we are explicitly * asked to do so or this is a proxy-throughput or a * forced redirect rule. */ if (r->main != NULL && (p->flags & RULEFLAG_IGNOREONSUBREQ || p->flags & RULEFLAG_PROXY || p->flags & RULEFLAG_FORCEREDIRECT )) { continue; } /* * Apply the current rule. */ rc = apply_rewrite_rule(r, p, perdir); if (rc) { /* * Indicate a change if this was not a match-only rule. */ if (rc != 2) { changed = 1; } /* * Pass-Through Feature (`RewriteRule .. .. [PT]'): * Because the Apache 1.x API is very limited we * need this hack to pass the rewritten URL to other * modules like mod_alias, mod_userdir, etc. */ if (p->flags & RULEFLAG_PASSTHROUGH) { rewritelog(r, 2, "forcing '%s' to get passed through " "to next API URI-to-filename handler", r->filename); r->filename = ap_pstrcat(r->pool, "passthrough:", r->filename, NULL); changed = 1; break; } /* * Rule has the "forbidden" flag set which means that * we stop processing and indicate this to the caller. */ if (p->flags & RULEFLAG_FORBIDDEN) { rewritelog(r, 2, "forcing '%s' to be forbidden", r->filename); r->filename = ap_pstrcat(r->pool, "forbidden:", r->filename, NULL); changed = 1; break; } /* * Rule has the "gone" flag set which means that * we stop processing and indicate this to the caller. */ if (p->flags & RULEFLAG_GONE) { rewritelog(r, 2, "forcing '%s' to be gone", r->filename); r->filename = ap_pstrcat(r->pool, "gone:", r->filename, NULL); changed = 1; break; } /* * Stop processing also on proxy pass-through and * last-rule and new-round flags. */ if (p->flags & RULEFLAG_PROXY) { break; } if (p->flags & RULEFLAG_LASTRULE) { break; } /* * On "new-round" flag we just start from the top of * the rewriting ruleset again. */ if (p->flags & RULEFLAG_NEWROUND) { goto loop; } /* * If we are forced to skip N next rules, do it now. */ if (p->skip > 0) { s = p->skip; while ( i < rewriterules->nelts && s > 0) { i++; p = &entries[i]; s--; } } } else { /* * If current rule is chained with next rule(s), * skip all this next rule(s) */ while ( i < rewriterules->nelts && p->flags & RULEFLAG_CHAIN) { i++; p = &entries[i]; } } } return changed;}/* * Apply a single(!) rewrite rule */static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, char *perdir){ char *uri; char *output; const char *vary; char newuri[MAX_STRING_LEN]; char env[MAX_STRING_LEN]; regex_t *regexp; regmatch_t regmatch[MAX_NMATCH]; backrefinfo *briRR = NULL; backrefinfo *briRC = NULL; int prefixstrip; int failed; array_header *rewriteconds; rewritecond_entry *conds; rewritecond_entry *c; int i; int rc; /* * Initialisation */ uri = r->filename; regexp = p->regexp; output = p->output; /* * Add (perhaps splitted away) PATH_INFO postfix to URL to * make sure we really match against the complete URL. */ if (perdir != NULL && r->path_info != NULL && r->path_info[0] != '\0') { rewritelog(r, 3, "[per-dir %s] add path-info postfix: %s -> %s%s", perdir, uri, uri, r->path_info); uri = ap_pstrcat(r->pool, uri, r->path_info, NULL); } /* * On per-directory context (.htaccess) strip the location * prefix from the URL to make sure patterns apply only to * the local part. Additionally indicate this special * threatment in the logfile. */ prefixstrip = 0; if (perdir != NULL) { if ( strlen(uri) >= strlen(perdir) && strncmp(uri, perdir, strlen(perdir)) == 0) { rewritelog(r, 3, "[per-dir %s] strip per-dir prefix: %s -> %s", perdir, uri, uri+strlen(perdir)); uri = uri+strlen(perdir); prefixstrip = 1; } } /* * Try to match the URI against the RewriteRule pattern * and exit immeddiately if it didn't apply. */ if (perdir == NULL) { rewritelog(r, 3, "applying pattern '%s' to uri '%s'", p->pattern, uri); } else { rewritelog(r, 3, "[per-dir %s] applying pattern '%s' to uri '%s'", perdir, p->pattern, uri); } rc = (regexec(regexp, uri, regexp->re_nsub+1, regmatch, 0) == 0); if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) || (!rc && (p->flags & RULEFLAG_NOTMATCH)) ) ) { return 0; } /* * Else create the RewriteRule `regsubinfo' structure which * holds the substitution information. */ briRR = (backrefinfo *)ap_palloc(r->pool, sizeof(backrefinfo)); if (!rc && (p->flags & RULEFLAG_NOTMATCH)) { /* empty info on negative patterns */ briRR->source = ""; briRR->nsub = 0; } else { briRR->source = ap_pstrdup(r->pool, uri); briRR->nsub = regexp->re_nsub; memcpy((void *)(briRR->regmatch), (void *)(regmatch), sizeof(regmatch)); } /* * Initiallally create the RewriteCond backrefinfo with * empty backrefinfo, i.e. not subst parts * (this one is adjusted inside apply_rewrite_cond() later!!) */ briRC = (backrefinfo *)ap_pcalloc(r->pool, sizeof(backrefinfo)); briRC->source = ""; briRC->nsub = 0; /* * Ok, we already know the pattern has matched, but we now * additionally have to check for all existing preconditions * (RewriteCond) which have to be also true. We do this at * this very late stage to avoid unnessesary checks which * would slow down the rewriting engine!! */ rewriteconds = p->rewriteconds; conds = (rewritecond_entry *)rewriteconds->elts; failed = 0; for (i = 0; i < rewriteconds->nelts; i++) { c = &conds[i]; rc = apply_rewrite_cond(r, c, perdir, briRR, briRC); if (c->flags & CONDFLAG_ORNEXT) { /* * The "OR" case */ if (rc == 0) { /* One condition is false, but another can be * still true, so we have to continue... */ ap_table_unset(r->notes, VARY_KEY_THIS); continue; } else { /* One true condition is enough in "or" case, so * skip the other conditions which are "ornext" * chained */ while ( i < rewriteconds->nelts && c->flags & CONDFLAG_ORNEXT) { i++; c = &conds[i]; } continue; } } else { /* * The "AND" case, i.e. no "or" flag, * so a single failure means total failure. */ if (rc == 0) { failed = 1; break; } } vary = ap_table_get(r->notes, VARY_KEY_THIS); if (vary != NULL) { ap_table_merge(r->notes, VARY_KEY, vary); ap_table_unset(r->notes, VARY_KEY_THIS); } } /* if any condition fails the complete rule fails */ if (failed) { ap_table_unset(r->notes, VARY_KEY); ap_table_unset(r->notes, VARY_KEY_THIS); return 0; } /* * Regardless of what we do next, we've found a match. Check to see * if any of the request header fields were involved, and add them * to the Vary field of the response. */ if ((vary = ap_table_get(r->notes, VARY_KEY)) != NULL) { ap_table_merge(r->headers_out, "Vary", vary); ap_table_unset(r->notes, VARY_KEY); } /* * If this is a pure matching rule (`RewriteRule <pat> -') * we stop processing and return immediately. The only thing * we have not to forget are the environment variables * (`RewriteRule <pat> - [E=...]') */ if (strcmp(output, "-") == 0) { for (i = 0; p->env[i] != NULL; i++) { /* 1. take the string */ ap_cpystrn(env, p->env[i], sizeof(env)); /* 2. expand $N (i.e. backrefs to RewriteRule pattern) */ expand_backref_inbuffer(r->pool, env, sizeof(env), briRR, '$'); /* 3. expand %N (i.e. backrefs to latest RewriteCond pattern) */ expand_backref_inbuffer(r->pool, env, sizeof(env), briRC, '%'); /* 4. expand %{...} (i.e. variables) */ expand_variables_inbuffer(r, env, sizeof(env)); /* 5. expand ${...} (RewriteMap lookups) */ expand_map_lookups(r, env, sizeof(env)); /* and add the variable to Apache's structures */ add_env_variable(r, env); } if (p->forced_mimetype != NULL) { if (perdir == NULL) { /* In the per-server context we can force the MIME-type * the correct way by notifying our MIME-type hook handler * to do the job when the MIME-type API stage is reached. */ rewritelog(r, 2, "remember %s to have MIME-type '%s'", r->filename, p->forced_mimetype); ap_table_setn(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR, p->forced_mimetype); } else { /* In per-directory context we operate in the Fixup API hook * which is after the MIME-type hook, so our MIME-type handler * has no chance to set r->content_type. And because we are * in the situation where no substitution takes place no
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -