683 lines
18 KiB
C++
683 lines
18 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 2000.
|
|
//
|
|
// File: V R O O T S . C P P
|
|
//
|
|
// Contents: Implements the virtual root system for the HTTP server
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: danielwe 2000/11/6
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include "httpd.h"
|
|
#include "ncreg.h"
|
|
|
|
// Used to split a URL and Path Translated apart for ISAPI/ASP scripts
|
|
inline void SetPathInfo(PSTR *ppszPathInfo,PSTR pszInputURL,int iURLLen)
|
|
{
|
|
int iLen = strlen(pszInputURL+iURLLen) + 2;
|
|
|
|
|
|
// If we've mapped the virtual root "/" to a script, need an extra "/" for the path
|
|
// (normally we use the origial trailing "/", but in this case the "/" is the URL
|
|
// BUGBUG: Probably should rewrite the Virtual roots parsing
|
|
// mechanism so that it's cleaner.
|
|
*ppszPathInfo = MySzAllocA((iURLLen == 1) ? iLen + 1 : iLen);
|
|
if (! (*ppszPathInfo))
|
|
goto done;
|
|
|
|
if (iURLLen == 1)
|
|
{
|
|
(*ppszPathInfo)[0] = '/';
|
|
memcpy( (*ppszPathInfo) +1, pszInputURL + iURLLen, iLen);
|
|
}
|
|
else
|
|
memcpy(*ppszPathInfo, pszInputURL + iURLLen, iLen);
|
|
|
|
|
|
done:
|
|
// URL shouldn't contain path info, break it apart
|
|
pszInputURL[iURLLen] = 0;
|
|
}
|
|
|
|
|
|
PVROOTINFO CVRoots::MatchVRoot(PCSTR pszInputURL, int iInputLen)
|
|
{
|
|
int i, iMatch;
|
|
|
|
// If there was an error on setting up the vroots, m_pVRoots = NULL.
|
|
if (!m_pVRoots)
|
|
return NULL;
|
|
|
|
for(i=0, iMatch=-1; i<m_nVRoots; i++)
|
|
{
|
|
int iLen = m_pVRoots[i].iURLLen;
|
|
|
|
// If this root maps to physical path "\", special case.
|
|
// In general we store pszURL without trailing "/", however we have
|
|
// to store trailing "/" for root directory.
|
|
|
|
if (m_pVRoots[i].bRootDir && iLen != 1)
|
|
iLen--;
|
|
|
|
if(iLen && iInputLen >= iLen)
|
|
{
|
|
if(0 == _memicmp(pszInputURL, m_pVRoots[i].pszURL, iLen))
|
|
{
|
|
// If it's not root dir, always matched. Otherwise it's possible
|
|
// there wasn't a match. For root dirs, pszURL[iLen] is always "/"
|
|
|
|
if (!m_pVRoots[i].bRootDir || m_pVRoots[i].iURLLen == 1 || pszInputURL[iLen] == '/' || pszInputURL[iLen] == '\0')
|
|
{
|
|
TraceTag(ttidWebServer, "URL %s matched VRoot %s (path %S, perm=%d, auth=%d)",
|
|
pszInputURL, m_pVRoots[i].pszURL,
|
|
m_pVRoots[i].wszPath,
|
|
m_pVRoots[i].dwPermissions,
|
|
m_pVRoots[i].AuthLevel);
|
|
return &(m_pVRoots[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
TraceTag(ttidWebServer, "URL %s did not matched any VRoot", pszInputURL);
|
|
return NULL;
|
|
}
|
|
|
|
BOOL CVRoots::FillVRoot(PVROOTINFO pvr, LPWSTR wszURL, LPWSTR wszPath)
|
|
{
|
|
int err = 0; // err variable is used in non-Debug mode
|
|
const char cszDLL[] = ".dll";
|
|
const char cszASP[] = ".asp";
|
|
|
|
CHAR pszURL[MAX_PATH+1];
|
|
CHAR pszPath[MAX_PATH+1];
|
|
// convert URL to MBCS
|
|
int iLen = pvr->iURLLen = MyW2A(wszURL, pszURL, sizeof(pszURL));
|
|
if(!iLen)
|
|
{ myleave(83); }
|
|
|
|
pvr->iURLLen--; // -1 for null-term
|
|
|
|
pvr->iPathLen = wcslen(wszPath);
|
|
MyW2A(wszPath, pszPath, sizeof(pszPath));
|
|
|
|
|
|
// check to see if Vroot ends in .dll or .asp, in this case we send
|
|
// client not to the directory but to the script page.
|
|
if (pvr->iPathLen >= sizeof(cszDLL) &&
|
|
0 == strcmpi(pszPath + pvr->iPathLen - sizeof(cszDLL) +1,cszDLL))
|
|
{
|
|
pvr->ScriptType = SCRIPT_TYPE_EXTENSION;
|
|
}
|
|
else if (pvr->iPathLen >= sizeof(cszASP) &&
|
|
0 == strcmpi(pszPath + pvr->iPathLen - sizeof(cszASP) +1,cszASP))
|
|
{
|
|
pvr->ScriptType = SCRIPT_TYPE_ASP;
|
|
}
|
|
else
|
|
{
|
|
pvr->ScriptType = SCRIPT_TYPE_NONE;
|
|
}
|
|
|
|
// If one of URL or path ends in a slash, the other must too.
|
|
// If either the URL ends in a "/" or when the path ends in "\", we remove
|
|
// the extra symbol. However, in the case where either URL or path is
|
|
// root we don't do this.
|
|
|
|
if (pvr->iURLLen != 1 && pszURL[pvr->iURLLen-1]=='/')
|
|
{
|
|
pszURL[pvr->iURLLen-1] = L'\0';
|
|
pvr->iURLLen--;
|
|
}
|
|
else if (pvr->iURLLen == 1 && pszURL[0]=='/' && pvr->ScriptType == SCRIPT_TYPE_NONE)
|
|
{
|
|
// if it's the root URL, make sure correspinding path ends with "\"
|
|
// (if it's a directory only, leave ASP + ISAPI's alone)
|
|
if (wszPath[pvr->iPathLen-1] != L'\\')
|
|
{
|
|
wszPath[pvr->iPathLen] = L'\\';
|
|
pvr->iPathLen++;
|
|
wszPath[pvr->iPathLen] = L'\0';
|
|
}
|
|
}
|
|
|
|
// If Path ends in "\" (and it's not the root path or root virtual root)
|
|
// remove the "\"
|
|
if (pvr->iURLLen != 1 && pvr->iPathLen != 1 && wszPath[pvr->iPathLen-1]==L'\\')
|
|
{
|
|
wszPath[pvr->iPathLen-1] = L'\0';
|
|
pvr->iPathLen--;
|
|
}
|
|
else if (pvr->iPathLen == 1 && wszPath[0]==L'\\')
|
|
{
|
|
// Trailing "/" must match "\". However, we need a slight HACK to make this work
|
|
if (pszURL[pvr->iURLLen-1] != '/')
|
|
{
|
|
pszURL[pvr->iURLLen] = '/';
|
|
pvr->iURLLen++;
|
|
pszURL[pvr->iURLLen] = '\0';
|
|
}
|
|
pvr->bRootDir = TRUE;
|
|
}
|
|
|
|
pvr->pszURL = MySzDupA(pszURL);
|
|
pvr->wszPath = MySzDupW(wszPath);
|
|
|
|
// Fill in defaults for these
|
|
pvr->wszUserList = NULL;
|
|
pvr->dwPermissions = HTTP_DEFAULTP_PERMISSIONS;
|
|
pvr->AuthLevel = AUTH_PUBLIC;
|
|
|
|
TraceTag(ttidWebServer, "VROOT: (%s)=>(%s) perm=%d auth=%d ScriptType=%d",
|
|
pvr->pszURL, pvr->wszPath, pvr->dwPermissions,
|
|
pvr->AuthLevel,pvr->ScriptType);
|
|
|
|
done:
|
|
if(err)
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
VOID CVRoots::Sort()
|
|
{
|
|
BOOL fChange;
|
|
int i=0;
|
|
|
|
// We now want to sort the VRoots in descending order of URL-length so
|
|
// that when we match we'll find the longest match first!!
|
|
// Using a slow bubble-sort :-(
|
|
do {
|
|
fChange = FALSE;
|
|
for(i=0; i<m_nVRoots-1; i++)
|
|
{
|
|
if(m_pVRoots[i].iURLLen < m_pVRoots[i+1].iURLLen)
|
|
{
|
|
// swap the 2 vroots
|
|
VROOTINFO vtemp = m_pVRoots[i+1];
|
|
m_pVRoots[i+1] = m_pVRoots[i];
|
|
m_pVRoots[i] = vtemp;
|
|
fChange = TRUE;
|
|
}
|
|
}
|
|
} while(fChange);
|
|
}
|
|
|
|
static const WCHAR c_szPrefix[] = L"\\\\?\\";
|
|
static const int c_cchPrefix = celems(c_szPrefix);
|
|
|
|
BOOL CVRoots::Init()
|
|
{
|
|
int err = 0; // err variable is used in non-Debug mode
|
|
int i=0;
|
|
|
|
InitializeCriticalSection(&m_csVroot);
|
|
|
|
// Registry doesnt allow keynames longer than MAX_PATH so we won't map URL prefixes longer than MAX_PATH
|
|
WCHAR wszURL[MAX_PATH+1];
|
|
WCHAR wszPath[MAX_PATH+1];
|
|
WCHAR wszPathReal[MAX_PATH + 1] = {0};
|
|
wszURL[0]=wszPath[0]=0;
|
|
|
|
// open the VRoots key
|
|
CReg topreg(HKEY_LOCAL_MACHINE, RK_HTTPDVROOTS);
|
|
|
|
// allocate space for as many VRoots as we have subkeys
|
|
m_nVRoots = topreg.NumSubkeys();
|
|
if(!m_nVRoots)
|
|
myleave(80);
|
|
// Zero the memory so we know what to deallocate and what not to.
|
|
if(!(m_pVRoots = MyRgAllocZ(VROOTINFO, m_nVRoots)))
|
|
myleave(81);
|
|
|
|
// enumerate all subkeys. Their names are URLs, their default value is the corresponding path
|
|
// Note: EnumKey takes sizes in chars, not bytes!
|
|
for(i=0; i<m_nVRoots && topreg.EnumKey(wszURL, CCHSIZEOF(wszURL)); i++)
|
|
{
|
|
CReg subreg(topreg, wszURL);
|
|
|
|
// get the unnamed value. Again size is in chars, not bytes.
|
|
if(!subreg.ValueSZ(NULL, wszPath, CCHSIZEOF(wszPath)))
|
|
{
|
|
// iURLLen and iPathLen set to 0 already, so no case of corruption in MatchVRoot
|
|
subreg.Reset();
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// Prepend the \\?\ prefix
|
|
//
|
|
lstrcpy(wszPathReal, c_szPrefix);
|
|
lstrcat(wszPathReal, wszPath);
|
|
|
|
if (!FillVRoot(&m_pVRoots[i], wszURL, wszPathReal))
|
|
myleave(121);
|
|
|
|
m_pVRoots[i].wszUserList = MySzDupW( subreg.ValueSZ(RV_USERLIST));
|
|
|
|
// default permissions is Read & Execute
|
|
m_pVRoots[i].dwPermissions = subreg.ValueDW(RV_PERM, HTTP_DEFAULTP_PERMISSIONS);
|
|
// default authentication is public
|
|
m_pVRoots[i].AuthLevel = (AUTHLEVEL)subreg.ValueDW(RV_AUTH, (DWORD)AUTH_PUBLIC);
|
|
|
|
// we don't fail if we can't load an extension map
|
|
LoadExtensionMap (&m_pVRoots[i], subreg);
|
|
}
|
|
|
|
subreg.Reset();
|
|
}
|
|
|
|
Sort();
|
|
|
|
done:
|
|
if(err)
|
|
{
|
|
TraceTag(ttidWebServer, "CVRoots::ctor FAILED due to err=%d GLE=%d "
|
|
"(num=%d i=%d pVRoots=0x%08x url=%s path=%s)",
|
|
err, GetLastError(), m_nVRoots, i, m_pVRoots, wszURL, wszPath);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CVRoots::Cleanup()
|
|
{
|
|
if(!m_pVRoots)
|
|
return;
|
|
for(int i=0; i<m_nVRoots; i++)
|
|
{
|
|
MyFree(m_pVRoots[i].pszURL);
|
|
MyFree(m_pVRoots[i].wszPath);
|
|
MyFree(m_pVRoots[i].wszUserList);
|
|
FreeExtensionMap (&m_pVRoots[i]);
|
|
}
|
|
MyFree(m_pVRoots);
|
|
|
|
DeleteCriticalSection(&m_csVroot);
|
|
}
|
|
|
|
BOOL CVRoots::AddVRoot(LPWSTR szUrl, LPWSTR szPath)
|
|
{
|
|
PVROOTINFO pvrNew;
|
|
int err = 0;
|
|
LPSTR szaUrl = NULL;
|
|
int iInputLen;
|
|
|
|
szaUrl = SzFromWsz(szUrl);
|
|
if (!szaUrl)
|
|
{
|
|
// Can't use myleave since we don't have the critsec here
|
|
//
|
|
err = 400;
|
|
goto err;
|
|
}
|
|
|
|
iInputLen = strlen(szaUrl);
|
|
|
|
EnterCriticalSection(&m_csVroot);
|
|
|
|
pvrNew = MatchVRoot(szaUrl, iInputLen);
|
|
if(pvrNew)
|
|
{
|
|
TraceError("CVRoots::AddVRoot - already present", E_FAIL);
|
|
myleave(10);
|
|
}
|
|
|
|
m_pVRoots = MyRgReAlloc(VROOTINFO, m_pVRoots, m_nVRoots, m_nVRoots + 1);
|
|
if(!m_nVRoots)
|
|
myleave(100);
|
|
|
|
pvrNew = &m_pVRoots[m_nVRoots];
|
|
|
|
if (!FillVRoot(pvrNew, szUrl, szPath))
|
|
{
|
|
myleave(101);
|
|
}
|
|
|
|
m_nVRoots++;
|
|
|
|
HKEY hkeyVroot;
|
|
HKEY hkeyNew;
|
|
HRESULT hr;
|
|
|
|
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_HTTPDVROOTS, KEY_ALL_ACCESS,
|
|
&hkeyVroot);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrRegCreateKeyEx(hkeyVroot, szUrl, 0, KEY_ALL_ACCESS, NULL,
|
|
&hkeyNew, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Pass NULL to set default value
|
|
//
|
|
hr = HrRegSetSz(hkeyNew, NULL, szPath);
|
|
|
|
RegCloseKey(hkeyNew);
|
|
}
|
|
RegCloseKey(hkeyVroot);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TraceError("CVRoots::AddVRoot", hr);
|
|
myleave(111);
|
|
}
|
|
else
|
|
{
|
|
Sort();
|
|
}
|
|
|
|
done:
|
|
|
|
delete [] szaUrl;
|
|
|
|
LeaveCriticalSection(&m_csVroot);
|
|
|
|
err:
|
|
if(err)
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CVRoots::RemoveVRoot(LPWSTR szwUrl)
|
|
{
|
|
int ivr;
|
|
LPSTR szUrl = NULL;
|
|
PVROOTINFO pvr;
|
|
int iInputLen;
|
|
int err = 0;
|
|
BOOL fFound = FALSE;
|
|
|
|
szUrl = SzFromWsz(szwUrl);
|
|
if (!szUrl)
|
|
{
|
|
myleave(100);
|
|
}
|
|
|
|
iInputLen = strlen(szUrl);
|
|
|
|
EnterCriticalSection(&m_csVroot);
|
|
|
|
pvr = MatchVRoot(szUrl, iInputLen);
|
|
if(!pvr)
|
|
{
|
|
myleave(140);
|
|
}
|
|
|
|
for (ivr = 0; ivr < m_nVRoots; ivr++)
|
|
{
|
|
if (&m_pVRoots[ivr] == pvr)
|
|
{
|
|
// Found the one to remove. So now let's shift the rest down by
|
|
// one
|
|
//
|
|
MoveMemory(&m_pVRoots[ivr], &m_pVRoots[ivr + 1],
|
|
sizeof(VROOTINFO) * (m_nVRoots - ivr - 1));
|
|
m_nVRoots--;
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
AssertSz(fFound, "How come it was there a minute ago??");
|
|
|
|
HKEY hkeyVroot;
|
|
HKEY hkeyNew;
|
|
HRESULT hr;
|
|
|
|
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_HTTPDVROOTS, KEY_ALL_ACCESS,
|
|
&hkeyVroot);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrRegDeleteKey(hkeyVroot, szwUrl);
|
|
|
|
RegCloseKey(hkeyVroot);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
TraceError("CVRoots::RemoveVRoot", hr);
|
|
myleave(111);
|
|
}
|
|
|
|
// No need to re-sort since we moved everything down by one
|
|
|
|
done:
|
|
LeaveCriticalSection(&m_csVroot);
|
|
|
|
delete [] szUrl;
|
|
|
|
if(err)
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
PWSTR CVRoots::URLAtoPathW(PSTR pszInputURL, PDWORD pdwPerm /*=0*/,
|
|
AUTHLEVEL* pAuthLevel /* =0 */,
|
|
SCRIPT_TYPE *pScriptType /*=0 */,
|
|
PSTR *ppszPathInfo /* =0 */,
|
|
WCHAR **ppwszUserList /*=0 */)
|
|
{
|
|
PSTR pszEndOfURL;
|
|
WCHAR *wszTemp = NULL;
|
|
int iInputLen = strlen(pszInputURL);
|
|
|
|
EnterCriticalSection(&m_csVroot);
|
|
|
|
PVROOTINFO pVRoot = MatchVRoot(pszInputURL, iInputLen);
|
|
if(!pVRoot)
|
|
{
|
|
LeaveCriticalSection(&m_csVroot);
|
|
return NULL;
|
|
}
|
|
|
|
// Do a lookup to see if the current URL contains and extension
|
|
// that is in the extension map for the VROOT. If so, this call
|
|
// will truncate the URL after the extension. Since the URL may
|
|
// have changed, the length is re-obtained on a successfull call.
|
|
|
|
if (MapExtToPath (pszInputURL, &pszEndOfURL))
|
|
{
|
|
if (ppszPathInfo && *ppszPathInfo == NULL)
|
|
*ppszPathInfo = MySzDupA (pszInputURL);
|
|
|
|
if (*pszEndOfURL != '\0')
|
|
{
|
|
*pszEndOfURL = 0;
|
|
iInputLen = strlen(pszInputURL);
|
|
}
|
|
}
|
|
|
|
// in computing the buffersize here we are assuming that an MBCS string of length N
|
|
// cannot produce a unicode string of length greater than N
|
|
int iOutLen = 1 + pVRoot->iPathLen + (iInputLen - pVRoot->iURLLen);
|
|
PWSTR wszOutPath = MyRgAllocNZ(WCHAR, iOutLen);
|
|
if (!wszOutPath)
|
|
{
|
|
LeaveCriticalSection(&m_csVroot);
|
|
return NULL;
|
|
}
|
|
|
|
// assemble the path. First, the mapped base path
|
|
memcpy(wszOutPath, pVRoot->wszPath, sizeof(WCHAR)*pVRoot->iPathLen);
|
|
|
|
if(pdwPerm)
|
|
*pdwPerm = pVRoot->dwPermissions;
|
|
if(pAuthLevel)
|
|
*pAuthLevel = pVRoot->AuthLevel;
|
|
if (pScriptType)
|
|
*pScriptType = pVRoot->ScriptType;
|
|
if (ppwszUserList)
|
|
*ppwszUserList = pVRoot->wszUserList;
|
|
|
|
// If the vroot specifies an ISAPI dll or ASP page don't copy path info over.
|
|
if (pVRoot->ScriptType != SCRIPT_TYPE_NONE)
|
|
{
|
|
if ( ppszPathInfo && pszInputURL[pVRoot->iURLLen] != 0)
|
|
{
|
|
SetPathInfo(ppszPathInfo,pszInputURL,pVRoot->iURLLen);
|
|
}
|
|
wszOutPath[pVRoot->iPathLen] = L'\0';
|
|
LeaveCriticalSection(&m_csVroot);
|
|
return wszOutPath;
|
|
}
|
|
|
|
// next the remainder of the URL, converted to wide
|
|
if (iOutLen-pVRoot->iPathLen == 0)
|
|
{
|
|
wszOutPath[pVRoot->iPathLen] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
int iRet = MyA2W(pszInputURL+pVRoot->iURLLen, wszOutPath+pVRoot->iPathLen, iOutLen-pVRoot->iPathLen);
|
|
DEBUGCHK(iRet);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csVroot);
|
|
|
|
// Flip forward slashes around to backslashes
|
|
|
|
LPWSTR pchFlip = wszOutPath;
|
|
|
|
while (*pchFlip)
|
|
{
|
|
if (*pchFlip == '/')
|
|
{
|
|
*pchFlip = '\\';
|
|
}
|
|
|
|
pchFlip++;
|
|
}
|
|
|
|
return wszOutPath;
|
|
}
|
|
|
|
BOOL CVRoots::LoadExtensionMap(PVROOTINFO pvr, HKEY rootreg)
|
|
{
|
|
BOOL bWildCard;
|
|
WCHAR wszExt[MAX_PATH+1];
|
|
WCHAR wszPath[MAX_PATH+1];
|
|
|
|
CReg mapreg(rootreg, RV_EXTENSIONMAP);
|
|
|
|
if (!mapreg.IsOK())
|
|
{
|
|
pvr->nExtensions = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
if (bWildCard = mapreg.ValueSZ(NULL, wszPath, CCHSIZEOF(wszPath)))
|
|
pvr->nExtensions = 1;
|
|
else
|
|
pvr->nExtensions = mapreg.NumValues();
|
|
|
|
if ((pvr->pExtMap = MyRgAllocZ(EXTMAP, pvr->nExtensions)) == NULL)
|
|
return FALSE;
|
|
|
|
if (bWildCard)
|
|
{
|
|
pvr->pExtMap[0].wszExt = MySzDupW(L"*");
|
|
pvr->pExtMap[0].wszPath = MySzDupW(wszPath);
|
|
return TRUE;
|
|
}
|
|
|
|
for (int i = 0; i < pvr->nExtensions; i++)
|
|
{
|
|
if (mapreg.EnumValue(wszExt, CCHSIZEOF(wszExt),
|
|
wszPath, CCHSIZEOF(wszPath)))
|
|
{
|
|
if (wszExt[0] != 0 && wszPath[0] != 0)
|
|
{
|
|
pvr->pExtMap[i].wszExt = MySzDupW(wszExt);
|
|
pvr->pExtMap[i].wszPath = MySzDupW(wszPath);
|
|
}
|
|
else
|
|
{
|
|
pvr->pExtMap[i].wszExt = MySzDupW(L"");
|
|
pvr->pExtMap[i].wszPath = MySzDupW(L"");
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CVRoots::FreeExtensionMap (PVROOTINFO pvr)
|
|
{
|
|
if (pvr->pExtMap == NULL) return;
|
|
|
|
for (int i=0; i < pvr->nExtensions; i++)
|
|
{
|
|
MyFree(pvr->pExtMap[i].wszExt);
|
|
MyFree(pvr->pExtMap[i].wszPath);
|
|
}
|
|
|
|
MyFree(pvr->pExtMap);
|
|
pvr->pExtMap = NULL;
|
|
}
|
|
|
|
PWSTR CVRoots::MapExtToPath (PSTR pszInputURL, PSTR *ppszEndOfURL)
|
|
{
|
|
PSTR pszTemp, pszStart, pszEnd;
|
|
PWSTR wszPath = NULL;
|
|
WCHAR wszExt[MAX_PATH+1];
|
|
PVROOTINFO pvr;
|
|
int iInputLen = strlen(pszInputURL);
|
|
|
|
if (!FindExtInURL (pszInputURL, &pszStart, &pszEnd))
|
|
return NULL;
|
|
|
|
MyA2W (pszStart, wszExt, (int)((INT_PTR)(pszEnd - pszStart)));
|
|
wszExt [pszEnd - pszStart] = L'\0';
|
|
|
|
EnterCriticalSection(&m_csVroot);
|
|
|
|
if (!(pvr = MatchVRoot(pszInputURL, iInputLen)))
|
|
{
|
|
LeaveCriticalSection(&m_csVroot);
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = 0; i < pvr->nExtensions; i++)
|
|
{
|
|
if ((i == 0 && pvr->pExtMap[i].wszExt[0] == L'*') ||
|
|
0 == _wcsicmp (pvr->pExtMap[i].wszExt, wszExt))
|
|
{
|
|
wszPath = pvr->pExtMap[i].wszPath;
|
|
|
|
if (ppszEndOfURL != NULL)
|
|
*ppszEndOfURL = pszEnd;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csVroot);
|
|
return wszPath;
|
|
}
|
|
|
|
BOOL CVRoots::FindExtInURL (PSTR pszInputURL, PSTR *ppszStart, PSTR *ppszEnd)
|
|
{
|
|
*ppszStart = strrchr (pszInputURL, '.');
|
|
|
|
if ((*ppszEnd = *ppszStart) == NULL)
|
|
return FALSE;
|
|
|
|
while (**ppszEnd != '/' && **ppszEnd != '\0')
|
|
*ppszEnd = *ppszEnd + 1;
|
|
|
|
return TRUE;
|
|
}
|