📄 mod_rewrite.c
字号:
/* append the QUERY_STRING part */ if (r->args) { r->filename = apr_pstrcat(r->pool, r->filename, "?", (rulestatus == ACTION_NOESCAPE) ? r->args : ap_escape_uri(r->pool, r->args), NULL); } /* determine HTTP redirect response code */ if (ap_is_HTTP_REDIRECT(r->status)) { n = r->status; r->status = HTTP_OK; /* make Apache kernel happy */ } else { n = HTTP_MOVED_TEMPORARILY; } /* now do the redirection */ apr_table_setn(r->headers_out, "Location", r->filename); rewritelog(r, 1, "[per-dir %s] redirect to %s [REDIRECT/%d]", dconf->directory, r->filename, n); return n; } else if (strlen(r->filename) > 10 && strncmp(r->filename, "forbidden:", 10) == 0) { /* This URL is forced to be forbidden for the requester */ return HTTP_FORBIDDEN; } else if (strlen(r->filename) > 5 && strncmp(r->filename, "gone:", 5) == 0) { /* This URL is forced to be gone */ return HTTP_GONE; } else { /* it was finally rewritten to a local path */ /* if someone used the PASSTHROUGH flag in per-dir * context we just ignore it. It is only useful * in per-server context */ if (strlen(r->filename) > 12 && strncmp(r->filename, "passthrough:", 12) == 0) { r->filename = apr_pstrdup(r->pool, r->filename+12); } /* the filename must be either an absolute local path or an * absolute local URL. */ if ( *r->filename != '/' && !ap_os_is_path_absolute(r->pool, r->filename)) { return HTTP_BAD_REQUEST; } /* Check for deadlooping: * At this point we KNOW that at least one rewriting * rule was applied, but when the resulting URL is * the same as the initial URL, we are not allowed to * use the following internal redirection stuff because * this would lead to a deadloop. */ if (ofilename != NULL && strcmp(r->filename, ofilename) == 0) { rewritelog(r, 1, "[per-dir %s] initial URL equal rewritten " "URL: %s [IGNORING REWRITE]", dconf->directory, r->filename); return OK; } /* if there is a valid base-URL then substitute * the per-dir prefix with this base-URL if the * current filename still is inside this per-dir * context. If not then treat the result as a * plain URL */ if (dconf->baseurl != NULL) { rewritelog(r, 2, "[per-dir %s] trying to replace prefix %s with %s", dconf->directory, dconf->directory, dconf->baseurl); r->filename = subst_prefix_path(r, r->filename, dconf->directory, dconf->baseurl); } else { /* if no explicit base-URL exists we assume * that the directory prefix is also a valid URL * for this webserver and only try to remove the * document_root if it is prefix */ if ((ccp = ap_document_root(r)) != NULL) { prefix = apr_pstrdup(r->pool, ccp); /* always NOT have a trailing slash */ l = strlen(prefix); if (prefix[l-1] == '/') { prefix[l-1] = '\0'; l--; } if (strncmp(r->filename, prefix, l) == 0) { rewritelog(r, 2, "[per-dir %s] strip document_root " "prefix: %s -> %s", dconf->directory, r->filename, r->filename+l); r->filename = apr_pstrdup(r->pool, r->filename+l); } } } /* now initiate the internal redirect */ rewritelog(r, 1, "[per-dir %s] internal redirect with %s " "[INTERNAL REDIRECT]", dconf->directory, r->filename); r->filename = apr_pstrcat(r->pool, "redirect:", r->filename, NULL); r->handler = "redirect-handler"; return OK; } } else { rewritelog(r, 1, "[per-dir %s] pass through %s", dconf->directory, r->filename); r->filename = ofilename; return DECLINED; }}/***** Content-Handlers**** [used for redirect support]***/static int handler_redirect(request_rec *r){ if (strcmp(r->handler, "redirect-handler")) { return DECLINED; } /* 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, 0, 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(apr_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 = apr_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, 0, 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, apr_array_header_t *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 = apr_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 = apr_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 = apr_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 failed; apr_array_header_t *rewriteconds; rewritecond_entry *conds; rewritecond_entry *c; int i; int rc; int is_proxyreq = 0; /* * 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_in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -