Read and process a Dissemino Sphere config XML document. Programs using the Dissemino method (DM) to serve HTTP/S, are invoked with a single XML config file. In the case of the DWE this must either be that of a single webapp with a <webappCfg> root tag, or that of a Dissemino Sphere (a set of one or more webapps), with a <sphereCfg> root tag. Where the program only handles a single webapp (the usual case), the config file must begin with <webappCfg> and describe a single webapp. Only the DWE requires a Dissemino Sphere and thus only the DWE calls this function. Within the <sphereCfg> tag, webapps are declared by either a <webappInternal> OR a <webappProxy> tag. In all cases the DWE will be accepting client connections on behalf of the webaps. Listening ports for the HTTP and/or HTTPS service must be specified, as must the location of any webapp specific security certificates. These parameters in the internal case, are supplied in the webapp config file. In the by proxy case, they are supplied in the <webapp> tag. Indeed, it is the presence of a listening port attribute in the <webapp> tag, that indicates that the webapp is by proxy. Note that should a multiple domain certificate apply, the files for this will be specified as attributes in the <sphereCfg> tag. Note also that webapps are usually in their own directory so where multiple webapps are to be hosted, the sphere file (containing the <sphereCfg> tag), should ideally be in none of them.
| Return Type | Function name | Arguments |
|---|---|---|
| hzEcode | hdsSphere::ReadSphere | (hzXmlNode*,) |
Declared in file: hzDissemino.h
Defined in file : hdsConfig.cpp
Function Logic:
Function body:
hzEcode hdsSphere::ReadSphere (hzXmlNode* pRoot)
{
// Category: Dissemino Config
//
// Read and process a Dissemino Sphere config XML document.
//
// Programs using the Dissemino method (DM) to serve HTTP/S, are invoked with a single XML config file. In the case of the DWE this must either be that of a single webapp with
// a <webappCfg> root tag, or that of a Dissemino Sphere (a set of one or more webapps), with a <sphereCfg> root tag. Where the program only handles a single webapp (the usual
// case), the config file must begin with <webappCfg> and describe a single webapp.
//
// Only the DWE requires a Dissemino Sphere and thus only the DWE calls this function.
//
// Within the <sphereCfg> tag, webapps are declared by either a <webappInternal> OR a <webappProxy> tag. In all cases the DWE will be accepting client connections on behalf of
// the webaps. Listening ports for the HTTP and/or HTTPS service must be specified, as must the location of any webapp specific security certificates. These parameters in the
// internal case, are supplied in the webapp config file. In the by proxy case, they are supplied in the <webapp> tag. Indeed, it is the presence of a listening port attribute
// in the <webapp> tag, that indicates that the webapp is by proxy.
//
// Note that should a multiple domain certificate apply, the files for this will be specified as attributes in the <sphereCfg> tag.
//
// Note also that webapps are usually in their own directory so where multiple webapps are to be hosted, the sphere file (containing the <sphereCfg> tag), should ideally be in
// none of them.
_hzfunc("hdsSphere::ReadSphere") ;
hzSet <hzString> appnames ; // Used for checking if appnames are unique
hzSet <uint32_t> ports ; // Used for checking if ports are unique
hzDocXml X ; // The config document
hzXmlNode* pN ; // Current node
hdsApp* pApp ; // Webapp pointer
_sphere_app* pSE ; // Sphere app entry
hzAttrset ai ; // XML node attribute iterator
hzDomain domain ; // Webapp domain name
hzDomain subdom ; // ALternative way of reaching site
hzString appname ; // Webapp name
hzString baseDir ; // Webapp base directory
hzString rootFile ; // Webapp root filename
hzString cfgfile ; // Webapp config file
hzString cookieBase ; // Cookie base is set at global level
hzString pvtKey ; // Webapp private key
hzString cert ; // Webapp certificate
hzString certCA ; // Webapp certificate authority
uint32_t nA ; // Webapp iterator
uint32_t nPortSTD ; // HTTP port
uint32_t nPortSSL ; // HTTPS port
bool bReal ; // Internal app
hzEcode rc = E_OK ; // Return code
InitJS_Events() ;
if (!pRoot->NameEQ("sphereCfg"))
{ m_pLog->Log("Expected root tag of <sphereCfg>. Tag <%s> disallowed\n", pRoot->txtName()) ; return E_CONFIG ; }
/*
** ** Get sphere parameters
** */
for (ai = pRoot ; ai.Valid() ; ai.Advance())
{
if (ai.NameEQ("sslPvtKey")) m_dfltSSL_PvtKey = ai.Value() ;
else if (ai.NameEQ("sslCert")) m_dfltSSL_Cert = ai.Value() ;
else if (ai.NameEQ("sslCertCA")) m_dfltSSL_CertCA = ai.Value() ;
else if (ai.NameEQ("portSTD")) m_nCommonPortSTD = ai.Value() ? atoi(ai.Value()) : 0;
else if (ai.NameEQ("portSSL")) m_nCommonPortSSL = ai.Value() ? atoi(ai.Value()) : 0;
else if (ai.NameEQ("blacklist")) m_Blacklist = ai.Value() ;
else
{
m_pLog->Log("File %s Line %d <sphereCfg> tag: Expect name|basedir|sslPvtKey|sslCert|sslCertCA|portSTD|portSSL only. Invalid param (%s=%s)\n",
pRoot->Fname(), pRoot->Line(), ai.Name(), ai.Value()) ;
rc = E_CONFIG ;
}
}
// Check ports are legal
if (!m_nCommonPortSTD || m_nCommonPortSTD > 0xffff)
{ rc = E_CONFIG ; m_pLog->Log("File %s Line %d <sphereCfg> No HTTP port set in the Sphere or the APP\n", pRoot->Fname(), pRoot->Line()) ; }
if (!m_nCommonPortSSL || m_nCommonPortSSL > 0xffff)
{ rc = E_CONFIG ; m_pLog->Log("File %s Line %d <sphereCfg> No HTTP port set in the Sphere or the APP\n", pRoot->Fname(), pRoot->Line()) ; }
// SSL all or none!
if ((m_dfltSSL_PvtKey || m_dfltSSL_Cert || m_dfltSSL_CertCA) && !(m_dfltSSL_PvtKey && m_dfltSSL_Cert && m_dfltSSL_CertCA))
{ rc = E_CONFIG ; m_pLog->Log("File %s Line %d <sphereCfg> Must set NONE or ALL SSL params\n", pRoot->Fname(), pRoot->Line()) ; }
if (rc != E_OK)
return rc ;
/*
** ** Get initial parameters for each application
** */
for (pN = pRoot->GetFirstChild() ; rc == E_OK && pN ; pN = pN->Sibling())
{
bReal = false ;
nPortSTD = nPortSSL = 0;
appname.Clear() ;
domain.Clear() ;
baseDir.Clear() ;
rootFile.Clear() ;
pvtKey.Clear() ;
cert.Clear() ;
certCA.Clear() ;
if (pN->NameEQ("webappProxy"))
{
for (ai = pN ; ai.Valid() ; ai.Advance())
{
if (ai.NameEQ("appname")) appname = ai.Value() ;
else if (ai.NameEQ("domain")) domain = ai.Value() ;
else if (ai.NameEQ("portSTD")) nPortSTD = ai.Value() ? atoi(ai.Value()) : 0;
else if (ai.NameEQ("portSSL")) nPortSSL = ai.Value() ? atoi(ai.Value()) : 0;
else
{
m_pLog->Log("File %s Line %d <webappProxy> tag: Expect appname|domain|portSTD|portSSL only. Invalid param (%s=%s)\n",
pRoot->Fname(), pRoot->Line(), ai.Name(), ai.Value()) ;
rc = E_CONFIG ;
}
}
// In the by-proxy case, the ports are compulsory
if (nPortSTD == 0|| nPortSTD > 0xffff)
{ rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webapp> HTTP port illegal (%u)\n", pRoot->Fname(), pRoot->Line(), nPortSTD) ; }
if (nPortSSL == 0|| nPortSSL > 0xffff)
{ rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webapp> HTTP port illegal (%u)\n", pRoot->Fname(), pRoot->Line(), nPortSTD) ; }
}
else if (pN->NameEQ("webappInternal"))
{
for (ai = pN ; ai.Valid() ; ai.Advance())
{
if (ai.NameEQ("appname")) appname = ai.Value() ;
else if (ai.NameEQ("domain")) domain = ai.Value() ;
else if (ai.NameEQ("basedir")) baseDir = ai.Value() ;
else if (ai.NameEQ("rootfile")) rootFile = ai.Value() ;
else if (ai.NameEQ("sslPvtKey")) pvtKey = ai.Value() ;
else if (ai.NameEQ("sslCert")) cert = ai.Value() ;
else if (ai.NameEQ("sslCertCA")) certCA = ai.Value() ;
else if (ai.NameEQ("portSTD")) nPortSTD = ai.Value() ? atoi(ai.Value()) : 0;
else if (ai.NameEQ("portSSL")) nPortSSL = ai.Value() ? atoi(ai.Value()) : 0;
else
{
m_pLog->Log("File %s Line %d <webapp> tag: Expect name|domain|basedir|rootfile|index|portSTD|portSSL only. Invalid param (%s=%s)\n",
pRoot->Fname(), pRoot->Line(), ai.Name(), ai.Value()) ;
rc = E_CONFIG ;
}
}
// Must have appname, domain, baseDir and rootFile
if (!appname) { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> No Appname\n", pRoot->Fname(), pRoot->Line()) ; }
if (!domain) { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> No Domain\n", pRoot->Fname(), pRoot->Line()) ; }
if (!baseDir) { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> No basedir\n", pRoot->Fname(), pRoot->Line()) ; }
if (!rootFile) { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> No config file\n", pRoot->Fname(), pRoot->Line()) ; }
// Ports not compulsory but if supplied, must be legal
if (nPortSTD && nPortSTD > 0xffff)
{ rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> HTTP port illegal (%u)\n", pRoot->Fname(), pRoot->Line(), nPortSTD) ; }
if (nPortSSL && nPortSSL > 0xffff)
{ rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> HTTP port illegal (%u)\n", pRoot->Fname(), pRoot->Line(), nPortSTD) ; }
bReal = true ;
}
else
{
rc = E_CONFIG ;
m_pLog->Log("File %s Line %d. Expected <webappInternal> or <webappProxy> tag, not <%s>\n", pN->Fname(), pN->Line(), pN->txtName()) ;
break ;
}
// Check appname is unique
if (appnames.Exists(appname))
{
rc = E_DUPLICATE ;
m_pLog->Log("File %s Line %d <%s> Appname %s already taken\n", pN->Fname(), pN->Line(), pN->txtName(), *appname) ;
break ;
}
appnames.Insert(appname) ;
// Check port settings do not conflict
if (nPortSTD && ports.Exists(nPortSTD))
{ rc = E_DUPLICATE ; m_pLog->Log("File %s Line %d <%s> Port %u already taken\n", pN->Fname(), pN->Line(), pN->txtName(), nPortSTD) ; }
ports.Insert(nPortSTD) ;
if (nPortSSL && ports.Exists(nPortSSL))
{ rc = E_DUPLICATE ; m_pLog->Log("File %s Line %d <%s> Port %u already taken\n", pN->Fname(), pN->Line(), pN->txtName(), nPortSTD) ; }
ports.Insert(nPortSSL) ;
if (rc != E_OK)
break ;
// Add the webapp to the sphere
pSE = new _sphere_app() ;
pSE->m_Appname = appname ;
pSE->m_Domain = domain ;
pSE->m_Basedir = baseDir ;
pSE->m_CfgFile = rootFile ;
pSE->m_PortHTTP = nPortSTD ;
pSE->m_PortHTTPS = nPortSSL ;
if (bReal)
{
// Create and initialize (pre-config), the hdsApp instance
pApp = pSE->m_pApp = hdsApp::GetInstance(*m_pLog) ;
pApp->m_Appname = pSE->m_Appname ;
pApp->m_Domain = pSE->m_Domain ;
pApp->m_BaseDir = pSE->m_Basedir ;
pApp->m_RootFile = pSE->m_CfgFile ;
}
m_AppsByHost.Insert(pSE->m_Domain, pSE) ;
m_pLog->Log("Added webapp %s %s\n", *appname, *domain) ;
}
m_pLog->Log("Initalizing Apps\n") ;
// INIT the Apps
for (nA = 0; rc == E_OK && nA < _hzGlobal_Sphere->Count() ; nA++)
{
pSE = m_AppsByHost.GetObj(nA) ;
if (!pSE->m_pApp)
{
m_pLog->Log("Webapp %s:- Hosted by proxy\n", *pSE->m_Appname) ;
continue ;
}
// App is to be hosted internally
pApp = pSE->m_pApp ;
rc = pApp->m_ADP.InitStandard(pSE->m_Appname) ;
if (rc != E_OK)
m_pLog->Log("Init Standard Failed err=%s\n", Err2Txt(rc)) ;
if (pApp->m_OpFlags & DS_APP_SITEINDEX)
pApp->m_ADP.InitSiteIndex("../data") ;
pApp->SetStdTypeValidations() ;
m_pLog->Log("Webapp %s:- Standard Types created\n", *pApp->m_Appname) ;
cfgfile = pApp->m_BaseDir ;
cfgfile += "/config/" ;
cfgfile += pApp->m_RootFile ;
m_pLog->Log("Processing Webapp Cfg File [%s]\n", *cfgfile) ;
rc = pApp->ReadWebappCfg(cfgfile) ;
if (rc != E_OK)
m_pLog->Log("ReadWebapp failed: err=%s\n", Err2Txt(rc)) ;
else
{
pApp->SetupMasterMenu() ;
m_pLog->Log("Webapp %s:- Data Model Editing initialized\n", *pApp->m_Domain) ;
rc = pApp->CheckProject() ;
if (rc != E_OK)
m_pLog->Log("Check project failed: err=%s\n", Err2Txt(rc)) ;
}
}
return rc ;
}