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

📄 davutil.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: davutil.cpp
Abstract: WebDAV utility functions
--*/


#include "httpd.h"

// Returns pointer to value part of the HTTP header, skipping past white space between ":" and value.
// NOTE: this string is not NULL terminated, but terminated by \r\n.


// Skip past "http(s)://CEHostName/".
PSTR SkipHTTPPrefixAndHostName(PSTR szURL) {
	PSTR szSlash;
	PSTR szFinalURL;
	
	if (*szURL == '/')
		return szURL; // URL is relative, no http://.../ stuff to begin with

	if (NULL == (szSlash = strchr(szURL,'/')))
		return NULL;

	// skip opening 2 /'s.
	szSlash += (szSlash[1] == '/') ? 2 : 1;

	// skip the host name
	szFinalURL = strchr(szSlash,'/');
	return szFinalURL ? szFinalURL : szSlash;
}


// Retrieves "Depth:" HTTP header and maps to approrpiate enumeration
BOOL CWebDav::GetDepth(DEPTH_TYPE depthDefault) {
	PSTR szHeader;

	// If we have depth already we're done.
	if (m_Depth != DEPTH_UNKNOWN)
		return TRUE;

	if (NULL == (szHeader = m_pRequest->FindHttpHeader(cszDepth,ccDepth))) {
		m_Depth = depthDefault;
		return TRUE;
	}

	if (0 == _strnicmp(szHeader,csz0,cc0))
		m_Depth = DEPTH_ZERO;
	else if (0 == _strnicmp(szHeader,csz1,cc1))
		m_Depth = DEPTH_ONE;
	else if (0 == _strnicmp(szHeader,cszInfinity,ccInfinity))
		m_Depth = DEPTH_INFINITY;
	else if (0 == _strnicmp(szHeader,csz1NoRoot,cc1NoRoot))
		m_Depth = DEPTH_ONE_NOROOT;
	else
		return FALSE;

	return TRUE;
}

void CWebDav::GetOverwrite(void) {
	PSTR szHeader = m_pRequest->FindHttpHeader(cszOverwrite,ccOverwrite);

	if ((NULL == szHeader) || (*szHeader == 't') || (*szHeader == 'T'))
		m_Overwrite = OVERWRITE_YES;
	else
		m_Overwrite = OVERWRITE_NO;

	szHeader = m_pRequest->FindHttpHeader(cszAllowRename,ccAllowRename);

	if (szHeader && (*szHeader == 't' || *szHeader == 'T'))
		m_Overwrite |= OVERWRITE_RENAME;
}


// szSrc and szDest are physical paths of source and destination of a move/copy.
// They cannot be a subset of one another, i.e. 'move \a \a\b' is disallowed.
BOOL IsPathSubDir(WCHAR *szSrc, DWORD ccSrc, WCHAR *szDest, DWORD ccDest) {
	if ((ccSrc == 0) || (ccDest == 0))
		return TRUE;

	if (ccSrc == ccDest)
		return (0 == PathNameCompare(szSrc,szDest));

	WCHAR *szShorter;
	WCHAR *szLonger;
	DWORD ccShorter;
	DWORD ccLonger;

	if (ccSrc > ccDest) {
		szShorter = szDest;
		szLonger  = szSrc;
		ccShorter = ccDest;
		ccLonger  = ccSrc;
	}
	else {
		szShorter = szSrc;
		szLonger  = szDest;
		ccShorter = ccSrc;
		ccLonger  = ccDest;	
	}

	// look for shorter path.  We check back-slashes to make sure things are really
	// equal, i.e. without backslash check '\windows\foo' and '\windows\foobar'
	// would match, which isn't what we're looking for.

	if (0 == PathNameCompareN(szSrc,szDest,ccShorter)) {
		if ( (L'\\' == szShorter[ccShorter-1]) ||
		     (L'/'  == szShorter[ccShorter-1]) ||
		     (L'\\' == szLonger [ccShorter])   ||
		     (L'/' == szLonger [ccShorter])) {
			return TRUE;
		}
	}
	return FALSE;
}

inline void SetFiletime(FILETIME *pftDest, FILETIME *pftSrc) {
	memcpy(pftDest,pftSrc,sizeof(FILETIME));
}

BOOL CWebDav::DavGetFileAttributesEx() {
	if (! m_fRetrievedFileAttribs) {
		if (!GetFileAttributesEx(m_pRequest->m_wszPath,GetFileExInfoStandard,&m_fileAttribs)) {
			DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: GetFileAttributesEx(%s) fails, GLE=0x%08x\r\n",m_pRequest->m_wszPath,GetLastError()));
			return FALSE;
		}

		m_fRetrievedFileAttribs = TRUE;
		return TRUE;
	}
	return TRUE;
}

// Make a copy of this data here rather than (possibly) having to alloc 1 KB of RAM
// in m_bufRespHeaders for every response.
const CHAR cszDefaultXMLHttpHeader[] = "Content-Type: text/xml\r\nTransfer-Encoding: chunked\r\n\r\n";

#define ADD_CRLF(sz,ccWrite)  (sz)[(ccWrite++)] = '\r'; (sz)[(ccWrite++)] = '\n';

DWORD AddHttpHeader(CHAR *szBuf, PCSTR szHeaderName, DWORD ccHeaderName, PCSTR szHeaderValue, DWORD ccHeaderValue) {
	DWORD ccWritten = 0; 
	
	strcpy(szBuf,szHeaderName);
	ccWritten = ccHeaderName;
	szBuf[ccWritten++] = ' ';

	strcpy(szBuf+ccWritten,szHeaderValue);
	ccWritten += ccHeaderValue;
	ADD_CRLF(szBuf,ccWritten);

	return ccWritten;
}

// For success cases (i.e. 2XX) where we also need to send XML in body.
BOOL CWebDav::SetStatusAndXMLBody(RESPONSESTATUS rs) {
	if (!m_fSetStatus) {
		CHAR  szHeaders[MINBUFSIZE];
		DWORD ccWritten;

		DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav setting response %d headers\r\n",rgStatus[rs].dwStatusNumber));

		ccWritten = AddHttpHeader(szHeaders,cszContent_Type,ccContent_Type,
		                                    cszTextXML,ccTextXML);

		if (m_pRequest->m_fResponseHTTP11) {
			ccWritten += AddHttpHeader(szHeaders+ccWritten,cszTransfer_Encoding,ccTransfer_Encoding,
			                                     cszChunked,ccChunked);
			ADD_CRLF(szHeaders,ccWritten); // closing CRLF at end of HTTP headers
			szHeaders[ccWritten++] = 0;
			CHttpResponse resp(m_pRequest, rs);
			resp.SendHeadersAndDefaultBodyIfAvailable(szHeaders,NULL);
		}
		else {
			m_pRequest->m_rs = rs;
			m_pRequest->m_bufRespHeaders.AppendData(szHeaders,ccWritten);
		}
		m_fSetStatus = TRUE;

		if (! m_bufResp.Append(cszXMLVersionA, ccXMLVersionA))
			return FALSE;

		if ((m_pRequest->m_rs == STATUS_MULTISTATUS) && !m_bufResp.StartTagNoEncode(cszMultiStatusNS,ccMultiStatusNS))
			return FALSE;

		DEBUGCHK(ccWritten < sizeof(szHeaders));
		m_fXMLBody = TRUE;
	}
	return TRUE;
}

BOOL CWebDav::FinalizeMultiStatusResponse(void) {
	DEBUGCHK(m_fSetStatus && m_fXMLBody);
	m_bufResp.BufferConsistencyChecks();

	DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav flushing buffer for the final time\r\n"));

	if ((m_pRequest->m_rs == STATUS_MULTISTATUS) && !m_bufResp.EndTag(cszMultiStatus))
		return FALSE;

	return m_bufResp.FlushBuffer(TRUE);
}


// Creates string in format "http(s)://CeServerName/[szRoot]".  Calling function
// will optionally add remainder of URL
BOOL CWebDav::BuildBaseURL(PCSTR szRoot, BOOL fHttpHeader, BOOL fAppendSlash) {
	BOOL fRet = FALSE;
	PCSTR szHostName;

#if defined (DEBUG)
	if (fAppendSlash)
		DEBUGCHK(!URLHasTrailingSlashA(szRoot));
#endif

	if (m_pRequest->m_pszHost) {
		szHostName = m_pRequest->m_pszHost;
		m_ccHostName = strlen(m_pRequest->m_pszHost);
	}
	else { 
		if (m_ccHostName == 0) {
			if (0 != gethostname(m_szHostName, sizeof(m_szHostName)))
				goto done;

			m_ccHostName = strlen(m_szHostName);
		}
		szHostName = m_szHostName;
	}

	if (fHttpHeader) {
		if (! m_pRequest->m_bufRespHeaders.AppendData(GetHttpPrefix(),GetHttpPrefixLen())   ||
		    ! m_pRequest->m_bufRespHeaders.AppendData(szHostName,m_ccHostName)            ||
		    ! m_pRequest->m_bufRespHeaders.EncodeURL(szRoot)                ||
		    (fAppendSlash && !m_pRequest->m_bufRespHeaders.AppendCHAR('/'))                ||
		    ! m_pRequest->m_bufRespHeaders.AppendData(cszCRLF,2)) {
			goto done;
		}
	}
	else {
		if (! m_bufResp.Append(GetHttpPrefix(),GetHttpPrefixLen())   ||
		    ! m_bufResp.Encode(szHostName)                           ||
		    ! m_bufResp.EncodeURL(szRoot)                            ||
            (fAppendSlash && !m_bufResp.AppendCHAR('/'))) {
			goto done;
		}
	}

	fRet = TRUE;
done:
	return fRet;
}


// Creates string in format "http(s)://CeServerName/[Root]/", where Root
// is the originally requested URL.  The URL is cleaned up for sending if needed.
BOOL CWebDav::BuildBaseURLFromSourceURL(BOOL fHttpHeader) {
	// For directories, tack trailing '/' to end of string if not there.  For files,
	// remove it.

	BOOL fAddSlash = IsCollection() && ! m_pRequest->URLHasTrailingSlash();
	return BuildBaseURL(m_pRequest->m_pszURL,fHttpHeader,fAddSlash);
}

// Adds "Content-Location:" HTTP response headers.
BOOL CWebDav::AddContentLocationHeader(void) {
	DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: Adding \"Content-Location:\" headers\r\n"));

	if (! m_pRequest->m_bufRespHeaders.AppendData(cszContent_Location,ccContent_Location)         || 
	    ! m_pRequest->m_bufRespHeaders.AppendData(" ",1)                       ||
	    ! BuildBaseURLFromSourceURL(TRUE))
	{
		DEBUGMSG(ZONE_ERROR,(L"HTTPD: Out of memory, unable to add http headers\r\n"));
		m_pRequest->m_bufRespHeaders.Reset(); 
		SetStatus(STATUS_INTERNALERR);
		return FALSE;
	}
	return TRUE;
}

// Adds "Content-Location:" to response headers when no trailing "/" on directories, effectively a redirect
BOOL CWebDav::AddContentLocationHeaderIfNeeded(void) {
	int iLen = strlen(m_pRequest->m_pszURL);
	DEBUGCHK(iLen >= 1);

	// If directory and no trailing "/", or a file and a trailing "/", 
	if (m_pRequest->URLHasTrailingSlash() == IsCollection())
		return TRUE; // no redirection needed.

	return AddContentLocationHeader();
}


// Writes contents of HTTP body into hFile
BOOL CWebDav::WriteBodyToFile(HANDLE hFile, BOOL fChunked) {
	CHAR  szBuf[HEADERBUFSIZE];
	DWORD cbBuf;
	DWORD dwWritten;

	DEBUGCHK(hFile != INVALID_HANDLE_VALUE);
	DEBUGCHK(!fChunked); // Chunked NYI...

	m_rcvBody.fChunked = fChunked;

	DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: WebDav WriteBodyToFile called, hFile=0x%08x, fChunked=%d\r\n",hFile,fChunked));

	// write any data we already have into the file immediatly.
	if (!fChunked) {
		DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav WriteBodyToFile writes initial %d bytes to file\r\n",m_pRequest->m_bufRequest.Count()));
		if (! WriteFile(hFile,m_pRequest->m_bufRequest.Data(),m_pRequest->m_bufRequest.Count(),&dwWritten,NULL)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WriteFile fails, GLE=0x%08x\r\n",GetLastError()));
			return FALSE;
		}

		// Request read in everything
		if (m_pRequest->m_dwContentLength == m_pRequest->m_bufRequest.Count())
			return TRUE;
	}

	// There's additional data that needs to be recv()'d
	while (1) {
		cbBuf = sizeof(szBuf);

		if (! ReadNextBodySegment(szBuf,&cbBuf))
			return FALSE;

		if (cbBuf == 0)
			return TRUE;

		DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav WriteBodyToFile writes extra %d bytes to file\r\n",cbBuf));
		if (! WriteFile(hFile,szBuf,cbBuf,&dwWritten,NULL)) {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: WriteFile fails, GLE=0x%08x\r\n",GetLastError()));
			return FALSE;
		}
	}

	DEBUGCHK(0);
	return FALSE;
}

// Reads body segment, keeping track of state as it goes along.
// Returns FALSE on errors or timeouts.  When done reading request, sets *pcbRead=0.

BOOL CWebDav::ReadNextBodySegment(PSTR szBuf, DWORD *pcbRead) {
	BOOL  fRet;

	if (m_rcvBody.dwRemaining == RECEIVE_SIZE_UNINITIALIZED) {

⌨️ 快捷键说明

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