📄 webdav.h
字号:
//
// 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: webdav.h
Abstract: Web Dav declarations
--*/
//
// Constants and enumerations
//
typedef enum {
RT_NULL = 0,
RT_DOCUMENT,
RT_STRUCTURED_DOCUMENT,
RT_COLLECTION
} RESOURCE_TYPE;
typedef enum {
DEPTH_UNKNOWN = 0,
DEPTH_ZERO,
DEPTH_ONE,
DEPTH_INFINITY,
DEPTH_ONE_NOROOT,
DEPTH_INFINITY_NOROOT,
} DEPTH_TYPE;
typedef enum {
OVERWRITE_NO = 0x0,
OVERWRITE_YES = 0x1,
OVERWRITE_RENAME = 0x2
} OVERWRITE_TYPE;
#define TokensEqualA(s1,s2,c1,c2) (((int)(c1)==(int)(c2)) && (0==strncmp((s1),(s2),(c1))))
#define TokensEqualAI(s1,s2,c1,c2) (((c1)==(c2)) && (0==_strnicmp((s1),(s2),(c1))))
// When using const data, assume there's a cszStrName and corresponding ccStrName
#define TokensEqualAC(s1, StrName, c1) TokensEqualA(s1,csz##StrName, c1, cc##StrName)
#define TokensEqualW2(s1,s2,c1,c2) (((c1)==(c2)) && (0==wcsncmp((s1),(s2),(c1))))
#define TokensEqualW(s1,s2,c1) TokensEqualW2(s1,s2,c1,SVSUTIL_CONSTSTRLEN(s2))
#define DEBUG_CHECK_ERRCODE(fRet) DEBUGCHK((fRet && IS_STATUS_2XX(m_pRequest->m_rs)) || (!fRet && !IS_STATUS_2XX(m_pRequest->m_rs)))
//
// Chunked Body Response Buffer
//
// How large to allocate on. Each initial alloc will be two times greater.
#define INITIAL_CHUNK_BUFFER_SIZE 0x2000
// This is the largest the actual body (non-chunked pieces) can grow to.
#define MAX_CHUNK_BODY_SIZE 0xFFEE
// reserve first 6 bytes of the buffer for length of the chunked encode (4 bytes) and for CRLF (2 bytes).
#define CHUNK_PREAMBLE 6
// How many bytes to set '0CRLFCRLF'
#define CHUNK_CLOSE_LEN 5
// reserve 7 extra bytes for closing of buffer. 2 for CRLF at end of each chunk, 5 for the final "0CRLFCRLF" that signifies we're done sending.
#define CHUNK_POSTAMBLE (CHUNK_CLOSE_LEN+2)
// How much extra space to reserve for the buffer
#define CHUNK_RESERVE_SPACE (CHUNK_PREAMBLE+CHUNK_POSTAMBLE)
// Largest buffer can grow to that holds all this stuff
#define MAX_CHUNK_BUFFER_SIZE (INITIAL_CHUNK_BUFFER_SIZE*8)
class CChunkedBuffer {
private:
// We use chunked-encoding on certain responses for optimization.
// When the buffer goes above MAX_CHUNK_BODY_SIZE, we immediatly send response.
// NOTE: these variables should *never* be accessed from functions outside this class,
// as there are a number of idiosyncracies in maintaining a chunked buffer.
// Always use accessors!
char *m_pszBuf; // pointer to allocated mem
DWORD m_iNextIn; // next character to read from
DWORD m_iSize; // size of buffer
protected:
CHttpRequest *m_pRequest;
BOOL m_fSentFirstChunk; // Have we sent our first body response to client yet?
void WriteCloseChunk(PSTR szBuf, DWORD dwOffset);
public:
CChunkedBuffer(CHttpRequest *pR) {
memset(this,0,sizeof(*this));
m_pRequest = pR;
}
~CChunkedBuffer() {
FinalBufferConsistencyCheck();
if (m_pszBuf)
g_funcFree(m_pszBuf,g_pvFreeData);
}
BOOL AllocMem(DWORD cbSize);
BOOL Append(PCSTR pszData, DWORD ccData);
BOOL FlushBuffer(BOOL fFinalChunk=FALSE);
BOOL AbortiveError(void);
BOOL AppendCHAR(const CHAR cAppend) {
return Append((char *)&cAppend,sizeof(CHAR));
}
BOOL IsEmpty(void) {
return ((m_pszBuf==NULL) && (m_iSize==0));
}
#if defined (DEBUG)
BOOL m_fFinalDataSent; // will be set true once we're done sending
void BufferConsistencyChecks(void) {
if (m_pszBuf)
DEBUGCHK(m_iNextIn && m_iSize);
else
DEBUGCHK(!m_iNextIn && !m_iSize);
DEBUGCHK(m_iNextIn <= m_iSize);
if (m_iNextIn)
DEBUGCHK(m_iNextIn >= CHUNK_PREAMBLE);
// buffer is allocated on predefined boundaries.
switch (m_iSize) {
case 0:
case INITIAL_CHUNK_BUFFER_SIZE:
case (INITIAL_CHUNK_BUFFER_SIZE*2):
case (INITIAL_CHUNK_BUFFER_SIZE*4):
case MAX_CHUNK_BUFFER_SIZE:
break;
default:
DEBUGCHK(0);
}
}
// Make sure that we've flushed the buffer.
void FinalBufferConsistencyCheck(void) {
BufferConsistencyChecks();
DEBUGCHK(m_iNextIn == 0 || m_iNextIn == CHUNK_PREAMBLE);
if (m_iNextIn)
DEBUGCHK(!m_pRequest->m_fResponseHTTP11 || m_fFinalDataSent);
}
#else
void BufferConsistencyChecks(void) { ; }
void FinalBufferConsistencyCheck(void) { ; }
#endif // DEBUG
};
extern const char cszPrefixBraceOpen[];
extern const DWORD ccPrefixBraceOpen;
extern const char cszPrefixBraceEnd[];
extern const DWORD ccPrefixBraceEnd;
class CXMLBuffer : public CChunkedBuffer {
public:
CXMLBuffer(CHttpRequest *pR) : CChunkedBuffer(pR) {
;
}
~CXMLBuffer() { ; }
BOOL Encode(PCSTR pszData);
BOOL EncodeURL(PCSTR pszData);
BOOL BeginBrace(void) {
return Append(cszPrefixBraceOpen,ccPrefixBraceOpen);
}
BOOL CloseBrace(void) {
return AppendCHAR('>');
}
BOOL EndBrace(void) {
return Append(cszPrefixBraceEnd,ccPrefixBraceEnd);
}
BOOL BeginBraceNoNS(void) {
return AppendCHAR('<');
}
BOOL StartTag(const CHAR *szElementName) {
if (!BeginBrace() ||
!Encode(szElementName) ||
!CloseBrace())
return FALSE;
return TRUE;
}
BOOL StartTagNoEncode(const CHAR *szElementName, int ccElementName=-1) {
if (!BeginBrace() ||
!Append(szElementName,(ccElementName==-1) ? strlen(szElementName) : ccElementName) ||
!CloseBrace())
return FALSE;
return TRUE;
}
BOOL EndTag(const CHAR *szElementName) {
if (!EndBrace() ||
!Encode(szElementName) ||
!CloseBrace() )
return FALSE;
return TRUE;
}
BOOL SetCRLF(void) {
return Append("\r\n",2);
}
BOOL SetEmptyElement(const CHAR *szElementName) {
if (!BeginBrace() ||
!Encode(szElementName) ||
!Append("/>",2))
return FALSE;
return TRUE;
}
BOOL SetEmptyElementNoEncode(const CHAR *szElementName, int ccElementName=-1) {
if (!BeginBrace() ||
!Append(szElementName,(ccElementName==-1) ? strlen(szElementName) : ccElementName) ||
!Append("/>",2))
return FALSE;
return TRUE;
}
// Setting tags in an 207 multistatus XML blob
BOOL SetStatusTag(RESPONSESTATUS rs);
};
#define RECEIVE_SIZE_UNINITIALIZED ((DWORD)-1)
// For keeping track of receiving POST data.
class CReceiveBody {
public:
BOOL fChunked;
// length of unread portion of current chunk, or length of remaining POST body in non-chunked.
DWORD dwRemaining;
CReceiveBody() {
dwRemaining = RECEIVE_SIZE_UNINITIALIZED;
}
~CReceiveBody() { ; }
} ;
// For recursing through directory structure.
class CWebDav;
class CWebDavFileNode;
typedef BOOL (WINAPI *PFN_RECURSIVE_VISIT)(CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot);
BOOL SendPropertiesVisitFcn (CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot);
BOOL SendPropertyNamesVisitFcn (CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot);
BOOL DeleteVisitFcn (CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot);
BOOL MoveCopyVisitFcn (CWebDav *pThis, WIN32_FIND_DATAW *pFindData, DWORD dwContext, WCHAR *szPath, BOOL fIsRoot);
// When recursing through directories performing a move or copy, info to keep
// our place in the stack during calls to MoveCopyVisitFcn().
class CMoveCopyContext {
public:
DWORD dwSrcPermFlags; // HSE_URL_FLAGS_xxx perms for source VRoot
DWORD dwDestPermFlags; // HSE_URL_FLAGS_xxx perms for destination VRoot
PSTR szDestURL; // canonicalized destination URL
WCHAR *wszDestPath; // root of physical path to write data to.
DWORD ccDestPath; // number of WCHARs in dest physical path
DWORD ccSrcPath; // number of WCHARs in source physical path
BOOL fDeleteSrc; // copy or move files?
CMoveCopyContext(BOOL fDelSrc, DWORD dwSrc, DWORD dwDest, PSTR szURL, WCHAR *wszPath, DWORD ccSrcP) {
dwSrcPermFlags = dwSrc;
dwDestPermFlags = dwDest;
szDestURL = szURL;
wszDestPath = wszPath;
ccDestPath = wcslen(wszDestPath);
ccSrcPath = ccSrcP;
fDeleteSrc = fDelSrc;
}
~CMoveCopyContext() {
// do not free string resources, they are pointers to static buffers in calling function.
}
};
// When recursing through directories on a delete, options info
class CDavDeleteContext {
public:
CHAR *szURL;
BOOL fSendErrorsToClient;
CDavDeleteContext(CHAR *sz, BOOL f) {
szURL = sz;
fSendErrorsToClient = f;
}
};
typedef SVSExpArray<__int64> LockIdArray;
//
// Main WebDAV class
//
class CWebDav {
friend class CWebDavFileLockManager;
public:
CHttpRequest *m_pRequest; // request class
private:
RESOURCE_TYPE m_rt; // are we a directory, file, or a non-existant resource?
DEPTH_TYPE m_Depth; // "Depth:" HTTP header
DWORD m_Overwrite; // "overwrite: " HTTP header
CXMLBuffer m_bufResp; // Response class that generates chunked HTTP and encodes XML data.
SVSSimpleBuffer m_bufUnknownTags; // PROPFIND or PROPPATCH tags that WinCE doesn't support are stored in a NULL separeted list of strings to be sent back later to client.
CHAR m_szHostName[MAX_PATH]; // cache the host name to only call gethostname() once
DWORD m_ccHostName; // length of m_szHostName
CReceiveBody m_rcvBody; // Context used when calling WriteFile during a PUT
BOOL m_fSetStatus; // Have we sent "207" headers already?
public:
BOOL m_fXMLBody; // are we sending XML?
DWORD m_dwPropPatchUpdate; // fields that have been updated during PROPPATCH.
private:
WIN32_FILE_ATTRIBUTE_DATA m_fileAttribs; // cache attribs to only call GetFileAttributesEx(m_pRequest->m_wszPath,...) once.
BOOL m_fRetrievedFileAttribs; // have we called GetFileAttributesEx() yet?
LockIdArray m_lockIds; // store lock tokens
int m_nLockTokens; // number of lock tokens we've parsed from (if: XXX field)
// ******************************************************
// Utility functions
// ******************************************************
BOOL IsGLELocked(void) {
// in theory ERROR_SHARING_VIOLATION should be only error code we'd take to mean a locking
// violation. However some CE filesystems set ERROR_ACCESS_DENIED as error code when
// they mean ERROR_SHARING_VIOLATION. BUGBUG - what are prospects for getting this fixed on all filesystems?
DWORD dw = GetLastError();
return ((dw == ERROR_SHARING_VIOLATION) || (dw == ERROR_ACCESS_DENIED));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -