📄 mod_rewrite.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. *//* _ _ _ * _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___ * | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \ * | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/ * |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___| * |_____| * * URL Rewriting Module * * This module uses a rule-based rewriting engine (based on a * regular-expression parser) to rewrite requested URLs on the fly. * * It supports an unlimited number of additional rule conditions (which can * operate on a lot of variables, even on HTTP headers) for granular * matching and even external database lookups (either via plain text * tables, DBM hash files or even external processes) for advanced URL * substitution. * * It operates on the full URLs (including the PATH_INFO part) both in * per-server context (httpd.conf) and per-dir context (.htaccess) and even * can generate QUERY_STRING parts on result. The rewriting result finally * can lead to internal subprocessing, external request redirection or even * to internal proxy throughput. * * This module was originally written in April 1996 and * gifted exclusively to the The Apache Software Foundation in July 1997 by * * Ralf S. Engelschall * rse engelschall.com * www.engelschall.com */#include "apr.h"#include "apr_strings.h"#include "apr_hash.h"#include "apr_user.h"#include "apr_lib.h"#include "apr_signal.h"#include "apr_global_mutex.h"#include "apr_dbm.h"#if APR_HAS_THREADS#include "apr_thread_mutex.h"#endif#define APR_WANT_MEMFUNC#define APR_WANT_STRFUNC#define APR_WANT_IOVEC#include "apr_want.h"/* XXX: Do we really need these headers? */#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#if APR_HAVE_SYS_TYPES_H#include <sys/types.h>#endif#if APR_HAVE_STDARG_H#include <stdarg.h>#endif#if APR_HAVE_STDLIB_H#include <stdlib.h>#endif#if APR_HAVE_CTYPE_H#include <ctype.h>#endif#include "ap_config.h"#include "httpd.h"#include "http_config.h"#include "http_request.h"#include "http_core.h"#include "http_log.h"#include "http_protocol.h"#include "http_vhost.h"#include "mod_ssl.h"#include "mod_rewrite.h"#ifdef AP_NEED_SET_MUTEX_PERMS#include "unixd.h"#endif/* * in order to improve performance on running production systems, you * may strip all rewritelog code entirely from mod_rewrite by using the * -DREWRITELOG_DISABLED compiler option. * * DO NOT USE THIS OPTION FOR PUBLIC BINARY RELEASES. Otherwise YOU are * responsible for answering all the mod_rewrite questions out there. */#ifndef REWRITELOG_DISABLED#define rewritelog(x) do_rewritelog x#define REWRITELOG_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )#define REWRITELOG_FLAGS ( APR_WRITE | APR_APPEND | APR_CREATE )#else /* !REWRITELOG_DISABLED */#define rewritelog(x)#endif /* REWRITELOG_DISABLED *//* remembered mime-type for [T=...] */#define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype"#define REWRITE_FORCED_HANDLER_NOTEVAR "rewrite-forced-handler"#define ENVVAR_SCRIPT_URL "SCRIPT_URL"#define REDIRECT_ENVVAR_SCRIPT_URL "REDIRECT_" ENVVAR_SCRIPT_URL#define ENVVAR_SCRIPT_URI "SCRIPT_URI"#define CONDFLAG_NONE 1<<0#define CONDFLAG_NOCASE 1<<1#define CONDFLAG_NOTMATCH 1<<2#define CONDFLAG_ORNEXT 1<<3#define CONDFLAG_NOVARY 1<<4#define RULEFLAG_NONE 1<<0#define RULEFLAG_FORCEREDIRECT 1<<1#define RULEFLAG_LASTRULE 1<<2#define RULEFLAG_NEWROUND 1<<3#define RULEFLAG_CHAIN 1<<4#define RULEFLAG_IGNOREONSUBREQ 1<<5#define RULEFLAG_NOTMATCH 1<<6#define RULEFLAG_PROXY 1<<7#define RULEFLAG_PASSTHROUGH 1<<8#define RULEFLAG_QSAPPEND 1<<9#define RULEFLAG_NOCASE 1<<10#define RULEFLAG_NOESCAPE 1<<11#define RULEFLAG_NOSUB 1<<12#define RULEFLAG_STATUS 1<<13#define RULEFLAG_ESCAPEBACKREF 1<<14/* return code of the rewrite rule * the result may be escaped - or not */#define ACTION_NORMAL 1<<0#define ACTION_NOESCAPE 1<<1#define ACTION_STATUS 1<<2#define MAPTYPE_TXT 1<<0#define MAPTYPE_DBM 1<<1#define MAPTYPE_PRG 1<<2#define MAPTYPE_INT 1<<3#define MAPTYPE_RND 1<<4#define ENGINE_DISABLED 1<<0#define ENGINE_ENABLED 1<<1#define OPTION_NONE 1<<0#define OPTION_INHERIT 1<<1#ifndef RAND_MAX#define RAND_MAX 32767#endif/* max cookie size in rfc 2109 *//* XXX: not used at all. We should do a check somewhere and/or cut the cookie */#define MAX_COOKIE_LEN 4096/* max line length (incl.\n) in text rewrite maps */#ifndef REWRITE_MAX_TXT_MAP_LINE#define REWRITE_MAX_TXT_MAP_LINE 1024#endif/* buffer length for prg rewrite maps */#ifndef REWRITE_PRG_MAP_BUF#define REWRITE_PRG_MAP_BUF 1024#endif/* for better readbility */#define LEFT_CURLY '{'#define RIGHT_CURLY '}'/* * expansion result items on the stack to save some cycles * * (5 == about 2 variables like "foo%{var}bar%{var}baz") */#define SMALL_EXPANSION 5/* * check that a subrequest won't cause infinite recursion * * either not in a subrequest, or in a subrequest * and URIs aren't NULL and sub/main URIs differ */#define subreq_ok(r) (!r->main || \ (r->main->uri && r->uri && strcmp(r->main->uri, r->uri)))/* * +-------------------------------------------------------+ * | | * | Types and Structures * | | * +-------------------------------------------------------+ */typedef struct { const char *datafile; /* filename for map data files */ const char *dbmtype; /* dbm type for dbm map data files */ const char *checkfile; /* filename to check for map existence */ const char *cachename; /* for cached maps (txt/rnd/dbm) */ int type; /* the type of the map */ apr_file_t *fpin; /* in file pointer for program maps */ apr_file_t *fpout; /* out file pointer for program maps */ apr_file_t *fperr; /* err file pointer for program maps */ char *(*func)(request_rec *, /* function pointer for internal maps */ char *); char **argv; /* argv of the external rewrite map */ const char *checkfile2; /* filename to check for map existence NULL if only one file */} rewritemap_entry;/* special pattern types for RewriteCond */typedef enum { CONDPAT_REGEX = 0, CONDPAT_FILE_EXISTS, CONDPAT_FILE_SIZE, CONDPAT_FILE_LINK, CONDPAT_FILE_DIR, CONDPAT_FILE_XBIT, CONDPAT_LU_URL, CONDPAT_LU_FILE, CONDPAT_STR_GT, CONDPAT_STR_LT, CONDPAT_STR_EQ} pattern_type;typedef struct { char *input; /* Input string of RewriteCond */ char *pattern; /* the RegExp pattern string */ ap_regex_t *regexp; /* the precompiled regexp */ int flags; /* Flags which control the match */ pattern_type ptype; /* pattern type */} rewritecond_entry;/* single linked list for env vars and cookies */typedef struct data_item { struct data_item *next; char *data;} data_item;typedef struct { apr_array_header_t *rewriteconds;/* the corresponding RewriteCond entries */ char *pattern; /* the RegExp pattern string */ ap_regex_t *regexp; /* the RegExp pattern compilation */ char *output; /* the Substitution string */ int flags; /* Flags which control the substitution */ char *forced_mimetype; /* forced MIME type of substitution */ char *forced_handler; /* forced content handler of subst. */ int forced_responsecode; /* forced HTTP response status */ data_item *env; /* added environment variables */ data_item *cookie; /* added cookies */ int skip; /* number of next rules to skip */} rewriterule_entry;typedef struct { int state; /* the RewriteEngine state */ int options; /* the RewriteOption state */#ifndef REWRITELOG_DISABLED const char *rewritelogfile; /* the RewriteLog filename */ apr_file_t *rewritelogfp; /* the RewriteLog open filepointer */ int rewriteloglevel; /* the RewriteLog level of verbosity */#endif apr_hash_t *rewritemaps; /* the RewriteMap entries */ apr_array_header_t *rewriteconds; /* the RewriteCond entries (temp.) */ apr_array_header_t *rewriterules; /* the RewriteRule entries */ server_rec *server; /* the corresponding server indicator */} rewrite_server_conf;typedef struct { int state; /* the RewriteEngine state */ int options; /* the RewriteOption state */ apr_array_header_t *rewriteconds; /* the RewriteCond entries (temp.) */ apr_array_header_t *rewriterules; /* the RewriteRule entries */ char *directory; /* the directory where it applies */ const char *baseurl; /* the base-URL where it applies */} rewrite_perdir_conf;/* the (per-child) cache structures. */typedef struct cache { apr_pool_t *pool; apr_hash_t *maps;#if APR_HAS_THREADS apr_thread_mutex_t *lock;#endif} cache;/* cached maps contain an mtime for the whole map and live in a subpool * of the cachep->pool. That makes it easy to forget them if necessary. */typedef struct { apr_time_t mtime; apr_pool_t *pool; apr_hash_t *entries;} cachedmap;/* the regex structure for the * substitution of backreferences */typedef struct backrefinfo { char *source; int nsub; ap_regmatch_t regmatch[AP_MAX_REG_MATCH];} backrefinfo;/* single linked list used for * variable expansion */typedef struct result_list { struct result_list *next; apr_size_t len; const char *string;} result_list;/* context structure for variable lookup and expansion */typedef struct { request_rec *r; const char *uri; const char *vary_this; const char *vary; char *perdir; backrefinfo briRR; backrefinfo briRC;} rewrite_ctx;/* * +-------------------------------------------------------+ * | | * | static module data * | | * +-------------------------------------------------------+ *//* the global module structure */module AP_MODULE_DECLARE_DATA rewrite_module;/* rewritemap int: handler function registry */static apr_hash_t *mapfunc_hash;/* the cache */static cache *cachep;/* whether proxy module is available or not */static int proxy_available;/* whether random seed can be reaped */static int rewrite_rand_init_done = 0;/* Locks/Mutexes */static const char *lockname;static apr_global_mutex_t *rewrite_mapr_lock_acquire = NULL;#ifndef REWRITELOG_DISABLEDstatic apr_global_mutex_t *rewrite_log_lock = NULL;#endif/* Optional functions imported from mod_ssl when loaded: */static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL;static APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL;/* * +-------------------------------------------------------+ * | | * | rewriting logfile support * | | * +-------------------------------------------------------+ */#ifndef REWRITELOG_DISABLEDstatic char *current_logtime(request_rec *r){ apr_time_exp_t t; char tstr[80]; apr_size_t len; apr_time_exp_lt(&t, apr_time_now()); apr_strftime(tstr, &len, sizeof(tstr), "[%d/%b/%Y:%H:%M:%S ", &t); apr_snprintf(tstr+len, sizeof(tstr)-len, "%c%.2d%.2d]", t.tm_gmtoff < 0 ? '-' : '+', t.tm_gmtoff / (60*60), t.tm_gmtoff % (60*60)); return apr_pstrdup(r->pool, tstr);}static int open_rewritelog(server_rec *s, apr_pool_t *p){ rewrite_server_conf *conf; const char *fname; conf = ap_get_module_config(s->module_config, &rewrite_module); /* - no logfile configured * - logfilename empty * - virtual log shared w/ main server */ if (!conf->rewritelogfile || !*conf->rewritelogfile || conf->rewritelogfp) { return 1; } if (*conf->rewritelogfile == '|') { piped_log *pl; fname = ap_server_root_relative(p, conf->rewritelogfile+1); if (!fname) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, "mod_rewrite: Invalid RewriteLog " "path %s", conf->rewritelogfile+1); return 0; } if ((pl = ap_open_piped_log(p, fname)) == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_rewrite: could not open reliable pipe " "to RewriteLog filter %s", fname);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -