#include "ep.h"
#include "epmacro.h"
static
char
* DoLogError (
struct
tReq * r,
struct
tApp * a,
int
rc,
const
char
* errdat1,
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 ;
}
char
* LogErrorParam (
struct
tApp * a,
int
rc,
const
char
* errdat1,
const
char
* errdat2)
{
return
DoLogError (NULL, a, rc, errdat1, errdat2) ;
}
char
* LogError (
register
req * r,
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
void
NewEscMode (
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
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
);
bitmask = SvPV(opset, len);
for
(i=0; i < opset_len; i++)
{
U16 bits = bitmask[i];
if
(!bits)
{
myopcode += 8;
continue
;
}
for
(j=0; j < 8 && myopcode < maxo; )
op_mask[myopcode++] |= bits & (1 << j++);
}
}
#endif
static
char
* CreateSessionCookie (
register
req * r,
SV * pSessionObj,
char
type,
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;
int
n ;
PUSHMARK(sp);
XPUSHs(pSessionObj) ;
XPUSHs(sv_2mortal(newSViv(bReturnCookie?0:1))) ;
PUTBACK;
n = perl_call_method (
"getids"
, G_ARRAY) ;
SPAGAIN;
if
(n > 2)
{
int
savewarn = dowarn ;
dowarn = 0 ;
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)))
{
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
static
void
SetupSafeNamespace (
register
req * r)
{
GV * gv;
dTHR ;
epTHX ;
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());
save_hptr(&defstash);
defstash = gv_stashpv(r -> Component.sCurrPackage, GV_ADDWARN);
if
(r -> Component.Config.bDebug)
lprintf (r -> pApp,
"[%d]REQ: switch to safe namespace %s\n"
, r -> pThread -> nPid, r -> Component.sCurrPackage) ;
gv = gv_fetchpv(
"main::"
, GV_ADDWARN, SVt_PVHV);
sv_free((SV*)GvHV(gv));
GvHV(gv) = (HV*)SvREFCNT_inc(defstash);
}
}
#endif
static
int
ResetRequest (
register
req * r,
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 ;
return
ok ;
}
static
int
StartOutput (
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 ;
#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
#endif
if
(r -> pApacheReq -> header_only)
return
ok ;
}
#endif
}
else
{
oBegin (r) ;
}
if
((r -> Config.nSessionMode & smodeSDatParam) && !r -> Component.pPrev)
{
char
* pCookie = CreateSessionCookie (r, r -> pApp -> pStateObj,
's'
, 0) ;
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 ;
}
static
int
GenerateErrorPage (
register
req * r,
int
rc)
{
epTHX_
dSP;
if
(r -> pApp -> Config.sMailErrorsTo)
{
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 ;
}
else
if
(r -> Component.pOutput && !(r -> Component.Config.bOptions & optDisableEmbperlErrorPage))
{
oRollbackOutput (r, NULL) ;
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 ;
}
int
embperl_SendHttpHeader (
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;
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)
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
{
int
save = r -> Component.pOutput -> nMarker ;
SV * pHeader ;
char
* p ;
HE * pEntry ;
char
* pKey ;
I32 l ;
char
* pContentType =
"text/html"
;
STRLEN ldummy ;
I32 loc;
r -> Component.pOutput -> nMarker = 0 ;
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 ;
}
static
int
OutputToMem (
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 ;
}
static
int
OutputToFile (
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 ;
}
static
int
AppendToUpperTree (
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 ;
}
static
int
EndOutput (
register
req * r,
int
rc,
SV * pOutData)
{
epTHX_
r -> Component.bEscModeSet = 0 ;
if
(rc != ok || r -> bError)
{
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 ;
}
static
int
export (
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 ;
}
static
int
ProcessFile (
register
req * r,
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 ;
}
/* ---------------------------------------------------------------------------- */
int
embperl_RunRequest (
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 ;
if
(c -> Param.pErrArray)
{
SvREFCNT_inc(c -> Param.pErrArray) ;
SvREFCNT_dec(r -> pErrArray) ;
r -> pErrArray = c -> Param.pErrArray ;
}
if
(rc == ok)
rc = StartOutput (r) ;
#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
)) != ok)
{
if
(rc == rcExit)
rc = ok ;
else
LogError (r, rc) ;
}
if
(r -> Component.Param.nImport > 0)
export (r) ;
}
FREETMPS ;
LEAVE;
r -> Component.bReqRunning = 0 ;
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
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
r -> pApacheReq = NULL ;
#endif
return
500 ;
}
#ifdef APACHE
r -> pApacheReq = NULL ;
#endif
return
ok ;
}
int
embperl_ExecuteRequest (
pTHX_
SV * pApacheReqSV,
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
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 ;
}
int
embperl_RunComponent (
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
)) != 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) ;
}
}
FREETMPS ;
LEAVE;
c -> bReqRunning = 0 ;
return
rc ;
}
int
embperl_ExecuteComponent(
tReq * r,
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 ;
}