📄 davutil.cpp
字号:
if (m_rcvBody.fChunked)
DEBUGCHK(0);
else {
m_rcvBody.dwRemaining = m_pRequest->m_dwContentLength-m_pRequest->m_bufRequest.Count();
DEBUGCHK((int)m_rcvBody.dwRemaining > 0);
}
}
if ((int) m_rcvBody.dwRemaining <= 0) {
*pcbRead = 0;
return TRUE;
}
*pcbRead = min(*pcbRead,m_rcvBody.dwRemaining);
fRet = m_pRequest->ReadClient(szBuf,pcbRead);
m_rcvBody.dwRemaining -= *pcbRead;
if (!m_rcvBody.fChunked)
return fRet;
// chunked needs to parse through buffer (actually to the end of, +5 bytes at most) to look for next read size.
return FALSE;
}
BOOL CWebDav::IsContentTypeXML(void) {
PSTR szHeader;
DWORD ccContent;
const CHAR rgcDelimitSet[] = { ';', '\t', ' ', '\r', '\0' };
if (NULL == (szHeader = m_pRequest->FindHttpHeader(cszContent_Type,ccContent_Type))) {
// Note: If there is no content-type header we should return FALSE in this case,
// however certain existing clients do not set the "content-type" field but send XML
// anyway. To work with them return TRUE.
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: Warning: WebDAV client did not set content-type, treating as if content-type: text/xml\r\n"));
return TRUE;
}
// Content-length: may have extra info like "; charset=\"utf8\" appended to content-type, ignore it.
ccContent = strcspn(szHeader,rgcDelimitSet);
DEBUGCHK(ccContent);
if ((TokensEqualAI(szHeader,cszTextXML,ccContent,ccTextXML)) ||
(TokensEqualAI(szHeader,cszApplicationXML,ccContent,ccApplicationXML)))
{
return TRUE;
}
return FALSE;
}
BOOL CXMLBuffer::SetStatusTag(RESPONSESTATUS rs) {
CHAR szStatus[256];
int iLen = sprintf(szStatus,"HTTP/1.1 %d %s",rgStatus[rs].dwStatusNumber,rgStatus[rs].pszStatusText);
DEBUGCHK(iLen < sizeof(szStatus));
DEBUGCHK(rs < STATUS_MAX);
return (StartTag(cszStatus) &&
Append(szStatus,iLen) &&
EndTag(cszStatus));
}
BOOL CWebDav::SetHREFTag(PCSTR szURL) {
if (! m_bufResp.StartTag(cszHref))
return FALSE;
if (!BuildBaseURLFromSourceURL())
return FALSE;
if (szURL && ! m_bufResp.EncodeURL(szURL))
return FALSE;
if (! m_bufResp.EndTag(cszHref))
return FALSE;
return TRUE;
}
BOOL CWebDav::SetHREFTagFromDestinationPath(WIN32_FIND_DATA *pFindData, WCHAR *szDirectory, BOOL fRootDir, PCSTR szRootURL, BOOL fSkipFileMunge) {
CHAR szBuf[MINBUFSIZE]; // temp write buffer
// When we're accessing root of physical filesystem, offset is different.
DWORD ccDestPath = m_pRequest->IsRootPath() ? 0 : m_pRequest->m_ccWPath;
if (!szRootURL)
szRootURL = m_pRequest->m_pszURL;
if (! m_bufResp.StartTag(cszHref))
return FALSE;
BOOL fAddSlash = (pFindData && !fSkipFileMunge && szDirectory && !URLHasTrailingSlashA(szRootURL));
if (!BuildBaseURL(szRootURL,FALSE,fAddSlash))
return FALSE;
if (!fSkipFileMunge) {
DEBUGCHK(pFindData != NULL);
// Build up the remainder of URL by adding everything past the root of the destination path.
DWORD ccBuf = 0;
if (!fRootDir) {
DEBUGCHK(wcslen(szDirectory+ccDestPath+1) > 0);
DEBUGCHK((szDirectory[ccDestPath] == '\\') || (szDirectory[ccDestPath] == '/'));
DWORD cc = MyW2UTF8(szDirectory+ccDestPath+1,szBuf,sizeof(szBuf));
if (0 == cc)
return FALSE;
ccBuf += (cc-1);
DEBUGCHK(szBuf[ccBuf] == 0);
for (DWORD i = 0; i < ccBuf; i++) {
if (szBuf[i] == '\\')
szBuf[i] = '/';
}
szBuf[ccBuf] = '/';
szBuf[++ccBuf] = 0;
}
PREFAST_SUPPRESS(11,"fSkipFileMunge==FALSE ==> pFindData != NULL.");
if (pFindData->cFileName[0]) {
DWORD cc = MyW2UTF8(pFindData->cFileName,szBuf+ccBuf,sizeof(szBuf)-ccBuf);
if (0 == cc)
return FALSE;
ccBuf += (cc-1);
}
if (IsDirectory(pFindData)) {
szBuf[ccBuf] = '/';
szBuf[++ccBuf] = 0;
}
DEBUGCHK((ccBuf+1) < sizeof(szBuf));
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav SetHREFTagFromDestinationPath sets buffer = <<%a>>\r\n",szBuf));
if (! m_bufResp.EncodeURL(szBuf))
return FALSE;
}
if (! m_bufResp.EndTag(cszHref))
return FALSE;
return TRUE;
}
// Buildup <response> blob.
BOOL CWebDav::SetResponseTag(PCSTR szURL, RESPONSESTATUS rs) {
DEBUGCHK(m_pRequest->m_rs == STATUS_MULTISTATUS);
return ( m_bufResp.StartTag(cszResponse) &&
SetHREFTag(szURL) &&
m_bufResp.SetStatusTag(rs) &&
m_bufResp.EndTag(cszResponse));
}
BOOL CWebDav::SetMultiStatusErrorFromDestinationPath(RESPONSESTATUS rs, WIN32_FIND_DATA *pFindData, WCHAR *szDirectory, BOOL fRootDir, PCSTR szRootURL, BOOL fSkipFileMunge) {
if (! SetMultiStatusResponse())
return FALSE;
return ( m_bufResp.StartTag(cszResponse) &&
SetHREFTagFromDestinationPath(pFindData,szDirectory,fRootDir,szRootURL,fSkipFileMunge) &&
m_bufResp.SetStatusTag(rs) &&
m_bufResp.EndTag(cszResponse));
}
BOOL CWebDav::SetMultiStatusErrorFromURL(RESPONSESTATUS rs, PCSTR szRootURL) {
if (! SetMultiStatusResponse())
return FALSE;
return ( m_bufResp.StartTag(cszResponse) &&
SetHREFTagFromDestinationPath(NULL,NULL,FALSE,szRootURL,TRUE) &&
m_bufResp.SetStatusTag(rs) &&
m_bufResp.EndTag(cszResponse));
}
// Stub functions to call into class
BOOL SendPropertiesVisitFcn(CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot) {
return pThis->SendPropertiesVisitFcn(pFindData, dwContext, szPath, fIsRoot);
}
BOOL SendPropertyNamesVisitFcn(CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot) {
return pThis->SendPropertyNamesVisitFcn(pFindData, dwContext, szPath, fIsRoot);
}
BOOL DeleteVisitFcn(CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot) {
return pThis->DeleteVisitFcn(pFindData, dwContext, szPath, fIsRoot);
}
BOOL MoveCopyVisitFcn(CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot) {
return pThis->MoveCopyVisitFcn(pFindData, dwContext, szPath, fIsRoot);
}
inline WCHAR * RemoveLastSlash(WCHAR *szBuffer) {
WCHAR *wszEnd = wcsrchr(szBuffer,L'\\');
// In case where szBuffer='\\', don't remove root slash
if (wszEnd == szBuffer)
wszEnd = szBuffer+1;
*wszEnd = 0;
return wszEnd;
}
typedef struct {
WIN32_FIND_DATAW findData;
} RecurseStructInfo;
#ifdef _PREFAST_
// We turn of prefast here and rely entirely on DEBUGCHK in dbg builds rather
// than adding (for instance) if (wcslen(szPath)+1) >= SVSUTIL_ARRLEN(wszBuf1)) { DEBUGCHK(0); return; }
// because... this is a pretty heavily used function and we don't want to degrade
// performance.
#pragma prefast(disable:204 394 417,"RecursiveVisitDirs correctly calculates length needed at each stage")
#endif
BOOL CWebDav::RecursiveVisitDirs(WCHAR *szPath, DWORD dwContext, PFN_RECURSIVE_VISIT pfnVisit, BOOL fDeferDirectoryProcess) {
WIN32_FIND_DATAW findData;
BOOL fRet = FALSE;
BOOL fMoreFiles = TRUE;
WCHAR wszBuf1[(10+MAX_PATH)*2];
WCHAR *wszEnd;
DWORD ccBuf1;
// keeps track of recursive decent through directory tree
SVSExpArray<RecurseStructInfo> findDataArray;
HANDLE hFileStack[MAX_PATH];
int iStackPtr = -1;
BOOL fIsRoot;
DEBUGCHK((wcslen(szPath)+1) < SVSUTIL_ARRLEN(wszBuf1));
wcscpy(wszBuf1,szPath);
ccBuf1 = wcslen(wszBuf1);
wszEnd = wszBuf1 + ccBuf1;
if (URLHasTrailingSlashW(wszBuf1,ccBuf1))
wcscpy(wszEnd,L"*");
else
wcscpy(wszEnd,L"\\*");
if (INVALID_HANDLE_VALUE == (hFileStack[0] = FindFirstFile(wszBuf1, &findData))) {
// root directory is empty. Not an error, but we are done in this case.
fRet = TRUE;
goto done;
}
*wszEnd = 0;
iStackPtr = 0;
GetDepth();
do {
startFileList:
DEBUGCHK((iStackPtr >= 0) && (iStackPtr < SVSUTIL_ARRLEN(hFileStack)));
fIsRoot = (iStackPtr==0);
do {
if (!fMoreFiles)
break;
if (IsDirectory(&findData) && fDeferDirectoryProcess) {
if (!findDataArray.SRealloc(iStackPtr+1))
goto done;
findDataArray[iStackPtr].findData = findData;
}
else if (! pfnVisit(this,&findData,dwContext,wszBuf1,fIsRoot))
goto done;
if (IsDirectory(&findData) && (m_Depth == DEPTH_INFINITY)) {
if (!URLHasTrailingSlashW(wszBuf1))
*wszEnd++ = '\\';
wcscpy(wszEnd,findData.cFileName);
wszEnd = wszEnd + wcslen(findData.cFileName);
wcscpy(wszEnd,L"\\*");
DEBUGCHK(wcslen(wszBuf1) < SVSUTIL_ARRLEN(wszBuf1));
// If call fails, continue processing.
if (INVALID_HANDLE_VALUE == (hFileStack[++iStackPtr] = FindFirstFile(wszBuf1, &findData))) {
*wszEnd = 0;
iStackPtr--;
if (fDeferDirectoryProcess) {
if (! pfnVisit(this,&findDataArray[iStackPtr].findData,dwContext,wszBuf1,fIsRoot))
goto done;
}
wszEnd = RemoveLastSlash(wszBuf1);
continue;
}
*wszEnd = 0;
goto startFileList;
}
}
while (FindNextFile(hFileStack[iStackPtr], &findData));
if (fDeferDirectoryProcess && !fIsRoot) {
DEBUGCHK(iStackPtr >= 1);
DEBUGCHK(IsDirectory(&findDataArray[iStackPtr-1].findData));
if (! pfnVisit(this,&findDataArray[iStackPtr-1].findData,dwContext,wszBuf1,fIsRoot))
goto done;
}
wszEnd = RemoveLastSlash(wszBuf1);
FindClose(hFileStack[iStackPtr--]);
if (iStackPtr == -1)
break;
fMoreFiles = FindNextFile(hFileStack[iStackPtr], &findData);
} while (1);
fRet = TRUE;
done:
for (int i = 0; i <= iStackPtr; i++) {
DEBUGCHK(hFileStack[i] != INVALID_HANDLE_VALUE);
FindClose(hFileStack[i]);
}
return fRet;
}
#ifdef _PREFAST_
#pragma prefast(enable:204 394 417,"")
#endif
//
// CChunkedBuffer implementation
//
// Initial buffer is 8KB, second one is 16 KB, then 32, then 64KB. We grow quickly
// because most likely scenarios are the tiny case (< 8KB) or the very large (>64KB),
// so there's no point in reallocating 1 or 2 KB at a time.
// Only alloc on specified boundaries
inline DWORD GetNextBufSize(DWORD cbRequired) {
if (cbRequired <= INITIAL_CHUNK_BUFFER_SIZE)
return INITIAL_CHUNK_BUFFER_SIZE;
else if (cbRequired <= (INITIAL_CHUNK_BUFFER_SIZE*2))
return INITIAL_CHUNK_BUFFER_SIZE*2;
else if (cbRequired <= (INITIAL_CHUNK_BUFFER_SIZE*4))
return INITIAL_CHUNK_BUFFER_SIZE*4;
else
return MAX_CHUNK_BUFFER_SIZE;
}
BOOL CChunkedBuffer::AllocMem(DWORD cbSize) {
BufferConsistencyChecks();
DWORD dwAlloc = cbSize + m_iNextIn + CHUNK_RESERVE_SPACE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -