⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 davimpl.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// 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 + -