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

📄 davmain.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: davmain.cpp
Abstract: WebDAV main verb handeling routines
--*/

#include "httpd.h"

const DWORD g_fWebDavModule = TRUE;

//
// Global initialization and deinitialization routines
// 

BOOL CGlobalVariables::InitWebDav(CReg *pWebsite) {
	// WebDAV is enabled by default, but can be disabled via registry.
	if (!pWebsite->ValueDW(RV_WEBDAV,TRUE))
		return FALSE;

	if (m_fRootSite && !g_pFileLockManager)
		g_pFileLockManager = new CWebDavFileLockManager;

	if (! (g_pFileLockManager && g_pFileLockManager->IsInitialized()))
		return FALSE;

	m_dwDavDefaultLockTimeout = pWebsite->ValueDW(RV_DEFAULT_DAV_LOCK,DEFAULT_DAV_LOCK_TIMEOUT);
	m_dwDavDefaultLockTimeout = m_dwDavDefaultLockTimeout / 1000; // store number in seconds.
	return TRUE;
}

void CGlobalVariables::DeInitWebDav(void) {
	DEBUGCHK(m_fRootSite);
	DEBUGCHK(g_fState == SERVICE_STATE_UNLOADING);

	if (g_pFileLockManager)
		delete g_pFileLockManager;

	return;
}

//
// Map a verb request into appropriate DAV handler
//
typedef BOOL (WINAPI *PFN_DAVEXECUTE)(CWebDav *pThis);

BOOL DavUnsupported(CWebDav *pThis) { return pThis->DavUnsupported(); }
BOOL DavOptions(CWebDav *pThis) { return pThis->DavOptions() ; }
BOOL DavPut(CWebDav *pThis) { return pThis->DavPut() ; }
BOOL DavMove(CWebDav *pThis) { return pThis->DavMove() ; }
BOOL DavCopy(CWebDav *pThis) { return pThis->DavCopy() ; }
BOOL DavDelete(CWebDav *pThis) { return pThis->DavDelete() ; }
BOOL DavMkcol(CWebDav *pThis) { return pThis->DavMkcol() ; }
BOOL DavPropfind(CWebDav *pThis) { return pThis->DavPropfind() ; }
BOOL DavProppatch(CWebDav *pThis) { return pThis->DavProppatch() ; }
BOOL DavLock(CWebDav *pThis) { return pThis->DavLock() ; }
BOOL DavUnlock(CWebDav *pThis) { return pThis->DavUnlock() ; }

#if 0
BOOL DavSearch(CWebDav *pThis) { return pThis->DavSearch() ; }
BOOL DavSubscribe(CWebDav *pThis) { return pThis->DavUnsubscribe() ; }
BOOL DavUnsubscribe(CWebDav *pThis) { return pThis->DavUnsubscribe() ; }
BOOL DavPoll(CWebDav *pThis) { return pThis->DavPoll() ; }
BOOL DavBDelete(CWebDav *pThis) { return pThis->DavBDelete() ; }
BOOL DavBCopy(CWebDav *pThis) { return pThis->DavBCopy() ; }
BOOL DavBMove(CWebDav *pThis) { return pThis->DavBMove() ; }
BOOL DavBProppatch(CWebDav *pThis) { return pThis->DavBProppatch() ; }
BOOL DavBPropfind(CWebDav *pThis) { return pThis->DavBPropfind() ; }
BOOL DavX_MS_Enumatts(CWebDav *pThis) { return pThis->DavX_MS_Enumatts() ; }
#endif // 0

// NOTE: this follows same order as "enum VERB" in request.h
PFN_DAVEXECUTE davTable[] = {
	DavUnsupported,
	DavUnsupported,
	DavUnsupported,
	DavUnsupported,
	DavOptions,
	DavPut,
	DavMove,
	DavCopy,
	DavDelete,
	DavMkcol,
	DavPropfind,
	DavProppatch,
//	DavSearch,  // SharePoint + IIS Specific
	DavLock,
	DavUnlock,
#if 0 // unsupported DAV vebs
	DavSubscribe,
	DavUnsubscribe,
	DavPoll,
	DavBDelete,
	DavBCopy,
	DavBMove,
	DavBProppatch,
	DavBPropfind,
	DavX_MS_Enumatts,
#endif // 0 
};

// Webdav entry point web server calls into.
// Note that WebDav handles the vast majority of errors it hits with descriptive 
// XML tags and a "207 Multistatus" response.  HandleWebDav() only returns
// FALSE when it needs the web server to send a 4XX or 5XX error code to the client.
BOOL CHttpRequest::HandleWebDav(void) {
	CWebDav dav(this);

	DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: WebDAV called to handle HTTP verb <<%a>>\r\n",m_pszMethod));

	DEBUGCHK(m_idMethod <= VERB_LAST_VALID && m_idMethod != VERB_UNKNOWN);
	DEBUGCHK(m_idMethod <= ARRAYSIZEOF(davTable));
	DEBUGCHK(m_bufRespBody.m_iNextIn    == 0);
	DEBUGCHK(m_rs == STATUS_OK);

	if (dav.IsCollection() || dav.IsNull())
		RemoveTrailingSlashToPhysicalPath();

	m_fResponseHTTP11 = MAKELONG(1,1) <= m_dwVersion;

	if (m_fDisabledNagle == FALSE) {
		// To increase performance of WebDAV, disable Nagling.
		BOOL fDisable = TRUE;
		int iErr;

		if (ERROR_SUCCESS != (iErr = setsockopt(m_socket,IPPROTO_TCP,TCP_NODELAY,(const char*)&fDisable,sizeof(BOOL)))) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: setsockopt(0x%08x,TCP_NODELAY) failed, err = 0x%08x\r\n",m_socket,iErr));
			DEBUGCHK(0);
		}
		m_fDisabledNagle = TRUE;
	}

	BOOL fRet = (davTable[m_idMethod])(&dav);
	if (dav.m_fXMLBody)
		dav.FinalizeMultiStatusResponse();
	
	dav.FinalConsistencyCheck(fRet);
	DEBUGCHK(! g_pFileLockManager->IsLocked());

	DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: WebDav processing completed.  Returning %d to HTTPD, status code = %d\r\n",fRet,rgStatus[m_rs].dwStatusNumber));
	return fRet;
}

// 
//  Handle HTTP verbs
// 

//
// DavOptions
// OPTIONS requests the capabilities of the server or the available operations on a given resource.
//

const CHAR cszDavCompliance[] = "DAV:";
const CHAR cszCompliance[]    = "1, 2";

const CHAR cszCache_Control[] = "Cache-Control:";
const CHAR cszCache_Control_Private[]	= "private";
// const CHAR cszCache_Control_NoCache[] = "no-cache";


BOOL CWebDav::DavOptions(void) {
	BOOL fRet = FALSE;
	BOOL fWriteAccess = (m_pRequest->GetPerms() & HSE_URL_FLAGS_WRITE);

	// alloc big enough buffer now so we don't have to check every AddHeader() call.
	if (!m_pRequest->m_bufRespHeaders.AllocMem(HEADERBUFSIZE)) {
		SetStatus(STATUS_INTERNALERR);
		goto done;
	}

	// "*" requests options for the entire server
	if (0 == strcmp(m_pRequest->m_pszURL,"*") || 0 == strcmp(m_pRequest->m_pszURL,"/*")) {
		m_pRequest->m_bufRespHeaders.AppendData(cszAllow,ccAllow);
		WritePublicOptions();

		m_pRequest->m_bufRespHeaders.AddHeader(cszAccept_Ranges,cszBytes);
		fRet = TRUE;
		goto done; // make sure common case headers are handled
	}

	if (m_pRequest->GetPerms() & HSE_URL_FLAGS_READ) {
		if (! CheckIfHeaders()) {
			SetStatus(STATUS_BADREQ);
			fRet = FALSE;
			goto done;
		}
	}

	// It doesn't make sense to check against LOCKs in this case, as OPTIONS doesn't modify resource in any way.

	// Print out "Allow: " header
	m_pRequest->m_bufRespHeaders.AppendData(cszAllow,ccAllow);
	m_pRequest->m_bufRespHeaders.AppendCHAR(' ');
	WriteSupportedVerb(VERB_OPTIONS,TRUE);
	WriteSupportedVerb(VERB_GET);
	WriteSupportedVerb(VERB_HEAD);

	if (fWriteAccess) {
		WriteSupportedVerb(VERB_DELETE);

		if (!IsCollection())
			WriteSupportedVerb(VERB_PUT);
	}

	if (m_pRequest->IsScript(TRUE))
		WriteSupportedVerb(VERB_POST);

	if (! IsCollection())
		WriteSupportedVerb(VERB_MKCOL);

	if (! IsNull()) {
		WriteSupportedVerb(VERB_COPY);

		if (fWriteAccess) {
			WriteSupportedVerb(VERB_MOVE);
			WriteSupportedVerb(VERB_PROPPATCH);
//			m_pRequest->m_bufRespHeaders.AppendData(cszDavSearch,SVSUTIL_CONSTSTRLEN(cszDavSearch));
		}
	}

	WriteSupportedVerb(VERB_LOCK);
	WriteSupportedVerb(VERB_UNLOCK);
	m_pRequest->m_bufRespHeaders.AppendData(cszCRLF,ccCRLF);

	m_pRequest->m_bufRespHeaders.AddHeader(cszAccept_Ranges,(m_rt == RT_COLLECTION) ? cszNone : cszBytes);
	
	fRet = TRUE;
done:
	if (fRet) {
		// common headers.
//		m_pRequest->m_bufRespHeaders.AddHeader(cszDasl,cszSqlQuery);
		m_pRequest->m_bufRespHeaders.AppendData(cszPublic, ccPublic);
		WritePublicOptions();

		m_pRequest->m_bufRespHeaders.AddHeader(cszDavCompliance, cszCompliance);
		m_pRequest->m_bufRespHeaders.AddHeader(cszCache_Control, cszCache_Control_Private);

		CHttpResponse resp(m_pRequest);
		resp.SetZeroLenBody();
		resp.SendResponse();
	}

	DEBUGCHK(m_pRequest->m_bufRespHeaders.m_iNextIn < HEADERBUFSIZE); 	// make sure we didn't use more than we claimed we would...
	return fRet;
}


BOOL CWebDav::DavPropfind(void) { 
	BOOL fRet = FALSE;

	if (! (m_pRequest->GetPerms() & HSE_URL_FLAGS_READ)) {
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: PROPFIND returns access denied because HSE_URL_FLAGS_READ is not set\r\n"));
		SetStatus(STATUS_FORBIDDEN);
		goto done;
	}

#if 0
	if (! m_pRequest->m_dwContentLength) {
		// BUGBUG : No chunked encoding support currently, so this won't help.  Look at other clients 
		// and how frequently POST is used to see if we need it.  If add this, review every place!!
		if (! m_pRequest->FindHttpHeader(cszTransfer_Encoding,ccTransfer_Encoding)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: PROPFIND fails because no content-length or transfer-encoding was set\r\n"));
			SetStatus(STATUS_REQUEST_TOO_LARGE);
			goto done;
		}
	}
#endif

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

	if (m_rt == RT_COLLECTION) {
		// depth only matters for directories
		if (! GetDepth()) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: PROPFIND fails because depth not set for directory\r\n"));
			SetStatus(STATUS_BADREQ);
			goto done;
		}
	}

	if (! CheckIfHeaders()) {
		SetStatus(STATUS_PRECONDITION_FAILED);
		goto done;

⌨️ 快捷键说明

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