#include "mod_perl.h"
static
const
char
c2x_table[] =
"0123456789abcdef"
;
static
unsigned
char
*c2x(unsigned what, unsigned
char
*where)
{
*where++ =
'_'
;
*where++ = c2x_table[what >> 4];
*where++ = c2x_table[what & 0xf];
return
where;
}
static
char
*uri2perlish(
char
*segment,
int
slen) {
register
int
x,y;
char
*copy = (
char
*)safemalloc(3 * slen + 1);
for
(x=0,y=0; segment[x]; x++,y++) {
char
c = segment[x];
if
((c <
'A'
|| c >
'Z'
) && (c <
'a'
|| c >
'z'
) && (c <
'0'
|| c >
'9'
)
&& c !=
'/'
)
{
c2x(c, ©[y]);
y += 2;
}
else
copy[y] = c;
}
copy[y] =
'\0'
;
return
copy;
}
static
SV *slash2stash(
const
char
*segment) {
register
int
x,y;
SV *sv = newSV(3 *
strlen
(segment));
for
(x=0,y=0; segment[x]; x++,y++) {
char
c=segment[x];
if
(c ==
'/'
) {
SvPVX(sv)[y] =
':'
;
SvPVX(sv)[++y] =
':'
;
if
(isDIGIT(segment[x+1])) {
char
d = segment[++x];
c2x(d, &SvPVX(sv)[++y]);
y += 2;
}
}
else
SvPVX(sv)[y] = c;
}
SvPVX(sv)[y] =
'\0'
;
SvCUR_set(sv, y);
SvPOK_on(sv);
return
sv;
}
#define ApachePerlRun_import_exit() \
"use Apache 'exit';\n"
#define ApachePerlRun_chdir_scwd() \
chdir(SvPV(perl_get_sv(
"Apache::Server::CWD"
, TRUE),na))
#ifndef ApachePerlRun_name_with_virtualhost
#define ApachePerlRun_name_with_virtualhost() \
perl_get_sv(
"Apache::Registry::NameWithVirtualHost"
, FALSE)
#endif
SV *ApachePerlRun_namespace(request_rec *r,
char
*root)
{
char
*copy, *uri;
int
uri_len;
SV *esc, *RETVAL;
uri = (
char
*)pstrdup(r->pool, r->uri);
uri_len =
strlen
(uri);
if
(r->path_info) {
int
n =
strlen
(r->path_info);
int
chop = (uri_len - n);
uri[chop] =
'\0'
;
}
if
(r->server->is_virtual && ApachePerlRun_name_with_virtualhost()) {
uri = pstrcat(r->pool, r->server->server_hostname, uri, NULL);
uri_len +=
strlen
(r->server->server_hostname);
}
copy = uri2perlish(uri, uri_len);
RETVAL = newSVpv(root ? root :
"Apache::ROOT"
,0);
esc = slash2stash(copy);
sv_setsv(perl_get_sv(
"Apache::Registry::curstash"
, TRUE), esc);
sv_catsv(RETVAL, esc);
safefree(copy);
SvREFCNT_dec(esc);
return
RETVAL;
}
#define log_scripterror(r, rc, msg) \
aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, \
"%s: %s"
, msg, r->filename); \
return
rc
int
ApachePerlRun_can_compile(request_rec *r)
{
if
(!(allow_options(r) & OPT_EXECCGI)) {
log_scripterror(r, FORBIDDEN,
"Options ExecCGI is off in this directory"
);
}
if
(r->finfo.st_mode == 0) {
log_scripterror(r, NOT_FOUND,
"script not found or unable to stat"
);
}
if
(S_ISDIR(r->finfo.st_mode)) {
return
DECLINED;
}
if
(!can_exec(&r->finfo)) {
log_scripterror(r, FORBIDDEN,
"file permissions deny server execution"
);
}
return
OK;
}
void
ApachePerlRun_compile(request_rec *r, SV *code_ref)
{
SV *code;
if
(SvROK(code_ref))
code = (SV*)SvRV(code_ref);
else
code = code_ref;
perl_eval_sv(code, G_DISCARD|G_KEEPERR);
}
#define ApachePerlRun_readscript mod_perl_slurp_filename
SV *ApachePerlRun_parse_cmdline(request_rec *r, SV *code)
{
char
*pos = (
char
*)
strstr
(SvPVX(code),
"\n"
), *shebang;
int
plen = pos - SvPVX(code);
SV *sv;
if
(!pos)
return
Nullsv;
sv = newSVpv(
""
,0);
shebang = (
char
*)safemalloc(
sizeof
(
char
)+plen);
strncpy
(shebang, SvPVX(code), plen);
if
(*shebang ==
'#'
) {
if
(
strstr
(shebang,
"-w"
)) {
sv_catpv(sv,
"BEGIN {$^W = 1;}; $^W = 1;\n"
);
}
}
safefree(shebang);
return
sv;
}
int
ApachePerlRun_error_check(request_rec *r)
{
dTHR;
if
((perl_eval_ok(r->server) != 0) && !strnEQ(SvPVX(ERRSV),
" at "
, 4)) {
hv_store(ERRHV, r->uri,
strlen
(r->uri), ERRSV, FALSE);
sv_setpv(ERRSV,
""
);
return
SERVER_ERROR;
}
else
return
OK;
}
void
ApachePerlRun_set_scriptname(request_rec *r)
{
SV *script_name = perl_get_sv(
"0"
, TRUE);
sv_setpv(script_name, r->filename);
}
int
handler(request_rec *r)
{
dTHR;
int
rc = ApachePerlRun_can_compile(r);
SV *package, *code, *eval, *cmdline;
if
(rc != OK)
return
rc;
ENTER;
package = ApachePerlRun_namespace(r, NULL);
SAVEFREESV(package);
code = ApachePerlRun_readscript(r);
SAVEFREESV(code);
eval = newSV(0);
SAVEFREESV(eval);
if
((cmdline = ApachePerlRun_parse_cmdline(r, (SV*)SvRV(code)))) {
sv_catsv(eval, cmdline);
SvREFCNT_dec(cmdline);
}
ApachePerlRun_set_scriptname(r);
chdir_file(r->filename);
SAVEI32(hints);
hints = 0;
sv_setpvf(eval,
"package %_;\n"
, package);
sv_catpv(eval, ApachePerlRun_import_exit());
sv_catpvf(eval,
"#line 1 %s\n"
, r->filename);
sv_catsv(eval, (SV*)SvRV(code));
sv_catpvn(eval,
"\n"
, 1);
ApachePerlRun_compile(r, eval);
hv_clear(gv_stashpv(SvPVX(package), TRUE));
ApachePerlRun_chdir_scwd();
LEAVE;
return
ApachePerlRun_error_check(r);
}
static
int
registry_handler(request_rec *r)
{
dTHR;
int
rc = ApachePerlRun_can_compile(r);
SV *code, *package;
SV *rgy_cache_rv = perl_get_sv(
"Apache::Registry"
, TRUE);
HV *rgy_cache, *pkg_ent = Nullhv;
bool
do_compile = FALSE;
if
(rc != OK)
return
rc;
if
(!SvTRUE(rgy_cache_rv))
sv_setsv(rgy_cache_rv, newRV((SV*)newHV()));
rgy_cache = (HV*)SvRV(rgy_cache_rv);
ENTER;
package = ApachePerlRun_namespace(r, NULL);
SAVEFREESV(package);
ApachePerlRun_set_scriptname(r);
chdir_file(r->filename);
SAVEI32(hints);
hints = FALSE;
SAVEI32(dowarn);
dowarn = FALSE;
chdir(SvPV(perl_get_sv(
"Apache::Server::CWD"
, TRUE),na));
if
(hv_exists(rgy_cache, SvPVX(package), SvCUR(package))) {
SV **rv = hv_fetch(rgy_cache, SvPVX(package), SvCUR(package), FALSE);
SV *mtime;
pkg_ent = (HV*)SvRV(*rv);
mtime = *hv_fetch(pkg_ent,
"mtime"
, 5, FALSE);
if
(SvTRUE(mtime) && ((
int
)SvIV(mtime) <= r->finfo.st_mtime)) {
}
else
do_compile = TRUE;
}
else
do_compile = TRUE;
if
(do_compile) {
int
i = 0;
SV *eval = newSVpv(
""
,0), *cmdline;
code = ApachePerlRun_readscript(r);
SAVEFREESV(code);
if
((cmdline = ApachePerlRun_parse_cmdline(r, (SV*)SvRV(code)))) {
sv_catsv(eval, cmdline);
SvREFCNT_dec(cmdline);
}
sv_catpvf(eval,
"package %_;\n"
, package);
sv_catpv(eval, ApachePerlRun_import_exit());
sv_catpv(eval,
"sub handler {\n"
);
sv_catpvf(eval,
"#line 1 %s\n"
, r->filename);
sv_catsv(eval, (SV*)SvRV(code));
sv_catpvn(eval,
"\n}"
, 2);
ApachePerlRun_compile(r, eval);
perl_stash_rgy_endav(r->uri,
perl_get_sv(
"Apache::Registry::curstash"
, TRUE));
SvREFCNT_dec(eval);
rc = ApachePerlRun_error_check(r);
if
(rc != OK) {
LEAVE;
return
rc;
}
mod_perl_clear_rgy_endav(r, package);
while
(!pkg_ent) {
SV **svp = hv_fetch(rgy_cache,
SvPVX(package), SvCUR(package), FALSE);
if
(svp) {
pkg_ent = (HV*)SvRV(*svp);
break
;
}
hv_store(rgy_cache, SvPVX(package), SvCUR(package),
newRV((SV*)newHV()), FALSE);
if
(++i > 10) {
fprintf
(stderr,
"STUCK\n"
);
break
;
}
}
hv_store(pkg_ent,
"mtime"
, 5, newSViv(r->finfo.st_mtime), FALSE);
}
{
dSP;
int
count;
SV *sub = newSVsv(package);
sv_catpvn(sub,
"::handler"
, 9);
ENTER;SAVETMPS;PUSHMARK(sp);
XPUSHs((SV*)perl_bless_request_rec(r));
PUTBACK;
count = perl_call_sv(sub, G_EVAL | G_SCALAR);
SvREFCNT_dec(sub);
FREETMPS;LEAVE;
}
ApachePerlRun_chdir_scwd();
LEAVE;
if
((rc = ApachePerlRun_error_check(r)) != OK)
return
rc;
return
r->status;
}
MODULE = Apache::PerlRunXS PACKAGE = Apache::RegistryXS PREFIX = registry_
int
registry_handler(r)
Apache r
MODULE = Apache::PerlRunXS PACKAGE = Apache::PerlRunXS PREFIX = ApachePerlRun_
PROTOTYPES: DISABLE
BOOT:
items = items;
int
handler(r)
Apache r
SV *
ApachePerlRun_namespace(r, root=
"Apache::ROOT"
)
Apache r
char
*root
void
ApachePerlRun_can_compile(r)
Apache r
PREINIT:
int
retval = OK;
PPCODE:
retval = ApachePerlRun_can_compile(r);
XPUSHs(sv_2mortal(newSViv(retval)));
if
(GIMME == G_ARRAY) {
XPUSHs(sv_2mortal(newSViv(r->finfo.st_mtime)));
}
void
ApachePerlRun_compile(r, code_ref)
Apache r
SV *code_ref
SV *
ApachePerlRun_readscript(r)
Apache r
int
ApachePerlRun_error_check(r)
Apache r