📄 davimpl.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*--
Module Name: davimpl.cpp
Abstract: WebDAV implementation
--*/
#include "httpd.h"
//
// OPTIONS helper functions
//
const char cszOptionVerbDelimiter[] = ", ";
// During call to OPTIONS, we list off verbs we support in the form ", VERBNAME1, VERBNAME2,..."
void CWebDav::WriteSupportedVerb(VERB v, BOOL fFirstVerbInList) {
DEBUGCHK(m_pRequest->m_idMethod == VERB_OPTIONS);
if (fFirstVerbInList)
m_pRequest->m_bufRespHeaders.AppendCHAR(' '); // put space between HTTP header and data.
else
m_pRequest->m_bufRespHeaders.AppendData(cszOptionVerbDelimiter,SVSUTIL_CONSTSTRLEN(cszOptionVerbDelimiter));
m_pRequest->m_bufRespHeaders.AppendData(rg_cszMethods[v-1],strlen(rg_cszMethods[v-1]));
}
void CWebDav::WritePublicOptions(void) {
WriteSupportedVerb(VERB_OPTIONS,TRUE);
WriteSupportedVerb(VERB_GET);
WriteSupportedVerb(VERB_HEAD);
WriteSupportedVerb(VERB_DELETE);
WriteSupportedVerb(VERB_PUT);
WriteSupportedVerb(VERB_POST);
WriteSupportedVerb(VERB_COPY);
WriteSupportedVerb(VERB_MOVE);
WriteSupportedVerb(VERB_MKCOL);
WriteSupportedVerb(VERB_PROPFIND);
WriteSupportedVerb(VERB_PROPPATCH);
WriteSupportedVerb(VERB_LOCK);
WriteSupportedVerb(VERB_UNLOCK);
m_pRequest->m_bufRespHeaders.AppendData(cszCRLF,ccCRLF);
}
//
// PROPFIND implementation
//
const CHAR cszIso8601FMT[] = "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ";
#define DEBUGMSG_VISIT_FCN(fcnName) \
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: %a file=%s, dwProperties=0x%08x, szTraversalPath=%s, fRootDir=%d\r\n", \
fcnName,(pFindData)->cFileName,dwContext,szTraversalPath,fRootDir));
// Send back an XML <response> block for given file or directory.
// if fIsRoot=TRUE, then we're returning info on requested URL.
// if fIsRoot=FALSE, we're searching sending info on one of its children.
BOOL CWebDav::SendPropertiesVisitFcn(WIN32_FIND_DATA *pFindData, DWORD dwContext, WCHAR *szTraversalPath, BOOL fRootDir) {
CHAR szBuf[MINBUFSIZE]; // temp write buffer
SYSTEMTIME st;
BOOL fRet = FALSE;
BOOL fIsRoot = (NULL==szTraversalPath);
BOOL fIsDirectory = IsDirectory(pFindData->dwFileAttributes) ? TRUE : FALSE;
DWORD dwProperties = dwContext;
DEBUGMSG_VISIT_FCN("SendPropertiesVisitFcn");
DEBUGCHK(m_pRequest->m_rs == STATUS_MULTISTATUS);
if (! dwProperties && !m_bufUnknownTags.pBuffer) {
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: SendPropertiesVisitFcn() returns TRUE, no properties (known or unknown) to send to client\r\n"));
return TRUE;
}
// <a:response>
if (! m_bufResp.StartTag(cszResponse))
goto done;
// <a:href>http://CEDevice/fileName/...</a:href>
if (! SetHREFTagFromDestinationPath(pFindData,szTraversalPath,fRootDir,NULL,fIsRoot))
goto done;
//
// <a:prop>
//
if (dwProperties) { // only put <prop> if we have known properties
// <a:propstat>
if (! m_bufResp.StartTag(cszPropstat))
goto done;
// <a:status>
if (! m_bufResp.SetStatusTag(STATUS_OK))
goto done;
if (! m_bufResp.StartTag(cszProp))
goto done;
}
// <getcontentlength>
if (dwProperties & DAV_PROP_CONTENT_LENGTH) {
_itoa(pFindData->nFileSizeLow,szBuf,10);
if (! m_bufResp.StartTagNoEncode(cszGetcontentLengthNS,ccGetcontentLengthNS) ||
! m_bufResp.Append(szBuf,strlen(szBuf)) ||
! m_bufResp.EndTag(cszGetcontentLength))
goto done;
}
// <creationdate>
if (dwProperties & DAV_PROP_CREATION_DATE) {
FileTimeToSystemTime(&pFindData->ftCreationTime,&st);
DWORD cc = sprintf(szBuf,cszIso8601FMT,st.wYear,st.wMonth,st.wDay,st.wHour,
st.wMinute,st.wSecond,st.wMilliseconds);
if (! m_bufResp.StartTagNoEncode(cszCreationDateNS,ccCreationDateNS) ||
! m_bufResp.Append(szBuf,cc) ||
! m_bufResp.EndTag(cszCreationDate))
goto done;
}
// <displayname>
if (dwProperties & DAV_PROP_DISPLAY_NAME) {
PSTR szDisplay;
CHAR cSave = 0;
PSTR pszSave = NULL;
BOOL fContinue = TRUE;
if (fIsRoot) {
// The display name is simply the file name by itself, no previous path,
// just as in the non-root case. However we have to do more work to
// rip out interesting portion.
szDisplay = m_pRequest->m_pszURL;
GetEndOfFileWithNoSlashes(&szDisplay,&pszSave,&cSave);
}
else {
MyW2UTF8(pFindData->cFileName,szBuf,sizeof(szBuf));
szDisplay = szBuf;
}
DEBUGCHK(strlen(szBuf) < sizeof(szBuf)); // sizeof(szBuf) > MAX_PATH so should always be safe.
if (! m_bufResp.StartTag(cszDisplayName) ||
! m_bufResp.Encode(szDisplay) ||
! m_bufResp.EndTag(cszDisplayName))
fContinue = FALSE;
if (pszSave)
*pszSave = cSave;
if (!fContinue)
goto done;
}
// <getetag>
if (dwProperties & DAV_PROP_GET_ETAG) {
DWORD cc = GetETagFromFiletime(&pFindData->ftLastWriteTime,pFindData->dwFileAttributes,szBuf);
if (! m_bufResp.StartTag(cszGetETag) ||
! m_bufResp.Append(szBuf,cc) ||
! m_bufResp.EndTag(cszGetETag))
goto done;
}
// <getlastmodified>
if (dwProperties & DAV_PROP_GET_LAST_MODIFIED) {
FileTimeToSystemTime(&pFindData->ftCreationTime,&st);
DWORD cc = WriteDateGMT(szBuf,&st);
if (! m_bufResp.StartTagNoEncode(cszLastModifiedNS,ccLastModifiedNS) ||
! m_bufResp.Append(szBuf,cc) ||
! m_bufResp.EndTag(cszLastModified))
goto done;
}
// <resourcetype>
if (dwProperties & DAV_PROP_RESOURCE_TYPE) {
if (fIsDirectory) {
if (! m_bufResp.StartTag(cszResourceType) ||
! m_bufResp.SetEmptyElement(cszCollection) ||
! m_bufResp.EndTag(cszResourceType)) {
goto done;
}
}
else {
if (! m_bufResp.SetEmptyElement(cszResourceType))
goto done;
}
}
// WebDAV doesn't support locks on directories
if ((dwProperties & DAV_PROP_SUPPORTED_LOCK)) {
if (fIsDirectory) {
if (! m_bufResp.SetEmptyElement(cszSupportedLock))
goto done;
}
else {
const CHAR *cszSupportedLocks[] = { cszExclusive, cszShared} ;
if (! m_bufResp.StartTag(cszSupportedLock))
goto done;
for (int i = 0; i < 2; i++) {
if (! m_bufResp.StartTag(cszLockEntry) ||
! m_bufResp.StartTag(cszLockScope) ||
! m_bufResp.SetEmptyElement(cszSupportedLocks[i]) ||
! m_bufResp.EndTag(cszLockScope) ||
! m_bufResp.StartTag(cszLockType) ||
! m_bufResp.SetEmptyElement(cszWrite) ||
! m_bufResp.EndTag(cszLockType) ||
! m_bufResp.EndTag(cszLockEntry))
{
goto done;
}
}
if (! m_bufResp.EndTag(cszSupportedLock))
goto done;
}
}
if ((dwProperties & DAV_PROP_LOCK_DISCOVERY) && !fIsDirectory) {
BOOL fSendEmptyLockDiscovery = TRUE;
WCHAR wszFile[MAX_PATH*2];
WCHAR *szLockFile;
if (!fIsDirectory) {
if (fIsRoot)
szLockFile = m_pRequest->m_wszPath;
else {
BuildFileName(wszFile,szTraversalPath,pFindData->cFileName);
szLockFile = wszFile;
}
g_pFileLockManager->Lock();
CWebDavFileNode *pFileNode = g_pFileLockManager->GetNodeFromFileName(szLockFile);
if (pFileNode) {
SendLockTags(pFileNode,FALSE);
fSendEmptyLockDiscovery = FALSE;
}
g_pFileLockManager->Unlock();
}
if (fSendEmptyLockDiscovery)
m_bufResp.SetEmptyElement(cszLockDiscovery);
}
// <ishidden>
if (dwProperties & DAV_PROP_IS_HIDDEN) {
_itoa((pFindData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? 1 : 0,szBuf,10);
DEBUGCHK(strlen(szBuf) == 1);
if (! m_bufResp.StartTagNoEncode(cszIsHiddenNS,ccIsHiddenNS) ||
! m_bufResp.Append(szBuf,1) ||
! m_bufResp.EndTag(cszIsHidden))
goto done;
}
// <iscollection>
if (dwProperties & DAV_PROP_IS_COLLECTION) {
_itoa(fIsDirectory,szBuf,10);
DEBUGCHK(strlen(szBuf) == 1);
if (! m_bufResp.StartTagNoEncode(cszIsCollectionNS,ccIsCollectionNS) ||
! m_bufResp.Append(szBuf,1) ||
! m_bufResp.EndTag(cszIsCollection))
goto done;
}
if (dwProperties & DAV_PROP_GET_CONTENT_TYPE) {
if (fIsDirectory) {
if (! m_bufResp.SetEmptyElement(cszGetcontentType))
goto done;
}
else {
WCHAR *szExtension = wcsrchr(pFindData->cFileName, L'.');
if (szExtension) {
m_pRequest->GetContentTypeOfRequestURI(szBuf,sizeof(szBuf),szExtension);
if (! m_bufResp.StartTag(cszGetcontentType) ||
! m_bufResp.Encode(szBuf) ||
! m_bufResp.EndTag(cszGetcontentType)) {
goto done;
}
}
}
}
if (dwProperties & DAV_PROP_W32_FILE_ATTRIBUTES) {
sprintf(szBuf,"%08x",pFindData->dwFileAttributes);
if (! SetTagWin32NS(&m_bufResp,cszWin32FileAttribs,ccWin32FileAttribs,szBuf))
goto done;
}
if (dwProperties & DAV_PROP_W32_CREATION_TIME) {
WriteDateGMT(szBuf,&pFindData->ftCreationTime);
if (! SetTagWin32NS(&m_bufResp,cszWin32CreationTime,ccWin32CreationTime,szBuf))
goto done;
}
if (dwProperties & DAV_PROP_W32_LAST_ACCESS_TIME) {
WriteDateGMT(szBuf,&pFindData->ftLastAccessTime);
if (! SetTagWin32NS(&m_bufResp,cszWin32LastAccessTime,ccWin32LastAccessTime,szBuf))
goto done;
}
if (dwProperties & DAV_PROP_W32_LAST_MODIFY_TIME) {
WriteDateGMT(szBuf,&pFindData->ftLastWriteTime);
if (! SetTagWin32NS(&m_bufResp,cszWin32LastModifiedTime,ccWin32LastModifiedTime,szBuf))
goto done;
}
// close up XML tags
if (dwProperties) {
if (! m_bufResp.EndTag(cszProp) ||
! m_bufResp.EndTag(cszPropstat))
goto done;
}
if (! SendUnknownXMLElementsIfNeeded(STATUS_NOTFOUND))
goto done;
if (! m_bufResp.EndTag(cszResponse))
goto done;
fRet = TRUE;
done:
return fRet;
}
// If a client has requested proptags that we don't support, create a new
// <propstat> element with appropriate status and a list of the tags that
// we can't fill out.
// NOTE: This function assumes that m_bufResp has already been filled out with
// initial <response> and (potentially) a <propstat>, and that caller will
// append </response>.
BOOL CWebDav::SendUnknownXMLElementsIfNeeded(RESPONSESTATUS rs) {
if (m_bufUnknownTags.pBuffer) {
PCSTR szTrav = (CHAR*)m_bufUnknownTags.pBuffer;
if (! m_bufUnknownTags.AppendCHAR('\0'))
return FALSE;
if (! m_bufResp.StartTag(cszPropstat) ||
! m_bufResp.SetStatusTag(rs) ||
! m_bufResp.StartTag(cszProp)) {
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -