mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
ALF-12866: WebDAV in-memory locking - threading issues.
* LockInfo instances provide a ReentrantReadWriteLock for clients to use * LockInfo client code synchronises uses provided RRWLs. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@34212 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -22,9 +22,13 @@ import java.io.Serializable;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to represent a WebDAV lock info
|
* Class to represent a WebDAV lock info. Instances of this class are accessible
|
||||||
|
* my multiple threads as they are kept in the {@link LockStore}. Clients of this
|
||||||
|
* class are expected to synchronise externally using the provided
|
||||||
|
* ReentrantReadWriteLock (use {@link #getRWLock()}).
|
||||||
*
|
*
|
||||||
* @author Ivan Rybnikov
|
* @author Ivan Rybnikov
|
||||||
*
|
*
|
||||||
@@ -33,6 +37,8 @@ public final class LockInfo implements Serializable
|
|||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
// Exclusive lock token
|
// Exclusive lock token
|
||||||
private String exclusiveLockToken = null;
|
private String exclusiveLockToken = null;
|
||||||
|
|
||||||
@@ -73,6 +79,20 @@ public final class LockInfo implements Serializable
|
|||||||
this.depth = depth;
|
this.depth = depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the {@link ReentrantReadWriteLock} associated with this LockInfo. This is
|
||||||
|
* to allow client code to protect against invalid concurrent access to the state of
|
||||||
|
* this class.
|
||||||
|
* <p>
|
||||||
|
* Not to be confused with WebDAV locks.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ReentrantReadWriteLock getRWLock()
|
||||||
|
{
|
||||||
|
return rwLock;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if node has shared or exclusive locks
|
* Returns true if node has shared or exclusive locks
|
||||||
*
|
*
|
||||||
@@ -294,15 +314,23 @@ public final class LockInfo implements Serializable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the expiry date/time to lockTimeout seconds into the future.
|
* Sets the expiry date/time to lockTimeout seconds into the future. Provide
|
||||||
|
* a lockTimeout of WebDAV.TIMEOUT_INFINITY for never expires.
|
||||||
*
|
*
|
||||||
* @param lockTimeout
|
* @param lockTimeout
|
||||||
*/
|
*/
|
||||||
public void setTimeoutSeconds(int lockTimeout)
|
public void setTimeoutSeconds(int lockTimeout)
|
||||||
{
|
{
|
||||||
int timeoutMillis = (lockTimeout * 60 * 1000);
|
if (lockTimeout == WebDAV.TIMEOUT_INFINITY)
|
||||||
Date now = new Date();
|
{
|
||||||
Date nextExpiry = new Date(now.getTime() + timeoutMillis);
|
setExpires(null);
|
||||||
setExpires(nextExpiry);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int timeoutMillis = (lockTimeout * 60 * 1000);
|
||||||
|
Date now = new Date();
|
||||||
|
Date nextExpiry = new Date(now.getTime() + timeoutMillis);
|
||||||
|
setExpires(nextExpiry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -336,25 +336,39 @@ public class LockMethod extends WebDAVMethod
|
|||||||
m_response.setStatus(HttpServletResponse.SC_CREATED);
|
m_response.setStatus(HttpServletResponse.SC_CREATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Check if this is a new lock or a lock refresh
|
// Check if this is a new lock or a lock refresh
|
||||||
if (hasLockToken())
|
if (hasLockToken())
|
||||||
{
|
{
|
||||||
this.lockInfo = checkNode(lockNodeInfo);
|
lockInfo = checkNode(lockNodeInfo);
|
||||||
// If a request body is not defined and "If" header is sent we have createExclusive as false,
|
lockInfo.getRWLock().writeLock().lock();
|
||||||
// but we need to check a previous LOCK was an exclusive. I.e. get the property for node. It
|
try
|
||||||
// is already has got in a checkNode method, so we need just get a scope from lockInfo.
|
{
|
||||||
// This particular case was raised as ALF-4008.
|
// If a request body is not defined and "If" header is sent we have createExclusive as false,
|
||||||
this.createExclusive = WebDAV.XML_EXCLUSIVE.equals(this.lockInfo.getScope());
|
// but we need to check a previous LOCK was an exclusive. I.e. get the property for node. It
|
||||||
// Refresh an existing lock
|
// is already has got in a checkNode method, so we need just get a scope from lockInfo.
|
||||||
refreshLock(lockNodeInfo, userName);
|
// This particular case was raised as ALF-4008.
|
||||||
|
this.createExclusive = WebDAV.XML_EXCLUSIVE.equals(this.lockInfo.getScope());
|
||||||
|
// Refresh an existing lock
|
||||||
|
refreshLock(lockNodeInfo, userName);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
lockInfo.getRWLock().writeLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.lockInfo = checkNode(lockNodeInfo, true, this.createExclusive);
|
lockInfo = checkNode(lockNodeInfo, true, createExclusive);
|
||||||
// Create a new lock
|
lockInfo.getRWLock().writeLock().lock();
|
||||||
createLock(lockNodeInfo, userName);
|
try
|
||||||
|
{
|
||||||
|
// Create a new lock
|
||||||
|
createLock(lockNodeInfo, userName);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
lockInfo.getRWLock().writeLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -391,30 +405,38 @@ public class LockMethod extends WebDAVMethod
|
|||||||
// Create Lock token
|
// Create Lock token
|
||||||
lockToken = WebDAV.makeLockToken(lockNode.getNodeRef(), userName);
|
lockToken = WebDAV.makeLockToken(lockNode.getNodeRef(), userName);
|
||||||
|
|
||||||
if (createExclusive)
|
lockInfo.getRWLock().writeLock().lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// Lock the node
|
if (createExclusive)
|
||||||
lockInfo.setTimeoutSeconds(getLockTimeout());
|
{
|
||||||
lockInfo.setExclusiveLockToken(lockToken);
|
// Lock the node
|
||||||
}
|
lockInfo.setTimeoutSeconds(getLockTimeout());
|
||||||
else
|
lockInfo.setExclusiveLockToken(lockToken);
|
||||||
{
|
}
|
||||||
lockInfo.addSharedLockToken(lockToken);
|
else
|
||||||
}
|
{
|
||||||
|
lockInfo.addSharedLockToken(lockToken);
|
||||||
|
}
|
||||||
|
|
||||||
// Store lock depth
|
// Store lock depth
|
||||||
lockInfo.setDepth(WebDAV.getDepthName(m_depth));
|
lockInfo.setDepth(WebDAV.getDepthName(m_depth));
|
||||||
// Store lock scope (shared/exclusive)
|
// Store lock scope (shared/exclusive)
|
||||||
String scope = createExclusive ? WebDAV.XML_EXCLUSIVE : WebDAV.XML_SHARED;
|
String scope = createExclusive ? WebDAV.XML_EXCLUSIVE : WebDAV.XML_SHARED;
|
||||||
lockInfo.setScope(scope);
|
lockInfo.setScope(scope);
|
||||||
// Store the owner of this lock
|
// Store the owner of this lock
|
||||||
lockInfo.setOwner(userName);
|
lockInfo.setOwner(userName);
|
||||||
// Lock the node
|
// Lock the node
|
||||||
getLockStore().put(lockNode.getNodeRef(), lockInfo);
|
getLockStore().put(lockNode.getNodeRef(), lockInfo);
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Locked node " + lockNode + ": " + lockInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
{
|
{
|
||||||
logger.debug("Locked node " + lockNode + ": " + lockInfo);
|
lockInfo.getRWLock().writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,11 +451,16 @@ public class LockMethod extends WebDAVMethod
|
|||||||
{
|
{
|
||||||
if (this.createExclusive)
|
if (this.createExclusive)
|
||||||
{
|
{
|
||||||
// Update the expiry for the lock
|
lockInfo.getRWLock().writeLock().lock();
|
||||||
if (lockInfo.getExpires() != null)
|
try
|
||||||
{
|
{
|
||||||
|
// Update the expiry for the lock
|
||||||
lockInfo.setTimeoutSeconds(getLockTimeout());
|
lockInfo.setTimeoutSeconds(getLockTimeout());
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
lockInfo.getRWLock().writeLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,21 +471,33 @@ public class LockMethod extends WebDAVMethod
|
|||||||
{
|
{
|
||||||
String scope;
|
String scope;
|
||||||
String lt;
|
String lt;
|
||||||
if (lockToken != null)
|
String owner;
|
||||||
|
Date expiry;
|
||||||
|
|
||||||
|
lockInfo.getRWLock().readLock().lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// In case of lock creation take the scope from request header
|
if (lockToken != null)
|
||||||
scope = this.createExclusive ? WebDAV.XML_EXCLUSIVE : WebDAV.XML_SHARED;
|
{
|
||||||
// Output created lock
|
// In case of lock creation take the scope from request header
|
||||||
lt = lockToken;
|
scope = this.createExclusive ? WebDAV.XML_EXCLUSIVE : WebDAV.XML_SHARED;
|
||||||
|
// Output created lock
|
||||||
|
lt = lockToken;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// In case of lock refreshing take the scope from previously stored lock
|
||||||
|
scope = this.lockInfo.getScope();
|
||||||
|
// Output refreshed lock
|
||||||
|
lt = this.lockInfo.getExclusiveLockToken();
|
||||||
|
}
|
||||||
|
owner = lockInfo.getOwner();
|
||||||
|
expiry = lockInfo.getExpires();
|
||||||
}
|
}
|
||||||
else
|
finally
|
||||||
{
|
{
|
||||||
// In case of lock refreshing take the scope from previously stored lock
|
lockInfo.getRWLock().readLock().unlock();
|
||||||
scope = this.lockInfo.getScope();
|
|
||||||
// Output refreshed lock
|
|
||||||
lt = this.lockInfo.getExclusiveLockToken();
|
|
||||||
}
|
}
|
||||||
String owner = lockInfo.getOwner();
|
|
||||||
|
|
||||||
XMLWriter xml = createXMLWriter();
|
XMLWriter xml = createXMLWriter();
|
||||||
|
|
||||||
@@ -468,7 +507,6 @@ public class LockMethod extends WebDAVMethod
|
|||||||
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROP + nsdec, WebDAV.XML_NS_PROP + nsdec, getDAVHelper().getNullAttributes());
|
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROP + nsdec, WebDAV.XML_NS_PROP + nsdec, getDAVHelper().getNullAttributes());
|
||||||
|
|
||||||
// Output the lock details
|
// Output the lock details
|
||||||
Date expiry = lockInfo.getExpires();
|
|
||||||
generateLockDiscoveryXML(xml, lockNodeInfo, false, scope, WebDAV.getDepthName(m_depth), lt, owner, expiry);
|
generateLockDiscoveryXML(xml, lockNodeInfo, false, scope, WebDAV.getDepthName(m_depth), lt, owner, expiry);
|
||||||
|
|
||||||
// Close off the XML
|
// Close off the XML
|
||||||
|
@@ -54,5 +54,11 @@ public interface LockStore
|
|||||||
LockInfo get(NodeRef nodeRef);
|
LockInfo get(NodeRef nodeRef);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove LockInfo for the specified NodeRef. The LockInfo cannot be considered locked
|
||||||
|
* once removed from the LockStore.
|
||||||
|
*
|
||||||
|
* @param nodeRef
|
||||||
|
*/
|
||||||
void remove(NodeRef nodeRef);
|
void remove(NodeRef nodeRef);
|
||||||
}
|
}
|
||||||
|
@@ -924,9 +924,17 @@ public class PropFindMethod extends WebDAVMethod
|
|||||||
// Output the lock status response
|
// Output the lock status response
|
||||||
|
|
||||||
LockInfo lockInfo = getNodeLockInfo(nodeInfo);
|
LockInfo lockInfo = getNodeLockInfo(nodeInfo);
|
||||||
if (lockInfo.isLocked())
|
lockInfo.getRWLock().readLock().lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
generateLockDiscoveryXML(xml, nodeInfo, lockInfo);
|
if (lockInfo.isLocked())
|
||||||
|
{
|
||||||
|
generateLockDiscoveryXML(xml, nodeInfo, lockInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
lockInfo.getRWLock().readLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -190,18 +190,29 @@ public class PutMethod extends WebDAVMethod
|
|||||||
String userName = getDAVHelper().getAuthenticationService().getCurrentUserName();
|
String userName = getDAVHelper().getAuthenticationService().getCurrentUserName();
|
||||||
LockInfo lockInfo = getLockStore().get(contentNodeInfo.getNodeRef());
|
LockInfo lockInfo = getLockStore().get(contentNodeInfo.getNodeRef());
|
||||||
|
|
||||||
if (lockInfo != null && lockInfo.isLocked() && !lockInfo.getOwner().equals(userName))
|
if (lockInfo != null)
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
lockInfo.getRWLock().readLock().lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
String path = getPath();
|
if (lockInfo.isLocked() && !lockInfo.getOwner().equals(userName))
|
||||||
String owner = lockInfo.getOwner();
|
{
|
||||||
logger.debug("Node locked: path=["+path+"], owner=["+owner+"], current user=["+userName+"]");
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
String path = getPath();
|
||||||
|
String owner = lockInfo.getOwner();
|
||||||
|
logger.debug("Node locked: path=["+path+"], owner=["+owner+"], current user=["+userName+"]");
|
||||||
|
}
|
||||||
|
// Indicate that the resource is locked
|
||||||
|
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
lockInfo.getRWLock().readLock().unlock();
|
||||||
}
|
}
|
||||||
// Indicate that the resource is locked
|
|
||||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Access the content
|
// Access the content
|
||||||
|
@@ -132,74 +132,92 @@ public class UnlockMethod extends WebDAVMethod
|
|||||||
NodeRef nodeRef = lockNodeInfo.getNodeRef();
|
NodeRef nodeRef = lockNodeInfo.getNodeRef();
|
||||||
LockInfo lockInfo = getLockStore().get(nodeRef);
|
LockInfo lockInfo = getLockStore().get(nodeRef);
|
||||||
|
|
||||||
if (lockInfo == null || !lockInfo.isLocked())
|
if (lockInfo == null)
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Unlock token=" + getLockToken() + " Not locked");
|
logger.debug("Unlock token=" + getLockToken() + " Not locked - no info in lock store.");
|
||||||
}
|
}
|
||||||
// Node is not locked
|
// Node is not locked
|
||||||
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
||||||
}
|
}
|
||||||
else if (lockInfo.isExpired())
|
|
||||||
|
lockInfo.getRWLock().writeLock().lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (!lockInfo.isLocked())
|
||||||
{
|
|
||||||
logger.debug("Unlock token=" + getLockToken() + " Lock expired");
|
|
||||||
}
|
|
||||||
// Return a success status
|
|
||||||
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
|
||||||
removeNoContentAspect(nodeRef);
|
|
||||||
}
|
|
||||||
else if (lockInfo.isExclusive())
|
|
||||||
{
|
|
||||||
String currentUser = getAuthenticationService().getCurrentUserName();
|
|
||||||
if (currentUser.equals(lockInfo.getOwner()))
|
|
||||||
{
|
|
||||||
getLockStore().remove(nodeRef);
|
|
||||||
|
|
||||||
// Indicate that the unlock was successful
|
|
||||||
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
|
||||||
removeNoContentAspect(nodeRef);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Unlock token=" + getLockToken() + " Successful");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Unlock token=" + getLockToken() + " Not lock owner");
|
logger.debug("Unlock token=" + getLockToken() + " Not locked");
|
||||||
}
|
}
|
||||||
// Node is not locked
|
// Node is not locked
|
||||||
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
else if (lockInfo.isExpired())
|
||||||
else if (lockInfo.isShared())
|
|
||||||
{
|
|
||||||
Set<String> sharedLocks = lockInfo.getSharedLockTokens();
|
|
||||||
if (sharedLocks.contains(m_strLockToken))
|
|
||||||
{
|
{
|
||||||
sharedLocks.remove(m_strLockToken);
|
|
||||||
|
|
||||||
// Indicate that the unlock was successful
|
|
||||||
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
|
||||||
removeNoContentAspect(nodeRef);
|
|
||||||
|
|
||||||
// DEBUG
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Unlock token=" + getLockToken() + " Successful");
|
logger.debug("Unlock token=" + getLockToken() + " Lock expired");
|
||||||
|
}
|
||||||
|
// Return a success status
|
||||||
|
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||||
|
removeNoContentAspect(nodeRef);
|
||||||
|
}
|
||||||
|
else if (lockInfo.isExclusive())
|
||||||
|
{
|
||||||
|
String currentUser = getAuthenticationService().getCurrentUserName();
|
||||||
|
if (currentUser.equals(lockInfo.getOwner()))
|
||||||
|
{
|
||||||
|
getLockStore().remove(nodeRef);
|
||||||
|
|
||||||
|
// Indicate that the unlock was successful
|
||||||
|
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||||
|
removeNoContentAspect(nodeRef);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Unlock token=" + getLockToken() + " Successful");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Unlock token=" + getLockToken() + " Not lock owner");
|
||||||
|
}
|
||||||
|
// Node is not locked
|
||||||
|
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (lockInfo.isShared())
|
||||||
|
{
|
||||||
|
Set<String> sharedLocks = lockInfo.getSharedLockTokens();
|
||||||
|
if (sharedLocks.contains(m_strLockToken))
|
||||||
|
{
|
||||||
|
sharedLocks.remove(m_strLockToken);
|
||||||
|
|
||||||
|
// Indicate that the unlock was successful
|
||||||
|
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||||
|
removeNoContentAspect(nodeRef);
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Unlock token=" + getLockToken() + " Successful");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Invalid LockInfo state: " + lockInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
finally
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("Invalid LockInfo state: " + lockInfo);
|
lockInfo.getRWLock().writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method removes a new zero byte node that has been locked, where the
|
// This method removes a new zero byte node that has been locked, where the
|
||||||
// PUT has not taken place but the client has issued an UNLOCK. The Timer
|
// PUT has not taken place but the client has issued an UNLOCK. The Timer
|
||||||
|
@@ -751,9 +751,23 @@ public abstract class WebDAVMethod
|
|||||||
*/
|
*/
|
||||||
protected void generateLockDiscoveryXML(XMLWriter xml, FileInfo lockNodeInfo, LockInfo lockInfo) throws Exception
|
protected void generateLockDiscoveryXML(XMLWriter xml, FileInfo lockNodeInfo, LockInfo lockInfo) throws Exception
|
||||||
{
|
{
|
||||||
String owner = lockInfo.getOwner();
|
String owner, scope, depth;
|
||||||
Date expiry = lockInfo.getExpires();
|
Date expiry;
|
||||||
generateLockDiscoveryXML(xml, lockNodeInfo, false, lockInfo.getScope(), lockInfo.getDepth(),
|
|
||||||
|
lockInfo.getRWLock().readLock().lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
owner = lockInfo.getOwner();
|
||||||
|
expiry = lockInfo.getExpires();
|
||||||
|
scope = lockInfo.getScope();
|
||||||
|
depth = lockInfo.getDepth();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
lockInfo.getRWLock().readLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
generateLockDiscoveryXML(xml, lockNodeInfo, false, scope, depth,
|
||||||
WebDAV.makeLockToken(lockNodeInfo.getNodeRef(), owner), owner, expiry);
|
WebDAV.makeLockToken(lockNodeInfo.getNodeRef(), owner), owner, expiry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -873,60 +887,69 @@ public abstract class WebDAVMethod
|
|||||||
protected LockInfo checkNode(FileInfo fileInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException
|
protected LockInfo checkNode(FileInfo fileInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException
|
||||||
{
|
{
|
||||||
LockInfo nodeLockInfo = getNodeLockInfo(fileInfo);
|
LockInfo nodeLockInfo = getNodeLockInfo(fileInfo);
|
||||||
String nodeETag = getDAVHelper().makeQuotedETag(fileInfo);
|
|
||||||
|
|
||||||
|
|
||||||
if (m_conditions == null)
|
nodeLockInfo.getRWLock().readLock().lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (!nodeLockInfo.isLocked())
|
String nodeETag = getDAVHelper().makeQuotedETag(fileInfo);
|
||||||
{
|
|
||||||
// Not locked
|
|
||||||
return nodeLockInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodeLockInfo.isShared())
|
if (m_conditions == null)
|
||||||
{
|
{
|
||||||
if (nodeLockInfo.getSharedLockTokens().isEmpty())
|
if (!nodeLockInfo.isLocked())
|
||||||
{
|
{
|
||||||
// Although flagged as shared - no shared locks.
|
// Not locked
|
||||||
return nodeLockInfo;
|
return nodeLockInfo;
|
||||||
}
|
}
|
||||||
if (!ignoreShared)
|
|
||||||
|
if (nodeLockInfo.isShared())
|
||||||
{
|
{
|
||||||
// Shared locks exist
|
if (nodeLockInfo.getSharedLockTokens().isEmpty())
|
||||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// ALF-3681 fix. WebDrive 10 client doesn't send If header when locked resource is updated so check the node by lockOwner.
|
|
||||||
if (m_userAgent != null && m_userAgent.equals(WebDAV.AGENT_MICROSOFT_DATA_ACCESS_INTERNET_PUBLISHING_PROVIDER_DAV))
|
|
||||||
{
|
|
||||||
String currentUser = getAuthenticationService().getCurrentUserName();
|
|
||||||
String lockOwner = nodeLockInfo.getOwner();
|
|
||||||
if (lockOwner.equals(currentUser))
|
|
||||||
{
|
{
|
||||||
// OK to write - lock is owned by current user.
|
// Although flagged as shared - no shared locks.
|
||||||
return nodeLockInfo;
|
return nodeLockInfo;
|
||||||
}
|
}
|
||||||
|
if (!ignoreShared)
|
||||||
|
{
|
||||||
|
// Shared locks exist
|
||||||
|
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Exclusive lock, owned by someone else
|
// ALF-3681 fix. WebDrive 10 client doesn't send If header when locked resource is updated so check the node by lockOwner.
|
||||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
if (m_userAgent != null && m_userAgent.equals(WebDAV.AGENT_MICROSOFT_DATA_ACCESS_INTERNET_PUBLISHING_PROVIDER_DAV))
|
||||||
|
{
|
||||||
|
String currentUser = getAuthenticationService().getCurrentUserName();
|
||||||
|
String lockOwner = nodeLockInfo.getOwner();
|
||||||
|
if (lockOwner.equals(currentUser))
|
||||||
|
{
|
||||||
|
// OK to write - lock is owned by current user.
|
||||||
|
return nodeLockInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Exclusive lock, owned by someone else
|
||||||
|
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Checking of the If tag consists of two checks:
|
// Checking of the If tag consists of two checks:
|
||||||
// 1. If the node is locked we need to check it's Lock token independently of conditions check result.
|
// 1. If the node is locked we need to check it's Lock token independently of conditions check result.
|
||||||
// For example "(<wrong token>) (Not <DAV:no-lock>)" if always true,
|
// For example "(<wrong token>) (Not <DAV:no-lock>)" if always true,
|
||||||
// but request must fail with 423 Locked response because node is locked.
|
// but request must fail with 423 Locked response because node is locked.
|
||||||
// 2. Check if ANY of the conditions in If header true.
|
// 2. Check if ANY of the conditions in If header true.
|
||||||
checkLockToken(nodeLockInfo, ignoreShared, lockMethod);
|
checkLockToken(nodeLockInfo, ignoreShared, lockMethod);
|
||||||
checkConditions(nodeLockInfo.getExclusiveLockToken(), nodeETag);
|
checkConditions(nodeLockInfo.getExclusiveLockToken(), nodeETag);
|
||||||
|
|
||||||
return nodeLockInfo;
|
return nodeLockInfo;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
nodeLockInfo.getRWLock().readLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -945,7 +968,6 @@ public abstract class WebDAVMethod
|
|||||||
/**
|
/**
|
||||||
* Checks if node can be accessed with WebDAV operation
|
* Checks if node can be accessed with WebDAV operation
|
||||||
*
|
*
|
||||||
* @param nodeLockToken - token to check
|
|
||||||
* @param lockInfo - node's lock info
|
* @param lockInfo - node's lock info
|
||||||
* @param ignoreShared - if true - ignores shared lock tokens
|
* @param ignoreShared - if true - ignores shared lock tokens
|
||||||
* @param lockMethod - must be true if used from lock method
|
* @param lockMethod - must be true if used from lock method
|
||||||
@@ -953,67 +975,75 @@ public abstract class WebDAVMethod
|
|||||||
*/
|
*/
|
||||||
private void checkLockToken(LockInfo lockInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException
|
private void checkLockToken(LockInfo lockInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException
|
||||||
{
|
{
|
||||||
String nodeLockToken = lockInfo.getExclusiveLockToken();
|
lockInfo.getRWLock().readLock().lock();
|
||||||
Set<String> sharedLockTokens = lockInfo.getSharedLockTokens();
|
try
|
||||||
|
|
||||||
if (m_conditions != null)
|
|
||||||
{
|
{
|
||||||
// Request has conditions to check
|
String nodeLockToken = lockInfo.getExclusiveLockToken();
|
||||||
if (lockInfo.isShared())
|
Set<String> sharedLockTokens = lockInfo.getSharedLockTokens();
|
||||||
|
|
||||||
|
if (m_conditions != null)
|
||||||
{
|
{
|
||||||
// Node has shared lock. Check if conditions contains lock token of the node.
|
// Request has conditions to check
|
||||||
// If not throw exception
|
if (lockInfo.isShared())
|
||||||
if (!sharedLockTokens.isEmpty())
|
|
||||||
{
|
{
|
||||||
if (!ignoreShared)
|
// Node has shared lock. Check if conditions contains lock token of the node.
|
||||||
|
// If not throw exception
|
||||||
|
if (!sharedLockTokens.isEmpty())
|
||||||
{
|
{
|
||||||
for (Condition condition : m_conditions)
|
if (!ignoreShared)
|
||||||
{
|
{
|
||||||
for (String sharedLockToken : sharedLockTokens)
|
for (Condition condition : m_conditions)
|
||||||
{
|
{
|
||||||
if (condition.getLockTokensMatch().contains(sharedLockToken))
|
for (String sharedLockToken : sharedLockTokens)
|
||||||
{
|
{
|
||||||
return;
|
if (condition.getLockTokensMatch().contains(sharedLockToken))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||||
}
|
}
|
||||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
return;
|
||||||
}
|
}
|
||||||
return;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Node has exclusive lock. Check if conditions contains lock token of the node
|
||||||
|
// If not throw exception
|
||||||
|
for (Condition condition : m_conditions)
|
||||||
|
{
|
||||||
|
if (nodeLockToken != null)
|
||||||
|
{
|
||||||
|
if (condition.getLockTokensMatch().contains(nodeLockToken))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Node has exclusive lock. Check if conditions contains lock token of the node
|
// Request has no conditions
|
||||||
// If not throw exception
|
if (lockInfo.isShared())
|
||||||
for (Condition condition : m_conditions)
|
|
||||||
{
|
{
|
||||||
if (nodeLockToken != null)
|
// If lock is shared and check was called not from LOCK method return
|
||||||
|
if (!lockMethod)
|
||||||
{
|
{
|
||||||
if (condition.getLockTokensMatch().contains(nodeLockToken))
|
return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Throw exception - we can't set lock on node with shared lock
|
||||||
|
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||||
}
|
}
|
||||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
finally
|
||||||
{
|
{
|
||||||
// Request has no conditions
|
lockInfo.getRWLock().readLock().unlock();
|
||||||
if (lockInfo.isShared())
|
|
||||||
{
|
|
||||||
// If lock is shared and check was called not from LOCK method return
|
|
||||||
if (!lockMethod)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Throw exception - we can't set lock on node with shared lock
|
|
||||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1136,9 +1166,20 @@ public abstract class WebDAVMethod
|
|||||||
|
|
||||||
lockInfo = m_parentLockInfo.get(parent);
|
lockInfo = m_parentLockInfo.get(parent);
|
||||||
|
|
||||||
if ((lockInfo != null) && (lockInfo.isLocked()))
|
if (lockInfo != null)
|
||||||
{
|
{
|
||||||
return lockInfo;
|
lockInfo.getRWLock().readLock().lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (lockInfo.isLocked())
|
||||||
|
{
|
||||||
|
return lockInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
lockInfo.getRWLock().readLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lockInfo == null)
|
if (lockInfo == null)
|
||||||
@@ -1177,12 +1218,24 @@ public abstract class WebDAVMethod
|
|||||||
{
|
{
|
||||||
LockInfo lock = getLockStore().get(nodeInfo.getNodeRef());
|
LockInfo lock = getLockStore().get(nodeInfo.getNodeRef());
|
||||||
|
|
||||||
if (lock != null && lock.isLocked())
|
if (lock == null)
|
||||||
{
|
{
|
||||||
return lock;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
lock.getRWLock().readLock().lock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (lock.isLocked())
|
||||||
|
{
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
lock.getRWLock().readLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1195,17 +1248,26 @@ public abstract class WebDAVMethod
|
|||||||
{
|
{
|
||||||
LockInfo parentLock = getLockStore().get(parent);
|
LockInfo parentLock = getLockStore().get(parent);
|
||||||
|
|
||||||
if (parentLock != null && WebDAV.INFINITY.equals(parentLock.getDepth()))
|
if (parentLock == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentLock.getRWLock().readLock().lock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// now check for lock status ...
|
// now check for lock status ...
|
||||||
if (parentLock.isLocked())
|
if (parentLock.isLocked() && WebDAV.INFINITY.equals(parentLock.getDepth()))
|
||||||
{
|
{
|
||||||
// In this case node is locked indirectly.
|
// In this case node is locked indirectly.
|
||||||
return parentLock;
|
return parentLock;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
parentLock.getRWLock().readLock().unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user