mod_rewrite.c revision 86e9b54992c0b0882a00fdffbd993779735759b0
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski/* Licensed to the Apache Software Foundation (ASF) under one or more
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * contributor license agreements. See the NOTICE file distributed with
e6d40133bc9f858308654afb1262b8b483ec5922Till Mossakowski * this work for additional information regarding copyright ownership.
980f1e5f03d0c0772698ebb372fc711431dd0114Christian Maeder * The ASF licenses this file to You under the Apache License, Version 2.0
97018cf5fa25b494adffd7e9b4e87320dae6bf47Christian Maeder * (the "License"); you may not use this file except in compliance with
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * the License. You may obtain a copy of the License at
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * http://www.apache.org/licenses/LICENSE-2.0
f3a94a197960e548ecd6520bb768cb0d547457bbChristian Maeder * Unless required by applicable law or agreed to in writing, software
e6d40133bc9f858308654afb1262b8b483ec5922Till Mossakowski * distributed under the License is distributed on an "AS IS" BASIS,
679d3f541f7a9ede4079e045f7758873bb901872Till Mossakowski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10a2cf8d9887524acde19d4ea59f8fea3a7f3258Till Mossakowski * See the License for the specific language governing permissions and
10a2cf8d9887524acde19d4ea59f8fea3a7f3258Till Mossakowski * limitations under the License.
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___|
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * URL Rewriting Module
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maeder * This module uses a rule-based rewriting engine (based on a
ad270004874ce1d0697fb30d7309f180553bb315Christian Maeder * regular-expression parser) to rewrite requested URLs on the fly.
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * It supports an unlimited number of additional rule conditions (which can
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * operate on a lot of variables, even on HTTP headers) for granular
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder * matching and even external database lookups (either via plain text
67869d63d1725c79e4c07b51acd466a31932b275Christian Maeder * tables, DBM hash files or even external processes) for advanced URL
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maeder * substitution.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * It operates on the full URLs (including the PATH_INFO part) both in
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * per-server context (httpd.conf) and per-dir context (.htaccess) and even
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * can generate QUERY_STRING parts on result. The rewriting result finally
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * can lead to internal subprocessing, external request redirection or even
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * to internal proxy throughput.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * This module was originally written in April 1996 and
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * gifted exclusively to the The Apache Software Foundation in July 1997 by
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * Ralf S. Engelschall
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* XXX: Do we really need these headers? */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL;
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowskistatic const char* really_last_key = "rewrite_really_last";
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder * in order to improve performance on running production systems, you
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * may strip all rewritelog code entirely from mod_rewrite by using the
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * -DREWRITELOG_DISABLED compiler option.
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * DO NOT USE THIS OPTION FOR PUBLIC BINARY RELEASES. Otherwise YOU are
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * responsible for answering all the mod_rewrite questions out there.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* If logging is limited to APLOG_DEBUG or lower, disable rewrite log, too */
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder#define REWRITELOG_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski#define REWRITELOG_FLAGS ( APR_WRITE | APR_APPEND | APR_CREATE )
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder#else /* !REWRITELOG_DISABLED */
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski#endif /* REWRITELOG_DISABLED */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder/* remembered mime-type for [T=...] */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski#define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype"
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski#define REWRITE_FORCED_HANDLER_NOTEVAR "rewrite-forced-handler"
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski#define REDIRECT_ENVVAR_SCRIPT_URL "REDIRECT_" ENVVAR_SCRIPT_URL
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder/* return code of the rewrite rule
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder * the result may be escaped - or not
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder/* max cookie size in rfc 2109 */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder/* XXX: not used at all. We should do a check somewhere and/or cut the cookie */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* max line length (incl.\n) in text rewrite maps */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder/* buffer length for prg rewrite maps */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder/* for better readbility */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * expansion result items on the stack to save some cycles
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder * (5 == about 2 variables like "foo%{var}bar%{var}baz")
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * check that a subrequest won't cause infinite recursion
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder * either not in a subrequest, or in a subrequest
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder * and URIs aren't NULL and sub/main URIs differ
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder (r->main->uri && r->uri && strcmp(r->main->uri, r->uri)))
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * +-------------------------------------------------------+
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * | Types and Structures
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * +-------------------------------------------------------+
68138d26bcddf5e89c30206aa83ab5ec006d170dChristian Maedertypedef struct {
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder const char *datafile; /* filename for map data files */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski const char *dbmtype; /* dbm type for dbm map data files */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder const char *checkfile; /* filename to check for map existence */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder const char *cachename; /* for cached maps (txt/rnd/dbm) */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski apr_file_t *fpin; /* in file pointer for program maps */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder apr_file_t *fpout; /* out file pointer for program maps */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder apr_file_t *fperr; /* err file pointer for program maps */
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder char *(*func)(request_rec *, /* function pointer for internal maps */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder char **argv; /* argv of the external rewrite map */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder const char *dbdq; /* SQL SELECT statement for rewritemap */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder const char *checkfile2; /* filename to check for map existence
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder NULL if only one file */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* special pattern types for RewriteCond */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maedertypedef enum {
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maedertypedef struct {
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder char *input; /* Input string of RewriteCond */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder char *pattern; /* the RegExp pattern string */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder ap_regex_t *regexp; /* the precompiled regexp */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder ap_expr_info_t *expr; /* the compiled ap_expr */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder int flags; /* Flags which control the match */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder int pskip; /* back-index to display pattern */
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder/* single linked list for env vars and cookies */
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maedertypedef struct data_item {
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maedertypedef struct {
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder apr_array_header_t *rewriteconds;/* the corresponding RewriteCond entries */
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder char *pattern; /* the RegExp pattern string */
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder ap_regex_t *regexp; /* the RegExp pattern compilation */
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder char *output; /* the Substitution string */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder int flags; /* Flags which control the substitution */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder char *forced_mimetype; /* forced MIME type of substitution */
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder char *forced_handler; /* forced content handler of subst. */
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder int forced_responsecode; /* forced HTTP response status */
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder data_item *env; /* added environment variables */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder int skip; /* number of next rules to skip */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maedertypedef struct {
68138d26bcddf5e89c30206aa83ab5ec006d170dChristian Maeder apr_hash_t *rewritemaps; /* the RewriteMap entries */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder apr_array_header_t *rewriteconds; /* the RewriteCond entries (temp.) */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder apr_array_header_t *rewriterules; /* the RewriteRule entries */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski server_rec *server; /* the corresponding server indicator */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskitypedef struct {
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder apr_array_header_t *rewriteconds; /* the RewriteCond entries (temp.) */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski apr_array_header_t *rewriterules; /* the RewriteRule entries */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski char *directory; /* the directory where it applies */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder const char *baseurl; /* the base-URL where it applies */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* the (per-child) cache structures.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskitypedef struct cache {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* cached maps contain an mtime for the whole map and live in a subpool
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * of the cachep->pool. That makes it easy to forget them if necessary.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskitypedef struct {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* the regex structure for the
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * substitution of backreferences
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskitypedef struct backrefinfo {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* single linked list used for
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * variable expansion
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskitypedef struct result_list {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* context structure for variable lookup and expansion
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskitypedef struct {
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * +-------------------------------------------------------+
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * | static module data
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * +-------------------------------------------------------+
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* the global module structure */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskimodule AP_MODULE_DECLARE_DATA rewrite_module;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* rewritemap int: handler function registry */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* the cache */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* whether proxy module is available or not */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* whether random seed can be reaped */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic apr_global_mutex_t *rewrite_mapr_lock_acquire = NULL;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskiconst char *rewritemap_mutex_type = "rewrite-map";
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/* Optional functions imported from mod_ssl when loaded: */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maederstatic APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL;
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maederstatic APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL;
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maederstatic char *escape_uri(apr_pool_t *p, const char *path);
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * +-------------------------------------------------------+
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * | rewriting logfile support
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * +-------------------------------------------------------+
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic void do_rewritelog(request_rec *r, int level, char *perdir,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski const char *fmt, ...)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic void do_rewritelog(request_rec *r, int level, char *perdir,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski const char *fmt, ...)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (!APLOG_R_IS_LEVEL(r, APLOG_DEBUG + level))
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski rhost = ap_get_remote_host(r->connection, r->per_dir_config,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski for (redir=0, req=r; req->prev; req = req->prev) {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski logline = apr_psprintf(r->pool, "%s %s %s [%s/sid#%pp][rid#%pp/%s%s%s] "
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski r->user ? (*r->user ? r->user : "\"\"") : "-",
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski AP_REWRITE_LOG((uintptr_t)r, level, r->main ? 0 : 1, (char *)ap_get_server_name(r), logline);
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski ap_log_rerror(APLOG_MARK, APLOG_DEBUG + level, 0, r, "%s", logline);
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder#endif /* !REWRITELOG_DISABLED */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * +-------------------------------------------------------+
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * | URI and path functions
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * +-------------------------------------------------------+
23a9158dd8e5c7a22a44e5687ff154be3d513242Till Mossakowski/* return number of chars of the scheme (incl. '://')
23a9158dd8e5c7a22a44e5687ff154be3d513242Till Mossakowski * if the URI is absolute (includes a scheme etc.)
23a9158dd8e5c7a22a44e5687ff154be3d513242Till Mossakowski * otherwise 0.
4705cb2fe71c52457c87a64d52a915337996dc23Christian Maeder * NOTE: If you add new schemes here, please have a
23a9158dd8e5c7a22a44e5687ff154be3d513242Till Mossakowski * look at escape_absolute_uri and splitout_queryargs.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * Not every scheme takes query strings and some schemes
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * may be handled in a special way.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * XXX: we may consider a scheme registry, perhaps with
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * appropriate escape callbacks to allow other modules
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * to extend mod_rewrite at runtime.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* fast exit */
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder switch (*uri++) {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (!strncasecmp(uri, "jp://", 5)) { /* ajp:// */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (!strncasecmp(uri, "alancer://", 10)) { /* balancer:// */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (!strncasecmp(uri, "tp://", 5)) { /* ftp:// */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder if (!strncasecmp(uri, "cgi://", 6)) { /* fcgi:// */
71a47e569372797d9c63c49cd43ca65361c9616fChristian Maeder if (!strncasecmp(uri, "opher://", 8)) { /* gopher:// */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (!strncasecmp(uri, "ttp://", 6)) { /* http:// */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski else if (!strncasecmp(uri, "ttps://", 7)) { /* https:// */
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder if (!strncasecmp(uri, "dap://", 6)) { /* ldap:// */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (!strncasecmp(uri, "ailto:", 6)) { /* mailto: */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (!strncasecmp(uri, "ews:", 4)) { /* news: */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski else if (!strncasecmp(uri, "ntp://", 6)) { /* nntp:// */
0e2ae85e2453466d03c1fc5884a3d693235bb9d9Christian Maeder if (!strncasecmp(uri, "cgi://", 6)) { /* scgi:// */
4601edb679f0ba530bbb085b25d82a411cd070aaChristian Maederstatic const char c2x_table[] = "0123456789abcdef";
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maederstatic APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski unsigned char *where)
73d1e87b6a3b0f95cc16b1d377fa1bcf379702efChristian Maeder what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
73d1e87b6a3b0f95cc16b1d377fa1bcf379702efChristian Maeder#endif /*APR_CHARSET_EBCDIC*/
a31f8ee3b25a6c24e032d95a615c1cbab0e2f556Christian Maeder * Escapes a uri in a similar way as php's urlencode does.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * Based on ap_os_escape_path in server/util.c
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic char *escape_uri(apr_pool_t *p, const char *path) {
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder char *copy = apr_palloc(p, 3 * strlen(path) + 3);
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski const unsigned char *s = (const unsigned char *)path;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski unsigned char *d = (unsigned char *)copy;
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maeder while ((c = *s)) {
73d1e87b6a3b0f95cc16b1d377fa1bcf379702efChristian Maeder else if (c == ' ') {
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * escape absolute uri, which may or may not be path oriented.
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * So let's handle them differently.
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maederstatic char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme)
f69658e57cba7ecb37c0d84181f4c563215c2534Till Mossakowski * NULL should indicate elsewhere, that something's wrong
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* scheme with authority part? */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder /* skip host part */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder /* nothing after the hostpart. ready! */
980f1e5f03d0c0772698ebb372fc711431dd0114Christian Maeder /* remember the hostname stuff */
980f1e5f03d0c0772698ebb372fc711431dd0114Christian Maeder /* special thing for ldap.
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * The parts are separated by question marks. From RFC 2255:
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maeder * ldapurl = scheme "://" [hostport] ["/"
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * [dn ["?" [attributes] ["?" [scope]
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maeder * ["?" [filter] ["?" extensions]]]]]]
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder return apr_pstrcat(p, apr_pstrndup(p, uri, scheme),
980f1e5f03d0c0772698ebb372fc711431dd0114Christian Maeder (c >= 1) ? ap_escape_uri(p, token[1]) : NULL,
980f1e5f03d0c0772698ebb372fc711431dd0114Christian Maeder (c >= 2) ? ap_escape_uri(p, token[2]) : NULL,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski (c >= 3) ? ap_escape_uri(p, token[3]) : NULL,
980f1e5f03d0c0772698ebb372fc711431dd0114Christian Maeder (c >= 4) ? ap_escape_uri(p, token[4]) : NULL,
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder /* Nothing special here. Apply normal escaping. */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder return apr_pstrcat(p, apr_pstrndup(p, uri, scheme),
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * split out a QUERY_STRING part from
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * the current URI string
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* don't touch, unless it's an http or mailto URL.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * See RFC 1738 and RFC 2368.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski && strncasecmp(r->filename, "mailto", 6)) {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski r->args = NULL; /* forget the query that's still flying around */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski rewritelog((r, 2, NULL, "discarding query string"));
03136b84a0c70d877e227444f0875e209506b9e4Christian Maeder olduri = apr_pstrdup(r->pool, r->filename);
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder r->args = apr_pstrcat(r->pool, q, "&", r->args, NULL);
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski rewritelog((r, 3, NULL, "split uri=%s -> uri=%s, args=%s", olduri,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski r->filename, r->args ? r->args : "<none>"));
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * strip 'http[s]://ourhost/' from URI
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski unsigned short port;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski scratch = apr_pstrdup(r->pool, r->filename); /* our scratchpad */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* cut the hostname and port out of the URI */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski cp = host = scratch + l + 3; /* 3 == strlen("://") */
0e2ae85e2453466d03c1fc5884a3d693235bb9d9Christian Maeder if (*cp == ':') { /* additional port given */
0e2ae85e2453466d03c1fc5884a3d693235bb9d9Christian Maeder /* now check whether we could reduce it to a local path... */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder if (ap_matches_request_vhost(r, host, port)) {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski rewritelog((r, 3, NULL, "reduce %s -> %s", r->filename, url));
const char *thisserver;
char *thisport;
int port;
r->filename);
const char *root;
const char *slash;
char *statpath;
const char *subst)
--len;
char *output;
++slen;
output));
return output;
return input;
char *val)
if (cachep) {
#if APR_HAS_THREADS
if (!map) {
apr_pool_t *p;
#if APR_HAS_THREADS
#if APR_HAS_THREADS
apr_pool_t *p)
if (cachep) {
#if APR_HAS_THREADS
if (map) {
if (val) {
#if APR_HAS_THREADS
return val;
#if APR_HAS_THREADS
for (p = key; *p; ++p) {
*p = apr_toupper(*p);
return key;
return key;
return key;
char *p = value;
if (!rewrite_rand_init_done) {
++value;
return value;
const char *desc)
procattr, p);
if (fpin) {
if (fpout) {
return (rc);
return APR_SUCCESS;
void *val;
return rc;
return APR_SUCCESS;
return NULL;
p = line;
c = key;
while (*p && apr_isspace(*p)) {
while (*p && !apr_isspace(*p)) {
return value;
char *value;
return NULL;
return value;
const char *errmsg;
if (rv != 0) {
return NULL;
return NULL;
char *buf;
int found_nl = 0;
#ifndef NO_WRITEV
return NULL;
if (rewrite_mapr_lock_acquire) {
#ifdef NO_WRITEV
--eolc;
if (i < eolc) {
i -= eolc;
++found_nl;
else if (eolc) {
eolc = 0;
++found_nl;
buf[i++] = c;
if (!buflist) {
combined_len += i;
if (buflist) {
while (buflist) {
i = combined_len;
if (rewrite_mapr_lock_acquire) {
return NULL;
return buf;
rewritemap_entry *s;
char *value;
return NULL;
switch (s->type) {
case MAPTYPE_RND:
case MAPTYPE_TXT:
s->checkfile);
return NULL;
if (!value) {
if (!value) {
return NULL;
case MAPTYPE_DBM:
s->checkfile);
return NULL;
if (!value) {
if (!value) {
return NULL;
return value;
case MAPTYPE_DBD:
if (!value) {
return NULL;
return value;
case MAPTYPE_DBD_CACHE:
if (!value) {
if (!value) {
return NULL;
return value;
case MAPTYPE_PRG:
if (!value) {
key));
return NULL;
return value;
case MAPTYPE_INT:
if (!value) {
key));
return NULL;
return value;
return NULL;
if (val) {
return val;
const char *result;
if (!result) {
if (!result) {
const char *path;
ctx->r = r;
return (char *)result;
NULL);
ctx->r = r;
return (char *)result;
for (p = var; *p; ++p) {
*p = apr_toupper(*p);
switch (varlen) {
return (char *)result;
#if APR_HAVE_IPV6
r->pool);
r->pool);
unsigned depth;
else if (*s == LEFT_CURLY) {
++depth;
return NULL;
unsigned depth;
return NULL;
else if (*s == LEFT_CURLY) {
++depth;
return NULL;
unsigned spc = 0;
sizeof(result_list));
++outlen;
char *endp;
if (!endp) {
char *key;
if (!key) {
if (dflt) {
if (key) {
++outlen;
sizeof(result_list));
p += span;
} while (result);
while (env) {
name++;
char *var;
char *val;
char *domain;
char *expires;
char *path;
char *secure;
char *httponly;
char *tok_cntx;
char *cookie;
char *notename;
void *data;
if (!data) {
if (expires) {
long exp_min;
if (exp_min) {
: NULL,
: NULL,
NULL);
var));
while (cookie) {
#if APR_HAS_USER
char *p, *user;
if (p > user) {
char *homedir;
return homedir;
return uri;
return rc;
return APR_SUCCESS;
if (rewrite_mapr_lock_acquire) {
char quote;
++str;
++str;
if (!*str) {
++str;
++str;
if (!*str) {
++str;
if (!*str) {
++str;
a->server = s;
sizeof(rewrite_server_conf));
sizeof(rewrite_perdir_conf));
return NULL;
int options = 0;
while (*option) {
return NULL;
const char *a2)
const char *fname;
if (colon) {
if (!fname) {
return NULL;
const char *a1)
return NULL;
const char *err;
++key;
while (*key) {
++key;
--endp;
if (val) {
if (err) {
return err;
return NULL;
return NULL;
const char *in_str)
char *a1;
char *a2;
char *a3;
const char *err;
++a2;
switch (*a2) {
? AP_REG_ICASE : 0));
if (!regexp) {
if (err)
return NULL;
int error = 0;
switch (*key++) {
++error;
if (!cp) {
++error;
if (!cp) {
++error;
++error;
++error;
++error;
++error;
++error;
++error;
++error;
int status = 0;
if (*val) {
int idx =
val);
++error;
++error;
++error;
++error;
if (error) {
return NULL;
const char *in_str)
char *a1;
char *a2;
char *a3;
const char *err;
++a1;
? AP_REG_ICASE : 0));
if (!regexp) {
sizeof(rewritecond_entry));
sizeof(rewritecond_entry));
return NULL;
for (i = 0; i < lena; ++i) {
int rc = 0;
int basis;
switch (p->ptype) {
case CONDPAT_FILE_EXISTS:
case CONDPAT_FILE_SIZE:
case CONDPAT_FILE_LINK:
#if !defined(OS2)
case CONDPAT_FILE_DIR:
case CONDPAT_FILE_XBIT:
case CONDPAT_LU_URL:
case CONDPAT_LU_FILE:
case CONDPAT_STR_GE:
basis = 0;
goto test_str_g;
case CONDPAT_STR_GT:
case CONDPAT_STR_LE:
basis = 0;
goto test_str_l;
case CONDPAT_STR_LT:
case CONDPAT_STR_EQ:
case CONDPAT_AP_EXPR:
rc = 0;
return rc;
char *expanded;
if (p->forced_mimetype) {
if (*expanded) {
expanded);
if (p->forced_handler) {
if (*expanded) {
expanded);
int i, rc;
int is_proxyreq = 0;
if (!rc) {
c = &conds[++i];
else if (!rc) {
NULL)
newuri));
r->filename));
r->filename));
reduce_uri(r);
char *perdir)
int changed;
int rc;
ctx->r = r;
changed = 0;
loop:
p = &entries[i];
if (rc) {
return ACTION_STATUS;
goto loop;
if (p->skip > 0) {
s = p->skip;
p = &entries[i];
return changed;
if (map_pfn_register) {
return OK;
server_rec *s)
return HTTP_INTERNAL_SERVER_ERROR;
for (; s; s = s->next) {
return HTTP_INTERNAL_SERVER_ERROR;
return OK;
if (rewrite_mapr_lock_acquire) {
if (!init_cache(p)) {
const char *saved_rulestatus;
const char *var;
const char *thisserver;
char *thisport;
const char *thisurl;
unsigned int port;
int rulestatus;
void *skipdata;
return DECLINED;
return DECLINED;
return DECLINED;
r->filename));
if (rulestatus) {
unsigned skip;
int n = r->status;
if (!proxy_available) {
return HTTP_FORBIDDEN;
r->filename));
return OK;
r->filename));
if (r->args) {
? r->args
NULL);
n = r->status;
return DECLINED;
#if APR_HAS_USER
return HTTP_BAD_REQUEST;
int res;
return res;
r->filename));
return OK;
return DECLINED;
char *cp;
char *cp2;
const char *ccp;
apr_size_t l;
int rulestatus;
int is_proxyreq;
void *skipdata;
return DECLINED;
return DECLINED;
return DECLINED;
* URL: http://localhost/foo and .htaccess is located in foo directory
if (!is_proxyreq) {
return DECLINED;
return DECLINED;
return HTTP_FORBIDDEN;
if (rulestatus) {
unsigned skip;
int n = r->status;
return OK;
* hostname and compare/substitute only the stuff after it.
r->filename));
if (r->args) {
? r->args
NULL);
r->args ,
n = r->status;
r->filename, n));
return HTTP_BAD_REQUEST;
return OK;
r->filename+l));
return OK;
return DECLINED;
r->filename, t));
ap_set_content_type(r, t);
r->handler = t;
return OK;
return DECLINED;
return DECLINED;
return OK;
{ NULL }