#include "ep.h"
#include "epmacro.h"
#include "xs/ep_xs_typedefs.h"
#include "xs/ep_xs_sv_convert.h"
#include "epdefault.c"
SV ep_sv_undef ;
#ifndef PERL_IMPLICIT_CONTEXT
SV * embperl_ThreadDataRV ;
#define SINGLETHREAD
#endif
#define OPTPREFIX EMBPERL_PACKAGE_STR
#define EMBPERL_APP_PACKAGE EMBPERL_PACKAGE_STR"::Application"
#define EMBPERL_REQ_PACKAGE EMBPERL_PACKAGE_STR"::Req"
#define EMBPERL_THREAD_PACKAGE EMBPERL_PACKAGE_STR"::Thread"
#define FDAT_NAME "fdat"
#define EMBPERL_FDAT_NAME EMBPERL_PACKAGE_STR"::"FDAT_NAME
#define EMBPERL_SPLIFDAT_NAME EMBPERL_PACKAGE_STR"::splitfdat"
#define FFLD_NAME "ffld"
#define EMBPERL_FFLD_NAME EMBPERL_PACKAGE_STR"::"FFLD_NAME
#define EMBPERL_HDR_NAME EMBPERL_PACKAGE_STR"::http_headers_out"
#define EMBPERL_IDAT_NAME EMBPERL_PACKAGE_STR"::idat"
#define PARAM_NAME "param"
#define EMBPERL_PARAM_NAME EMBPERL_PACKAGE_STR"::"PARAM_NAME
#define EMBPERL_REQ_NAME EMBPERL_PACKAGE_STR"::req"
#define EMBPERL_APP_NAME EMBPERL_PACKAGE_STR"::app"
#define EMBPERL_ENV_NAME "ENV"
#define EMBPERL_EscMode_NAME EMBPERL_PACKAGE_STR"::escmode"
#define EMBPERL_CurrNode_NAME EMBPERL_PACKAGE_STR"::_ep_node"
#define MAX_FORMDATA_SIZE 67108864 /* 64 MB */
#define MAX_FORMDATA_SIZE_XXSTR(A) MAX_FORMDATA_SIZE_XSTR(A)
#define MAX_FORMDATA_SIZE_XSTR(A) #A
#define MAX_FORMDATA_SIZE_STR MAX_FORMDATA_SIZE_XXSTR(MAX_FORMDATA_SIZE)
static
int
bInitDone = 0 ;
static
int
nRequestCount = 1 ;
static
perl_mutex RequestCountMutex ;
static
tMemPool * pMainPool ;
static
tReq NullRequest ;
#define OPTION(a,b) { #a, a}, { #b, a},
tOptionEntry OptionsDEBUG[] =
{
OPTION(dbgStd, std)
OPTION(dbgMem,Mem)
OPTION(dbgEval,Eval)
OPTION(dbgCmd,Cmd)
OPTION(dbgEnv,Env)
OPTION(dbgForm,Form)
OPTION(dbgTab,Tab)
OPTION(dbgInput,Input)
OPTION(dbgFlushOutput,FlushOutput)
OPTION(dbgFlushLog,FlushLog)
OPTION(dbgAllCmds,AllCmds)
OPTION(dbgSource,Source)
OPTION(dbgFunc,Func)
OPTION(dbgLogLink,LogLink)
OPTION(dbgDefEval,DefEval)
OPTION(dbgOutput,Output)
OPTION(dbgDOM,DOM)
OPTION(dbgRun,Run)
OPTION(dbgHeadersIn,HeadersIn)
OPTION(dbgShowCleanup,ShowCleanup)
OPTION(dbgProfile,Profile)
OPTION(dbgSession,Session)
OPTION(dbgImport,Import)
OPTION(dbgBuildToken,BuildToken)
OPTION(dbgParse,Parse)
OPTION(dbgObjectSearch,ObjectSearch)
OPTION(dbgCache,Cache)
OPTION(dbgCompile,Compile)
OPTION(dbgXML,XML)
OPTION(dbgXSLT,XSLT)
OPTION(dbgCheckpoint,Checkpoint)
OPTION(dbgAll,All)
} ;
#define OPTION_OPT(a) OPTION(opt##a, a)
tOptionEntry OptionsOPTIONS[] =
{
OPTION_OPT(DisableVarCleanup)
OPTION_OPT(DisableEmbperlErrorPage)
OPTION_OPT(SafeNamespace)
OPTION_OPT(OpcodeMask)
OPTION_OPT(RawInput)
OPTION_OPT(SendHttpHeader)
OPTION_OPT(EarlyHttpHeader)
OPTION_OPT(DisableChdir)
OPTION_OPT(DisableFormData)
OPTION_OPT(DisableHtmlScan)
OPTION_OPT(DisableInputScan)
OPTION_OPT(DisableTableScan)
OPTION_OPT(DisableMetaScan)
OPTION_OPT(AllFormData)
OPTION_OPT(RedirectStdout)
OPTION_OPT(UndefToEmptyValue)
OPTION_OPT(NoHiddenEmptyValue)
OPTION_OPT(AllowZeroFilesize)
OPTION_OPT(ReturnError)
OPTION_OPT(KeepSrcInMemory)
OPTION_OPT(KeepSpaces)
OPTION_OPT(OpenLogEarly)
OPTION_OPT(NoUncloseWarn)
OPTION_OPT(DisableSelectScan)
OPTION_OPT(ShowBacktrace)
OPTION_OPT(EnableChdir)
OPTION_OPT(FormDataNoUtf8)
} ;
#define OPTION_ESC(a) OPTION(esc##a, a)
tOptionEntry OptionsESCMODE[] =
{
OPTION_ESC(None)
OPTION_ESC(Html)
OPTION_ESC(Url)
OPTION_ESC(Escape)
OPTION_ESC(XML)
OPTION_ESC(Std)
} ;
#define OPTION_IESC(a) OPTION(iesc##a, a)
tOptionEntry OptionsINPUT_ESCMODE[] =
{
OPTION_IESC(None)
OPTION_IESC(Html)
OPTION_IESC(Url)
OPTION_IESC(RemoveTags)
} ;
#define OPTION_OMODE(a) OPTION(omode##a, a)
tOptionEntry OptionsOUTPUT_MODE[] =
{
OPTION_OMODE(Html)
OPTION_OMODE(Xml)
} ;
#define OPTION_OCHARSET(a) OPTION(ocharset##a, a)
tOptionEntry OptionsOUTPUT_ESC_CHARSET[] =
{
OPTION_OCHARSET(Utf8)
OPTION_OCHARSET(Latin1)
OPTION_OCHARSET(Latin2)
} ;
#define OPTION_SMODE(a) OPTION(smode##a, a)
tOptionEntry OptionsSESSION_MODE[] =
{
OPTION_SMODE(None)
OPTION_SMODE(UDatCookie)
OPTION_SMODE(UDatParam)
OPTION_SMODE(UDatUrl)
OPTION_SMODE(SDatParam)
} ;
int
embperl_SetupThread (
pTHX_
tThreadData * * ppThread)
{
tThreadData * pThread ;
SV * * ppSV ;
#ifdef SINGLETHREAD
ppSV = &embperl_ThreadDataRV ;
#else
ppSV = hv_fetch (PL_modglobal,
"Embperl::Thread"
, 15, 1) ;
#endif
if
(!ppSV)
{
LogErrorParam (NULL, rcHashError,
"PL_modglobal (key=Embperl::Thread)"
,
""
) ;
return
rcHashError ;
}
if
(!*ppSV || !SvOK(*ppSV))
{
SV * pThreadRV ;
SV * pThreadSV ;
HV * pStash = gv_stashpv (EMBPERL_PACKAGE_STR, 1) ;
tMemPool * pPool = ep_make_sub_pool (pMainPool) ;
epxs_Embperl__Thread_create_obj(pThread,pThreadSV,pThreadRV,ep_palloc(pPool,
sizeof
(*pThread))) ;
#ifdef PERL_IMPLICIT_CONTEXT
pThread -> pPerlTHX = aTHX ;
#endif
pThread -> pPool = pPool ;
pThread -> pMainPool = pMainPool ;
pThread -> nPid = getpid () ;
pThread -> pApplications = newHV () ;
pThread -> pFormHash = perl_get_hv (EMBPERL_FDAT_NAME, GV_ADD | GV_ADDMULTI) ;
SvREFCNT_inc(pThread -> pFormHash) ;
pThread -> pFormHashGV = *((GV **)hv_fetch (pStash, FDAT_NAME,
sizeof
(FDAT_NAME) - 1, 0)) ;
pThread -> pFormSplitHash = perl_get_hv (EMBPERL_SPLIFDAT_NAME, GV_ADD | GV_ADDMULTI) ;
SvREFCNT_inc(pThread -> pFormSplitHash) ;
pThread -> pFormArray = perl_get_av (EMBPERL_FFLD_NAME, GV_ADD | GV_ADDMULTI) ;
SvREFCNT_inc(pThread -> pFormArray) ;
pThread -> pFormArrayGV = *((GV **)hv_fetch (pStash, FFLD_NAME,
sizeof
(FFLD_NAME) - 1, 0)) ;
pThread -> pHeaderHash = perl_get_hv (EMBPERL_HDR_NAME, GV_ADD | GV_ADDMULTI) ;
SvREFCNT_inc(pThread -> pHeaderHash) ;
pThread -> pInputHash = perl_get_hv (EMBPERL_IDAT_NAME, GV_ADD | GV_ADDMULTI) ;
SvREFCNT_inc(pThread -> pInputHash) ;
#ifdef DMALLOC
pThread -> pEnvHash = Perl_get_hv(aTHX_ EMBPERL_ENV_NAME, GV_ADD | GV_ADDMULTI) ;
#else
pThread -> pEnvHash = perl_get_hv (EMBPERL_ENV_NAME, GV_ADD | GV_ADDMULTI) ;
#endif
SvREFCNT_inc(pThread -> pEnvHash) ;
pThread -> pParamArray = perl_get_av (EMBPERL_PARAM_NAME, GV_ADD | GV_ADDMULTI) ;
SvREFCNT_inc(pThread -> pParamArray) ;
pThread -> pParamArrayGV = *((GV **)hv_fetch (pStash, PARAM_NAME,
sizeof
(PARAM_NAME) - 1, 0)) ;
pThread -> pReqRV = perl_get_sv (EMBPERL_REQ_NAME, GV_ADD | GV_ADDMULTI) ;
SvREFCNT_inc(pThread -> pReqRV) ;
pThread -> pAppRV = perl_get_sv (EMBPERL_APP_NAME, GV_ADD | GV_ADDMULTI) ;
SvREFCNT_inc(pThread -> pAppRV) ;
*ppSV = pThreadRV ;
}
else
{
pThread = epxs_sv2_Embperl__Thread(*ppSV) ;
}
*ppThread = pThread ;
return
ok ;
}
tThreadData * embperl_GetThread (
pTHX)
{
tThreadData * pThread ;
int
rc ;
if
((rc = embperl_SetupThread (aTHX_ &pThread)) != ok)
{
LogError (NULL, rc) ;
return
NULL ;
}
return
pThread ;
}
int
embperl_EndPass1 (
void
)
{
tThreadData * pThread ;
dTHX ;
pThread = embperl_GetThread (aTHX) ;
hv_clear (pThread -> pApplications) ;
return
ok ;
}
static
int
embperl_CreateSessionObject(
tApp * a,
HV * pArgs,
HV * * ppHash,
SV * * ppObj)
{
epaTHX_
dSP ;
tAppConfig * pCfg = &a -> Config ;
char
* sPackage = pCfg -> sSessionHandlerClass ;
HV * pHash = newHV () ;
SV * pTie = NULL ;
int
n ;
SV * pSVCode ;
pSVCode = newSVpvf (
"require %s"
, sPackage) ;
newSVpvf2(pSVCode) ;
perl_eval_sv(pSVCode, G_EVAL | G_DISCARD) ;
SvREFCNT_dec(pSVCode);
tainted = 0 ;
if
(SvTRUE (ERRSV))
{
STRLEN l ;
if
(
strcmp
(sPackage,
"Apache::SessionX"
) != 0 ||
GetHashValueStr (aTHX_ a -> pThread -> pEnvHash,
"GATEWAY_INTERFACE"
, NULL))
LogErrorParam (a, rcSetupSessionErr, SvPV (ERRSV, l), NULL) ;
sv_setpv(ERRSV,
""
);
return
rcEvalErr ;
}
SPAGAIN;
PUSHMARK(sp);
XPUSHs(sv_2mortal(newSVpv(sPackage, 0)));
XPUSHs(&sv_undef);
XPUSHs(sv_2mortal (newRV((SV *)pArgs)));
PUTBACK;
n = perl_call_method (
"TIEHASH"
, G_EVAL | G_SCALAR) ;
SPAGAIN;
if
(n > 0)
pTie = POPs ;
PUTBACK;
if
(SvTRUE (ERRSV))
{
STRLEN l ;
LogErrorParam (a, rcSetupSessionErr, SvPV (ERRSV, l), NULL) ;
sv_setpv(ERRSV,
""
);
return
rcEvalErr ;
}
if
(n == 0 || !SvROK(pTie))
{
LogErrorParam (a, rcSetupSessionErr,
"TIEHASH didn't returns a hashref"
, sPackage) ;
return
rcNotHashRef ;
}
hv_magic(pHash, (GV *)pTie,
'P'
) ;
*ppHash = pHash ;
*ppObj = SvREFCNT_inc(pTie) ;
return
ok ;
}
int
embperl_SetupSessionObjects (
tApp * a)
{
epaTHX_
int
rc ;
SV * pStore ;
SV ** ppStore ;
SV * pLocker ;
SV ** ppLocker ;
SV * pSerializer ;
SV ** ppSerializer ;
SV * pGenerator ;
SV ** ppGenerator ;
tAppConfig * pCfg = &a -> Config ;
HV * pArgs = pCfg -> pSessionArgs ;
HV * pArgs1 ;
HV * pArgs2 ;
HV * pArgs3 ;
dSP ;
if
(
strcmp
(pCfg -> sSessionHandlerClass,
"no"
) == 0)
return
ok ;
if
(!pArgs)
pCfg -> pSessionArgs = pArgs = newHV() ;
if
(pCfg -> pSessionClasses)
{
if
((ppStore = av_fetch (pCfg -> pSessionClasses, 0, 0)))
pStore = SvREFCNT_inc(*ppStore) ;
else
pStore = newSVpv(
"File"
, 4) ;
hv_store (pArgs,
"Store"
, 5, pStore, 0) ;
if
((ppLocker = av_fetch (pCfg -> pSessionClasses, 1, 0)))
pLocker = SvREFCNT_inc(*ppLocker) ;
else
pLocker = newSVpv(
"Null"
, 4) ;
hv_store (pArgs,
"Lock"
, 4, pLocker, 0) ;
if
((ppSerializer = av_fetch (pCfg -> pSessionClasses, 2, 0)))
pSerializer = SvREFCNT_inc(*ppSerializer) ;
else
pSerializer = newSVpv(
"Storable"
, 8) ;
hv_store (pArgs,
"Serialize"
, 9, pSerializer, 0) ;
if
((ppGenerator = av_fetch (pCfg -> pSessionClasses, 3, 0)))
pGenerator = SvREFCNT_inc(*ppGenerator) ;
else
pGenerator = newSVpv(
"MD5"
, 3) ;
hv_store (pArgs,
"Generate"
, 8, pGenerator, 0) ;
}
else
{
hv_store (pArgs,
"__dummy1__"
, 10, newSViv (1), 0) ;
hv_store (pArgs,
"__dummy2__"
, 10, newSViv (1), 0) ;
hv_store (pArgs,
"__dummy3__"
, 10, newSViv (1), 0) ;
hv_store (pArgs,
"__dummy4__"
, 10, newSViv (1), 0) ;
}
if
(pCfg -> sSessionConfig)
hv_store (pArgs,
"config"
, 5, newSVpv (pCfg -> sSessionConfig, 0), 0) ;
hv_store (pArgs,
"lazy"
, 4, newSViv (1), 0) ;
hv_store (pArgs,
"create_unknown"
, 14, newSViv (1), 0) ;
pArgs1 = newHVhv(pArgs) ;
hv_store (pArgs1,
"Transaction"
, 11, newSViv (1), 0) ;
pArgs2 = newHVhv(pArgs) ;
hv_store (pArgs2,
"recreate_id"
, 11, newSViv (1), 0) ;
pArgs3 = newHVhv(pArgs2) ;
if
((rc = embperl_CreateSessionObject (a, pArgs1, &a -> pAppHash, &a -> pAppObj)) != ok)
return
rc ;
SPAGAIN ;
PUSHMARK(sp);
XPUSHs(a -> pAppObj);
XPUSHs(sv_2mortal (newSVpv(a -> Config.sAppName, 0)));
PUTBACK;
perl_call_method (
"setidfrom"
, G_DISCARD) ;
if
((rc = embperl_CreateSessionObject (a, pArgs2, &a -> pUserHash, &a -> pUserObj)) != ok)
return
rc ;
hv_store (pArgs3,
"newid"
, 5, newSViv (1), 0) ;
if
((rc = embperl_CreateSessionObject (a, pArgs3, &a -> pStateHash, &a -> pStateObj)) != ok)
return
rc ;
return
ok ;
}
int
embperl_SetupApp (
pTHX_
tThreadData * pThread,
tApacheDirConfig * pApacheCfg,
SV * pPerlParam,
tApp * * ppApp)
{
char
* sAppName = NULL ;
tApp * pApp = NULL ;
HV * pParam = NULL ;
if
(pPerlParam && SvROK(pPerlParam))
{
pParam = (HV *)SvRV(pPerlParam) ;
sAppName = GetHashValueStr (aTHX_ pParam,
"app_name"
, NULL) ;
if
(!sAppName)
sAppName = GetHashValueStr (aTHX_ pParam,
"appname"
, NULL) ;
}
if
(!sAppName)
{
#ifdef APACHE
if
(pApacheCfg)
sAppName = embperl_GetApacheAppName (pApacheCfg) ;
else
#endif
sAppName = embperl_GetCGIAppName (pThread) ;
}
if
(sAppName)
pApp = (tApp * )GetHashValuePtr (NULL, pThread -> pApplications, sAppName, NULL) ;
if
(!pApp)
{
int
rc ;
SV * pAppSV ;
SV * pAppRV ;
SV * pSV ;
SV * pRV ;
tAppConfig * pCfg ;
tMemPool * pPool = ep_make_sub_pool (pThread -> pPool) ;
epxs_Embperl__App_create_obj(pApp,pAppSV,pAppRV,ep_palloc(pPool,
sizeof
(*pApp))) ;
epxs_Embperl__App__Config_create_obj(pCfg,pSV,pRV,&pApp -> Config) ;
#ifdef PERL_IMPLICIT_CONTEXT
pApp -> pPerlTHX = aTHX ;
#endif
pApp -> pPool = pPool ;
pCfg -> pPool = pPool ;
#ifdef APACHE
if
(pApacheCfg)
embperl_GetApacheAppConfig (pThread, pPool, pApacheCfg, &pApp -> Config) ;
else
#endif
{
bool
bUseEnv = 0 ;
bool
bUseRedirectEnv = 0 ;
if
(pParam)
{
bUseEnv = (
bool
)GetHashValueInt (aTHX_ pParam,
"use_env"
, 0) ;
bUseRedirectEnv = (
bool
)GetHashValueInt (aTHX_ pParam,
"use_redirect_env"
, 0) ;
}
embperl_GetCGIAppConfig (pThread, pPool, &pApp -> Config, bUseEnv, bUseRedirectEnv, 1) ;
}
SetHashValueInt (NULL, pThread -> pApplications, sAppName, (IV)pApp) ;
pApp -> pThread = pThread ;
if
(pParam)
Embperl__App__Config_new_init(aTHX_ &pApp -> Config, (SV *)pParam, 0) ;
tainted = 0 ;
if
(pApp -> Config.sLog && pApp -> Config.sLog[0])
{
if
((rc = OpenLog (pApp)) != ok)
{
pApp -> Config.bDebug = 0 ;
LogErrorParam (pApp, rc, pApp -> Config.sLog, Strerror(
errno
)) ;
}
}
if
(pApp -> Config.sAppHandlerClass)
{
HV * stash = gv_stashpv(pApp -> Config.sAppHandlerClass, TRUE) ;
sv_bless(pApp -> _perlsv, stash) ;
}
embperl_SetupSessionObjects (pApp) ;
}
sv_setsv(pThread -> pAppRV, pApp -> _perlsv) ;
*ppApp = pApp ;
return
ok ;
}
static
int
notused ;
#if 0
INTMG (TabCount, pCurrReq -> TableStack.State.nCount, pCurrReq -> TableStack.State.nCountUsed, ;)
INTMG (TabRow, pCurrReq -> TableStack.State.nRow, pCurrReq -> TableStack.State.nRowUsed, ;)
INTMG (TabCol, pCurrReq -> TableStack.State.nCol, pCurrReq -> TableStack.State.nColUsed, ;)
INTMG (TabMaxRow, pCurrReq -> nTabMaxRow, notused, ;)
INTMG (TabMaxCol, pCurrReq -> nTabMaxCol, notused, ;)
INTMG (TabMode, pCurrReq -> nTabMode, notused, ;)
#endif
INTMG_COMP (EscMode, Config.nEscMode, notused, NewEscMode (CurrReq, pSV))
#ifdef EP2
INTMGshort_COMP (CurrNode, xCurrNode)
#endif
OPTMGRD_COMP (optDisableVarCleanup , Config.bOptions)
OPTMG_COMP (optDisableEmbperlErrorPage, Config.bOptions)
OPTMG_COMP (optReturnError , Config.bOptions)
OPTMGRD_COMP (optSafeNamespace , Config.bOptions)
OPTMGRD_COMP (optOpcodeMask , Config.bOptions)
OPTMG_COMP (optRawInput , Config.bOptions)
OPTMG_COMP (optSendHttpHeader , Config.bOptions)
OPTMGRD_COMP (optDisableChdir , Config.bOptions)
OPTMG_COMP (optDisableHtmlScan , Config.bOptions)
OPTMGRD_COMP (optEarlyHttpHeader , Config.bOptions)
OPTMGRD_COMP (optDisableFormData , Config.bOptions)
OPTMG_COMP (optDisableInputScan , Config.bOptions)
OPTMG_COMP (optDisableTableScan , Config.bOptions)
OPTMG_COMP (optDisableMetaScan , Config.bOptions)
OPTMGRD_COMP (optAllFormData , Config.bOptions)
OPTMGRD_COMP (optRedirectStdout , Config.bOptions)
OPTMG_COMP (optUndefToEmptyValue , Config.bOptions)
OPTMG_COMP (optNoHiddenEmptyValue , Config.bOptions)
OPTMGRD_COMP (optAllowZeroFilesize , Config.bOptions)
OPTMGRD_COMP (optKeepSrcInMemory , Config.bOptions)
OPTMG_COMP (optKeepSpaces , Config.bOptions)
OPTMG_COMP (optOpenLogEarly , Config.bOptions)
OPTMG_COMP (optNoUncloseWarn , Config.bOptions)
OPTMG_COMP (dbgStd , Config.bDebug)
OPTMG_COMP (dbgMem , Config.bDebug)
OPTMG_COMP (dbgEval , Config.bDebug)
OPTMG_COMP (dbgCmd , Config.bDebug)
OPTMG_COMP (dbgEnv , Config.bDebug)
OPTMG_COMP (dbgForm , Config.bDebug)
OPTMG_COMP (dbgTab , Config.bDebug)
OPTMG_COMP (dbgInput , Config.bDebug)
OPTMG_COMP (dbgFlushOutput , Config.bDebug)
OPTMG_COMP (dbgFlushLog , Config.bDebug)
OPTMG_COMP (dbgAllCmds , Config.bDebug)
OPTMG_COMP (dbgSource , Config.bDebug)
OPTMG_COMP (dbgFunc , Config.bDebug)
OPTMG_COMP (dbgLogLink , Config.bDebug)
OPTMG_COMP (dbgDefEval , Config.bDebug)
OPTMG_COMP (dbgHeadersIn , Config.bDebug)
OPTMG_COMP (dbgShowCleanup , Config.bDebug)
OPTMG_COMP (dbgProfile , Config.bDebug)
OPTMG_COMP (dbgSession , Config.bDebug)
OPTMG_COMP (dbgImport , Config.bDebug)
static
int
AddMagic (
tApp * a,
char
* sVarName,
MGVTBL * pVirtTab)
{
SV * pSV ;
struct
magic * pMagic ;
epaTHX ;
EPENTRY (AddMagic) ;
pSV = perl_get_sv (sVarName, TRUE) ;
sv_magic (pSV, NULL, 0, sVarName,
strlen
(sVarName)) ;
sv_setiv (pSV, 0) ;
pMagic = mg_find (pSV, 0) ;
if
(pMagic)
pMagic -> mg_virtual = pVirtTab ;
else
{
LogError (NULL, rcMagicError) ;
return
1 ;
}
perl_get_sv (sVarName, TRUE) ;
return
ok ;
}
int
AddMagicAV (
register
req * r,
char
* sVarName,
MGVTBL * pVirtTab)
{
SV * pSV ;
struct
magic * pMagic ;
epTHX ;
EPENTRY (AddMagicAV) ;
pSV = (SV *)perl_get_av (sVarName, TRUE) ;
sv_magic (pSV, NULL,
'P'
, sVarName,
strlen
(sVarName)) ;
pMagic = mg_find (pSV, 0) ;
if
(pMagic)
pMagic -> mg_virtual = pVirtTab ;
else
{
LogError (r, rcMagicError) ;
return
1 ;
}
return
ok ;
}
int
embperl_Init (
pTHX_
SV * pApacheSrvSV,
SV * pPerlParam,
server_rec * ap_s)
{
int
rc ;
tThreadData * pThread ;
tApp * pApp ;
tApacheDirConfig * pApacheCfg = NULL ;
memcpy
(&ep_sv_undef, &PL_sv_undef,
sizeof
(PL_sv_undef)) ;
#ifdef APACHE
if
(pApacheSrvSV && SvROK (pApacheSrvSV))
{
ap_s = epxs_sv2_Apache__Server(pApacheSrvSV) ;
embperl_ApacheAddModule () ;
#ifdef APACHE2
#else
return
ok ;
#endif
}
#endif
if
(!pMainPool)
pMainPool = ep_init_alloc() ;
if
((rc = embperl_SetupThread (aTHX_ &pThread)) != ok)
return
rc ;
#ifdef APACHE
if
(ap_s)
{
embperl_GetApacheConfig (pThread, NULL, ap_s, &pApacheCfg) ;
}
#endif
if
((rc = embperl_SetupApp (aTHX_ pThread, pApacheCfg, pPerlParam, &pApp)) != ok)
return
rc ;
ADDINTMG (EscMode)
ADDINTMG (CurrNode)
ADDOPTMG (optDisableVarCleanup )
ADDOPTMG (optDisableEmbperlErrorPage)
ADDOPTMG (optReturnError)
ADDOPTMG (optSafeNamespace )
ADDOPTMG (optOpcodeMask )
ADDOPTMG (optRawInput )
ADDOPTMG (optSendHttpHeader )
ADDOPTMG (optDisableChdir )
ADDOPTMG (optDisableHtmlScan )
ADDOPTMG (optEarlyHttpHeader )
ADDOPTMG (optDisableFormData )
ADDOPTMG (optDisableInputScan )
ADDOPTMG (optDisableTableScan )
ADDOPTMG (optDisableMetaScan )
ADDOPTMG (optAllFormData )
ADDOPTMG (optRedirectStdout )
ADDOPTMG (optUndefToEmptyValue )
ADDOPTMG (optNoHiddenEmptyValue )
ADDOPTMG (optAllowZeroFilesize )
ADDOPTMG (optKeepSrcInMemory )
ADDOPTMG (optKeepSpaces )
ADDOPTMG (optOpenLogEarly )
ADDOPTMG (optNoUncloseWarn )
ADDOPTMG (dbgStd )
ADDOPTMG (dbgMem )
ADDOPTMG (dbgEval )
ADDOPTMG (dbgCmd )
ADDOPTMG (dbgEnv )
ADDOPTMG (dbgForm )
ADDOPTMG (dbgTab )
ADDOPTMG (dbgInput )
ADDOPTMG (dbgFlushOutput )
ADDOPTMG (dbgFlushLog )
ADDOPTMG (dbgAllCmds )
ADDOPTMG (dbgSource )
ADDOPTMG (dbgFunc )
ADDOPTMG (dbgLogLink )
ADDOPTMG (dbgDefEval )
ADDOPTMG (dbgHeadersIn )
ADDOPTMG (dbgShowCleanup )
ADDOPTMG (dbgProfile )
ADDOPTMG (dbgSession )
ADDOPTMG (dbgImport )
if
(bInitDone)
return
ok ;
#if defined (_MDEBUG) && defined (WIN32)
_CrtSetReportHook( EmbperlCRTDebugOutput );
#endif
DomInit (pApp) ;
Cache_Init (pApp) ;
Provider_Init (pApp) ;
#ifdef APACHE2
ApFilter_Init (pApp) ;
#endif
#ifdef XALAN
embperl_Xalan_Init () ;
#endif
#ifdef LIBXSLT
embperl_LibXSLT_Init () ;
#endif
ep_create_mutex(RequestCountMutex) ;
bInitDone = 1 ;
#ifdef APACHE
{
int
preload = 1 ;
if
(ap_s)
{
module * m ;
if
((m = ap_find_linked_module(
"mod_perl.c"
)))
{
if
(m -> dynamic_load_handle)
preload = 0 ;
}
}
if
(preload)
{
dSP;
PUSHMARK(sp) ;
perl_call_pv (
"Embperl::PreLoadFiles"
, G_DISCARD) ;
}
}
#else
{
dSP;
PUSHMARK(sp) ;
perl_call_pv (
"Embperl::PreLoadFiles"
, G_DISCARD) ;
}
#endif
return
rc ;
}
static
int
embperl_GetFormData (
register
req * r,
char
* pQueryString,
int
nLen)
{
int
num ;
char
* p ;
char
* pMem ;
int
nVal ;
int
nKey ;
char
* pKey ;
char
* pVal ;
SV * pSVV ;
SV * pSVK ;
SV * * ppSV ;
AV * pFormArray = r -> pThread -> pFormArray ;
HV * pFormHash = r -> pThread -> pFormHash ;
bool
bAll = (r -> Config.bOptions & optAllFormData) != 0 ;
bool
bNoUtf8 = (r -> Config.bOptions & optFormDataNoUtf8) != 0 ;
bool
bDebug = (r -> Config.bDebug & dbgForm) != 0 ;
int
mayutf8 = 0 ;
bool
bInValue = 0 ;
char
c ;
epTHX ;
if
(nLen == 0)
return
ok ;
if
((pMem = _malloc (r, nLen + 4)) == NULL)
return
rcOutOfMemory ;
p = pMem ;
nKey = nVal = 0 ;
pKey = pVal = p ;
while
(1)
{
switch
(nLen > 0?*pQueryString:
'\0'
)
{
case
'+'
:
pQueryString++ ;
nLen-- ;
*p++ =
' '
;
break
;
case
'%'
:
pQueryString++ ;
nLen-- ;
num = 0 ;
if
(*pQueryString)
{
if
(
toupper
(*pQueryString) >=
'A'
)
num += (
toupper
(*pQueryString) -
'A'
+ 10) << 4 ;
else
num += ((*pQueryString) -
'0'
) << 4 ;
pQueryString++ ;
}
if
(*pQueryString)
{
if
(
toupper
(*pQueryString) >=
'A'
)
num += (
toupper
(*pQueryString) -
'A'
+ 10) ;
else
num += ((*pQueryString) -
'0'
) ;
pQueryString++ ;
nLen-- ;
}
*p++ = num ;
break
;
case
';'
:
case
'&'
:
bInValue = 0 ;
pQueryString++ ;
nLen-- ;
case
'\0'
:
nVal = p - pVal ;
*p++ =
'\0'
;
if
(nKey > 0 && (nVal > 0 || (bAll)))
{
char
* sid = NULL ;
sid = r -> pApp -> Config.sCookieName ;
if
(sid)
{
if
(
strncmp
(pKey, sid, nKey) != 0)
sid = NULL ;
else
{
char
* p =
strchr
(pVal,
':'
) ;
if
(p && *p)
{
char
* p2 =
strchr
(p+1,
':'
) ;
if
(p2)
*p2 =
'\0'
;
r -> sSessionUserID = ep_pstrdup (r -> pPool, p + 1) ;
*p =
'\0'
;
}
if
(*pVal)
r -> sSessionStateID = ep_pstrdup (r -> pPool, pVal) ;
}
}
if
(sid == NULL)
{
if
(pVal > pKey)
pVal[-1] =
'\0'
;
if
((ppSV = hv_fetch (pFormHash, pKey, nKey, 0)))
{
sv_catpvn (*ppSV, &r -> Config.cMultFieldSep , 1) ;
sv_catpvn (*ppSV, pVal, nVal) ;
}
else
{
pSVV = newSVpv (pVal, nVal) ;
#ifdef UTF8_IS_START
if
(mayutf8 && is_utf8_string((U8*)pVal, nVal))
SvUTF8_on (pSVV) ;
#endif
if
(hv_store (pFormHash, pKey, nKey, pSVV, 0) == NULL)
{
_free (r, pMem) ;
strcpy
(r -> errdat1,
"fdat"
) ;
return
rcHashError ;
}
pSVK = newSVpv (pKey, nKey) ;
av_push (pFormArray, pSVK) ;
}
if
(bDebug)
lprintf (r -> pApp,
"[%d]FORM: %s=%s\n"
, r -> pThread -> nPid, pKey, pVal) ;
}
}
pKey = pVal = p ;
nKey = nVal = 0 ;
mayutf8 = 0 ;
if
(*pQueryString ==
'\0'
)
{
_free (r, pMem) ;
return
ok ;
}
break
;
case
'='
:
if
(!bInValue)
{
nKey = p - pKey ;
*p++ = r -> Config.cMultFieldSep ;
nVal = 0 ;
pVal = p ;
pQueryString++ ;
nLen-- ;
bInValue = 1 ;
break
;
}
default
:
c = *p++ = *pQueryString++ ;
nLen-- ;
#ifdef UTF8_IS_START
if
(!bNoUtf8)
mayutf8 += UTF8_IS_START(c) ;
#endif
break
;
}
}
return
ok ;
}
static
int
embperl_SetupFormData (
register
req * r)
{
epTHX_
char
* p = NULL ;
char
* f ;
int
rc = ok ;
STRLEN len = 0 ;
char
sLen [20] ;
const
char
* sType ;
hv_clear (r -> pThread -> pFormHash) ;
hv_clear (r -> pThread -> pFormSplitHash) ;
av_clear (r -> pThread -> pFormArray) ;
hv_clear (r -> pThread -> pInputHash) ;
if
(r -> Config.bOptions & optDisableFormData)
return
ok ;
tainted = 0 ;
#ifdef APACHE
if
(r -> pApacheReq)
{
const
char
* sLength = apr_table_get(r -> pApacheReq->headers_in,
"Content-Length"
) ;
sType = apr_table_get(r -> pApacheReq->headers_in,
"Content-Type"
) ;
len = sLength?
atoi
(sLength):0 ;
}
else
#endif
{
sLen [0] =
'\0'
;
GetHashValue (r, r -> pThread -> pEnvHash,
"CONTENT_LENGTH"
,
sizeof
(sLen) - 1, sLen) ;
sType = GetHashValueStr (aTHX_ r -> pThread -> pEnvHash,
"CONTENT_TYPE"
,
""
) ;
len =
atoi
(sLen) ;
}
if
(sType &&
strncmp
(sType,
"multipart/form-data"
, 19) == 0)
{
dSP ;
PUSHMARK(sp);
XPUSHs(r -> _perlsv);
PUTBACK;
perl_call_method (
"get_multipart_formdata"
, G_EVAL) ;
if
(SvTRUE (ERRSV))
{
STRLEN l ;
strncpy
(r -> errdat1, SvPV (ERRSV, l),
sizeof
(r -> errdat1) - 1) ;
LogError (r, rcEvalErr) ;
sv_setpv(ERRSV,
""
);
POPs ;
}
tainted = 0 ;
return
ok ;
}
if
(len > MAX_FORMDATA_SIZE)
{
LogErrorParam (r, rcFormDataTruncated, MAX_FORMDATA_SIZE_STR, NULL) ;
len = MAX_FORMDATA_SIZE ;
}
if
(len == 0)
{
p = r -> Param.sQueryInfo ;
len = p?
strlen
(p):0 ;
f = NULL ;
}
else
{
if
((p = _malloc (r, len + 1)) == NULL)
return
rcOutOfMemory ;
if
((rc = OpenInput (r, NULL)) != ok)
{
_free (r, p) ;
return
rc ;
}
iread (r, p, len) ;
CloseInput (r) ;
p[len] =
'\0'
;
f = p ;
}
if
(r -> Config.bDebug & dbgForm)
lprintf (r -> pApp,
"[%d]Formdata... length = %d\n"
, r -> pThread -> nPid, len) ;
rc = embperl_GetFormData (r, p, len) ;
if
(len > 0 && f)
{
r -> Param.sQueryInfo = f ;
f[len] =
'\0'
;
}
return
rc ;
}
static
void
embperl_LogStartReq (
req * r)
{
epTHX ;
if
(r -> Config.bDebug)
{
time_t
t =
time
(NULL) ;
lprintf (r -> pApp,
"[%d]REQ: ***** Start Request at %s"
, r -> pThread -> nPid,
ctime
(&t)) ;
lprintf (r -> pApp,
"[%d]Use App: %s\n"
, r -> pApp -> pThread -> nPid, r -> pApp -> Config.sAppName) ;
}
#ifdef APACHE
if
(r -> pApacheReq && (r -> 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_in);
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) ;
}
#endif
if
(r -> Config.bDebug & dbgEnv)
{
SV * psv ;
HE * pEntry ;
char
* pKey ;
I32 l ;
int
savewarn = dowarn ;
dowarn = 0 ;
hv_iterinit (r -> pThread -> pEnvHash) ;
while
((pEntry = hv_iternext (r -> pThread -> pEnvHash)))
{
pKey = hv_iterkey (pEntry, &l) ;
psv = hv_iterval (r -> pThread -> pEnvHash, pEntry) ;
lprintf (r -> pApp,
"[%d]ENV: %s=%s\n"
, r -> pThread -> nPid, pKey, SvPV (psv, na)) ;
}
dowarn = savewarn ;
}
}
int
embperl_SetupRequest (
pTHX_
SV * pApacheReqSV,
tApp * pApp,
tApacheDirConfig * pApacheCfg,
SV * pPerlParam,
tReq * * ppReq)
{
tReq * r ;
tThreadData * pThread ;
SV * pReqSV ;
SV * pReqRV ;
SV * pSV ;
SV * pRV ;
tReqConfig * pConfig ;
tReqParam * pParam ;
char
* pCookieName ;
HV * pParamHV = NULL ;
dSP ;
#ifdef APACHE
request_rec * pApacheReq ;
#endif
tMemPool * pPool = ep_make_sub_pool (pApp -> pPool) ;
tainted = 0 ;
if
(pPerlParam && SvROK(pPerlParam))
pParamHV = (HV *)SvRV(pPerlParam) ;
epxs_Embperl__Req_create_obj(r,pReqSV,pReqRV,ep_palloc(pPool,
sizeof
(*r))) ;
epxs_Embperl__Req__Config_create_obj(pConfig,pSV,pRV,&r->Config) ;
epxs_Embperl__Req__Param_create_obj(pParam,pSV,pRV,&r->Param) ;
#ifdef PERL_IMPLICIT_CONTEXT
r -> pPerlTHX = aTHX ;
#endif
r -> pPool = pPool ;
pConfig -> pPool = pPool ;
pParam -> pPool = pPool ;
r -> pApp = pApp ;
pThread = r -> pThread = pApp -> pThread ;
r -> pPrevReq = pThread -> pCurrReq ;
pThread -> pCurrReq = r ;
pApp -> pCurrReq = r ;
sv_setsv(pThread -> pReqRV, r -> _perlsv) ;
r -> startclock =
clock
() ;
r -> stsv_count = sv_count ;
#ifdef PERL_IMPLICIT_CONTEXT
r -> pPerlTHX = aTHX ;
#endif
#ifdef APACHE
if
(SvROK (pApacheReqSV))
pApacheReq = r -> pApacheReq = (request_rec *)SvIV((SV*)SvRV(pApacheReqSV));
else
pApacheReq = r -> pApacheReq = NULL ;
r -> pApacheReqSV = SvREFCNT_inc(pApacheReqSV) ;
if
(pApacheReq)
{
embperl_GetApacheReqConfig (pApp, pPool, pApacheCfg, &r -> Config) ;
embperl_GetApacheReqParam (pApp, pPool, pApacheReq, &r -> Param) ;
}
else
#endif
{
bool
bUseEnv = 0 ;
bool
bUseRedirectEnv = 0 ;
if
(pParamHV)
{
bUseEnv = (
bool
)GetHashValueInt (aTHX_ pParamHV,
"use_env"
, 0) ;
bUseRedirectEnv = (
bool
)GetHashValueInt (aTHX_ pParamHV,
"use_redirect_env"
, 0) ;
}
embperl_GetCGIReqConfig (pApp, pPool, &r -> Config, bUseEnv, bUseRedirectEnv, 1) ;
embperl_GetCGIReqParam (pApp, pPool, &r -> Param) ;
}
if
(pParamHV)
{
char
* fn = GetHashValueStrDup(aTHX_ pPool, pParamHV,
"inputfile"
, NULL) ;
Embperl__Req__Config_new_init(aTHX_ &r -> Config, (SV *)pParamHV, 0) ;
Embperl__Req__Param_new_init(aTHX_ &r -> Param, (SV *)pParamHV, 0) ;
if
(fn)
r -> Param.sFilename = fn ;
}
tainted = 0 ;
ep_acquire_mutex(RequestCountMutex) ;
r -> nRequestCount = nRequestCount++ ;
ep_release_mutex(RequestCountMutex) ;
r -> nRequestTime =
time
(NULL) ;
r -> pErrArray = newAV () ;
r -> pDomTreeAV = newAV () ;
r -> pCleanupAV = newAV () ;
r -> pCleanupPackagesHV = newHV () ;
r -> pMessages = newAV () ;
r -> pDefaultMessages = newAV () ;
pCookieName = r -> pApp -> Config.sCookieName ;
if
(pCookieName)
{
char
* pVal = GetHashValueStr (aTHX_ r -> Param.pCookies, pCookieName, NULL) ;
if
(pVal)
r -> sSessionUserID = ep_pstrdup (r -> pPool, pVal) ;
}
if
(r -> pApp -> Config.sCookieExpires)
{
char
buf[256] ;
if
(!embperl_CalcExpires(r -> pApp -> Config.sCookieExpires, buf, 0))
LogErrorParam (r -> pApp, rcTimeFormatErr,
"EMBPERL_COOKIE_EXPIRES"
, r -> pApp -> Config.sCookieExpires) ;
else
r -> sCookieExpires = ep_pstrdup (r -> pPool, buf) ;
}
if
(r -> pApp -> pUserHash)
r -> nSessionMgnt = 1 ;
r -> nLogFileStartPos = GetLogFilePos (pApp) ;
hv_clear (pThread -> pHeaderHash) ;
embperl_LogStartReq (r) ;
embperl_SetupFormData (r) ;
if
(r -> sSessionUserID && pApp -> pUserObj)
{
tainted = 0 ;
SPAGAIN;
PUSHMARK(sp);
XPUSHs(pApp -> pUserObj);
XPUSHs(sv_2mortal(newSVpv(r -> sSessionUserID, 0)));
PUTBACK;
perl_call_method (
"setid"
, 0) ;
}
if
(r -> sSessionStateID && pApp -> pStateObj)
{
tainted = 0 ;
SPAGAIN;
PUSHMARK(sp);
XPUSHs(pApp -> pStateObj);
XPUSHs(sv_2mortal(newSVpv(r -> sSessionStateID, 0)));
PUTBACK;
perl_call_method (
"setid"
, 0) ;
}
r -> sInitialCWD = ep_palloc(pPool, PATH_MAX * 2) ;
getcwd (r -> sInitialCWD, PATH_MAX * 2 - 1) ;
*ppReq = r ;
if
(pApp -> Config.sAppHandlerClass)
{
tainted = 0 ;
SPAGAIN ;
PUSHMARK(sp);
XPUSHs(pApp -> _perlsv);
XPUSHs(r -> _perlsv);
PUTBACK;
perl_call_method (
"init"
, G_EVAL) ;
tainted = 0 ;
if
(SvTRUE (ERRSV))
{
STRLEN l ;
POPs ;
LogErrorParam (pApp, rcEvalErr, SvPV (ERRSV, l),
" while calling APP_HANDLER_CLASS -> init"
) ;
sv_setpv(ERRSV,
""
);
return
rcEvalErr ;
}
}
tainted = 0 ;
return
ok ;
}
int
embperl_CleanupOutput (
tReq * r,
tComponent * c)
{
epTHX_
tComponentOutput * pOutput = c -> pOutput ;
if
(!pOutput || (c -> pPrev && c -> pPrev -> pOutput == pOutput))
{
return
ok ;
}
CloseOutput (r, pOutput) ;
if
(SvREFCNT(SvRV(pOutput -> _perlsv)) != 1)
{
char
buf[20] ;
sprintf
(buf,
"%d"
, (
int
)SvREFCNT(SvRV(pOutput -> _perlsv)) - 1) ;
LogErrorParam (r -> pApp, rcRefcntNotOne, buf,
"request.component.output"
) ;
}
sv_unmagic(SvRV(pOutput -> _perlsv),
'~'
) ;
SvREFCNT_dec (pOutput -> _perlsv) ;
ep_destroy_pool (pOutput -> pPool) ;
return
ok ;
}
int
embperl_CleanupComponent (
tComponent * c)
{
tReq * r = c -> pReq ;
epTHX_
SV * pHV ;
MAGIC * mg;
if
(c -> Param.sISA && c -> sCurrPackage)
{
STRLEN l ;
SV * pName = newSVpvf (
"%s::ISA"
, c -> sImportPackage) ;
AV * pCallerISA = perl_get_av (SvPV(pName, l), TRUE) ;
int
i ;
int
n = av_len(pCallerISA) + 1;
SV ** ppSV ;
newSVpvf2(pName) ;
SvREFCNT_dec (pName) ;
for
(i = 0; i < n; i++)
{
if
((ppSV = av_fetch(pCallerISA, i, 0)) && *ppSV &&
strcmp
(SvPV(*ppSV, l), c -> sCurrPackage) == 0)
break
;
}
if
(n == i)
av_push(pCallerISA, newSVpv (c -> sCurrPackage, 0)) ;
}
embperl_CleanupOutput (r, c) ;
if
(SvREFCNT(SvRV(c -> Config._perlsv)) != 1)
{
char
buf[20] ;
sprintf
(buf,
"%d"
, (
int
)SvREFCNT(SvRV(c -> Config._perlsv)) - 1) ;
LogErrorParam (r -> pApp, rcRefcntNotOne, buf,
"request.component.config"
) ;
}
if
(SvREFCNT(SvRV(c -> Param._perlsv)) != 1)
{
char
buf[20] ;
sprintf
(buf,
"%d"
, (
int
)SvREFCNT(SvRV(c -> Param._perlsv)) - 1) ;
LogErrorParam (r -> pApp, rcRefcntNotOne, buf,
"request.component.param"
) ;
}
if
(SvREFCNT(c -> _perlsv) != 1)
{
char
buf[20] ;
sprintf
(buf,
"%d"
, (
int
)SvREFCNT(SvRV(c -> _perlsv)) - 1) ;
LogErrorParam (r -> pApp, rcRefcntNotOne, buf,
"request.component"
) ;
}
Embperl__Component__Config_destroy(aTHX_ &c -> Config) ;
Embperl__Component__Param_destroy(aTHX_ &c -> Param) ;
Embperl__Component_destroy(aTHX_ c) ;
pHV = SvRV (c -> _perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponent **)(mg -> mg_ptr)) = &NullRequest.Component ;
pHV = SvRV (c -> Config._perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponentConfig **)(mg -> mg_ptr)) = &NullRequest.Component.Config ;
pHV = SvRV (c -> Param._perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponentParam **)(mg -> mg_ptr)) = &NullRequest.Component.Param ;
SvREFCNT_dec (c -> Config._perlsv) ;
SvREFCNT_dec (c -> Param._perlsv) ;
SvREFCNT_dec (c -> _perlsv) ;
if
(c == &r -> Component && c -> pPrev)
{
tComponent * pPrev = c -> pPrev;
memcpy
(c, pPrev,
sizeof
(*c)) ;
pHV = SvRV (c -> _perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponent **)(mg -> mg_ptr)) = c ;
pHV = SvRV (c -> Config._perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponentConfig **)(mg -> mg_ptr)) = &c -> Config ;
pHV = SvRV (c -> Param._perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponentParam **)(mg -> mg_ptr)) = &c -> Param ;
}
else
{
c -> _perlsv = NULL ;
}
return
ok ;
}
int
embperl_CleanupRequest (
tReq * r)
{
epTHX_
int
i ;
HE * pEntry ;
I32 l ;
tApp * pApp = r -> pApp ;
SV * pHV ;
MAGIC * mg;
dSP ;
hv_iterinit (r -> pCleanupPackagesHV) ;
while
((pEntry = hv_iternext (r -> pCleanupPackagesHV)))
{
char
* sPackage = hv_iterkey (pEntry, &l) ;
ClearSymtab (r, sPackage, r -> Config.bDebug & dbgShowCleanup) ;
}
tainted = 0 ;
sv_setsv(r -> pThread -> pReqRV, &sv_undef) ;
while
(r -> Component._perlsv)
embperl_CleanupComponent(&r -> Component) ;
if
(r -> nSessionMgnt)
{
SPAGAIN ;
PUSHMARK(sp);
XPUSHs(pApp -> pAppObj);
PUTBACK;
perl_call_method (
"cleanup"
, G_DISCARD) ;
SPAGAIN ;
PUSHMARK(sp);
XPUSHs(pApp -> pUserObj);
PUTBACK;
perl_call_method (
"cleanup"
, G_DISCARD) ;
SPAGAIN ;
PUSHMARK(sp);
XPUSHs(pApp -> pStateObj);
PUTBACK;
perl_call_method (
"cleanup"
, G_DISCARD) ;
SPAGAIN ;
}
hv_clear (r -> pThread -> pHeaderHash) ;
hv_clear (r -> pThread -> pInputHash) ;
av_clear (r -> pThread -> pFormArray) ;
hv_clear (r -> pThread -> pFormHash) ;
hv_clear (r -> pThread -> pFormSplitHash) ;
av_clear (r -> pDomTreeAV) ;
SvREFCNT_dec (r -> pDomTreeAV) ;
for
(i = 0 ; i <= av_len (r -> pCleanupAV); i++)
{
SV ** ppSV = av_fetch (r -> pCleanupAV, i, 0) ;
SV * pSV = * ppSV ;
if
(SvROK(pSV))
sv_setsv (SvRV(pSV), &sv_undef) ;
}
av_clear (r -> pCleanupAV) ;
Cache_CleanupRequest (r) ;
if
(SvREFCNT(SvRV(r -> Config._perlsv)) != 1)
{
char
buf[20] ;
sprintf
(buf,
"%d"
, (
int
)SvREFCNT(SvRV(r -> Config._perlsv)) - 1) ;
LogErrorParam (r -> pApp, rcRefcntNotOne, buf,
"request.config"
) ;
}
if
(SvREFCNT(SvRV(r -> Param._perlsv)) != 1)
{
char
buf[20] ;
sprintf
(buf,
"%d"
, (
int
)SvREFCNT(SvRV(r -> Param._perlsv)) - 1) ;
LogErrorParam (r -> pApp, rcRefcntNotOne, buf,
"request.param"
) ;
}
SvREFCNT_dec (r -> pErrArray) ;
r -> pErrArray = NULL ;
Embperl__Req__Config_destroy(aTHX_ &r -> Config) ;
Embperl__Req__Param_destroy(aTHX_ &r -> Param) ;
Embperl__Req_destroy(aTHX_ r) ;
pHV = SvRV (r -> _perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tReq **)(mg -> mg_ptr)) = &NullRequest ;
pHV = SvRV (r -> Config._perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tReqConfig **)(mg -> mg_ptr)) = &NullRequest.Config ;
pHV = SvRV (r -> Param._perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tReqParam **)(mg -> mg_ptr)) = &NullRequest.Param ;
SvREFCNT_dec (r -> Config._perlsv) ;
SvREFCNT_dec (r -> Param._perlsv) ;
SvREFCNT_dec (r -> _perlsv) ;
ep_destroy_pool (r -> pPool) ;
sv_setpv(ERRSV,
""
);
if
(r -> Config.bDebug)
DomStats (r -> pApp) ;
r -> pThread -> pCurrReq = r -> pPrevReq ;
r -> pApp -> pCurrReq = r -> pPrevReq ;
if
(r -> pPrevReq)
sv_setsv(r -> pThread -> pReqRV, r -> pPrevReq -> _perlsv) ;
return
ok ;
}
int
embperl_SetupOutput (
tReq * r,
tComponent * c)
{
epTHX_
int
rc ;
SV * pSV ;
SV * pRV ;
tComponentOutput * pOutput ;
tMemPool * pPool ;
if
(!c -> Param.pOutput && !c -> Param.sOutputfile && c -> pPrev && !r -> Component.pImportStash)
{
c -> pOutput = c -> pPrev -> pOutput ;
return
ok ;
}
pPool = ep_make_sub_pool (r -> pPool) ;
tainted = 0 ;
epxs_Embperl__Component__Output_create_obj(pOutput,pSV,pRV,ep_palloc(pPool,
sizeof
(tComponentOutput))) ;
tainted = 0 ;
pOutput -> pPool = pPool ;
c -> pOutput = pOutput ;
if
(r -> Component.pImportStash)
pOutput -> bDisableOutput = 1 ;
else
if
(c -> Param.pOutput)
{
if
((rc = OpenOutput (r,
""
)) != ok)
return
rc ;
}
else
{
if
((rc = OpenOutput (r, embperl_File2Abs(r, pOutput -> pPool, c -> Param.sOutputfile))) != ok)
return
rc ;
}
return
ok ;
}
int
embperl_SetupComponent (
tReq * r,
SV * pPerlParam,
tComponent * * ppComponent)
{
int
rc ;
SV * pComponentSV ;
SV * pComponentRV ;
SV * pSV ;
SV * pRV ;
tComponent * c ;
tComponentParam * pParam ;
tComponentConfig * pConfig ;
epTHX_
tComponent * pPrev = NULL ;
char
* p ;
HV * pParamHV = NULL ;
if
(r -> Component._perlsv)
{
SV * pHV ;
MAGIC * mg ;
pPrev = ep_palloc(r->pPool,
sizeof
(*pPrev)) ;
memcpy
(pPrev, &r -> Component,
sizeof
(*pPrev)) ;
pHV = SvRV (pPrev -> _perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponent **)(mg -> mg_ptr)) = pPrev ;
pHV = SvRV (pPrev -> Config._perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponentConfig **)(mg -> mg_ptr)) = &pPrev -> Config ;
pHV = SvRV (pPrev -> Param._perlsv) ;
if
((mg = mg_find (pHV,
'~'
)))
*((tComponentParam **)(mg -> mg_ptr)) = &pPrev -> Param ;
}
if
(pPerlParam && SvROK(pPerlParam))
pParamHV = (HV *)SvRV(pPerlParam) ;
epxs_Embperl__Component_create_obj(c,pComponentSV, pComponentRV,&r->Component) ;
epxs_Embperl__Component__Param_create_obj(pParam,pSV, pRV,&r->Component.Param) ;
epxs_Embperl__Component__Config_create_obj(pConfig,pSV, pRV,&r->Component.Config) ;
r -> Component.pPrev = pPrev ;
c -> pPool = r -> pPool ;
pParam -> pPool = r -> pPool ;
pConfig -> pPool = r -> pPool ;
c -> Param.nImport = -1 ;
c -> Param.nFirstLine = 1 ;
c -> pReq = r ;
#ifdef APACHE
if
(r -> pApacheReq)
{
embperl_GetApacheComponentConfig (r, r -> pPool, r -> pApacheConfig, &c -> Config) ;
}
else
#endif
{
bool
bUseEnv = 0 ;
bool
bUseRedirectEnv = 0 ;
if
(pParamHV)
{
bUseEnv = (
bool
)GetHashValueInt (aTHX_ pParamHV,
"use_env"
, 0) ;
bUseRedirectEnv = (
bool
)GetHashValueInt (aTHX_ pParamHV,
"use_redirect_env"
, 0) ;
}
embperl_GetCGIComponentConfig (r, r -> pPool, &c -> Config, bUseEnv, bUseRedirectEnv, 1) ;
}
if
(pPrev)
c -> Config.bOptions &= ~optReturnError ;
if
(pParamHV)
{
Embperl__Component__Config_new_init (aTHX_ &c -> Config, (SV *)pParamHV, 0) ;
Embperl__Component__Param_new_init (aTHX_ &c -> Param, (SV *)pParamHV, 0) ;
}
c -> sCWD = pPrev?pPrev -> sCWD:r -> sInitialCWD ;
if
(c -> sCWD == NULL)
c -> sCWD =
""
;
NewEscMode (r, NULL) ;
c -> bEscModeSet = 0 ;
if
(c -> Param.nImport < 0 && (c -> Param.sObject || c -> Param.sISA))
c -> Param.nImport = 0 ;
if
(c -> Param.nImport >= 0)
{
char
code[40] ;
SV * pSVImport ;
STRLEN l ;
sprintf
(code,
"caller(%d)"
, c -> Param.nImport>0?c -> Param.nImport:1) ;
pSVImport = perl_eval_pv(code, 0) ;
if
(!SvOK(pSVImport))
{
if
(c -> Param.nImport == 0)
c -> sImportPackage =
"main"
;
else
{
LogError (r, rcImportStashErr) ;
c -> sImportPackage = NULL ;
}
}
else
c -> sImportPackage = ep_pstrdup(r -> pPool, SvPV (pSVImport, l)) ;
if
(c -> sImportPackage)
{
if
((c -> pImportStash = gv_stashpv (c -> sImportPackage, 0)) == NULL)
{
strncpy
(r -> errdat1, c -> sImportPackage,
sizeof
(r -> errdat1) - 1);
LogError (r, rcImportStashErr) ;
}
SvREFCNT_inc(c -> pImportStash) ;
}
}
c -> nSourceline = pParam -> nFirstLine ;
if
(!pParam -> sInputfile)
{
if
(pParam -> sISA)
pParam -> sInputfile = pParam -> sISA ;
else
if
(pParam -> sObject)
pParam -> sInputfile = pParam -> sObject ;
else
{
if
(pPrev)
pParam -> sInputfile = pPrev -> sSourcefile ;
if
(!pParam -> sInputfile)
pParam -> sInputfile = r -> Param.sFilename ;
}
}
else
if
((p =
strchr
(pParam -> sInputfile,
'#'
)))
{
pParam -> sSub = p + 1 ;
if
(p == pParam -> sInputfile && c -> pPrev)
pParam -> sInputfile = c -> pPrev -> sSourcefile ;
else
*p =
'\0'
;
}
if
(!pParam -> sInputfile || !*pParam -> sInputfile ||
strcmp
(pParam -> sInputfile,
"*"
) == 0)
pParam -> sInputfile = r -> Param.sFilename ;
else
if
(
strcmp
(pParam -> sInputfile,
"../*"
) == 0)
{
#ifdef WIN32
char
* p =
strrchr
(r -> Param.sFilename,
'\\'
) ;
if
(!p)
p =
strrchr
(r -> Param.sFilename,
'/'
) ;
#else
char
* p =
strrchr
(r -> Param.sFilename,
'/'
) ;
#endif
if
(!p)
p = r -> Param.sFilename ;
else
p++ ;
pParam -> sInputfile = ep_pstrcat(r -> pPool,
"../"
, p, NULL) ;
}
*ppComponent = c ;
if
(!pParam -> sInputfile)
rc = rcMissingInput ;
else
rc = embperl_SetupOutput (r, c) ;
if
(rc != ok)
LogError (r, rc) ;
return
rc ;
}
/*---------------------------------------------------------------------------
* embperl_InitRequest
*/
int
embperl_InitAppForRequest (
pTHX_
SV * pApacheReqSV,
SV * pPerlParam,
tThreadData * * ppThread,
tApp * * ppApp,
tApacheDirConfig * * ppApacheCfg)
{
int
rc ;
tThreadData * pThread ;
tApp * pApp ;
tApacheDirConfig * pApacheCfg = NULL ;
if
((rc = embperl_SetupThread (aTHX_ &pThread)) != ok)
{
LogError (NULL, rc) ;
return
rc ;
}
#ifdef APACHE
if
(pApacheReqSV && SvROK (pApacheReqSV))
{
request_rec * ap_r = (request_rec *)SvIV((SV*)SvRV(pApacheReqSV));
embperl_GetApacheConfig (pThread, ap_r, ap_r -> server, &pApacheCfg) ;
}
#endif
if
((rc = embperl_SetupApp (aTHX_ pThread, pApacheCfg, pPerlParam, &pApp)) != ok)
{
LogError (NULL, rc) ;
return
rc ;
}
*ppThread = pThread ;
*ppApp = pApp ;
*ppApacheCfg = pApacheCfg ;
return
ok ;
}
int
embperl_InitRequest (
pTHX_
SV * pApacheReqSV,
SV * pPerlParam,
tReq * * ppReq)
{
int
rc ;
tThreadData * pThread ;
tApp * pApp ;
tReq * r ;
tApacheDirConfig * pApacheCfg = NULL ;
if
((rc = embperl_InitAppForRequest (aTHX_
pApacheReqSV,
pPerlParam,
&pThread,
&pApp,
&pApacheCfg)) != ok)
{
LogError (NULL, rc) ;
return
rc ;
}
if
((rc = embperl_SetupRequest (aTHX_ pApacheReqSV, pApp, pApacheCfg, pPerlParam, &r)) != ok)
{
LogErrorParam (pApp, rc, NULL, NULL) ;
return
rc ;
}
r -> pApacheConfig = pApacheCfg ;
*ppReq = r ;
if
(r -> Config.pAllow || r -> Config.pUriMatch)
{
SV * args[1] ;
SV * pRet ;
STRLEN l ;
if
(r -> Param.sUri && *r -> Param.sUri)
args[0] = newSVpv (r -> Param.sUri, 0) ;
else
if
(r -> Param.sFilename && *r -> Param.sFilename)
args[0] = newSVpv (r -> Param.sFilename, 0) ;
else
if
(pPerlParam && SvROK(pPerlParam))
args[0] = (SV *)GetHashValueSVinc (r, (HV *)SvRV(pPerlParam),
"inputfile"
, &sv_undef) ;
else
{
LogError (r, rcCannotCheckUri) ;
return
rcCannotCheckUri ;
}
if
(r -> Config.pAllow)
{
CallStoredCV (r,
"ALLOW"
, r -> Config.pAllow, 1, args, 0, &pRet) ;
if
(pRet && !SvTRUE(pRet))
{
strncpy
(r -> errdat1, SvPV(args[0], l),
sizeof
(r -> errdat1) - 1) ;
SvREFCNT_dec(args[0]) ;
if
(pRet)
SvREFCNT_dec(pRet) ;
LogError (r, rcForbidden) ;
return
rcForbidden ;
}
if
(pRet)
SvREFCNT_dec(pRet) ;
}
if
(r -> Config.pUriMatch)
{
CallStoredCV (r,
"URIMATCH"
, r -> Config.pUriMatch, 1, args, 0, &pRet) ;
if
(pRet && !SvTRUE(pRet))
{
strncpy
(r -> errdat1, SvPV(args[0], l),
sizeof
(r -> errdat1) - 1) ;
SvREFCNT_dec(args[0]) ;
if
(pRet)
SvREFCNT_dec(pRet) ;
return
rcDecline ;
}
if
(pRet)
SvREFCNT_dec(pRet) ;
}
SvREFCNT_dec(args[0]) ;
}
return
ok ;
}
int
embperl_InitRequestComponent (
pTHX_
SV * pApacheReqSV,
SV * pPerlParam,
tReq * * ppReq)
{
int
rc ;
tComponent * pComponent ;
if
((rc = embperl_InitRequest (aTHX_ pApacheReqSV, pPerlParam, ppReq)) != ok)
return
rc ;
return
embperl_SetupComponent (*ppReq, pPerlParam, &pComponent) ;
}