mod_rewrite.c
来自「apache 安装教程 apache 安装教程」· C语言 代码 · 共 1,959 行 · 第 1/5 页
C
1,959 行
**** [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; } if (is_redirect_limit_exceeded(r)) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, "mod_rewrite: maximum number of internal redirects " "reached. Assuming configuration error. Use " "'RewriteOptions MaxRedirects' to increase the limit " "if neccessary."); return HTTP_INTERNAL_SERVER_ERROR; } /* 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;}/* * check whether redirect limit is reached */static int is_redirect_limit_exceeded(request_rec *r){ request_rec *top = r; rewrite_request_conf *reqc; rewrite_perdir_conf *dconf; /* we store it in the top request */ while (top->main) { top = top->main; } while (top->prev) { top = top->prev; } /* fetch our config */ reqc = (rewrite_request_conf *) ap_get_module_config(top->request_config, &rewrite_module); /* no config there? create one. */ if (!reqc) { rewrite_server_conf *sconf; reqc = ap_palloc(top->pool, sizeof(rewrite_request_conf)); sconf = ap_get_module_config(r->server->module_config, &rewrite_module); reqc->redirects = 0; reqc->redirect_limit = sconf->redirect_limit ? sconf->redirect_limit : REWRITE_REDIRECT_LIMIT; /* associate it with this request */ ap_set_module_config(top->request_config, &rewrite_module, reqc); } /* allow to change the limit during redirects. */ dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config, &rewrite_module); /* 0 == unset; take server conf ... */ if (dconf->redirect_limit) { reqc->redirect_limit = dconf->redirect_limit; } ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r, "mod_rewrite's internal redirect status: %d/%d.", reqc->redirects, reqc->redirect_limit); /* and now give the caller a hint */ return (reqc->redirects++ >= reqc->redirect_limit);}/*** +-------------------------------------------------------+** | |** | 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 = ((p->flags & RULEFLAG_NOESCAPE) ? ACTION_NOESCAPE : ACTION_NORMAL); } /* * 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 = ACTION_NORMAL; 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 = ACTION_NORMAL; 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 = ACTION_NORMAL; 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]; regex_t *regexp; regmatch_t regmatch[AP_MAX_REG_MATCH]; 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 = (ap_regexec(regexp, uri, AP_MAX_REG_MATCH, 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, VA
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?