Title: REBIND method: missing postcondition DAV:lock-deleted

A minor (?) bug has just been discovered in my project for which I just checked-in a fix in the HEAD branch (plus two new testcases).

<<cvs commit: jakarta-slide/src/webdav/server/org/apache/slide/webdav/method RebindMethod.java>> <<cvs commit: jakarta-slide/testsuite/testsuite/junit/xmltestcases/BIND/functional/postcondition lock-delete.xml lock-delete2.xml>>

For the REBIND method, the Binding spec states the following postcondition, which was not implemented in Slide:

"(DAV:lock-deleted): If the URL specified in the DAV:href element in the request body was protected by a write-lock at the time of the request, that write-lock must have been deleted by the request."

That means, that proper locks (i.e. non-inherited) are to be removed from the "moved" resource after REBIND. As in case of binding being enabled, MOVE is mapped onto REBIND in Slide, this bug also can affect the MOVE method. [BTW, also the WebDAV spec states, that proper locks are not to be moved along with a resource (see section 7.7)].

Question:
Is this something I should check-in in the SLIDE_2_1_RELEASE_BRANCH? I suppose not, as we are already voting for 2.1-final :) ... and the bug is certainly not a show stopper. OTOH, the fix is rather trivial.

Regards,
Peter

--- Begin Message ---
Title: cvs commit: jakarta-slide/src/webdav/server/org/apache/slide/webdav/method RebindMethod.java

pnever      2004/12/14 06:07:42

  Modified:    src/share/org/apache/slide/macro MacroImpl.java
               src/webdav/server/org/apache/slide/webdav/method
                        RebindMethod.java
  Log:
  REBIND Method: postcondition DAV:lock-deleted was not implemented.
  The Binding spec states that (non-inherited) locks are to be removed after
  rebinding a resource. If binding is enabled, Slide maps the MOVE method
  onto REBIND, so that MOVE was affected in this case too.
 
  Revision  Changes    Path
  1.52      +10 -4     jakarta-slide/src/share/org/apache/slide/macro/MacroImpl.java
 
  Index: MacroImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/macro/MacroImpl.java,v
  retrieving revision 1.51
  retrieving revision 1.52
  diff -u -r1.51 -r1.52
  --- MacroImpl.java    7 Dec 2004 14:10:06 -0000       1.51
  +++ MacroImpl.java    14 Dec 2004 14:07:42 -0000      1.52
  @@ -393,6 +393,12 @@
              
               structureHelper.addBinding( token, destinationParentNode, destinationSegment, sourceNode );
               structureHelper.removeBinding( token, sourceParentNode, sourceSegment );
  +           
  +            // Postcondition: DAV:lock-delete
  +            Enumeration locksEnum = lockHelper.enumerateLocks(token, destinationUri, false);
  +            while (locksEnum.hasMoreElements()) {
  +                lockHelper.unlock(token, (NodeLock)locksEnum.nextElement());
  +            }
           }
           catch (SlideException x) {
               e.addException(x);
 
 
 
  1.19      +33 -24    jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/RebindMethod.java
 
  Index: RebindMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/RebindMethod.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- RebindMethod.java 31 Oct 2004 11:32:40 -0000      1.18
  +++ RebindMethod.java 14 Dec 2004 14:07:42 -0000      1.19
  @@ -5,7 +5,7 @@
    *
    * ====================================================================
    *
  - * Copyright 1999-2002 The Apache Software Foundation
  + * Copyright 1999-2002 The Apache Software Foundation
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
  @@ -24,12 +24,14 @@
   package org.apache.slide.webdav.method;
  
   import java.io.IOException;
  +import java.util.Enumeration;
   import java.util.List;
  -
   import org.apache.slide.common.NamespaceAccessToken;
   import org.apache.slide.common.ServiceAccessException;
   import org.apache.slide.common.SlideException;
  +import org.apache.slide.common.UriPath;
   import org.apache.slide.event.EventDispatcher;
  +import org.apache.slide.lock.NodeLock;
   import org.apache.slide.lock.ObjectLockedException;
   import org.apache.slide.structure.CrossServerBindingException;
   import org.apache.slide.structure.ObjectNode;
  @@ -59,8 +61,8 @@
       private ObjectNode sourceNode = null;
       private ObjectNode sourceParentNode = null;
       private ObjectNode collectionNode = null;
  -
  -
  +   
  +   
       /**
        * Constructor.
        *
  @@ -70,7 +72,7 @@
       public RebindMethod(NamespaceAccessToken token, WebdavServletConfig config) {
           super(token, config);
       }
  -
  +   
       /**
        * @see org.apache.slide.webdav.method.FineGrainedLockingMethod#acquireFineGrainLocks()
        */
  @@ -89,10 +91,10 @@
           if (collectionUri == null) {
               collectionUri = "/";
           }
  -
  +       
           List content;
  -
  -//        readRequestContent();
  +       
  +        //        readRequestContent();
           try{
               content = parseRequestContent(E_REBIND).getChildren();
               segment = MethodUtil.getChildText(content, E_SEGMENT);
  @@ -108,15 +110,15 @@
               sendError( statusCode, e );
               throw new WebdavException( statusCode );
           }
  -
  +       
           collectionUri = requestUri;
           if (collectionUri == null) {
               collectionUri = "/";
           }
  -
  +       
           overwrite = requestHeaders.getOverwrite(true);
       }
  -
  +   
       private void checkPreconditions() throws PreconditionViolationException, ServiceAccessException {
           resp.setStatus( WebdavStatus.SC_CREATED );
           UriHandler sourceUh = UriHandler.getUriHandler(sourceUri);
  @@ -125,7 +127,7 @@
           if (sourceParentUh != null) {
               sourceParentUri = sourceUh.getParentUriHandler().toString();
           }
  -
  +       
           try {
               collectionNode = structure.retrieve( slideToken, collectionUri );
           }
  @@ -133,7 +135,7 @@
               throw e;
           }
           catch (SlideException e) {} // ignore silently
  -
  +       
           try {
               sourceNode = structure.retrieve( slideToken, sourceUri );
           }
  @@ -141,7 +143,7 @@
               throw e;
           }
           catch (SlideException e) {} // ignore silently
  -
  +       
           try {
               sourceParentNode = structure.retrieve( slideToken, sourceParentUri );
           }
  @@ -149,7 +151,7 @@
               throw e;
           }
           catch (SlideException e) {} // ignore silently
  -
  +       
           if (collectionNode == null || !isCollection(collectionUri)) {
               throw new PreconditionViolationException(
                   new ViolatedPrecondition(C_REBIND_INTO_COLLECTION, WebdavStatus.SC_CONFLICT), collectionUri);
  @@ -178,17 +180,17 @@
               }
           }
       }
  -
  +   
       /**
        * Execute the request.
        *
        * @exception WebdavException
        */
       protected void executeRequest() throws WebdavException, IOException {
  -
  +       
           // Prevent dirty reads
           slideToken.setForceStoreEnlistment(true);
  -
  +       
           // check lock-null resources
           try {
               if (isLockNull(collectionUri)) {
  @@ -202,13 +204,20 @@
               sendError( statusCode, e );
               throw new WebdavException( statusCode );
           }
  -
  +       
           try {
               if ( WebdavEvent.REBIND.isEnabled() ) EventDispatcher.getInstance().fireVetoableEvent(WebdavEvent.REBIND, new WebdavEvent(this));
  -
  +           
               checkPreconditions();
               structure.addBinding( slideToken, collectionNode, segment, sourceNode );
               structure.removeBinding( slideToken, sourceParentNode, sourceSegment );
  +           
  +            // Postcondition: DAV:lock-delete
  +            UriPath destUp = new UriPath(collectionUri).child(segment);
  +            Enumeration locksEnum = lock.enumerateLocks(slideToken, destUp.toString(), false);
  +            while (locksEnum.hasMoreElements()) {
  +                lock.unlock(slideToken, (NodeLock)locksEnum.nextElement());
  +            }
           }
           catch (CrossServerBindingException e) {
               sendPreconditionViolation(
  @@ -250,6 +259,6 @@
               throw new WebdavException( statusCode );
           }
       }
  -
  +   
   }
  
 
 
 

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


--- End Message ---
--- Begin Message ---
Title: cvs commit: jakarta-slide/testsuite/testsuite/junit/xmltestcases/BIND/functional/postcondition lock-delete.xml lock-delete2.xml

pnever      2004/12/14 06:08:53

  Added:       testsuite/testsuite/junit/xmltestcases/BIND/functional/postcondition
                        lock-delete.xml lock-delete2.xml
  Log:
  REBIND Method: postcondition DAV:lock-deleted was not implemented.
  The Binding spec states that (non-inherited) locks are to be removed after
  rebinding a resource. If binding is enabled, Slide maps the MOVE method
  onto REBIND, so that MOVE was affected in this case too.
 
  Revision  Changes    Path
  1.1                  jakarta-slide/testsuite/testsuite/junit/xmltestcases/BIND/functional/postcondition/lock-delete.xml
 
  Index: lock-delete.xml
  ===================================================================
  <?xml version="1.0" encoding="utf-8"?>
  <!DOCTYPE test SYSTEM "../../../../Tprocessor.dtd">
  <test>
    <specification>
      <abstract> checks postcondition lock-delete </abstract>
      <description> The test case consist of following steps:
                                                1) create collection test
                                                1) create collection test/test1
                                                2) lock test1
                                                3) rebind test (test2 -> test/test1)
                                                3) check that test2 is not locked
                </description>
      <expectedResult></expectedResult>
    </specification>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">MKCOL %globalVariableServerName%/%globalVariableCollection%/test HTTP/1.1</command>
      </request>
      <response>
        <command>HTTP/1.0 201 Created</command>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">MKCOL %globalVariableServerName%/%globalVariableCollection%/test/test1 HTTP/1.1</command>
      </request>
      <response>
        <command>HTTP/1.0 201 Created</command>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">LOCK %globalVariableServerName%/%globalVariableCollection%/test/test1 HTTP/1.1</command>
        <header>Timeout: Second-604800</header>
        <header>Content-Type: text/xml</header>
        <body><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <A:lockinfo xmlns:A="DAV:">
    <A:locktype>
      <A:write />
    </A:locktype>
    <A:lockscope>
      <A:exclusive />
    </A:lockscope>
    <owner xmlns="DAV:">some owner</owner>
  </A:lockinfo>
  ]]></body>
      </request>
      <response>
        <command>HTTP/1.0 200 OK</command>
        <body varDefinition="locktoken" varPath="prop/lockdiscovery/activelock/locktoken/href"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <D:prop xmlns:D="DAV:">
    <D:lockdiscovery>
      <D:activelock>
        <D:locktype><D:write/></D:locktype>
        <D:lockscope><D:exclusive/></D:lockscope>
        <D:depth>infinity</D:depth>
        <D:timeout>Second-3599</D:timeout>
        <D:locktoken><D:href>opaquelocktoken:8866bed69d52f601c31c8b1a1fd805ef</D:href></D:locktoken>
        <d:principal-URL xmlns:d="DAV:"><d:href>*</d:href></d:principal-URL>
        <owner xmlns="DAV:">*</owner>
      </D:activelock>
    </D:lockdiscovery>
  </D:prop>
  ]]></body>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">REBIND %globalVariableServerName%/%globalVariableCollection%/test HTTP/1.1</command>
        <header>Overwrite: F</header>
        <header varUsage="locktoken"><![CDATA[If: (<%locktoken%>)]]></header>
        <body varUsage="globalVariableCollection,globalVariableServerName"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <rebind>
    <segment>test2</segment>
    <href>%globalVariableServerName%/%globalVariableCollection%/test/test1</href>
  </rebind>
  ]]></body>
      </request>
      <response>
        <command>HTTP/1.1 201 Created</command>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,userNumber,globalVariableServerName">PROPFIND %globalVariableServerName%/%globalVariableCollection%/test/test2 HTTP/1.1</command>
        <header>Content-Type: text/xml</header>
        <header>Depth: 0</header>
        <body><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <D:propfind xmlns:D="DAV:">
    <D:prop>
      <D:lockdiscovery/>
    </D:prop>
  </D:propfind>
  ]]></body>
      </request>
      <response>
        <command>HTTP/1.0 207 Multi Status</command>
        <body varUsage="globalVariableCollection,VHR,globalVariableServerName"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <multistatus xmlns="DAV:">
    <response>
      <href>%globalVariableServerName%/%globalVariableCollection%/test/test2</href>
      <propstat>
        <prop>
          <lockdiscovery/>
        </prop>
        <status>HTTP/1.1 200 OK</status>
      </propstat>
    </response>
  </multistatus>
  ]]></body>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">DELETE %globalVariableServerName%/%globalVariableCollection%/test HTTP/1.1</command>
        <header varUsage="locktoken"><![CDATA[If: (<%locktoken%>)]]></header>
      </request>
      <response>
        <command>HTTP/1.0 204 No Content</command>
      </response>
    </step>
  </test>
 
 
 
 
  1.1                  jakarta-slide/testsuite/testsuite/junit/xmltestcases/BIND/functional/postcondition/lock-delete2.xml
 
  Index: lock-delete2.xml
  ===================================================================
  <?xml version="1.0" encoding="utf-8"?>
  <!DOCTYPE test SYSTEM "../../../../Tprocessor.dtd">
  <test>
    <specification>
      <abstract> checks postcondition lock-delete </abstract>
      <description> The test case consist of following steps:
                                                1) create collection test
                                                1) create collection test/test1
                                                2) lock test1
                                                3) move test/test1 -> test/test2
                                                3) check that test2 is not locked
                </description>
      <expectedResult></expectedResult>
    </specification>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">MKCOL %globalVariableServerName%/%globalVariableCollection%/test HTTP/1.1</command>
      </request>
      <response>
        <command>HTTP/1.0 201 Created</command>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">MKCOL %globalVariableServerName%/%globalVariableCollection%/test/test1 HTTP/1.1</command>
      </request>
      <response>
        <command>HTTP/1.0 201 Created</command>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">LOCK %globalVariableServerName%/%globalVariableCollection%/test/test1 HTTP/1.1</command>
        <header>Timeout: Second-604800</header>
        <header>Content-Type: text/xml</header>
        <body><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <A:lockinfo xmlns:A="DAV:">
    <A:locktype>
      <A:write />
    </A:locktype>
    <A:lockscope>
      <A:exclusive />
    </A:lockscope>
    <owner xmlns="DAV:">some owner</owner>
  </A:lockinfo>
  ]]></body>
      </request>
      <response>
        <command>HTTP/1.0 200 OK</command>
        <body varDefinition="locktoken" varPath="prop/lockdiscovery/activelock/locktoken/href"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <D:prop xmlns:D="DAV:">
    <D:lockdiscovery>
      <D:activelock>
        <D:locktype><D:write/></D:locktype>
        <D:lockscope><D:exclusive/></D:lockscope>
        <D:depth>infinity</D:depth>
        <D:timeout>Second-3599</D:timeout>
        <D:locktoken><D:href>opaquelocktoken:8866bed69d52f601c31c8b1a1fd805ef</D:href></D:locktoken>
        <d:principal-URL xmlns:d="DAV:"><d:href>*</d:href></d:principal-URL>
        <owner xmlns="DAV:">*</owner>
      </D:activelock>
    </D:lockdiscovery>
  </D:prop>
  ]]></body>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">MOVE %globalVariableServerName%/%globalVariableCollection%/test/test1 HTTP/1.1</command>
        <header>Overwrite: F</header>
        <header varUsage="globalVariableServerName,globalVariableCollection">Destination: %globalVariableServerName%/%globalVariableCollection%/test/test2</header>
        <header varUsage="locktoken"><![CDATA[If: (<%locktoken%>)]]></header>
      </request>
      <response>
        <command>HTTP/1.1 201 Created</command>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,userNumber,globalVariableServerName">PROPFIND %globalVariableServerName%/%globalVariableCollection%/test/test2 HTTP/1.1</command>
        <header>Content-Type: text/xml</header>
        <header>Depth: 0</header>
        <body><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <D:propfind xmlns:D="DAV:">
    <D:prop>
      <D:lockdiscovery/>
    </D:prop>
  </D:propfind>
  ]]></body>
      </request>
      <response>
        <command>HTTP/1.0 207 Multi Status</command>
        <body varUsage="globalVariableCollection,VHR,globalVariableServerName"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
  <multistatus xmlns="DAV:">
    <response>
      <href>%globalVariableServerName%/%globalVariableCollection%/test/test2</href>
      <propstat>
        <prop>
          <lockdiscovery/>
        </prop>
        <status>HTTP/1.1 200 OK</status>
      </propstat>
    </response>
  </multistatus>
  ]]></body>
      </response>
    </step>
    <step>
      <request>
        <command varUsage="globalVariableCollection,globalVariableServerName">DELETE %globalVariableServerName%/%globalVariableCollection%/test HTTP/1.1</command>
        <header varUsage="locktoken"><![CDATA[If: (<%locktoken%>)]]></header>
      </request>
      <response>
        <command>HTTP/1.0 204 No Content</command>
      </response>
    </step>
  </test>
 
 
 
 

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


--- End Message ---
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to