[
https://issues.apache.org/jira/browse/JCR-4954?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17784019#comment-17784019
]
Claus Köll commented on JCR-4954:
---------------------------------
[~baedke] i have found some time to make a little debug session without your
patch (i will explain why later) :)
It's really hard to debug but for me it's really clear now where the problem
comes from.
It's importand to know that every DAVEX call from Server A
(SimpleWebDavServlet) to Server B (JcrRemotingServlet) makes a new session on
Server B.
So lets look at the LOCK Request from Server A to Server B.
Server B performs the lock operation and creates a valid LockToken
(6007b5ba-b2c2-4bd1-8a27-9457a39a5ba7-Y) and returns it to Server A
{code:java}
Trace on Server B
Request Method [LOCK] ->
/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/46b237050a0a80969a8156c54ced1b37.doc
Response Method [LOCK] ->
/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/46b237050a0a80969a8156c54ced1b37.doc
Response-Header: Name [Lock-Token] Value
[<opaquelocktoken:dccce564-412e-11e1-b969-00059a3c7a00:6007b5ba-b2c2-4bd1-8a27-9457a39a5ba7-Y>]{code}
On Server B the DavSession will be stored into the DavSessionCache with the
LockToken Key (6007b5ba-b2c2-4bd1-8a27-9457a39a5ba7-Y)
{code:java}
org.apache.jackrabbit.webdav.jcr.DefaultItemCollection.java
public ActiveLock lock(LockInfo reqLockInfo) throws DavException {
....
getSession().addReference(lock.getToken());
return lock;
}{code}
The returned lockToken will not be used an Server A instead a PROPFIND Request
lockDiscovery will be made more times to Server B.
{code:java}
Trace on Server B
Request Method [PROPFIND] ->
/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/46b237050a0a80969a8156c54ced1b37.doc
Response Method [PROPFIND] ->
/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/46b237050a0a80969a8156c54ced1b37.doc
Response-Payload [<?xml version="1.0" encoding="UTF-8"
standalone="no"?><D:multistatus
xmlns:D="DAV:"><D:response><D:href>http://localhost:9080/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/46b237050a0a80969a8156c54ced1b37.doc/</D:href><D:propstat><D:prop><D:lockdiscovery><D:activelock><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype><D:depth>infinity</D:depth><D:timeout>Second-3320</D:timeout><D:owner>LV\udvt0047</D:owner><D:locktoken><D:href>opaquelocktoken:4403ef44-4124-11e1-b965-00059a3c7a00:6007b5ba-b2c2-4bd1-8a27-9457a39a5ba7</D:href></D:locktoken><D:lockroot><D:href>http://localhost:9080/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/46b237050a0a80969a8156c54ced1b37.doc</D:href></D:lockroot></D:activelock></D:lockdiscovery><dcr:parent
xmlns:dcr="http://www.day.com/jcr/webdav/1.0"><D:href>http://localhost:9080/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/</D:href></dcr:parent></D:prop><D:status>HTTP/1.1
200 OK</D:status></D:propstat></D:response></D:multistatus>]{code}
As you can see the return value looks like
{code:java}
opaquelocktoken:4403ef44-4124-11e1-b965-00059a3c7a00:6007b5ba-b2c2-4bd1-8a27-9457a39a5ba7
{code}
It is only the UUID from the opened Node. Looking at the code from
LockTokenMapper
{code:java}
org.apache.jackrabbit.webdav.jcr.lock.LockTokenMapper.java
public static String getDavLocktoken(Lock lock) throws RepositoryException {
String jcrLockToken = lock.getLockToken();
if (jcrLockToken == null) {
return SESSPREFIX + Text.escape(lock.getNode().getIdentifier());
} else {
return OPENPREFIX + Text.escape(jcrLockToken);
}
}
{code}
lock.getLockToken() returns null because of
{code:java}
org.apache.jackrabbit.core.lock.LockImpl.java
public String getLockToken() {
if (!info.isSessionScoped() && (info.isLockHolder(node.getSession()) ||
isAdminUser(node.getSession()))) {
return info.getLockToken();
} else {
return null;
}
}
{code}
The current session is not the lockHolder so it returns null.
The lockToken from the PROPFIND Request lockDiscovery will be send back to the
WebDAVClient.
On UNLOCK this token is send from Server A to Server B
{code:java}
Trace on Server B
Request Method [UNLOCK] ->
/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/46b237050a0a80969a8156c54ced1b37.doc
Request-Header: Name [Lock-Token] Value
[<opaquelocktoken:4403ef44-4124-11e1-b965-00059a3c7a00:6007b5ba-b2c2-4bd1-8a27-9457a39a5ba7>]
Response Method [UNLOCK] ->
/jcr/server/template/jcr%3aroot/tirolgvat/2016/9/4/2/10/24/46b237050a0a80969a8156c54ced1b37.doc
Response-Payload [<?xml version="1.0" encoding="UTF-8"
standalone="no"?><D:error xmlns:D="DAV:"><dcr:exception
xmlns:dcr="http://www.day.com/jcr/webdav/1.0"><dcr:class&amp;amp;amp;amp;gt;javax.jcr.lock.LockException</dcr:class&amp;amp;amp;amp;gt;<dcr:message>Node
not locked by session:
6007b5ba-b2c2-4bd1-8a27-9457a39a5ba7</dcr:message></dcr:exception></D:error>]{code}
As you can see the LockToken is the value from the PROPFIND
{code:java}
opaquelocktoken:4403ef44-4124-11e1-b965-00059a3c7a00:6007b5ba-b2c2-4bd1-8a27-9457a39a5ba7{code}
This will end up in a LockException because Server B is unable to unlock the
node with this LockToken because the DavSessionCache will not return the
DavSession which holds the real Lock.
{code:java}
org.apache.jackrabbit.server.jcr.JCRWebdavServer.java
public boolean attachSession(WebdavRequest request) throws DavException {
DavSession session = cache.get(request);
request.setDavSession(session);
return true;
}
private DavSession get(WebdavRequest request) throws DavException {
...
session = getSessionByReference(lockToken);
//session is null and a new Session will be created !
}
{code}
I hope you will understand the problem now ;)
Your patch which eliminates the double wrapped LockTokens breaks the UNLOCK
Operation. It's hard to explain but the patch prevents Server A to send the
Request to Server B.
{code:java}
org.apache.jackrabbit.spi2dav.RepositoryServiceImpl.java
public void unlock(SessionInfo sessionInfo, NodeId nodeId) throws
RepositoryException {
checkSessionInfo(sessionInfo);
String uri = getItemUri(nodeId, sessionInfo);
// Note: since sessionInfo does not allow to identify the id of the
// lock holding node, we need to access the token via lockInfo
// TODO: review this.
LockInfoImpl lInfo = (LockInfoImpl) getLockInfo(sessionInfo, nodeId);
if (lInfo == null) {
throw new LockException("No Lock present on Node with id " +
saveGetIdString(nodeId, sessionInfo));
}
String lockToken = lInfo.getActiveLock().getToken();
boolean isSessionScoped = lInfo.isSessionScoped();
if (!((SessionInfoImpl)
sessionInfo).getAllLockTokens().contains(lockToken)) {
throw new LockException("Lock " + lockToken + " not owned by this
session");
}
HttpUnlock unlockRequest = new HttpUnlock(uri, lockToken);
try {
execute(unlockRequest, sessionInfo);
((SessionInfoImpl) sessionInfo).removeLockToken(lockToken,
isSessionScoped);
} finally {
unlockRequest.releaseConnection();
}
}
{code}
The if Statement "(!((SessionInfoImpl)
sessionInfo).getAllLockTokens().contains(lockToken))" returns true and a
LockException will be thrown directly on Server A before the Request will be
send to Server B. The LockTokens on the SessionInfoImpl do not match anymore
the given lockToken.
For me it's not clear how to fix the problem but I think Server B should return
on PROPFIND lockDiscovery the same LockToken as created on LOCK Operation.
As mentioned before this prevents the current Code in
org.apache.jackrabbit.core.lock.LockImpl
> Problem with WebDav Client and Repository Server Deployment Model
> -----------------------------------------------------------------
>
> Key: JCR-4954
> URL: https://issues.apache.org/jira/browse/JCR-4954
> Project: Jackrabbit Content Repository
> Issue Type: Bug
> Components: jackrabbit-jcr-server, jackrabbit-webdav
> Reporter: Claus Köll
> Assignee: Manfred Baedke
> Priority: Major
> Fix For: 2.22
>
> Attachments: Call-Hierarchy.txt, JcrRemotingServlet.txt,
> JcrRemotingServlet_2.txt, SimpleWebDavServlet.txt, SimpleWebDavServlet_2.txt,
> config.xml, jcr-4954-diagnose.patch
>
>
> We have one WebApp where we have deployed the SimpleWebDavServlet
> (WebDav-WebApp). From there we connect to a other WebApp where we have
> exposed a Repository through DavEx
> (org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet)
> and also the RMI-Layer by the RMI Registry (Repository-WebApp)
> Until now we connected over RMI but now we tried to switch to DavEx. The
> Problem is, that we are now unable to unlock a opened WebDav Document.
> The Lock Request in the Repository-WebApp adds a Reference (LockToken) to the
> DavSession so a future Requests can obtain the same DavSession to perform the
> unlock.
> https://github.com/apache/jackrabbit/blob/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/DefaultItemCollection.java#L700
> The Reference (Locktoken) looks like
> opaquelocktoken:dccce564-412e-11e1-b969-00059a3c7a00:0089610c-02e5-43cd-bfec-3a90361350f4-0
> It will be generated by the LockTokenMapper
> https://github.com/apache/jackrabbit/blob/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/lock/LockTokenMapper.java#L53
> In the WebDav-WebApp the HeaderLockToken will be stored in this format
> opaquelocktoken:dccce564-412e-11e1-b969-00059a3c7a00:opaquelocktoken%3a4403ef44-4124-11e1-b965-00059a3c7a00%3a0089610c-02e5-43cd-bfec-3a90361350f4
> As you can see it will be double wrapped. That's not really a Problem because
> on unlock the WebDav-WebApp removes the prefix
> opaquelocktoken:dccce564-412e-11e1-b969-00059a3c7a00:
> Finally this locktoken will be send from the WebDav-App to the
> Repository-WebApp
> opaquelocktoken:4403ef44-4124-11e1-b965-00059a3c7a00:0089610c-02e5-43cd-bfec-3a90361350f4
> On the Repository-WebApp the JCRWebdavServer will look for a DavSession in
> the Cache based on the lockToken
> https://github.com/apache/jackrabbit/blob/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/jcr/JCRWebdavServer.java#L210
> So the problem is that the DavSession whitch have created the Lock, is stored
> with a lockToken that do not match with the incoming lockToken
> Cache-Key-Token:
> opaquelocktoken:dccce564-412e-11e1-b969-00059a3c7a00:0089610c-02e5-43cd-bfec-3a90361350f4-0
> Incoming-Token:
> opaquelocktoken:4403ef44-4124-11e1-b965-00059a3c7a00:0089610c-02e5-43cd-bfec-3a90361350f4
> The DavSession-Cache Key is taken from the LockInfo (LockTokenCheckDigit is
> present)
> https://github.com/apache/jackrabbit/blob/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockInfo.java#L118
> Maybe someone which is familiar with the code of LockTokenMapper can explain
> the two different Scopes (SESSIONSCOPED/OPENSCOPED)
> One possible solution could be to change the code in the LockTokenMapper to
> always return the Node Identifier with the same SCOPE-PREFIX?
--
This message was sent by Atlassian Jira
(v8.20.10#820010)