#include "httpd.h"
#include "http_config.h"
typedef
struct
{
char
*real;
char
*fake;
char
*handler;
regex_t *regexp;
int
redir_status;
} alias_entry;
typedef
struct
{
array_header *aliases;
array_header *redirects;
} alias_server_conf;
typedef
struct
{
array_header *redirects;
} alias_dir_conf;
module MODULE_VAR_EXPORT alias_module;
static
void
*create_alias_config(pool *p, server_rec *s)
{
alias_server_conf *a =
(alias_server_conf *) ap_pcalloc(p,
sizeof
(alias_server_conf));
a->aliases = ap_make_array(p, 20,
sizeof
(alias_entry));
a->redirects = ap_make_array(p, 20,
sizeof
(alias_entry));
return
a;
}
static
void
*create_alias_dir_config(pool *p,
char
*d)
{
alias_dir_conf *a =
(alias_dir_conf *) ap_pcalloc(p,
sizeof
(alias_dir_conf));
a->redirects = ap_make_array(p, 2,
sizeof
(alias_entry));
return
a;
}
static
void
*merge_alias_config(pool *p,
void
*basev,
void
*overridesv)
{
alias_server_conf *a =
(alias_server_conf *) ap_pcalloc(p,
sizeof
(alias_server_conf));
alias_server_conf *base = (alias_server_conf *) basev, *overrides = (alias_server_conf *) overridesv;
a->aliases = ap_append_arrays(p, overrides->aliases, base->aliases);
a->redirects = ap_append_arrays(p, overrides->redirects, base->redirects);
return
a;
}
static
void
*merge_alias_dir_config(pool *p,
void
*basev,
void
*overridesv)
{
alias_dir_conf *a =
(alias_dir_conf *) ap_pcalloc(p,
sizeof
(alias_dir_conf));
alias_dir_conf *base = (alias_dir_conf *) basev, *overrides = (alias_dir_conf *) overridesv;
a->redirects = ap_append_arrays(p, overrides->redirects, base->redirects);
return
a;
}
static
const
char
*add_alias_internal(cmd_parms *cmd,
void
*dummy,
char
*f,
char
*r,
int
use_regex)
{
server_rec *s = cmd->server;
alias_server_conf *conf =
(alias_server_conf *) ap_get_module_config(s->module_config, &alias_module);
alias_entry *
new
= ap_push_array(conf->aliases);
if
(use_regex) {
new
->regexp = ap_pregcomp(cmd->pool, f, REG_EXTENDED);
if
(
new
->regexp == NULL)
return
"Regular expression could not be compiled."
;
new
->real = r;
}
#ifndef OS2
else
new
->real = ap_os_canonical_filename(cmd->pool, r);
#else
new
->real = r;
#endif
new
->fake = f;
new
->handler = cmd->info;
return
NULL;
}
static
const
char
*add_alias(cmd_parms *cmd,
void
*dummy,
char
*f,
char
*r)
{
return
add_alias_internal(cmd, dummy, f, r, 0);
}
static
const
char
*add_alias_regex(cmd_parms *cmd,
void
*dummy,
char
*f,
char
*r)
{
return
add_alias_internal(cmd, dummy, f, r, 1);
}
static
const
char
*add_redirect_internal(cmd_parms *cmd, alias_dir_conf * dirconf,
char
*arg1,
char
*arg2,
char
*arg3,
int
use_regex)
{
alias_entry *
new
;
server_rec *s = cmd->server;
alias_server_conf *serverconf =
(alias_server_conf *) ap_get_module_config(s->module_config, &alias_module);
int
status = (
int
) (
long
) cmd->info;
regex_t *r = NULL;
char
*f = arg2;
char
*url = arg3;
if
(!strcasecmp(arg1,
"gone"
))
status = HTTP_GONE;
else
if
(!strcasecmp(arg1,
"permanent"
))
status = HTTP_MOVED_PERMANENTLY;
else
if
(!strcasecmp(arg1,
"temp"
))
status = HTTP_MOVED_TEMPORARILY;
else
if
(!strcasecmp(arg1,
"seeother"
))
status = HTTP_SEE_OTHER;
else
if
(ap_isdigit(*arg1))
status =
atoi
(arg1);
else
{
f = arg1;
url = arg2;
}
if
(use_regex) {
r = ap_pregcomp(cmd->pool, f, REG_EXTENDED);
if
(r == NULL)
return
"Regular expression could not be compiled."
;
}
if
(ap_is_HTTP_REDIRECT(status)) {
if
(!url)
return
"URL to redirect to is missing"
;
if
(!use_regex && !ap_is_url(url))
return
"Redirect to non-URL"
;
}
else
{
if
(url)
return
"Redirect URL not valid for this status"
;
}
if
(cmd->path)
new
= ap_push_array(dirconf->redirects);
else
new
= ap_push_array(serverconf->redirects);
new
->fake = f;
new
->real = url;
new
->regexp = r;
new
->redir_status = status;
return
NULL;
}
static
const
char
*add_redirect(cmd_parms *cmd, alias_dir_conf * dirconf,
char
*arg1,
char
*arg2,
char
*arg3)
{
return
add_redirect_internal(cmd, dirconf, arg1, arg2, arg3, 0);
}
static
const
char
*add_redirect_regex(cmd_parms *cmd, alias_dir_conf * dirconf,
char
*arg1,
char
*arg2,
char
*arg3)
{
return
add_redirect_internal(cmd, dirconf, arg1, arg2, arg3, 1);
}
static
const
command_rec alias_cmds[] =
{
{
"Alias"
, add_alias, NULL, RSRC_CONF, TAKE2,
"a fakename and a realname"
},
{
"ScriptAlias"
, add_alias,
"cgi-script"
, RSRC_CONF, TAKE2,
"a fakename and a realname"
},
{
"Redirect"
, add_redirect, (
void
*) HTTP_MOVED_TEMPORARILY,
OR_FILEINFO, TAKE23,
"an optional status, then document to be redirected and destination URL"
},
{
"AliasMatch"
, add_alias_regex, NULL, RSRC_CONF, TAKE2,
"a regular expression and a filename"
},
{
"ScriptAliasMatch"
, add_alias_regex,
"cgi-script"
, RSRC_CONF, TAKE2,
"a regular expression and a filename"
},
{
"RedirectMatch"
, add_redirect_regex, (
void
*) HTTP_MOVED_TEMPORARILY,
OR_FILEINFO, TAKE23,
"an optional status, then a regular expression and destination URL"
},
{
"RedirectTemp"
, add_redirect, (
void
*) HTTP_MOVED_TEMPORARILY,
OR_FILEINFO, TAKE2,
"a document to be redirected, then the destination URL"
},
{
"RedirectPermanent"
, add_redirect, (
void
*) HTTP_MOVED_PERMANENTLY,
OR_FILEINFO, TAKE2,
"a document to be redirected, then the destination URL"
},
{NULL}
};
static
int
alias_matches(
const
char
*uri,
const
char
*alias_fakename)
{
const
char
*end_fakename = alias_fakename +
strlen
(alias_fakename);
const
char
*aliasp = alias_fakename, *urip = uri;
while
(aliasp < end_fakename) {
if
(*aliasp ==
'/'
) {
if
(*urip !=
'/'
)
return
0;
while
(*aliasp ==
'/'
)
++aliasp;
while
(*urip ==
'/'
)
++urip;
}
else
{
if
(*urip++ != *aliasp++)
return
0;
}
}
if
(aliasp[-1] !=
'/'
&& *urip !=
'\0'
&& *urip !=
'/'
)
return
0;
return
urip - uri;
}
static
char
*try_alias_list(request_rec *r, array_header *aliases,
int
doesc,
int
*status)
{
alias_entry *entries = (alias_entry *) aliases->elts;
regmatch_t regm[10];
char
*found = NULL;
int
i;
for
(i = 0; i < aliases->nelts; ++i) {
alias_entry *p = &entries[i];
int
l;
if
(p->regexp) {
if
(!ap_regexec(p->regexp, r->uri, p->regexp->re_nsub + 1, regm, 0)) {
if
(p->real) {
found = ap_pregsub(r->pool, p->real, r->uri,
p->regexp->re_nsub + 1, regm);
if
(found && doesc) {
found = ap_escape_uri(r->pool, found);
}
}
else
{
found = ap_pstrdup(r->pool,
""
);
}
}
}
else
{
l = alias_matches(r->uri, p->fake);
if
(l > 0) {
if
(doesc) {
char
*escurl;
escurl = ap_os_escape_path(r->pool, r->uri + l, 1);
found = ap_pstrcat(r->pool, p->real, escurl, NULL);
}
else
found = ap_pstrcat(r->pool, p->real, r->uri + l, NULL);
}
}
if
(found) {
if
(p->handler) {
r->handler = p->handler;
ap_table_setn(r->notes,
"alias-forced-type"
, r->handler);
}
*status = p->redir_status;
return
found;
}
}
return
NULL;
}
static
int
translate_alias_redir(request_rec *r)
{
void
*sconf = r->server->module_config;
alias_server_conf *serverconf =
(alias_server_conf *) ap_get_module_config(sconf, &alias_module);
char
*ret;
int
status;
if
(r->uri[0] !=
'/'
&& r->uri[0] !=
'\0'
)
return
DECLINED;
if
((ret = try_alias_list(r, serverconf->redirects, 1, &status)) != NULL) {
if
(ap_is_HTTP_REDIRECT(status)) {
if
(r->args) {
ret = ap_pstrcat(r->pool, ret,
"?"
, r->args, NULL);
}
ap_table_setn(r->headers_out,
"Location"
, ret);
}
return
status;
}
if
((ret = try_alias_list(r, serverconf->aliases, 0, &status)) != NULL) {
r->filename = ret;
return
OK;
}
return
DECLINED;
}
static
int
fixup_redir(request_rec *r)
{
void
*dconf = r->per_dir_config;
alias_dir_conf *dirconf =
(alias_dir_conf *) ap_get_module_config(dconf, &alias_module);
char
*ret;
int
status;
if
((ret = try_alias_list(r, dirconf->redirects, 1, &status)) != NULL) {
if
(ap_is_HTTP_REDIRECT(status))
ap_table_setn(r->headers_out,
"Location"
, ret);
return
status;
}
return
DECLINED;
}
module MODULE_VAR_EXPORT alias_module =
{
STANDARD_MODULE_STUFF,
NULL,
create_alias_dir_config,
merge_alias_dir_config,
create_alias_config,
merge_alias_config,
alias_cmds,
NULL,
translate_alias_redir,
NULL,
NULL,
NULL,
NULL,
fixup_redir,
NULL,
NULL,
NULL,
NULL,
NULL
};