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

📄 davlock.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: davlock.cpp
Abstract: WebDAV implementation of locking functions
--*/


#include "httpd.h"


#if defined (DEBUG)
inline void DebugCheckCacheManagerLocked(void) { DEBUGCHK(g_pFileLockManager->IsLocked()); }
inline void DebugCheckCacheManagerNotLocked(void) { DEBUGCHK(! g_pFileLockManager->IsLocked()); }
#else
inline void DebugCheckCacheManagerLocked(void) { ; }
inline void DebugCheckCacheManagerNotLocked(void) { ; }
#endif



// BUGBUG - Our filesys doesn't do the right thing in protecting MOVE files.  
// This applies to both static and to ISAPIs loaded with LoadLibrary().

//  *********************************************************
//  Main VERB handeling routines.
//  *********************************************************

BOOL CWebDav::DavLock(void) { 
	CWebDavFileNode *pFileNode    = NULL;
	BOOL fRet                     = FALSE;
	PSTR szLockHeader;


	if (! (m_pRequest->GetPerms() & HSE_URL_FLAGS_WRITE)) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK fails, write permissions not turned on\r\n"));
		SetStatus(STATUS_FORBIDDEN);
		goto done;
	}

	if (IsCollection()) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK fails, WinCE DAV does not support locking collections\r\n"));
		SetStatus(STATUS_FORBIDDEN);
		goto done;
	}

	if (! CheckIfHeaders())
		goto done;

	if (! CheckLockHeader())
		goto done;

	if (NULL != (szLockHeader = m_pRequest->FindHttpHeader(cszIfToken,ccIfToken))) {
		// If LOCK sets a "Lock-Token", the only supported scenario is refreshing
		// the timeout on a lock.
		DWORD dwTimeout = 0;

		if (m_pRequest->m_dwContentLength) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDav LOCK sets Lock-Token but has a body, illegal\r\n"));
			SetStatus(STATUS_UNSUPPORTED_MEDIA_TYPE);
			goto done;
		}

		if (! GetLockTimeout(&dwTimeout) || (dwTimeout == 0)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV lock unable to set updated lock, failing request\r\n"));
			SetStatus(STATUS_BADREQ);
			goto done;
		}

		if (m_nLockTokens != 1) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK refresh timeout sent %d lock tokens, need exactly 1\r\n",m_nLockTokens));
			SetStatus(STATUS_BADREQ);
			goto done;
		}

		g_pFileLockManager->Lock();
		
		if (NULL != (pFileNode = g_pFileLockManager->GetNodeFromFileName(m_pRequest->m_wszPath))) {
			CWebDavLock *pLock;
			if (pFileNode->HasLockId(m_lockIds[0],&pLock)) {
				DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: LOCK updating timeout on LockID=%I64d, file=%s, timeout seconds=%d\r\n",m_lockIds[0],m_pRequest->m_wszPath,dwTimeout));
				pLock->SetTimeout(dwTimeout);

				SetStatusAndXMLBody(STATUS_OK);
				SendLockTags(pFileNode);
				fRet = TRUE;
			}
			else {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK update timer failed, file %s not associated with lockID %I64d\r\n",m_pRequest->m_wszPath,m_lockIds[0]));
				SetStatus(STATUS_PRECONDITION_FAILED);
			}
		}
		else {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK update timer failed, file %s does not have any locks associated with it\r\n",m_pRequest->m_wszPath));
			SetStatus(STATUS_PRECONDITION_FAILED);
		}

		g_pFileLockManager->Unlock();
	}
	else {
		// Request for a new lock.
		CLockParse      lockParse(this);
	
		if (! GetDepth(DEPTH_ZERO) || ((m_Depth != DEPTH_INFINITY) && (m_Depth != DEPTH_ZERO))) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV LOCK fails, depth not set to infinity or zero\r\n"));
			SetStatus(STATUS_BADREQ);
			goto done;
		}
#if defined (DEBUG)
		// Like IIS's behavior in accepting depth infinity.
		if (m_Depth == DEPTH_INFINITY)
			DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: Warning, LOCK accepting depth infinite tag, however it will be treated like depth: 0 because WinCE doesn't support locking collections.\r\n"));
#endif
		if (! ParseXMLBody(&lockParse,FALSE))
			goto done;

		fRet = g_pFileLockManager->CreateLock(&lockParse,this);
	}

done:
	return fRet; 
}

BOOL CWebDav::DavUnlock(void) {
	BOOL fRet = FALSE;
	__int64 iLockId;

	if (! (m_pRequest->GetPerms() & HSE_URL_FLAGS_WRITE)) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: UNLOCK fails, write permissions not turned on\r\n"));
		SetStatus(STATUS_FORBIDDEN);
		goto done;
	}

	if (IsCollection()) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: UNLOCK fails, WinCE DAV does not support locking collections\r\n"));
		SetStatus(STATUS_FORBIDDEN);
		goto done;
	}

	if (IsNull()) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: UNLOCK fails, file %s does not exist\r\n",m_pRequest->m_wszPath));
		SetStatus(STATUS_NOTFOUND);
		goto done;		
	}

	if (0 == (iLockId = CheckLockTokenHeader())) {
		DEBUGCHK(m_pRequest->m_rs != STATUS_OK); //CheckLockTokenHeader sets errors 
		goto done;
	}

	if (! g_pFileLockManager->IsFileAssociatedWithLockId(m_pRequest->m_wszPath,iLockId)) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: File <%s> is not associated with LockID %I64d\r\n",m_pRequest->m_wszPath,iLockId));
		SetStatus(STATUS_PRECONDITION_FAILED);
		goto done;
	}

	if (! g_pFileLockManager->DeleteLock(iLockId)) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD UNLOCK fails, lockID %I64d does not exist\r\n",iLockId));
		SetStatus(STATUS_PRECONDITION_FAILED);
		goto done;
	}

	DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: UNLOCK successfully deleted LockID %I64d\r\n",iLockId));
	fRet = TRUE;
done:
	if (fRet) {
		DEBUGCHK(m_pRequest->m_rs == STATUS_OK);
		CHttpResponse resp(m_pRequest,STATUS_NOCONTENT);
		resp.SendResponse();
	}

	return fRet;
}


//  *********************************************************
//  Helper routines for LOCK, UNLOCK, and other verbs
//  like MOVE and DELETE that query lock status.
//  *********************************************************


BOOL CWebDav::GetLockTimeout(DWORD *pdwTimeout) {
	DEBUGCHK((*pdwTimeout) == 0);
	DEBUGCHK(m_pRequest->m_idMethod == VERB_LOCK);

	CHAR *szTimeout = m_pRequest->FindHttpHeader(cszTimeOut,ccTimeOut);
	CHAR *szTrav;
	
	if (! szTimeout) {
		DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDAV did not send \"timeout:\" http header\r\n"));
		return TRUE; // lack of header is not an error.
	}

	CHeaderIter header(szTimeout);
	for (szTrav = header.GetNext(); szTrav; szTrav = header.GetNext()) {
		if (0 == _strnicmp(szTrav,cszSecond,ccSecond)) {
			szTrav += ccSecond;
			if (0 == (*pdwTimeout = atoi(szTrav))) {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: LOCK \"timeout:\" header not propertly formatted\r\n"));
				SetStatus(STATUS_BADREQ);	
				return FALSE;
			}
			break;
		}
		else if (0 == _strnicmp(szTrav,cszInfinite,ccInfinite)) {
			*pdwTimeout = INFINITE;
			break;
		}
#if defined (DEBUG)
		else {
			DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: Received unknown field in \"timeout:\" header.  Ignoring, no error\r\n"));
		}
#endif // DEBUG
	}

	if (*pdwTimeout > MAX_DAV_LOCK_TIMEOUT) {
		DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: WebDAV LOCK requested timeout of %ud seconds, setting to maximum allowed %ud seconds\r\n",*pdwTimeout,MAX_DAV_LOCK_TIMEOUT));
		*pdwTimeout = MAX_DAV_LOCK_TIMEOUT;
	}

	return TRUE;
}


PSTR CHeaderIter::GetNext(void) {
	ResetSaved();
	PSTR szTrav = m_szNextString;

	SkipWhiteSpaceNonCRLF(szTrav);

	if (*szTrav == 0 || *szTrav == '\r')
		return NULL;

	m_szStartString = szTrav;

	// look for ','
	while ((*szTrav != '\r') && (*szTrav != ','))
		szTrav++;

	m_szNextString = szTrav+1;
	szTrav--;

	// backup to remove existing spaces
	while (IsNonCRLFSpace(*szTrav)) szTrav--;

	m_szSave  = (szTrav+1);
	cSave     = *m_szSave;
	*m_szSave = 0;

	return m_szStartString;
}

// Skip W/ in weak header parsing
inline PSTR SkipWeakTagIfNeeded(PSTR pszToken) {
	if (*pszToken == 'W' && *(pszToken+1) == '/')
		return pszToken+2;

	return pszToken;
}

BOOL ETagEqualsHeader(PSTR szHeader, PSTR szETag) {
	DEBUGCHK(szHeader);
	PSTR    szToken;

	CHeaderIter headIter(szHeader);

	for (szToken = headIter.GetNext(); szToken; szToken = headIter.GetNext()) {
		szToken = SkipWeakTagIfNeeded(szToken);

		if (*szToken == '*')
			return TRUE;
		else if (0 == strcmp(szETag,szToken))
			return TRUE;
	}
	
	return FALSE;
}

int WriteOpaqueLockToken(PSTR szBuf, __int64 iLockId, BOOL fClosingBrackets) {
	PSTR szWrite = szBuf;

	if (fClosingBrackets)
		*szWrite++ = '<';

	strcpy(szWrite,cszOpaquelocktokenPrefix);
	szWrite += ccOpaquelocktokenPrefix;

	strcpy(szWrite,g_pFileLockManager->m_szLockGUID);
	szWrite += SVSUTIL_GUID_STR_LENGTH;

	*szWrite++ = ':';

	szWrite += sprintf(szWrite,"%I64d",iLockId);

	if (fClosingBrackets) {
		*szWrite++ = '>';
		*szWrite++ = 0;
	}

	return (szWrite - szBuf);
}

// Checks that szHeader is equal to "opaquelocktoken:CE_SERVER_GUID:" and removes the LockID after
// returns a pointer to next.  Returns 0 on failure.
__int64 GetLockIDFromOpaqueHeader(PSTR szToken) {
	__int64 iLockId;

	if (0 != _strnicmp(szToken,cszOpaquelocktokenPrefix,ccOpaquelocktokenPrefix)) {
		DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: DAV Lock header check fails, '<' not followed by %s\r\n",cszOpaquelocktokenPrefix));
		return 0;
	}

	szToken += ccOpaquelocktokenPrefix;
	if (0 != _strnicmp(szToken,g_pFileLockManager->m_szLockGUID,SVSUTIL_GUID_STR_LENGTH)) {
		DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: DAV Lock header check fails, GUID sent does not match system's, which is <<%s>>\r\n",g_pFileLockManager->m_szLockGUID));
		return 0;
	}

	szToken += SVSUTIL_GUID_STR_LENGTH;
	if (*szToken != ':') {
		DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: DAV Lock header check fails, GUID sent does not contain ':' at end\r\n"));
		return 0;
	}
	szToken++;  // skip ':'

	if (0 == (iLockId = _atoi64(szToken))) {
		DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: DAV Lock header check fails, GUID does not contain 64 bit lockID\r\n"));
		return 0;
	}
	return iLockId;
}


#define OPEN_URI         '<'
#define CLOSE_URI        '>'
#define OPEN_LIST        '('
#define CLOSE_LIST       ')'
#define OPEN_LOCK_TOKEN  '<'
#define CLOSE_LOCK_TOKEN '>'
#define OPEN_ETAG        '['
#define CLOSE_ETAG       ']'


// Per RFC 2518, section 9.5:
//   Lock-Token = "Lock-Token" ":" Coded-URL
//   Coded-URL  = "<" URI ">"

__int64 CWebDav::CheckLockTokenHeader(void) {
	PSTR szLockToken = NULL;
	PSTR szTrav;
	PSTR szEndOfURI;
	PSTR szEndOfHeader;
	__int64 iLockId = 0;

	DEBUGCHK(m_pRequest->m_idMethod == VERB_UNLOCK);

	if (NULL == (szLockToken = m_pRequest->FindHttpHeader(cszLockToken,ccLockToken))) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: UNLOCK fails, \"Lock-token\" not sent and is required\r\n"));
		SetStatus(STATUS_BADREQ);
		goto done;
	}
	szTrav = szLockToken;

	svsutil_SkipWhiteSpace(szTrav);
	if (*szTrav != OPEN_URI) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: UNLOCK fails, \"Lock-token\" header does not begin with '<'\r\n"));
		SetStatus(STATUS_BADREQ);
		goto done;
	}
	szTrav++;  // skip '<'

	szEndOfHeader = strchr(szLockToken,'\r');
	szEndOfURI = strchr(szTrav,CLOSE_URI);

	if (!szEndOfURI || (szEndOfURI > szEndOfHeader)) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: UNLOCK fails,\"Lock-token\" did not terminate with '>'\r\n"));
		SetStatus(STATUS_BADREQ);
		goto done;
	}

	iLockId = GetLockIDFromOpaqueHeader(szTrav);

	if (iLockId == 0) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: UNLOCK fails, \"Lock-token\" fields formatted incorrectly\r\n"));
		SetStatus(STATUS_BADREQ);
		goto done;
	}
done:
	return iLockId;
}


// Constants and logic in CheckLockHeader per RFC 2518, section 9.4 parsing of "If:" header rules
//	Format of the If header
//		If = "If" ":" ( 1*No-tag-list | 1*Tagged-list)
//		No-tag-list = List
//		Tagged-list = Resource 1*List
//		Resource = Coded-url
//		List = "(" 1*(["Not"](State-token | "[" entity-tag "]")) ")"
//		State-token = Coded-url
//		Coded-url = "<" URI ">"

// Parses "If:" HTTP header to see what locks we have.
BOOL CWebDav::CheckLockHeader(void) {
	PSTR    szLockHeaderInBuf;    // points inside main request class, do not free
	PSTR    szLockHeader        = NULL;
	PSTR    szEndOfHeader       = NULL;
	PSTR    szEndOfStatement    = NULL;
	BOOL    fRet                = FALSE;
//	BOOL    fFirstPass          = TRUE;
	WCHAR   *wszPhysicalPath    = NULL;
	PSTR    szTrav;
	SVSSimpleBuffer urlBuf(512);

	if (NULL == (szLockHeaderInBuf = m_pRequest->FindHttpHeader(cszIfToken,ccIfToken)))
		return TRUE;

	szEndOfHeader = strchr(szLockHeaderInBuf,'\r');
	DEBUGCHK(szEndOfHeader); // otherwise invalid HTTP headers

	*szEndOfHeader = 0;
	szLockHeader = MySzDupA(szLockHeaderInBuf);
	*szEndOfHeader = '\r';

	if (!szLockHeader) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV out of memory\r\n"));
		SetStatus(STATUS_INTERNALERR);
		goto done;
	}
	szTrav = szLockHeader;

	while (*szTrav) {
		urlBuf.Reset();
	
		svsutil_SkipWhiteSpace(szTrav);
		if (*szTrav != OPEN_URI) {

#if 0  // New policy is to be more lenient, accept this case at any time.  See RFC 2518, section 8.9.6 for example of why we accept this.
			// On the first pass through loop, we'll treat a no-tag production 
			// as if it refers to the request URI
		
			if (!fFirstPass) {
				DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDAV does not have '<' for tagged-list, skipping to end\r\n"));
				fRet = TRUE;
				goto done;
			}
#endif

			MyFreeNZ(wszPhysicalPath);
			wszPhysicalPath = NULL;
		}
		else {
			PSTR szEndOfUrl = NULL;
			szTrav++;  // skip '<'
			szTrav = SkipHTTPPrefixAndHostName(szTrav);

			if (szTrav)
				szEndOfUrl = strchr(szTrav,CLOSE_URI);
			
			if (NULL == szEndOfUrl) {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV skipping host name and headers of tagged-URL failed in \"if:\" header\r\n"));
				SetStatus(STATUS_BADREQ);
				goto done;
			}

			// need to copy results to a new buffer, as canonicilization changes data in place.
			if (! urlBuf.AllocMem(szEndOfUrl-szTrav+1)) {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV out of memory\r\n"));
				SetStatus(STATUS_INTERNALERR);
				goto done;
			}
			*szEndOfUrl = 0;
			svsutil_HttpCanonicalizeUrlA(szTrav,(CHAR*)urlBuf.pBuffer);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -