/* ==================================================================== * Copyright (c) 1995-1998 The Apache Group. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see . * */ #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; } /* * s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg; */ 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; } /* * s{ * (/+) # directory * (\d?) # package's first character * }[ * "::" . ($2 ? sprintf("_%2x",unpack("C",$2)) : "") * ]egx; */ 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); } /* * { * local $/ = undef; * my $fh = gensym; * open $fh, $r->filename; * my $code = <$fh>; * close $fh; * return \$code; * } */ #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); /*save_item(script_name);*/ 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); /*flush the namespace*/ 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)) { /*we have compiled this subroutine already, nothing left to do*/ } 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; /*avoid warning*/ 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