📄 davlock.cpp
字号:
*szEndOfUrl = CLOSE_URI;
MyFreeNZ(wszPhysicalPath);
wszPhysicalPath = m_pRequest->m_pWebsite->m_pVroots->URLAtoPathW((CHAR*)urlBuf.pBuffer);
szTrav = szEndOfUrl+1; // skip past the URI and the '>'
}
// fFirstPass = FALSE;
svsutil_SkipWhiteSpace(szTrav);
if (*szTrav != OPEN_LIST) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV \"If:\" headers did not send a statement, got %c when expecting %c\r\n",*szTrav,OPEN_LIST));
SetStatus(STATUS_BADREQ);
goto done;
}
szTrav++; // skip '('
svsutil_SkipWhiteSpace(szTrav);
if (NULL == (szEndOfStatement = strchr(szTrav,CLOSE_LIST))) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV \"If:\" headers did not send closing end of statement ')' character\r\n"));
SetStatus(STATUS_BADREQ);
goto done;
}
*szEndOfStatement = 0;
while (szTrav < szEndOfStatement) {
// A list has one or more state-tokens and/or entity tags. Parse these now.
// There are two types of "failure" conditions we can hit during parsing:
// an out and out parse error (for instance not closing '>'), which should cause
// request to fail, send 400. However we can also have case where a lock doesn't match
// what we were requested, but this is allowed if it's preceeded by a "NOT" token.
BOOL fNot;
BOOL fSuccess = FALSE;
// NOT statement's scope is for the immediatly proceeding state-token/entity tag.
if (0 == _strnicmp(szTrav,cszNot,ccNot)) {
fNot = TRUE;
szTrav += ccNot;
svsutil_SkipWhiteSpace(szTrav);
}
else
fNot = FALSE;
if (*szTrav == OPEN_LOCK_TOKEN) {
PSTR szEndToken;
if (NULL == (szEndToken = strchr(szTrav,CLOSE_LOCK_TOKEN))) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV \"If:\" headers did not send closing end of statement '>' character\r\n"));
SetStatus(STATUS_BADREQ);
goto done;
}
*szEndToken = 0;
fSuccess = CheckTokenExpression(++szTrav,wszPhysicalPath);
*szEndToken = CLOSE_LOCK_TOKEN;
szTrav = szEndToken+1;
}
else if (*szTrav == OPEN_ETAG) {
PSTR szEndEtag;
if (NULL == (szEndEtag = strchr(szTrav,CLOSE_ETAG))) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV \"If:\" headers did not send closing end of statement ']' character\r\n"));
SetStatus(STATUS_BADREQ);
goto done;
}
*szEndEtag = 0;
fSuccess = CheckETagExpression(++szTrav,wszPhysicalPath);
*szEndEtag = CLOSE_ETAG;
szTrav = szEndEtag+1;
}
else {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDav \"If:\" headers did not set '<' or '[' inside statement, invalid statement\r\n"));
SetStatus(STATUS_BADREQ);
goto done;
}
// Either we successfully matched a token but we shouldn't have (NOT before rule)
// or we didn't match a token and there was not a "NOT" string.
if ((fSuccess && fNot) || (!fSuccess && !fNot)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: DAV parsing \"If:\" headers failed, condition not met\r\n"));
SetStatus(STATUS_PRECONDITION_FAILED);
goto done;
}
svsutil_SkipWhiteSpace(szTrav);
}
*szEndOfStatement = CLOSE_LIST;
szTrav = szEndOfStatement + 1;
szEndOfStatement = NULL;
svsutil_SkipWhiteSpace(szTrav);
}
DEBUGCHK((szTrav-szLockHeader) == (int)strlen(szLockHeader));
fRet = TRUE;
done:
DebugCheckCacheManagerNotLocked();
MyFreeNZ(szLockHeader);
MyFreeNZ(wszPhysicalPath);
if (szEndOfStatement)
*szEndOfStatement = CLOSE_LIST;
return fRet;
}
// Checks contetns of <...> statement in an "if:" lock header
// Note: Don't set error in here or in helper functions because if "Not"
// prepends the string then failure is expected.
BOOL CWebDav::CheckTokenExpression(PSTR szToken, WCHAR *szPath) {
svsutil_SkipWhiteSpace(szToken);
__int64 iLockId;
if (*szToken == '\"' || *szToken == '<')
szToken++;
if (0 == (iLockId = GetLockIDFromOpaqueHeader(szToken)))
return FALSE;
if (szPath && ! g_pFileLockManager->IsFileAssociatedWithLockId(szPath,iLockId))
return FALSE;
// store the lockId for possible later use during the request.
if (! m_lockIds.SRealloc(m_nLockTokens+1))
return FALSE;
m_lockIds[m_nLockTokens++] = iLockId;
return TRUE;
}
// Don't set error here because if "not" prepends string then failure is expected.
BOOL CWebDav::CheckETagExpression(PSTR szToken, WCHAR *szPath) {
svsutil_SkipWhiteSpace(szToken);
WIN32_FILE_ATTRIBUTE_DATA w32Data;
WIN32_FILE_ATTRIBUTE_DATA *pData;
CHAR szETag[MAX_PATH];
// If szPath is known use it, otherwise default to
if (szPath) {
if (! GetFileAttributesEx(szPath,GetFileExInfoStandard,&w32Data)) {
DEBUGMSG(ZONE_WEBDAV,(L"HTTPD: GetFileAttributesEx(%s) failed, GLE=0x%08x\r\n",szPath,GetLastError()));
return FALSE;
}
pData = &w32Data;
}
else {
if (! DavGetFileAttributesEx())
return FALSE;
pData = &m_fileAttribs;
}
GetETagFromFiletime(&pData->ftLastWriteTime,pData->dwFileAttributes,szETag);
szToken = SkipWeakTagIfNeeded(szToken);
return (0 == (strcmp(szToken,szETag)));
}
// looks at 'if-match' and 'if-not-match' fields to determine whether to continue processing.
BOOL CWebDav::CheckIfHeaders(void) {
PSTR szHeader;
CHAR szETag[256];
if (IsNull()) {
// If file doesn't exist, "If-match" headers are invalid.
if (m_pRequest->FindHttpHeader(cszIf_Match,ccIf_Match)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: resource %s is not existant, so \"if-match\" headers sent cause request to fail\r\n",m_pRequest->m_wszPath));
SetStatus(STATUS_PRECONDITION_FAILED);
return FALSE;
}
return TRUE;
}
if (! DavGetFileAttributesEx()) {
DEBUGCHK(0); // resource should be NULL in this case.
return FALSE;
}
GetETagFromFiletime(&m_fileAttribs.ftLastWriteTime,m_fileAttribs.dwFileAttributes,szETag);
if (szHeader = m_pRequest->FindHttpHeader(cszIf_Match,ccIf_Match)) {
if (! ETagEqualsHeader(szHeader,szETag)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV request fails because if-match header doesn't match, required etag=%s\r\n",szETag));
SetStatus(STATUS_PRECONDITION_FAILED);
return FALSE;
}
}
if (szHeader = m_pRequest->FindHttpHeader(cszIf_None_Match,ccIf_None_Match)) {
if (ETagEqualsHeader(szHeader,szETag)) {
DEBUGMSG(ZONE_ERROR,(L"HTTPD: WebDAV request fails because if-not-match header matches etag=%s\r\n",szETag));
SetStatus(STATUS_PRECONDITION_FAILED);
return FALSE;
}
}
return TRUE;
}
// prints out information about lock(s) associated with a file.
BOOL CWebDav::SendLockTags(CWebDavFileNode *pLockedNode, BOOL fPrintPropTag) {
DebugCheckCacheManagerLocked();
CHAR szBuf[256];
BOOL fRet = FALSE;
CWebDavLock *pLock = pLockedNode->m_pLockList;
PCSTR szScope = pLockedNode->IsSharedLock() ? cszShared : cszExclusive;
if (fPrintPropTag) {
if (! m_bufResp.StartTagNoEncode(cszPropNS,ccPropNS))
goto done;
}
while (pLock) {
WriteOpaqueLockToken(szBuf,pLock->m_i64LockId,FALSE);
if (! m_bufResp.StartTag(cszLockDiscovery) ||
! m_bufResp.StartTag(cszActiveLock) ||
! m_bufResp.StartTag(cszLockType) ||
! m_bufResp.SetEmptyElement(cszWrite) || // spec only supports <write> locks currently
! m_bufResp.EndTag(cszLockType) ||
! m_bufResp.StartTag(cszLockScope) ||
! m_bufResp.SetEmptyElement(szScope) ||
! m_bufResp.EndTag(cszLockScope) ||
! m_bufResp.StartTag(cszLockTokenTag) ||
! m_bufResp.StartTag(cszHref) ||
! m_bufResp.Encode(szBuf) ||
! m_bufResp.EndTag(cszHref) ||
! m_bufResp.EndTag(cszLockTokenTag))
{
goto done;
}
if (pLock->m_szOwner) {
if (! m_bufResp.BeginBrace() ||
! m_bufResp.Append(cszOwner,ccOwner)) {
goto done;
}
if (pLock->m_szOwnerNSTags) {
if (! m_bufResp.AppendCHAR(' ') ||
! m_bufResp.Append(pLock->m_szOwnerNSTags,pLock->m_ccOwnerNSTags)) {
goto done;
}
}
if (! m_bufResp.CloseBrace() ||
! m_bufResp.Append(pLock->m_szOwner,pLock->m_ccOwner) ||
! m_bufResp.EndTag(cszOwner))
{
goto done;
}
}
sprintf(szBuf,"%s%d",cszSecond,pLock->m_dwBaseTimeout);
if ( !m_bufResp.StartTag(cszDepthTag) ||
!m_bufResp.Append(csz0,cc0) ||
!m_bufResp.EndTag(cszDepthTag) ||
!m_bufResp.StartTag(cszTimeoutTag) ||
!m_bufResp.Encode(szBuf) ||
!m_bufResp.EndTag(cszTimeoutTag))
{
goto done;
}
if (! m_bufResp.EndTag(cszActiveLock) ||
! m_bufResp.EndTag(cszLockDiscovery))
{
goto done;
}
pLock = pLock->m_pNext;
}
if (fPrintPropTag) {
if (! m_bufResp.EndTag(cszProp))
goto done;
}
fRet = TRUE;
done:
return fRet;
}
// Certain VERBs want STATUS_CONFLICT on a not found, or can also handle LOCKed.
void CWebDav::SendLockedConflictOrErr(WCHAR *szPath, WCHAR *szAlternatPath) {
if (SendLockErrorInfoIfNeeded(szPath))
return;
if (szAlternatPath && IsFileLocked(szAlternatPath)) {
SetMultiStatusErrorFromURL(STATUS_LOCKED,m_pRequest->m_pszURL);
return;
}
DWORD dwErr = GetLastError();
if (dwErr == ERROR_PATH_NOT_FOUND)
SetStatus(STATUS_CONFLICT);
else
SetStatus(GLEtoStatus(dwErr));
}
BOOL CWebDav::IsFileLocked(const WCHAR *szPath) {
BOOL fRet = FALSE;
if (IsGLELocked()) {
g_pFileLockManager->Lock();
if (g_pFileLockManager->GetNodeFromFileName((WCHAR*)szPath))
fRet = TRUE;
g_pFileLockManager->Unlock();
}
return fRet;
}
// If a file is locked and we have lock info about it, then send this to the client.
// If we're not locked, return FALSE so that the calling function can set its own error.
BOOL CWebDav::SendLockErrorInfoIfNeeded(WCHAR *szPath) {
BOOL fRet = FALSE;
if (IsGLELocked()) {
g_pFileLockManager->Lock();
CWebDavFileNode *pFileNode = g_pFileLockManager->GetNodeFromFileName(szPath);
if (pFileNode) {
SetStatusAndXMLBody(STATUS_LOCKED);
SendLockTags(pFileNode);
fRet = TRUE;
}
g_pFileLockManager->Unlock();
}
return fRet;
}
// *********************************************************
// Implementation of Lock cache manager
// *********************************************************
static const char cszXMLNS[] = "xmlns:";
static const DWORD ccXMLNS = SVSUTIL_CONSTSTRLEN(cszXMLNS);
//
// CWebDavLock
//
BOOL CWebDavLock::InitLock(PSTR szOwner, CNameSpaceMap *pNSMap, __int64 iLockId, DWORD dwBaseTimeout) {
// m_szOwner is allowed to be NULL, not a required field.
m_pNext = NULL;
m_szOwner = m_szOwnerNSTags = NULL;
if (szOwner && (NULL == (m_szOwner = MySzDupA(szOwner))))
return FALSE;
if (m_szOwner)
m_ccOwner = strlen(m_szOwner);
else
m_ccOwner = 0;
// Setup NameSpace prefix->URI tags that are put in <owner> XML tag.
if (m_szOwner && pNSMap) {
CNameSpaceMap *pTrav = pNSMap;
int iLenRequired = 0;
int iOffset = 0;
while (pTrav) {
iLenRequired += MyW2UTF8(pTrav->m_szPrefix,0,0) + MyW2UTF8(pTrav->m_szURI,0,0) + ccXMLNS + 15;
pTrav = pTrav->m_pNext;
}
if (NULL == (m_szOwnerNSTags = MySzAllocA(iLenRequired)))
return FALSE;
pTrav = pNSMap;
while (pTrav) {
// If there are multiple URI's with the same Namespace, use the last one
// put into the list for the URI.
CNameSpaceMap *pNode = pTrav;
while (pNode->m_pChild)
pNode = pNode->m_pChild;
// The code below is effectively doing this sprintf. Don't use sprintf
// because we want UTF8 conversion if it's available, sprintf does CP_ACP on %S.
// iOffset += sprintf(m_szOwnerNSTags+iOffset," %s%S=\"%S\"",cszXMLNS,pTrav->m_szPrefix,pNode->m_szURI);
// don't spit out ' ' on 1st pass.
if (iOffset != 0)
m_szOwnerNSTags[iOffset++] = ' ';
strcpy(m_szOwnerNSTags+iOffset,cszXMLNS);
iOffset += ccXMLNS;
iOffset += MyW2UTF8(pTrav->m_szPrefix,m_szOwnerNSTags+iOffset,iLenRequired-iOffset) - 1;
m_szOwnerNSTags[iOffset++] = '=';
m_szOwnerNSTags[iOffset++] = '\"';
iOffset += MyW2UTF8(pNode->m_szURI,m_szOwnerNSTags+iOffset,iLenRequired-iOffset) - 1;
m_szOwnerNSTags[iOffset++] = '\"';
pTrav = pTrav->m_pNext;
}
m_szOwnerNSTags[iOffset++] = 0;
m_ccOwnerNSTags = strlen(m_szOwnerNSTags);
DEBUGCHK(m_ccOwnerNSTags < (DWORD)iLenRequired);
}
else {
m_ccOwnerNSTags = 0;
}
m_i64LockId = iLockId;
SetTimeout(dwBaseTimeout);
return TRUE;
}
void CWebDavLock::SetTimeout(DWORD dwSecondsToLive) {
DEBUGCHK(dwSecondsToLive != 0);
__int64 ft;
GetCurrentFT((FILETIME*)&ft);
m_ftExpires = ft + (dwSecondsToLive*1000*FILETIME_TO_MILLISECONDS);
m_dwBaseTimeout = dwSecondsToLive;
}
void CWebDavLock::DeInitLock(void) {
MyFreeNZ(m_szOwner);
MyFreeNZ(m_szOwnerNSTags);
}
//
// CWebDavFileNode
//
BOOL CWebDavFileNode::InitFileNode(WCHAR *szFile, DAV_LOCK_SHARE_MODE lockShareMode, HANDLE hFile) {
DebugCheckCacheManagerLocked();
DEBUGCHK(IsValidLockState(lockShareMode));
DEBUGCHK(hFile != INVALID_HANDLE_VALUE);
if (NULL == (m_szFileName = MySzDupW(szFile)))
return FALSE;
m_lockShareMode = lockShareMode;
m_hFile = hFile;
m_pNext = NULL;
m_pLockList = NULL;
m_fBusy = FALSE;
return TRUE;
}
void CWebDavFileNode::DeInitFileNode(void) {
DebugCheckCacheManagerLocked();
CWebDavLock *pNext;
while (m_pLockList) {
pNext = m_pLockList->m_pNext;
DeInitAndFreeLock(m_pLockList);
m_pLockList = pNext;
}
MyFreeNZ(m_szFileName);
MyCloseHandle(m_hFile);
}
BOOL CWebDavFileNode::AddLock(PSTR szOwner, CNameSpaceMap *pNSMap, __int64 iLockId, DWORD dwBaseTimeout) {
CWebDavLock *pLock = g_pFileLockManager->AllocFixedLock();
if (!pLock)
return FALSE;
if (! pLock->InitLock(szOwner,pNSMap,iLockId,dwBaseTimeout)) {
g_pFileLockManager->FreeFixedLock(pLock);
return FALSE;
}
pLock->m_pNext = m_pLockList;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -