From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

/*###################################################################################
#
# Embperl - Copyright (c) 1997-2008 Gerald Richter / ecos gmbh www.ecos.de
# Embperl - Copyright (c) 2008-2015 Gerald Richter
# Embperl - Copyright (c) 2015-2023 actevy.io
#
# You may distribute under the terms of either the GNU General Public
# License or the Artistic License, as specified in the Perl README file.
# For use with Apache httpd and mod_perl, see also Apache copyright.
#
# THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
###################################################################################*/
#include "ep.h"
#include "epmacro.h"
/*---------------------------------------------------------------------------
* DoLogError
*/
/*!
*
* \_en
* Logs the occurence of an error to the embperl logfile and the httpd error log
*
* @param r the request object (maybe NULL)
* @param a the application object (maybe NULL)
* @param rc the error code
* @param errdat1 addtional information
* @param errdat2 addtional information
* \endif
*
* \_de
* logged das auftreten eines Fehler in das Embperl Logfile und den httpd
* error log
*
* @param r das Requestobjekt (kann NULL sein)
* @param a das Applikationobjekt (kann NULL sein)
* @param rc Fehlercode
* @param errdat1 Zusätzliche Informationen
* @param errdat2 Zusätzliche Informationen
* \endif
*
* ------------------------------------------------------------------------ */
static char * DoLogError (/*i/o*/ struct tReq * r,
/*i/o*/ struct tApp * a,
/*in*/ int rc,
/*in*/ const char * errdat1,
/*in*/ const char * errdat2)
{
const char * msg ;
char * sText ;
SV * pSV ;
SV * pSVLine = NULL ;
STRLEN l ;
pid_t nPid ;
#ifdef PERL_IMPLICIT_CONTEXT
pTHX ;
if (r)
aTHX = r -> pPerlTHX ;
else if (a)
aTHX = a -> pPerlTHX ;
else
aTHX = PERL_GET_THX ;
#endif
if (r)
{
r -> errdat1 [sizeof (r -> errdat1) - 1] = '\0' ;
r -> errdat2 [sizeof (r -> errdat2) - 1] = '\0' ;
GetLineNo (r) ;
errdat1 = r -> errdat1 ;
errdat2 = r -> errdat2 ;
if (rc != rcPerlWarn)
r -> bError = 1 ;
nPid = r -> pThread -> nPid ;
a = r -> pApp ;
}
else if (a)
{
nPid = a -> pThread -> nPid ;
}
else
nPid = getpid() ;
if (!errdat1)
errdat1 = "" ;
if (!errdat2)
errdat2 = "" ;
switch (rc)
{
case ok: msg ="[%d]ERR: %d: %s ok%s%s" ; break ;
case rcStackOverflow: msg ="[%d]ERR: %d: %s Stack Overflow%s%s" ; break ;
case rcArgStackOverflow: msg ="[%d]ERR: %d: %s Argumnet Stack Overflow (%s)%s" ; break ;
case rcStackUnderflow: msg ="[%d]ERR: %d: %s Stack Underflow%s%s" ; break ;
case rcEndifWithoutIf: msg ="[%d]ERR: %d: %s endif without if%s%s" ; break ;
case rcElseWithoutIf: msg ="[%d]ERR: %d: %s else without if%s%s" ; break ;
case rcEndwhileWithoutWhile: msg ="[%d]ERR: %d: %s endwhile without while%s%s" ; break ;
case rcEndtableWithoutTable: msg ="[%d]ERR: %d: %s blockend <%s> does not match blockstart <%s>" ; break ;
case rcTablerowOutsideOfTable: msg ="[%d]ERR: %d: %s <tr> outside of table%s%s" ; break ;
case rcCmdNotFound: msg ="[%d]ERR: %d: %s Unknown Command %s%s" ; break ;
case rcOutOfMemory: msg ="[%d]ERR: %d: %s Out of memory %s %s" ; break ;
case rcPerlVarError: msg ="[%d]ERR: %d: %s Perl variable error %s%s" ; break ;
case rcHashError: msg ="[%d]ERR: %d: %s Perl hash error, %%%s does not exist%s" ; break ;
case rcArrayError: msg ="[%d]ERR: %d: %s Perl array error , @%s does not exist%s" ; break ;
case rcFileOpenErr: msg ="[%d]ERR: %d: %s File %s open error: %s" ; break ;
case rcLogFileOpenErr: msg ="[%d]ERR: %d: %s Logfile %s open error: %s" ; break ;
case rcMissingRight: msg ="[%d]ERR: %d: %s Missing right %s%s" ; break ;
case rcNoRetFifo: msg ="[%d]ERR: %d: %s No Return Fifo%s%s" ; break ;
case rcMagicError: msg ="[%d]ERR: %d: %s Perl Magic Error%s%s" ; break ;
case rcWriteErr: msg ="[%d]ERR: %d: %s File write Error%s%s" ; break ;
case rcUnknownNameSpace: msg ="[%d]ERR: %d: %s Namespace %s unknown%s" ; break ;
case rcInputNotSupported: msg ="[%d]ERR: %d: %s Input not supported in mod_perl mode%s%s" ; break ;
case rcCannotUsedRecursive: msg ="[%d]ERR: %d: %s Cannot be called recursively in mod_perl mode%s%s" ; break ;
case rcEndtableWithoutTablerow: msg ="[%d]ERR: %d: %s </tr> without <tr>%s%s" ; break ;
case rcEndtextareaWithoutTextarea: msg ="[%d]ERR: %d: %s </textarea> without <textarea>%s%s" ; break ;
case rcEvalErr: msg ="[%d]ERR: %d: %s Error in Perl code: %s%s" ; break ;
case rcNotCompiledForModPerl: msg ="[%d]ERR: %d: %s Embperl is not compiled for mod_perl. Rerun Makefile.PL and give the correct Apache source tree location %s%s" ; break ;
case rcExecCGIMissing: msg ="[%d]ERR: %d: %s Forbidden %s: Options ExecCGI not set in your Apache configs%s" ; break ;
case rcIsDir: msg ="[%d]ERR: %d: %s Forbidden %s is a directory%s" ; break ;
case rcXNotSet: msg ="[%d]ERR: %d: %s Forbidden %s X Bit not set%s" ; break ;
case rcNotFound: msg ="[%d]ERR: %d: %s Not found '%s', searched: %s" ; break ;
case rcTokenNotFound: msg ="[%d]ERR: %d: %s Token not found '%s', %s" ; break ;
case rcUnknownVarType: msg ="[%d]ERR: %d: %s Type for Variable %s is unknown %s" ; break ;
case rcPerlWarn: msg ="[%d]ERR: %d: %s Warning in Perl code: %s%s" ; break ;
case rcVirtLogNotSet: msg ="[%d]ERR: %d: %s EMBPERL_VIRTLOG must be set, when dbgLogLink is set %s%s" ; break ;
case rcMissingInput: msg ="[%d]ERR: %d: %s Sourcedata/-file missing %s%s" ; break ;
case rcUntilWithoutDo: msg ="[%d]ERR: %d: %s until without do%s%s" ; break ;
case rcEndforeachWithoutForeach:msg ="[%d]ERR: %d: %s endforeach without foreach%s%s" ; break ;
case rcMissingArgs: msg ="[%d]ERR: %d: %s Too few arguments%s%s" ; break ;
case rcNotAnArray: msg ="[%d]ERR: %d: %s Second Argument must be array/list%s%s" ; break ;
case rcCallInputFuncFailed: msg ="[%d]ERR: %d: %s Call to Input Function failed: %s%s" ; break ;
case rcCallOutputFuncFailed: msg ="[%d]ERR: %d: %s Call to Output Function failed: %s%s" ; break ;
case rcSubNotFound: msg ="[%d]ERR: %d: %s Call to unknown Embperl macro %s%s" ; break ;
case rcImportStashErr: msg ="[%d]ERR: %d: %s Package %s for import unknown%s" ; break ;
case rcCGIError: msg ="[%d]ERR: %d: %s Setup of CGI.pm failed: %s%s" ; break ;
case rcUnclosedHtml: msg ="[%d]ERR: %d: %s Unclosed HTML tag <%s> at end of file %s" ; break ;
case rcUnclosedCmd: msg ="[%d]ERR: %d: %s Unclosed command [$ %s $] at end of file %s" ; break ;
case rcNotAllowed: msg ="[%d]ERR: %d: %s Forbidden %s: Does not match EMBPERL_ALLOW %s" ; break ;
case rcNotHashRef: msg ="[%d]ERR: %d: %s %s need hashref in '%s'" ; break ;
case rcTagMismatch: msg ="[%d]ERR: %d: %s Endtag '%s' doesn't match starttag '%s'" ; break ;
case rcCleanupErr: msg ="[%d]ERR: %d: %s Error in cleanup %s%s" ; break ;
case rcCryptoWrongHeader: msg ="[%d]ERR: %d: %s Decrypt-error: Not encrypted (%s)%s" ; break ;
case rcCryptoWrongSyntax: msg ="[%d]ERR: %d: %s Decrypt-error: Wrong syntax (%s)%s" ; break ;
case rcCryptoNotSupported: msg ="[%d]ERR: %d: %s Decrypt-error: Not supported (%s)%s" ; break ;
case rcCryptoBufferOverflow: msg ="[%d]ERR: %d: %s Decrypt-error: Buffer overflow (%s)%s" ; break ;
case rcCryptoErr: msg ="[%d]ERR: %d: %s Decrypt-error: OpenSSL error (%s)%s" ; break ;
case rcUnknownProvider: msg ="[%d]ERR: %d: %s Unknown Provider %s %s" ; break ;
case rcXalanError: msg ="[%d]ERR: %d: %s Xalan Error: %s: %s" ; break ;
case rcLibXSLTError: msg ="[%d]ERR: %d: %s LibXSLT Error: %s: %s" ; break ;
case rcMissingParam: msg ="[%d]ERR: %d: %s Missing Parameter %s %s" ; break ;
case rcNotCodeRef: msg ="[%d]ERR: %d: %s %s need coderef in '%s'" ; break ;
case rcUnknownRecipe: msg ="[%d]ERR: %d: %s Unknown recipe '%s'" ; break ;
case rcTypeMismatch: msg ="[%d]ERR: %d: %s Unsupported Outputformat %s of %s" ; break ;
case rcChdirError: msg ="[%d]ERR: %d: %s Cannot change to directory %s %s" ; break ;
case rcUnknownSyntax: msg ="[%d]ERR: %d: %s Unknown syntax '%s'" ; break ;
case rcForbidden: msg ="[%d]ERR: %d: %s Access Forbidden for '%s'" ; break ;
case rcDecline: msg ="[%d]ERR: %d: %s Decline for '%s'" ; break ;
case rcCannotCheckUri: msg ="[%d]ERR: %d: %s Cannot check URI against ALLOW and/or URIMATCH because URI is unknown" ; break ;
case rcSetupSessionErr: msg ="[%d]ERR: %d: %s Embperl Session handling DISABLED because of the following error: %s\nSet EMBPERL_SESSION_HANDLER_CLASS to 'no' to avoid this message. %s" ; break ;
case rcRefcntNotOne: msg ="[%d]ERR: %d: %s There is still %s reference(s) to the %s object, while there shouldn't be any." ; break ;
case rcApacheErr: msg ="[%d]ERR: %d: %s Apache returns Error: %s %s" ; break ;
case rcTooDeepNested: msg ="[%d]ERR: %d: %s Source data is too deep nested %s %s" ; break ;
case rcUnknownOption: msg ="[%d]ERR: %d: %s Unknown option '%s' in configuration directive '%s'" ; break ;
case rcTimeFormatErr: msg ="[%d]ERR: %d: %s Format error in %s = %s" ; break ;
case rcSubCallNotRequest: msg ="[%d]ERR: %d: %s A Embperl sub is called and no Embperl request is running %s %s" ; break ;
case rcNotScalarRef: msg ="[%d]ERR: %d: %s %s need scalar in '%s'" ; break ;
case rcFormDataTruncated: msg ="[%d]ERR: %d: %s Formdata exceeded length of %s bytes, truncated" ; break ;
default: msg ="[%d]ERR: %d: %s Error (no description) %s %s" ; break ;
}
if (r && ((rc != rcPerlWarn && rc != rcEvalErr) || r -> errdat1[0] == '\0'))
{
char * p = NULL ;
char buf[20] = "" ;
char * f ;
tComponent * c = &r -> Component ;
if (!(f = c -> sSourcefile))
{
c = r -> Component.pPrev ;
if (c && !(f = c -> sSourcefile))
f = "", p = "" ;
}
if (f)
{
if (!p)
p = strrchr (f, '/') ;
if (p)
p++ ;
else
{
p = strrchr (f, '\\') ;
if (!p)
p = f ;
else
p++ ;
}
}
else
if (!p)
p = "" ;
if (c && c -> nSourceline)
sprintf (buf, "(%d)", c -> nSourceline) ;
pSVLine = newSVpvf ("%s%s:", p, buf) ;
newSVpvf2(pSVLine) ;
}
pSV = newSVpvf (msg, nPid , rc, pSVLine?SvPV(pSVLine, l):"", errdat1, errdat2) ;
newSVpvf2(pSV) ;
if (r && r -> Component.Config.bOptions & optShowBacktrace)
{
tComponent * c = &r -> Component ;
while (c)
{
sv_catpvf(pSV, "\n * %s", (!c -> sSourcefile)?"<no filename available>":c -> sSourcefile) ;
c = c -> pPrev ;
}
}
if (pSVLine)
SvREFCNT_dec(pSVLine) ;
sText = SvPV (pSV, l) ;
if (a)
lprintf (a, "%s\n", sText) ;
#ifdef APACHE
if (r && r -> pApacheReq)
{
#ifdef APLOG_ERR
if (rc != rcPerlWarn)
ap_log_error (APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, APLOG_STATUSCODE r -> pApacheReq -> server, "%s", sText) ;
else
ap_log_error (APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, APLOG_STATUSCODE r -> pApacheReq -> server, "%s", sText) ;
#else
log_error (sText, r -> pApacheReq -> server) ;
#endif
}
else
#endif
{
#ifdef WIN32
PerlIO_printf (PerlIO_stderr(), "%s\n", sText) ;
PerlIO_flush (PerlIO_stderr()) ;
#else
#undef fprintf
#undef fflush
fprintf (stderr, "%s\n", sText) ;
fflush (stderr) ;
#endif
}
if (r)
{
if (rc == rcPerlWarn)
strncpy (r -> lastwarn, r -> errdat1, sizeof (r -> lastwarn) - 1) ;
if (r -> pErrArray)
{
av_push (r -> pErrArray, r -> pErrSV?SvREFCNT_inc(r -> pErrSV):pSV) ;
}
else
SvREFCNT_dec (pSV) ;
r -> errdat1[0] = '\0' ;
r -> errdat2[0] = '\0' ;
}
else
SvREFCNT_dec (pSV) ;
return sText ;
}
/*---------------------------------------------------------------------------
* LogErrorParam
*/
/*!
*
* \_en
* Logs the occurence of an error to the embperl logfile and the httpd error log
*
* @param a the application object
* @param rc the error code
* @param errdat1 addtional information
* @param errdat2 addtional information
* \endif
*
* \_de
* logged das auftreten eines Fehler in das Embperl Logfile und den httpd
* error log
*
* @param a das Applikationobjekt
* @param rc Fehlercode
* @param errdat1 Zusätzliche Informationen
* @param errdat2 Zusätzliche Informationen
* \endif
*
* ------------------------------------------------------------------------ */
char * LogErrorParam (/*i/o*/ struct tApp * a,
/*in*/ int rc,
/*in*/ const char * errdat1,
/*in*/ const char * errdat2)
{
return DoLogError (NULL, a, rc, errdat1, errdat2) ;
}
/*---------------------------------------------------------------------------
* LogError
*/
/*!
*
* \_en
* Logs the occurence of an error to the embperl logfile and the httpd error log
* Addtional information, like stack backtrace, is taken from the request object
*
* @param r the request object
* @param rc the error code
* \endif
*
* \_de
* Logged das auftreten eines Fehler in das Embperl Logfile und den httpd
* error log. Zusätzlich Informationen, wie z.B. ein Stackbacktrace, werden
* dem Requestobjket entnommen
*
* @param a das Requestobjekt
* @param rc Fehlercode
* \endif
*
* ------------------------------------------------------------------------ */
char * LogError (/*i/o*/ register req * r,
/*in*/ int rc)
{
return DoLogError (r, NULL, rc, NULL, NULL) ;
}
#if defined (_MDEBUG) && defined (WIN32)
static int EmbperlCRTDebugOutput( int reportType, char *userMessage, int *retVal )
{
lprintf (CurrReq, "[%d]CRTDBG: %s\n", pCurrReq -> nPid, userMessage) ;
return TRUE ;
}
#endif
/* */
/* Magic */
/* */
void NewEscMode (/*i/o*/ register req * r,
SV * pSV)
{
if (r -> Component.Config.nEscMode & escXML && !r -> Component.bEscInUrl)
r -> Component.pNextEscape = Char2XML ;
else if (r -> Component.Config.nEscMode & escHtml && !r -> Component.bEscInUrl)
{
struct tCharTrans * pChar2Html ;
if (r -> Config.nOutputEscCharset == ocharsetLatin1)
pChar2Html = Char2Html ;
else if (r -> Config.nOutputEscCharset == ocharsetLatin2)
pChar2Html = Char2HtmlLatin2 ;
else
pChar2Html = Char2HtmlMin ;
r -> Component.pNextEscape = pChar2Html ;
}
else if (r -> Component.Config.nEscMode & escUrl)
r -> Component.pNextEscape = Char2Url ;
else
r -> Component.pNextEscape = NULL ;
if (r -> Component.bEscModeSet < 1)
{
r -> Component.pCurrEscape = r -> Component.pNextEscape ;
r -> Component.nCurrEscMode = r -> Component.Config.nEscMode ;
}
if (r -> Component.bEscModeSet < 0 && pSV && SvOK (pSV))
r -> Component.bEscModeSet = 1 ;
}
#ifdef UNUSED
/* ---------------------------------------------------------------------------- */
/* */
/* Localise op_mask then opmask_add() */
/* */
/* Just copied from Opcode.xs */
/* */
/* ---------------------------------------------------------------------------- */
static void
opmask_addlocal(pTHX_
SV * opset,
char * op_mask_buf)
{
char *orig_op_mask = op_mask;
int i,j;
char *bitmask;
STRLEN len;
int myopcode = 0;
int opset_len = (maxo + 7) / 8 ;
SAVEPPTR(op_mask);
op_mask = &op_mask_buf[0];
if (orig_op_mask)
Copy(orig_op_mask, op_mask, maxo, char);
else
Zero(op_mask, maxo, char);
/* OPCODES ALREADY MASKED ARE NEVER UNMASKED. See opmask_addlocal() */
bitmask = SvPV(opset, len);
for (i=0; i < opset_len; i++)
{
U16 bits = bitmask[i];
if (!bits)
{ /* optimise for sparse masks */
myopcode += 8;
continue;
}
for (j=0; j < 8 && myopcode < maxo; )
op_mask[myopcode++] |= bits & (1 << j++);
}
}
#endif
/* ---------------------------------------------------------------------------- */
/* */
/* Create Session cookie */
/* */
/* ---------------------------------------------------------------------------- */
static char * CreateSessionCookie (/*i/o*/ register req * r,
/*in*/ SV * pSessionObj,
/*in*/ char type,
/*in*/ int bReturnCookie)
{
SV * pSVID = NULL ;
SV * pSVUID = NULL ;
char * pUID = NULL ;
char * pInitialUID = NULL ;
STRLEN ulen = 0 ;
STRLEN ilen = 0 ;
IV bModified = 0 ;
char * pCookie = NULL ;
STRLEN ldummy ;
tAppConfig * pCfg = &r -> pApp -> Config ;
epTHX ;
if (r -> nSessionMgnt)
{
dSP; /* initialize stack pointer */
int n ;
PUSHMARK(sp); /* remember the stack pointer */
XPUSHs(pSessionObj) ; /* push pointer to obeject */
XPUSHs(sv_2mortal(newSViv(bReturnCookie?0:1))) ; /* init session if not for cookie */
PUTBACK;
n = perl_call_method ("getids", G_ARRAY) ; /* call the function */
SPAGAIN;
if (n > 2)
{
int savewarn = dowarn ;
dowarn = 0 ; /* no warnings here */
bModified = POPi ;
pSVUID = POPs;
pUID = SvPV (pSVUID, ulen) ;
pSVID = POPs;
pInitialUID = SvPV (pSVID, ilen) ;
dowarn = savewarn ;
}
PUTBACK;
if (r -> Config.bDebug & dbgSession)
lprintf (r -> pApp, "[%d]SES: Received Cookie ID: %s New Cookie ID: %s %s data is%s modified\n", r -> pThread -> nPid, pInitialUID, pUID, type == 's'?"State":"User", bModified?"":" NOT") ;
if (ilen > 0 && (ulen == 0 || (!bModified && strcmp ("!DELETE", pInitialUID) == 0)))
{ /* delete cookie */
if (bReturnCookie)
{
pCookie = ep_pstrcat (r -> pPool, pCfg -> sCookieName, type == 's'?"s=":"=", "; expires=Thu, 1-Jan-1970 00:00:01 GMT", NULL) ;
if (pCfg -> sCookieDomain)
pCookie = ep_pstrcat (r -> pPool, pCookie, "; domain=", pCfg -> sCookieDomain, NULL) ;
if (pCfg -> sCookiePath)
pCookie = ep_pstrcat (r -> pPool, pCookie, "; path=", pCfg -> sCookiePath, NULL) ;
if (pCfg -> bCookieSecure)
pCookie = ep_pstrcat (r -> pPool, pCookie, "; secure", NULL) ;
}
if (r -> Config.bDebug & dbgSession)
lprintf (r -> pApp, "[%d]SES: Delete Cookie -> %s\n", r -> pThread -> nPid, pCookie) ;
}
else if (ulen > 0 &&
((bModified && (ilen == 0 || strcmp (pInitialUID, pUID) !=0)) ||
(r -> nSessionMgnt & 4) || !bReturnCookie))
{
if (bReturnCookie)
{
pCookie = ep_pstrcat (r -> pPool, pCfg -> sCookieName, type == 's'?"s=":"=", pUID, NULL) ;
if (pCfg -> sCookieDomain)
pCookie = ep_pstrcat (r -> pPool, pCookie, "; domain=", pCfg -> sCookieDomain, NULL) ;
if (pCfg -> sCookiePath)
pCookie = ep_pstrcat (r -> pPool, pCookie, "; path=", pCfg -> sCookiePath, NULL) ;
if (r -> sCookieExpires)
pCookie = ep_pstrcat (r -> pPool, pCookie, "; expires=", r -> sCookieExpires, NULL) ;
if (pCfg -> bCookieSecure)
pCookie = ep_pstrcat (r -> pPool, pCookie, "; secure", NULL) ;
if (r -> Config.bDebug & dbgSession)
lprintf (r -> pApp, "[%d]SES: Send Cookie -> %s\n", r -> pThread -> nPid, pCookie) ;
}
else
{
pCookie = ep_pstrdup (r -> pPool, SvPV(pSVUID, ldummy)) ;
if (r -> Config.bDebug & dbgSession)
lprintf (r -> pApp, "[%d]SES: Add ID to URL type=%c id=%s\n", r -> pThread -> nPid, type, pCookie) ;
}
}
}
return pCookie ;
}
#ifdef UNUSED
/* ---------------------------------------------------------------------------- */
/* */
/* Setup Safe Namespace */
/* */
/* ---------------------------------------------------------------------------- */
static void SetupSafeNamespace (/*i/o*/ register req * r)
{
GV * gv;
dTHR ;
epTHX ;
/* The following is borrowed from Opcode.xs */
if (r -> Component.Config.bOptions & optOpcodeMask)
opmask_addlocal(aTHX_ r -> Component.Config.pOpcodeMask, r -> Component.op_mask_buf);
if (r -> Component.Config.bOptions & optSafeNamespace)
{
save_aptr(&endav);
endav = (AV*)sv_2mortal((SV*)newAV()); /* ignore END blocks for now */
save_hptr(&defstash); /* save current default stack */
/* the assignment to global defstash changes our sense of 'main' */
defstash = gv_stashpv(r -> Component.sCurrPackage, GV_ADDWARN); /* should exist already */
if (r -> Component.Config.bDebug)
lprintf (r -> pApp, "[%d]REQ: switch to safe namespace %s\n", r -> pThread -> nPid, r -> Component.sCurrPackage) ;
/* defstash must itself contain a main:: so we'll add that now */
/* take care with the ref counts (was cause of long standing bug) */
/* XXX I'm still not sure if this is right, GV_ADDWARN should warn! */
gv = gv_fetchpv("main::", GV_ADDWARN, SVt_PVHV);
sv_free((SV*)GvHV(gv));
GvHV(gv) = (HV*)SvREFCNT_inc(defstash);
}
}
#endif
/* ---------------------------------------------------------------------------- */
/* */
/* Reset Request */
/* */
/* ---------------------------------------------------------------------------- */
static int ResetRequest (/*i/o*/ register req * r,
/*in*/ char * sInputfile)
{
epTHX ;
if (r -> Component.Config.bDebug)
{
clock_t cl = clock () ;
time_t t ;
struct tm * tm ;
time (&t) ;
tm =localtime (&t) ;
lprintf (r -> pApp, "[%d]PERF: input = %s\n", r -> pThread -> nPid, sInputfile?sInputfile:"???") ;
#ifdef CLOCKS_PER_SEC
lprintf (r -> pApp, "[%d]PERF: Time: %d ms ", r -> pThread -> nPid, ((cl - r -> startclock) * 1000 / CLOCKS_PER_SEC)) ;
#else
lprintf (r -> pApp, "[%d]PERF: ", r -> pThread -> nPid) ;
#endif
lprintf (r -> pApp, "\n") ;
lprintf (r -> pApp, "[%d]%sRequest finished. %s. Entry-SVs: %d Exit-SVs: %d \n", r -> pThread -> nPid,
(r -> Component.pPrev?"Sub-":""), asctime(tm), r -> stsv_count, sv_count) ;
#ifdef DMALLOC
dmalloc_message ( "[%d]%sRequest finished. Entry-SVs: %d Exit-SVs: %d \n", r -> pThread -> nPid,
(r -> Component.pPrev?"Sub-":""), r -> stsv_count, sv_count) ;
#endif
}
r -> Component.pCurrPos = NULL ;
FlushLog (r -> pApp) ;
r -> Component.nSourceline = 1 ;
r -> Component.pSourcelinePos = NULL ;
r -> Component.pLineNoCurrPos = NULL ;
r -> Component.bReqRunning = 0 ;
/*
av_clear (r -> pErrFill) ;
av_clear (r -> pErrState) ;
*/
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* Start the output stream */
/* */
/* ---------------------------------------------------------------------------- */
static int StartOutput (/*i/o*/ register req * r)
{
int bOutToMem = r -> Component.Param.pOutput && SvROK (r -> Component.Param.pOutput) ;
epTHX_
#ifdef APACHE
if (r -> pApacheReq && r -> pApacheReq -> main)
r -> Config.bOptions |= optEarlyHttpHeader ; /* do not direct output to memory on internal redirect */
#endif
if (bOutToMem)
r -> Config.bOptions &= ~optEarlyHttpHeader ;
if (r -> Component.pPrev || r -> Component.pImportStash)
r -> Config.bOptions &= ~optSendHttpHeader ;
if (r -> Config.bOptions & optEarlyHttpHeader)
{
#ifdef APACHE
if (r -> pApacheReq == NULL)
{
#endif
if (r -> Config.bOptions & optSendHttpHeader)
oputs (r, "Content-type: text/html\n\n") ;
#ifdef APACHE
}
else
{
#ifndef APACHE2
if (r -> pApacheReq -> main == NULL && (r -> Config.bOptions & optSendHttpHeader))
send_http_header (r -> pApacheReq) ;
#endif
#ifndef WIN32
/* shouldn't be necessary for newer mod_perl versions !? */
/* mod_perl_sent_header(r -> pApacheReq, 1) ; */
#endif
if (r -> pApacheReq -> header_only)
return ok ;
}
#endif
}
else
{
/*
if (r -> nIOType == epIOCGI && (r -> Config.bOptions & optSendHttpHeader))
oputs (r, "Content-type: text/html\n\n") ;
*/
oBegin (r) ;
}
if ((r -> Config.nSessionMode & smodeSDatParam) && !r -> Component.pPrev)
{
char * pCookie = CreateSessionCookie (r, r -> pApp -> pStateObj, 's', 0) ;
/* lprintf (r -> pApp, "opt %x optadd %x options %x cookie %s\n", optAddStateSessionToLinks, r -> Component.Config.bOptions & optAddStateSessionToLinks, r -> Component.Config.bOptions, SvPV(pCookie, l)) ; */
if (pCookie)
r -> sSessionID = ep_pstrcat (r -> pPool, r -> pApp -> Config.sCookieName, "=", pCookie, NULL) ;
}
if ((r -> Config.nSessionMode & smodeUDatParam) && !r -> Component.pPrev)
{
char * pCookie = CreateSessionCookie (r, r -> pApp -> pUserObj, 'u', 0) ;
if (pCookie)
{
if (r -> sSessionID)
r -> sSessionID = ep_pstrcat (r -> pPool, r -> sSessionID, ":", pCookie, NULL) ;
else
r -> sSessionID = ep_pstrcat (r -> pPool, r -> pApp -> Config.sCookieName, "=:", pCookie, NULL) ;
}
}
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* GenerateErrorPage */
/* */
/* ---------------------------------------------------------------------------- */
static int GenerateErrorPage (/*i/o*/ register req * r,
/*in*/ int rc)
{
epTHX_
dSP; /* initialize stack pointer */
if (r -> pApp -> Config.sMailErrorsTo)
{
/* --- check if error should be mailed --- */
tApp * a = r -> pApp ;
time_t nTime = time(NULL) ;
if (a -> nErrorsLastTime < nTime - a -> Config.nMailErrorsResetTime)
a -> nErrorsCount = 0 ;
else if (a -> nErrorsLastSendTime < nTime - a -> Config.nMailErrorsResendTime)
a -> nErrorsCount = 0 ;
a -> nErrorsLastTime = nTime ;
if (a -> Config.nMailErrorsLimit == 0 || a -> nErrorsCount < a -> Config.nMailErrorsLimit)
{
a -> nErrorsCount++ ;
a -> nErrorsLastSendTime = nTime ;
PUSHMARK(sp);
XPUSHs(r -> pApp -> _perlsv) ;
XPUSHs(r -> _perlsv) ;
PUTBACK;
perl_call_method ("mail_errors", G_DISCARD) ;
SPAGAIN ;
}
}
if (r -> Component.Config.bOptions & optReturnError)
{
oRollbackOutput (r, NULL) ;
if (r -> Component.Param.pOutput && SvROK (r -> Component.Param.pOutput))
{
sv_setsv (SvRV (r -> Component.Param.pOutput), &sv_undef) ;
}
r -> bExit = 1 ;
return ok ; /* No further output or header, this should be handle by the server */
}
else if (r -> Component.pOutput && !(r -> Component.Config.bOptions & optDisableEmbperlErrorPage))
{
oRollbackOutput (r, NULL) ; /* forget everything outputed so far */
oBegin (r) ;
SPAGAIN ;
PUSHMARK(sp);
XPUSHs(r -> pApp -> _perlsv) ;
XPUSHs(r -> _perlsv) ;
PUTBACK;
perl_call_method ("send_error_page", G_DISCARD) ;
SPAGAIN ;
#ifdef APACHE
if (r -> pApacheReq)
{
if (rc >= 400)
r -> pApacheReq -> status = rc ;
else
r -> pApacheReq -> status = 500 ;
}
#endif
SetHashValueInt (r, r -> pThread -> pHeaderHash, "Content-Length", GetContentLength (r) ) ;
}
r -> bError = 1 ;
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* SendHttpHeader */
/* */
/* ---------------------------------------------------------------------------- */
int embperl_SendHttpHeader (/*i/o*/ register req * r)
{
epTHX_
char * pCookie = NULL ;
if (r -> Config.nSessionMode & smodeUDatCookie)
pCookie = CreateSessionCookie (r, r -> pApp -> pUserObj, 'u', 1) ;
#ifdef APACHE
if (r -> pApacheReq)
{
SV * pHeader ;
char * p ;
HE * pEntry ;
char * pKey ;
I32 l ;
STRLEN ldummy ;
I32 i;
I32 len;
AV *arr;
SV **svp;
/* loc = 0 => no location header found
* loc = 1 => location header found
* loc = 2 => location header + value found
* loc = 3 => location header + value + status found
*/
I32 loc;
I32 loc_status = 301;
hv_iterinit (r -> pThread -> pHeaderHash) ;
while ((pEntry = hv_iternext (r -> pThread -> pHeaderHash)))
{
pKey = hv_iterkey (pEntry, &l) ;
pHeader = hv_iterval (r -> pThread -> pHeaderHash, pEntry) ;
loc = 0;
if (pHeader && pKey)
{
if (stricmp (pKey, "location") == 0)
loc = 1;
if (stricmp (pKey, "content-type") == 0)
{
p = NULL;
if ( SvROK(pHeader) && SvTYPE(SvRV(pHeader)) == SVt_PVAV )
{
arr = (AV *)SvRV(pHeader);
if (av_len(arr) >= 0)
{
svp = av_fetch(arr, 0, 0);
p = SvPV(*svp, ldummy);
}
}
else
{
p = SvPV(pHeader, ldummy);
}
if (p)
r->pApacheReq->content_type = apr_pstrdup(r->pApacheReq->pool, p);
}
else if (SvROK(pHeader) && SvTYPE(SvRV(pHeader)) == SVt_PVAV )
{
arr = (AV *)SvRV(pHeader);
len = av_len(arr);
for (i = 0; i <= len; i++)
{
svp = av_fetch(arr, i, 0);
if (loc == 2)
{
loc = 3;
loc_status = SvIV(*svp);
break;
}
p = SvPV(*svp, ldummy);
apr_table_add( r->pApacheReq->headers_out, apr_pstrdup(r->pApacheReq->pool, pKey),
apr_pstrdup(r->pApacheReq->pool, p ) );
if (loc == 1)
loc = 2;
}
}
else
{
p = SvPV(pHeader, ldummy);
apr_table_set(r -> pApacheReq->headers_out, apr_pstrdup(r -> pApacheReq->pool, pKey), apr_pstrdup(r -> pApacheReq->pool, p)) ;
if (loc == 1) loc = 2;
}
if (loc >= 2) r->pApacheReq->status = loc_status;
}
}
if (pCookie)
apr_table_add(r -> pApacheReq->headers_out, "Set-Cookie", pCookie) ;
#if 0
if (r -> Component.Config.bEP1Compat) /* Embperl 2 currently cannot calc Content Length */
set_content_length (r -> pApacheReq, GetContentLength (r) + (r -> Component.pCurrEscape?2:0)) ;
#endif
#ifndef APACHE2
send_http_header (r -> pApacheReq) ;
#endif
if (r -> Component.Config.bDebug & dbgHeadersIn)
{
int i;
const apr_array_header_t *hdrs_arr;
apr_table_entry_t *hdrs;
hdrs_arr = apr_table_elts (r -> pApacheReq->headers_out);
hdrs = (apr_table_entry_t *)hdrs_arr->elts;
lprintf (r -> pApp, "[%d]HDR: %d\n", r -> pThread -> nPid, hdrs_arr->nelts) ;
for (i = 0; i < hdrs_arr->nelts; ++i)
if (hdrs[i].key)
lprintf (r -> pApp, "[%d]HDR: %s=%s\n", r -> pThread -> nPid, hdrs[i].key, hdrs[i].val) ;
}
}
else
#endif
{
/*char txt[100] ;*/
int save = r -> Component.pOutput -> nMarker ;
SV * pHeader ;
char * p ;
HE * pEntry ;
char * pKey ;
I32 l ;
char * pContentType = "text/html";
STRLEN ldummy ;
/* loc = 0 => no location header found
* loc = 1 => location header found
*/
I32 loc;
r -> Component.pOutput -> nMarker = 0 ; /* output directly */
hv_iterinit (r -> pThread -> pHeaderHash) ;
while ((pEntry = hv_iternext (r -> pThread -> pHeaderHash)))
{
pKey = hv_iterkey (pEntry, &l) ;
pHeader = hv_iterval (r -> pThread -> pHeaderHash, pEntry) ;
loc = 0;
if (pHeader && pKey)
{
if (stricmp (pKey, "location") == 0)
loc = 1;
if (SvROK(pHeader) && SvTYPE(SvRV(pHeader)) == SVt_PVAV )
{
AV * arr = (AV *)SvRV(pHeader);
I32 len = av_len(arr);
int i ;
for (i = 0; i <= len; i++)
{
SV ** svp = av_fetch(arr, i, 0);
p = SvPV(*svp, ldummy);
oputs (r, pKey) ;
oputs (r, ": ") ;
oputs (r, p) ;
oputs (r, "\n") ;
if (r -> Component.Config.bDebug & dbgHeadersIn)
lprintf (r -> pApp, "[%d]HDR: %s: %s\n", r -> pThread -> nPid, pKey, p) ;
if (loc == 1)
break;
}
}
else
{
p = SvPV (pHeader, na) ;
if (stricmp (pKey, "content-type") == 0)
pContentType = p ;
else
{
oputs (r, pKey) ;
oputs (r, ": ") ;
oputs (r, p) ;
oputs (r, "\n") ;
}
if (r -> Component.Config.bDebug & dbgHeadersIn)
lprintf (r -> pApp, "[%d]HDR: %s: %s\n", r -> pThread -> nPid, pKey, p) ;
}
}
}
oputs (r, "Content-Type: ") ;
oputs (r, pContentType) ;
oputs (r, "\n") ;
if (pCookie)
{
oputs (r, "Set-Cookie") ;
oputs (r, ": ") ;
oputs (r, pCookie) ;
oputs (r, "\n") ;
}
oputs (r, "\n") ;
r -> Component.pOutput -> nMarker = save ;
}
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* End the output stream to memory */
/* */
/* ---------------------------------------------------------------------------- */
static int OutputToMem (/*i/o*/ register req * r)
{
epTHX_
SV * pOut ;
char * pData ;
STRLEN l ;
if (!SvROK (r -> Component.Param.pOutput))
{
strcpy (r -> errdat1, "OutputToMem") ;
strcpy (r -> errdat2, "parameter output") ;
return rcNotScalarRef ;
}
pOut = SvRV (r -> Component.Param.pOutput) ;
if (!r -> bError && r -> Component.pOutputSV && !r -> Component.pImportStash)
{
sv_setsv (pOut, r -> Component.pOutputSV) ;
}
else
{
if (!r -> bError && !r -> Component.pImportStash)
{
tDomTree * pDomTree = DomTree_self (r -> Component.xCurrDomTree) ;
Node_toString (r, pDomTree, pDomTree -> xDocument, 0) ;
}
l = GetContentLength (r) + 1 ;
sv_setpv (pOut, "") ;
SvGROW (pOut, l) ;
pData = SvPVX (pOut) ;
oCommitToMem (r, NULL, pData) ;
SvCUR_set (pOut, l - 1) ;
}
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* End the output stream to file */
/* */
/* ---------------------------------------------------------------------------- */
static int OutputToFile (/*i/o*/ register req * r)
{
epTHX_
oCommit (r, NULL) ;
if (!r -> bError && !r -> Component.pImportStash)
{
if (r -> Component.pOutputSV)
{
STRLEN l ;
char * p = SvPV (r -> Component.pOutputSV, l) ;
owrite (r, p, l) ;
}
else
{
tDomTree * pDomTree = DomTree_self (r -> Component.xCurrDomTree) ;
Node_toString (r, pDomTree, pDomTree -> xDocument, 0) ;
}
}
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* Append tree to upper tree */
/* */
/* ---------------------------------------------------------------------------- */
static int AppendToUpperTree (/*i/o*/ register req * r)
{
epTHX_
tDomTree * pDomTree = DomTree_self (r -> Component.xCurrDomTree) ;
tComponent * lc = r -> Component.pPrev ;
if (lc -> xCurrNode)
{
if (r -> Component.pOutputSV)
{
STRLEN len ;
char * p = SvPV (r -> Component.pOutputSV, len) ;
lc -> xCurrNode = Node_insertAfter_CDATA (r -> pApp, p, len, 0, DomTree_self (lc -> xCurrDomTree), lc -> xCurrNode, lc -> nCurrRepeatLevel) ;
}
else if (pDomTree -> xDocument)
{
lc -> xCurrNode = Node_insertAfter (r -> pApp, pDomTree, pDomTree -> xDocument, 0, DomTree_self (lc -> xCurrDomTree), lc -> xCurrNode, lc -> nCurrRepeatLevel) ;
}
}
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* End the output stream */
/* */
/* ---------------------------------------------------------------------------- */
static int EndOutput (/*i/o*/ register req * r,
/*in*/ int rc,
/*in*/ SV * pOutData)
{
epTHX_
r -> Component.bEscModeSet = 0 ;
if (rc != ok || r -> bError)
{ /* --- generate error page if necessary --- */
GenerateErrorPage (r, rc) ;
if (r -> bExit)
return ok ;
}
if (!(r -> Config.bOptions & optEarlyHttpHeader) &&
(r -> Config.bOptions & optSendHttpHeader) && !r -> Component.Param.pOutput)
embperl_SendHttpHeader (r) ;
if (r -> Component.Param.pOutput)
return OutputToMem (r) ;
rc = OutputToFile (r) ;
#ifdef APACHE
if (r -> pApacheReq)
ap_finalize_request_protocol (r -> pApacheReq) ;
#endif
oflush (r) ;
return rc ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* export symbols into caller package */
/* */
/* ---------------------------------------------------------------------------- */
static int export (/*in*/ tReq * r)
{
epTHX_
SV * sCaller = sv_2mortal(newSVpv (HvNAME (r -> Component.pImportStash), 0)) ;
dSP ;
PUSHMARK(sp);
XPUSHs(r -> _perlsv);
XPUSHs(sCaller) ;
PUTBACK;
perl_call_method ("export", G_SCALAR | G_EVAL) ;
SPAGAIN ;
if (SvTRUE (ERRSV))
{
STRLEN l ;
strncpy (r -> errdat1, SvPV (ERRSV, l), sizeof (r -> errdat1) - 1) ;
LogError (r, rcEvalErr) ;
POPs ;
sv_setpv(ERRSV,"");
}
tainted = 0 ;
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* Process the file */
/* */
/* ---------------------------------------------------------------------------- */
static int ProcessFile (/*i/o*/ register req * r,
/*in*/ int nFileSize)
{
epTHX_
int rc ;
SV * pParam ;
SV * pParamRV = NULL ;
SV * pRecipe = r -> Component.Config.pRecipe ;
STRLEN l ;
int num ;
dSP ;
tainted = 0 ;
if (!pRecipe || !SvOK(pRecipe))
pRecipe = sv_2mortal(newSVpv("Embperl", 7)) ;
if (SvPOK(pRecipe))
{
PUSHMARK(sp);
XPUSHs(r -> pApp -> _perlsv);
XPUSHs(r -> _perlsv);
XPUSHs(pRecipe);
PUTBACK;
num = perl_call_method ("get_recipe", G_SCALAR | G_EVAL) ;
tainted = 0 ;
SPAGAIN;
if (num == 1)
pParamRV = POPs ;
PUTBACK;
if (SvTRUE (ERRSV))
{
STRLEN l ;
strncpy (r -> errdat1, SvPV (ERRSV, l), sizeof (r -> errdat1) - 1) ;
LogError (r, rcEvalErr) ;
sv_setpv(ERRSV,"");
num = 0 ;
}
if (num != 1 || !SvROK (pParamRV) || !(pParam = SvRV(pParamRV)) ||
(SvTYPE((SV *)pParam) != SVt_PVHV && SvTYPE(pParam) != SVt_PVAV))
{
strncpy (r -> errdat1, SvPV(pRecipe, l), sizeof (r -> errdat1) - 1) ;
return rcUnknownRecipe ;
}
}
else if (SvROK(pRecipe))
pParam = SvRV(pRecipe) ;
else
pParam = pRecipe ;
if ((rc = Cache_New (r, pParam, -1, 1, &r -> Component.pOutputCache)) != ok)
return rc ;
if (strncmp (r -> Component.pOutputCache -> pProvider -> sOutputType, "text/", 5) == 0)
{
if ((rc = Cache_GetContentSV (r, r -> Component.pOutputCache, &r -> Component.pOutputSV, FALSE)) != ok)
return rc ;
}
else if (strcmp (r -> Component.pOutputCache -> pProvider -> sOutputType, "X-Embperl/DomTree") == 0)
{
if ((rc = Cache_GetContentIndex (r, r -> Component.pOutputCache, &r -> Component.xCurrDomTree, FALSE)) != ok)
return rc ;
}
else
{
sprintf (r -> errdat1, "'%s' (accpetable are 'text/*', 'X-Embperl/DomTree')", r -> Component.pOutputCache -> pProvider -> sOutputType) ;
strncpy (r -> errdat2, r -> Component.pOutputCache -> sKey, sizeof (r -> errdat2) - 1) ;
return rcTypeMismatch ;
}
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* Request handler */
/* */
/* ---------------------------------------------------------------------------- */
int embperl_RunRequest (/*i/o*/ register req * r)
{
int rc = ok ;
tComponent * c = &r -> Component ;
char * sInputfile = c -> sSourcefile ;
dTHR ;
epTHX ;
EPENTRY (ExecuteReq) ;
if (!r -> Component.pExportHash)
r -> Component.pExportHash = newHV () ;
ENTER;
SAVETMPS ;
/* SetupSafeNamespace (r) ; */
if (c -> Param.pErrArray)
{
SvREFCNT_inc(c -> Param.pErrArray) ;
SvREFCNT_dec(r -> pErrArray) ;
r -> pErrArray = c -> Param.pErrArray ;
}
/* --- open output and send http header if EarlyHttpHeaders --- */
if (rc == ok)
rc = StartOutput (r) ;
/* --- ok so far? if not exit ---- */
#ifdef APACHE
if (rc != ok || (r -> pApacheReq && r -> pApacheReq -> header_only && (r -> Config.bOptions & optEarlyHttpHeader)))
#else
if (rc != ok)
#endif
{
if (rc != ok)
LogError (r, rc);
#ifdef APACHE
r -> pApacheReq = NULL ;
#endif
r -> Component.bReqRunning = 0 ;
FREETMPS ;
LEAVE;
return rc ;
}
r -> Component.bReqRunning = 1 ;
if (!r -> bError)
{
if ((rc = ProcessFile (r, 0 /*r -> Buf.pFile -> nFilesize*/)) != ok)
{
if (rc == rcExit)
rc = ok ;
else
LogError (r, rc) ;
}
if (r -> Component.Param.nImport > 0)
export (r) ;
}
/* --- Restore Operatormask and Package, destroy temp perl sv's --- */
FREETMPS ;
LEAVE;
r -> Component.bReqRunning = 0 ;
/* --- send http header and data to the browser if not already done --- */
if ((rc = EndOutput (r, rc, r -> Component.Param.pOutput)) != ok)
LogError (r, rc) ;
#ifdef EP2
if (r -> Component.pOutputCache)
Cache_ReleaseContent (r, r -> Component.pOutputCache) ;
#endif
/* --- reset variables and log end of request --- */
if ((rc = ResetRequest (r, sInputfile)) != ok)
LogError (r, rc) ;
#if defined (_MDEBUG) && defined (WIN32)
_ASSERTE( _CrtCheckMemory( ) );
#endif
if ((c -> Config.bOptions & optReturnError) && r -> bError)
{
#ifdef APACHE
if (r -> pApacheReq && r -> pApacheReqSV)
{
dSP ;
PUSHMARK(sp);
XPUSHs(r -> pApacheReqSV);
XPUSHs(sv_2mortal(newSVpv("EMBPERL_ERRORS", 14)));
XPUSHs(sv_2mortal(newRV((SV*)r -> pErrArray)));
PUTBACK;
perl_call_method ("pnotes", G_DISCARD) ;
}
#endif
#ifdef APACHE
/* This must be the very very very last !!!!! */
r -> pApacheReq = NULL ;
#endif
return 500 ;
}
#ifdef APACHE
/* This must be the very very very last !!!!! */
r -> pApacheReq = NULL ;
#endif
return ok ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* Run Request */
/* */
/* ---------------------------------------------------------------------------- */
int embperl_ExecuteRequest (/*in*/ pTHX_
/*in*/ SV * pApacheReqSV,
/*in*/ SV * pPerlParam)
{
int rc ;
tReq * r = NULL ;
#ifdef DMALLOC
time_t t = time(NULL) ;
static unsigned long nMemCheckpoint ;
static unsigned long nMemCheckpoint2 ;
dmalloc_message ("[%d]REQ: Start Request at %s\n", getpid(), ctime (&t)) ;
#endif
#if defined (_MDEBUG) && defined (WIN32)
_CrtMemCheckpoint(&r -> MemCheckpoint);
#endif
#ifdef DMALLOC
nMemCheckpoint2 = nMemCheckpoint ;
nMemCheckpoint = dmalloc_mark () ;
#endif
ENTER;
SAVETMPS ;
rc = embperl_InitRequestComponent (aTHX_ pApacheReqSV, pPerlParam, &r) ;
#ifdef DMALLOC
r -> MemCheckpoint = nMemCheckpoint;
#endif
if (rc == ok)
rc = embperl_RunRequest (r) ;
#ifdef DMALLOC
dmalloc_message ( "[%d]%sRequest will be freed. Entry-SVs: %d: %%d\n", r -> pThread -> nPid,
(r -> Component.pPrev?"Sub-":""), r -> stsv_count) ;
#endif
if (r)
embperl_CleanupRequest (r) ;
FREETMPS ;
LEAVE;
#if defined (_MDEBUG) && defined (WIN32)
_CrtMemDumpAllObjectsSince(&r -> MemCheckpoint);
#endif
#ifdef DMALLOC
/* unsigned long mark, int not_freed_b, int freed_b, int details_b */
dmalloc_log_changed (nMemCheckpoint, 1, 0, 1) ;
dmalloc_message ( "[%d]Request freed. Exit-SVs: %d\n", getpid(),
sv_count) ;
if (nMemCheckpoint2)
{
dmalloc_message ( "***TO PREVIOUS REQUEST***\n") ;
dmalloc_log_changed (nMemCheckpoint2, 1, 0, 1) ;
}
#endif
return rc ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* Run Component */
/* */
/* ---------------------------------------------------------------------------- */
int embperl_RunComponent (/*in*/ tComponent * c)
{
tReq * r = c -> pReq ;
epTHX_
int rc ;
ENTER;
SAVETMPS ;
c -> bReqRunning = 1 ;
if ((c -> Config.bOptions & optReturnError) )
save_int(&r -> bError) ;
if (c -> Param.pErrArray)
{
save_int(&r -> bError) ;
save_aptr(&r -> pErrArray) ;
r -> pErrArray = c -> Param.pErrArray ;
}
if ((c -> Config.bOptions & optEarlyHttpHeader) == 0)
oBegin (r) ;
if ((rc = ProcessFile (r, 0 /*r -> Buf.pFile -> nFilesize*/)) != ok)
{
if (rc == rcExit)
rc = ok ;
else
LogError (r, rc) ;
}
if (rc == ok && (c -> Config.bOptions & optReturnError) && r -> bError)
rc = 500 ;
if (!r -> bError)
{
if (c -> Param.nImport > 0)
export (r) ;
else if (c -> pOutput && !c -> pOutput -> bDisableOutput)
{
if (c -> Param.pOutput)
OutputToMem (r) ;
else if (r -> Component.pPrev && c -> pOutput == r -> Component.pPrev -> pOutput)
AppendToUpperTree (r) ;
else
OutputToFile (r) ;
}
}
/* --- Restore Operatormask and Package, destroy temp perl sv's --- */
FREETMPS ;
LEAVE;
c -> bReqRunning = 0 ;
return rc ;
}
/* ---------------------------------------------------------------------------- */
/* */
/* Execute Component */
/* */
/* ---------------------------------------------------------------------------- */
int embperl_ExecuteComponent(/*in*/ tReq * r,
/*in*/ SV * pPerlParam)
{
epTHX_
int rc ;
tComponent * pComponent ;
rc = embperl_SetupComponent (r, pPerlParam, &pComponent) ;
if (rc == ok)
{
rc = embperl_RunComponent (pComponent) ;
embperl_CleanupComponent (pComponent) ;
}
return rc ;
}