📄 davxml.cpp
字号:
//
// 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: davxml.cpp
Abstract: WebDAV main verb handeling routines
--*/
#include "httpd.h"
// *****************************************************************
// Utility functions for parsing XML
// *****************************************************************
BOOL UTF8ToBSTR(PSTR psz, BSTR *ppBstr) {
DWORD cp = CP_UTF8;
int iLen = MultiByteToWideChar(cp, 0, psz, -1, NULL, NULL);
if (0 == iLen) {
cp = CP_ACP;
iLen = MultiByteToWideChar(cp, 0, psz, -1, NULL, NULL);
if (0 == iLen) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Unable to convert UTF8 text to UNICODE. GLE=0x%08x\r\n",GetLastError()));
return FALSE;
}
}
if (NULL == ((*ppBstr) = SysAllocStringByteLen(NULL,(iLen+1)*sizeof(WCHAR)))) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: SysAllocStringByteLen fails. GLE=0x%08x\r\n",GetLastError()));
return FALSE;
}
MultiByteToWideChar(cp, 0, psz, -1, *ppBstr, iLen);
return TRUE;
}
// Creates a SAX parser and passes it pParser, which implements logic for
// particular verb.
BOOL CWebDav::ParseXMLBody(ISAXContentHandler *pParser, BOOL fSetDefaultStatus) {
BOOL fCoUnInit = FALSE;
HRESULT hr = E_FAIL;
RESPONSESTATUS rs = STATUS_INTERNALERR;
ISAXXMLReader* pReader = NULL;
VARIANT varInput;
memset(&varInput,0,sizeof(varInput));
DEBUGCHK(m_pRequest->m_rs == STATUS_OK);
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav initiating SAX parser to parse XML body\r\n"));
if (STATUS_OK != (rs = VerifyXMLBody()))
goto done;
rs = STATUS_INTERNALERR;
if (FAILED(hr = CoInitializeEx(NULL,COINIT_MULTITHREADED))) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: CoInitializeEx failed, GLE=0x%08x\r\n",GetLastError()));
goto done;
}
fCoUnInit = TRUE;
if (FAILED(hr = CoCreateInstance(CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER, IID_ISAXXMLReader, (void**)&pReader))) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: CoCreateInstance(CLSID_SAXXMLReader) failed, error=0x%08x\r\n",hr));
goto done;
}
if (FAILED(hr = pReader->putContentHandler(pParser))) {
DEBUGMSG(ZONE_ERROR, (L"HTTPD: ISAXXMLReader::putContentHandler failed, error=0x%08x\r\n",hr));
goto done;
}
varInput.vt = VT_BSTR;
if (!UTF8ToBSTR((PSTR)m_pRequest->m_bufRequest.Data(),&varInput.bstrVal))
goto done;
if (FAILED(hr = pReader->parse(varInput))) {
// If the parse routines didn't set the error otherwise, assume it was invalid XML that caused problem.
if (m_pRequest->m_rs == STATUS_OK)
rs = STATUS_BADREQ;
DEBUGMSG (ZONE_ERROR, (L"HTTPD: ISAXXMLReader::parse(). Error = 0x%08x\r\n",hr));
goto done;
}
hr = S_OK;
done:
if (varInput.bstrVal)
SysFreeString(varInput.bstrVal);
if (pReader)
pReader->Release();
if (fCoUnInit)
CoUninitialize();
if (fSetDefaultStatus) {
// For PROPFIND, the ISAXContentHandler implementation does all the logic processing.
// If it did not set a status, means that the XML tags it required to see
// never were parsed, so set appropriate errors now as appropriate.
if ((hr==S_OK) && !m_fSetStatus) {
rs = STATUS_BADREQ;
}
DEBUGCHK(rs != STATUS_OK);
if (m_pRequest->m_rs == STATUS_OK) {
SetStatus(rs);
return FALSE;
}
}
else if ((hr != S_OK) && !m_fSetStatus) {
// On PROPPATCH and LOCK, routine outside of ISAXContentHandler,
// handles most of the logic, so don't set default errors.
SetStatus(rs);
}
return (hr == S_OK);
}
//
BOOL CLockParse::WriteXMLTagToBuffer(const wchar_t * pwchNamespaceUri, int cchNamespaceUri, const wchar_t * pwchLocalName,
int cchLocalName, const wchar_t * pwchQName, int cchQName, ISAXAttributes * pAttributes, BOOL fIsStartTag) {
if (fIsStartTag) {
if (FAILED(m_OwnerXML.startElement(pwchNamespaceUri,cchNamespaceUri,pwchLocalName,cchLocalName,pwchQName,cchQName,pAttributes)))
return FALSE;
}
else {
if (FAILED(m_OwnerXML.endElement(pwchNamespaceUri,cchNamespaceUri,pwchLocalName,cchLocalName,pwchQName,cchQName)))
return FALSE;
}
return TRUE;
}
#if defined (DEBUG)
inline void DebugOutUnexpectedToken(const CHAR *szTokenExpected, const CHAR *szLocalName, int ccLocalName) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Error parsing xml, expecting token \"%a:\", got %*a\r\n",szTokenExpected,ccLocalName,szLocalName));
}
inline void DebugOutInvalidChild(const CHAR *szCurrentNode) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Error parsing xml, node \"%a:\" has a child node, illegal\r\n",szCurrentNode));
}
inline void DebugOutUnknown(void) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Error, xml parser in unknown state due to unhandled tags. Reqeust fails.\r\n"));
}
#else
inline void DebugOutUnexpectedToken(const CHAR *szTokenExpected, const CHAR *szLocalName, int ccLocalName) { ; }
inline void DebugOutInvalidChild(const CHAR *szCurrentNode) { ; }
inline void DebugOutUnknown(void) { ; }
#endif
const WCHAR cwszDavNameSpace[] = L"DAV:";
const DWORD ccDavNameSpace = SVSUTIL_CONSTSTRLEN(cwszDavNameSpace);
BOOL CDavParse::VerifyNS(DAV_NAMESPACE ns, const WCHAR *szNamespace, DWORD ccNamespace) {
switch (ns) {
case NAMESPACE_DAV:
if ( ! TokensEqualW(szNamespace,cwszDavNameSpace,ccNamespace)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Error parsing DAV xml, expecting NS \"%s:\", got %*s\r\n",cwszDavNameSpace,ccNamespace,szNamespace));
return FALSE;
}
break;
/* case NAMESPACE_MS:
if ( ! TokensEqualW(szNamespace,cwszMSNamespace,ccNamespace)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: Error parsing DAV xml, expecting NS \"%s:\", got %*s\r\n",cwszMSNamespace,ccNamespace,szNamespace));
return FALSE;
}
break;
*/
default:
SVSUTIL_ASSERT(0);
return FALSE;
}
return TRUE;
}
#define VerifyRequiredTagC(szTokenExpected,szLocalName,ccLocalName) VerifyRequiredTag(szTokenExpected,SVSUTIL_CONSTSTRLEN(szTokenExpected),szLocalName,ccLocalName)
BOOL CDavParse::PrepareNonEmptyBuf(void) {
if (m_Chars.uiNextIn == 0) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV request fails, an element that requires data did not set it\r\n"));
return FALSE;
}
if (! m_Chars.AppendWCHAR(L'\0')) {
return FALSE;
}
return TRUE;
}
// called when a token must match szTokenExpected.
BOOL CDavParse::VerifyRequiredTag(const CHAR *szTokenExpected, DWORD ccExpected, const CHAR *szLocalName, DWORD ccLocalName) {
if (! TokensEqualA(szTokenExpected,szLocalName,ccExpected,ccLocalName)) {
DebugOutUnexpectedToken(szTokenExpected,szLocalName,ccLocalName);
return FALSE;
}
return TRUE;
}
// Checks that content-length !=0, that the content-type is xml, and that we're not
// receiving more than m_dwPostReadSize bytes.
RESPONSESTATUS CWebDav::VerifyXMLBody(void) {
if (! IsContentTypeXML()) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDav request fails, client did not set content-type to XML\r\n"));
return STATUS_BADREQ;
}
if (! HasBody()) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDav request fails, client did not send body (required)\r\n"));
return STATUS_LENGTH_REQUIRED;
}
if (! HasServerReadAllData()) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDav request fails, client sent %d body bytes, content-length = %d\r\n",m_pRequest->m_bufRequest.Count(),m_pRequest->m_dwContentLength));
return STATUS_REQUEST_TOO_LARGE;
}
return STATUS_OK;
}
// *****************************************************************
// Implementations of classes that parse XML.
// *****************************************************************
//
// PROPFIND
//
const CHAR cszPropfind[] = "propfind";
const DWORD ccPropfind = SVSUTIL_CONSTSTRLEN(cszPropfind);
const CHAR cszPropName[] = "propname";
const DWORD ccPropName = SVSUTIL_CONSTSTRLEN(cszPropName);
const CHAR cszAllProp[] = "allprop";
const DWORD ccAllProp = SVSUTIL_CONSTSTRLEN(cszAllProp);
#define LOCAL_NAME_SIZE 256
inline BOOL ConvertXMLTagToANSI(const wchar_t * pwchLocalName, int cchLocalName, PSTR szLocalName) {
int nChars;
UINT uiCodePage = GetUTF8OrACP();
if (0 == (nChars = WideCharToMultiByte(uiCodePage, 0, pwchLocalName, cchLocalName, szLocalName, LOCAL_NAME_SIZE-1, 0, 0))) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: DAV request failed, WideCharToMultiByte(%s,len=%d) failed, GLE=0x%08x\r\n",pwchLocalName,cchLocalName));
return FALSE;
}
szLocalName[nChars] = 0;
return TRUE;
}
HRESULT STDMETHODCALLTYPE CPropFindParse::startElement(const wchar_t * pwchNamespaceUri, int cchNamespaceUri, const wchar_t * pwchLocalName,
int cchLocalName, const wchar_t * pwchQName, int cchQName, ISAXAttributes * pAttributes) {
m_Chars.Reset();
CHAR szLocalName[LOCAL_NAME_SIZE];
if (! ConvertXMLTagToANSI(pwchLocalName,cchLocalName,szLocalName))
return E_FAIL;
switch (m_State) {
case DAV_STATE_UNINITAILIZED:
if (! VerifyNS(NAMESPACE_DAV,pwchNamespaceUri,cchNamespaceUri) ||
! VerifyRequiredTagC(cszPropfind,szLocalName,cchLocalName))
return E_FAIL;
m_State = PROPFIND_STATE_PROPFIND;
break;
case PROPFIND_STATE_ALLPROP:
case PROPFIND_STATE_PROPNAME:
case DAV_STATE_UNKNOWN:
DebugOutUnknown();
return E_FAIL;
break;
case PROPFIND_STATE_PROPFIND:
if (! VerifyNS(NAMESPACE_DAV,pwchNamespaceUri,cchNamespaceUri))
return E_FAIL;
if (TokensEqualAC(szLocalName,AllProp,cchLocalName))
m_State = PROPFIND_STATE_ALLPROP;
else if (TokensEqualAC(szLocalName,PropName,cchLocalName))
m_State = PROPFIND_STATE_PROPNAME;
else if (TokensEqualAC(szLocalName,Prop,cchLocalName))
m_State = PROPFIND_STATE_PROP;
else {
DebugOutUnexpectedToken("prop, propname, or anyprop",szLocalName,cchLocalName);
return E_FAIL;
}
break;
case PROPFIND_STATE_PROP:
// if (! VerifyNS(NAMESPACE_DAV,pwchNamespaceUri,cchNamespaceUri))
// return E_FAIL;
if (TokensEqualAC(szLocalName,GetcontentLength,cchLocalName))
m_State = PROPFIND_STATE_CONTENT_LEN;
else if (TokensEqualAC(szLocalName,DisplayName,cchLocalName))
m_State = PROPFIND_STATE_DISPLAY_NAME;
else if (TokensEqualAC(szLocalName,CreationDate,cchLocalName))
m_State = PROPFIND_STATE_CREATION_DATE;
else if (TokensEqualAC(szLocalName,GetETag,cchLocalName))
m_State = PROPFIND_STATE_GET_ETAG;
else if (TokensEqualAC(szLocalName,LastModified,cchLocalName))
m_State = PROPFIND_STATE_LAST_MODIFIED;
else if (TokensEqualAC(szLocalName,ResourceType,cchLocalName))
m_State = PROPFIND_STATE_RESOURCE_TYPE;
else if (TokensEqualAC(szLocalName,IsHidden,cchLocalName))
m_State = PROPFIND_STATE_IS_HIDDEN;
else if (TokensEqualAC(szLocalName,IsCollection,cchLocalName))
m_State = PROPFIND_STATE_IS_COLLECTION;
else if (TokensEqualAC(szLocalName,SupportedLock,cchLocalName))
m_State = PROPFIND_STATE_SUPPORTED_LOCK;
else if (TokensEqualAC(szLocalName,LockDiscovery,cchLocalName))
m_State = PROPFIND_STATE_LOCK_DISCOVERY;
else if (TokensEqualAC(szLocalName,GetcontentType,cchLocalName))
m_State = PROPFIND_STATE_CONTENT_TYPE;
else {
DebugOutUnexpectedToken("recognized prop tags",szLocalName,cchLocalName);
if ((m_iUnknownDepth == 0) && ! m_pWebDav->AddUnknownXMLElement(pwchQName,cchQName))
return E_FAIL;
SetUnknownTag();
}
break;
default:
DebugOutUnexpectedToken("???",szLocalName,cchLocalName);
//SetUnknownTag();
return E_FAIL;
break;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CPropFindParse::endElement(const wchar_t *pwchNamespaceUri, int cchNamespaceUri, const wchar_t *pwchLocalName,
int cchLocalName, const wchar_t *pwchQName, int cchQName) {
BOOL fRet = TRUE;
switch (m_State) {
case PROPFIND_STATE_PROPFIND:
m_State = DAV_STATE_UNKNOWN;
break;
case PROPFIND_STATE_ALLPROP:
m_State = PROPFIND_STATE_PROPFIND;
fRet = m_pWebDav->SendProperties(DAV_PROP_ALL,FALSE);
break;
case PROPFIND_STATE_PROPNAME:
m_State = PROPFIND_STATE_PROPFIND;
fRet = m_pWebDav->SendProperties(DAV_PROP_ALL,TRUE);
break;
case PROPFIND_STATE_PROP:
m_State = PROPFIND_STATE_PROPFIND;
fRet = m_pWebDav->SendProperties(m_dwDavProperties,FALSE);
break;
case PROPFIND_STATE_CONTENT_LEN:
m_dwDavProperties |= DAV_PROP_CONTENT_LENGTH;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_DISPLAY_NAME:
m_dwDavProperties |= DAV_PROP_DISPLAY_NAME;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_CREATION_DATE:
m_dwDavProperties |= DAV_PROP_CREATION_DATE;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_GET_ETAG:
m_dwDavProperties |= DAV_PROP_GET_ETAG;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_LAST_MODIFIED:
m_dwDavProperties |= DAV_PROP_GET_LAST_MODIFIED;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_RESOURCE_TYPE:
m_dwDavProperties |= DAV_PROP_RESOURCE_TYPE;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_IS_HIDDEN:
m_dwDavProperties |= DAV_PROP_IS_HIDDEN;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_IS_COLLECTION:
m_dwDavProperties |= DAV_PROP_IS_COLLECTION;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_SUPPORTED_LOCK:
m_dwDavProperties |= DAV_PROP_SUPPORTED_LOCK;
m_State = PROPFIND_STATE_PROP;
break;
case PROPFIND_STATE_LOCK_DISCOVERY:
m_dwDavProperties |= DAV_PROP_LOCK_DISCOVERY;
m_State = PROPFIND_STATE_PROP;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -