Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

349 lines
7.3 KiB

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// L O C K M E T A . C P P
//
// HTTP 1.1/DAV 1.0 request handling via ISAPI
//
//
// Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
//
#include <_davprs.h>
#include <tchar.h> //_strspnp
#include <gencache.h>
#include <sz.h>
#include <xemit.h>
#include <xlock.h>
#include <statetok.h>
#include <nonimpl.h>
// LockDiscovery -------------------------------------------------------------
//
SCODE
ScAddInLockToken (CEmitterNode& en, LPCWSTR pwszLockToken)
{
// Outer nodes must be declared first
//
CEmitterNode enLToken;
CEmitterNode enToken;
SCODE sc = S_OK;
WCHAR rgwsz[MAX_LOCKTOKEN_LENGTH];
LPCWSTR pwsz;
// Make sure they give us a locktoken string.
//
Assert(pwszLockToken);
// AND remove the quote marks (currently <>)
//
if (L'<' == pwszLockToken[0])
pwszLockToken++;
pwsz = wcschr(pwszLockToken, L'>');
if (pwsz)
{
UINT cch = static_cast<UINT>(pwsz - pwszLockToken);
if (MAX_LOCKTOKEN_LENGTH - 1 < cch)
{
sc = E_FAIL;
goto ret;
}
Assert(MAX_LOCKTOKEN_LENGTH > cch);
memcpy(rgwsz, pwszLockToken, cch * sizeof(WCHAR));
rgwsz[cch] = L'\0';
pwszLockToken = rgwsz;
}
// Create and add a locktoken node under activelock.
// (locktoken node contains a single href node.)
//
sc = en.ScAddNode (gc_wszLockToken, enLToken);
if (FAILED (sc))
goto ret;
sc = enLToken.ScAddNode (gc_wszXML__Href, enToken, pwszLockToken);
if (FAILED (sc))
goto ret;
ret:
return sc;
}
// ========================================================================
//
// ScBuildLockDiscovery
//
// Takes an emitter and an already-constructed lockdiscovery node,
// and adds an activelock node under it.
// May be called multiple times -- each call will add a new activelock
// node under the lockdiscovery node in en.
//
SCODE
ScBuildLockDiscovery (CXMLEmitter& emitter,
CEmitterNode& en,
LPCWSTR pwszLockToken,
LPCWSTR pwszLockType,
LPCWSTR pwszLockScope,
BOOL fRollback,
BOOL fDepthInfinity,
DWORD dwTimeout,
LPCWSTR pwszOwnerComment,
LPCWSTR pwszSubType)
{
CEmitterNode enActive;
SCODE sc = S_OK;
WCHAR wsz[50];
// Zero is an invalid timeout.
//
Assert(dwTimeout);
// Add in the 'DAV:activelock' node
//
sc = en.ScAddNode (gc_wszLockActive, enActive);
if (FAILED (sc))
goto ret;
// Create a node for the locktype.
//
{
CEmitterNode enLType;
sc = enActive.ScAddNode (gc_wszLockType, enLType);
if (FAILED (sc))
goto ret;
{
CEmitterNode enType;
sc = enLType.ScAddNode (pwszLockType, enType);
if (FAILED (sc))
goto ret;
if (pwszSubType)
{
CEmitterNode enSubLType;
sc = enType.ScAddNode (pwszSubType, enSubLType);
if (FAILED (sc))
goto ret;
}
}
}
// Create a node for the lockscope
//
{
CEmitterNode enLScope;
sc = enActive.ScAddNode (gc_wszLockScope, enLScope);
if (FAILED (sc))
goto ret;
{
CEmitterNode enScope;
sc = enLScope.ScAddNode (pwszLockScope, enScope);
if (FAILED (sc))
goto ret;
}
}
// Create a node for the owner. The comment is well contructed XML already
//
if (pwszOwnerComment)
{
sc = enActive.Pxn()->ScSetFormatedXML (pwszOwnerComment, static_cast<UINT>(wcslen(pwszOwnerComment)));
if (FAILED (sc))
goto ret;
}
// If this is a rollback lock...
//
if (fRollback)
{
CEmitterNode enRollback;
sc = enActive.ScAddNode (gc_wszLockRollback, enRollback);
if (FAILED (sc))
goto ret;
}
// Add in the lock token
//
sc = ScAddInLockToken (enActive, pwszLockToken);
if (FAILED (sc))
goto ret;
// Add an appropriate depth node.
//
{
CEmitterNode enDepth;
if (fDepthInfinity)
{
sc = enActive.ScAddNode (gc_wszLockDepth, enDepth, gc_wszInfinity);
if (FAILED (sc))
goto ret;
}
else
{
sc = enActive.ScAddNode (gc_wszLockDepth, enDepth, gc_wsz0);
if (FAILED (sc))
goto ret;
}
}
// Finally, create and add a timeout node
//
{
CEmitterNode enTimeout;
wsprintfW (wsz, L"Second-%d", dwTimeout);
sc = enActive.ScAddNode (gc_wszLockTimeout, enTimeout, wsz);
if (FAILED (sc))
goto ret;
}
ret:
return sc;
}
// ========================================================================
//
// Lock utility functions
//
//$REVIEW: This should really be common impl code. Move to _davcom later.
//
// ------------------------------------------------------------------------
//
// FGetLockTimeout
//
// Fetches and parses an incoming Time-Out header on the request.
// Returns FALSE if an invalid option was encountered.
// Returns TRUE with *pdwSeconds=gc_cSecondsDefaultLock
// if NO Time-Out header was present.
//
BOOL
FGetLockTimeout (LPMETHUTIL pmu, DWORD * pdwSeconds, DWORD dwMaxOverride)
{
LPCWSTR pwsz;
DWORD dwMax = gc_cSecondsMaxLock;
Assert (pmu);
Assert (pdwSeconds);
*pdwSeconds = gc_cSecondsDefaultLock;
// If there is NO Time-Out header, leave our timeout set to the default,
// which was set at construction time.
// NOTE: It IS valid to have NO Time-Out header. Just use the defaults.
//
pwsz = pmu->LpwszGetRequestHeader (gc_szTimeout, FALSE);
if (!pwsz)
{
LockTrace ("Dav: No Timeout header found.\n");
goto ret;
}
// Skip any initial whitespace.
//
pwsz = _wcsspnp(pwsz, gc_wszLWS);
if (!pwsz)
{
LockTrace ("Dav: No params found in LOCK Time-Out header.\n");
return FALSE;
}
Assert(pwsz);
// Check for a new-style timeout header.
//
// Load a header iterator -- there could be multiple values here.
//
{
HDRITER_W hdr(pwsz);
pwsz = hdr.PszNext();
if (!pwsz)
{
// No data found. That's an error.
//
return FALSE;
}
if (dwMaxOverride)
dwMax = dwMaxOverride;
while (pwsz)
{
// Loop until we find an acceptable time.
// (Ignore any header values we don't understand.)
// If no acceptable time is found, it's okay.
// dwSeconds stays zero, and return TRUE.
//
if (!_wcsnicmp (gc_wszSecondDash, pwsz, gc_cchSecondDash))
{
DWORD dwSeconds;
pwsz += gc_cchSecondDash;
if (!*pwsz)
return FALSE;
dwSeconds = _wtol(pwsz);
if (dwSeconds > dwMax)
{
// Remember that they asked for something huge.
//
*pdwSeconds = dwMax;
}
else
{
// We found a request that we'll grant.
// Set it and stop looping.
//
*pdwSeconds = dwSeconds;
break;
}
}
else if (!_wcsnicmp (gc_wszInfinite, pwsz, gc_cchInfinite))
{
// We don't yet handle infinite timeouts.
// Remember that they asked for something huge.
// Skip to the next token.
//
*pdwSeconds = dwMax;
}
// else skip to next token
// (ignore unrecognized tokens).
//
pwsz = hdr.PszNext();
} // elihw
}
ret:
//$HACK:ROSEBUD_OFFICE9_TIMEOUT_HACK
// For the bug where rosebud waits until the last second
// before issueing the refresh. Need to filter out this check with
// the user agent string. The hack is to increase the timeout
// by 30 seconds and return the actual timeout.
//
if (pmu->FIsOffice9Request())
{
*pdwSeconds += gc_dwSecondsHackTimeoutForRosebud;
}
//$HACK:END:ROSEBUD_OFFICE9_TIMEOUT_HACK
return TRUE;
}