This is an automated email from the ASF dual-hosted git repository. remm pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new eeb52a0e3f Improve locks handling eeb52a0e3f is described below commit eeb52a0e3f5c102b08e4669b55b9cab9c32fe563 Author: remm <r...@apache.org> AuthorDate: Thu Apr 25 12:11:52 2024 +0200 Improve locks handling Fix WebDAV lock null (locks for non existing resources) thread safety and removal. Add periodic checking for WebDAV locks expiration. --- .../apache/catalina/servlets/WebdavServlet.java | 53 ++++++++++++++++++---- webapps/docs/changelog.xml | 7 +++ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/java/org/apache/catalina/servlets/WebdavServlet.java b/java/org/apache/catalina/servlets/WebdavServlet.java index fb543280fb..4922f2bf6d 100644 --- a/java/org/apache/catalina/servlets/WebdavServlet.java +++ b/java/org/apache/catalina/servlets/WebdavServlet.java @@ -37,6 +37,7 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; @@ -52,6 +53,7 @@ import org.apache.catalina.WebResource; import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.util.DOMWriter; import org.apache.catalina.util.XMLWriter; +import org.apache.tomcat.PeriodicEventListener; import org.apache.tomcat.util.buf.HexUtils; import org.apache.tomcat.util.http.ConcurrentDateFormat; import org.apache.tomcat.util.http.FastHttpDateFormat; @@ -128,11 +130,9 @@ import org.xml.sax.SAXException; * access will be able to edit content available via http://host:port/context/content using * http://host:port/context/webdavedit/content * - * @author Remy Maucherat - * * @see <a href="https://tools.ietf.org/html/rfc4918">RFC 4918</a> */ -public class WebdavServlet extends DefaultServlet { +public class WebdavServlet extends DefaultServlet implements PeriodicEventListener { private static final long serialVersionUID = 1L; @@ -272,6 +272,26 @@ public class WebdavServlet extends DefaultServlet { } + @Override + public void periodicEvent() { + // Check expiration of all locks + for (LockInfo currentLock : resourceLocks.values()) { + if (currentLock.hasExpired()) { + resourceLocks.remove(currentLock.path); + removeLockNull(currentLock.path); + } + } + Iterator<LockInfo> collectionLocksIterator = collectionLocks.iterator(); + while (collectionLocksIterator.hasNext()) { + LockInfo currentLock = collectionLocksIterator.next(); + if (currentLock.hasExpired()) { + collectionLocksIterator.remove(); + removeLockNull(currentLock.path); + } + } + } + + // ------------------------------------------------------ Protected Methods /** @@ -726,7 +746,7 @@ public class WebdavServlet extends DefaultServlet { if (resources.mkdir(path)) { resp.setStatus(WebdavStatus.SC_CREATED); // Removing any lock-null resource which would be present - lockNullResources.remove(path); + removeLockNull(path); } else { resp.sendError(WebdavStatus.SC_CONFLICT); } @@ -786,7 +806,7 @@ public class WebdavServlet extends DefaultServlet { super.doPut(req, resp); // Removing any lock-null resource which would be present - lockNullResources.remove(path); + removeLockNull(path); } @@ -1176,7 +1196,7 @@ public class WebdavServlet extends DefaultServlet { int slash = lock.path.lastIndexOf('/'); String parentPath = lock.path.substring(0, slash); - lockNullResources.computeIfAbsent(parentPath, k -> new ArrayList<>()).add(lock.path); + lockNullResources.computeIfAbsent(parentPath, k -> new CopyOnWriteArrayList<>()).add(lock.path); } // Add the Lock-Token header as by RFC 2518 8.10.1 @@ -1286,7 +1306,7 @@ public class WebdavServlet extends DefaultServlet { if (lock.tokens.isEmpty()) { resourceLocks.remove(path); // Removing any lock-null resource which would be present - lockNullResources.remove(path); + removeLockNull(path); } } @@ -1307,7 +1327,7 @@ public class WebdavServlet extends DefaultServlet { if (lock.tokens.isEmpty()) { collectionLocksList.remove(); // Removing any lock-null resource which would be present - lockNullResources.remove(path); + removeLockNull(path); } } } @@ -1551,7 +1571,7 @@ public class WebdavServlet extends DefaultServlet { // Removing any lock-null resource which would be present at // the destination path - lockNullResources.remove(destinationPath); + removeLockNull(destinationPath); return true; } @@ -2195,6 +2215,21 @@ public class WebdavServlet extends DefaultServlet { } + private void removeLockNull(String path) { + int slash = path.lastIndexOf('/'); + if (slash >= 0) { + String parentPath = path.substring(0, slash); + List<String> paths = lockNullResources.get(parentPath); + if (paths != null) { + paths.remove(path); + } + if (paths.isEmpty()) { + lockNullResources.remove(parentPath); + } + } + } + + // -------------------------------------------------- LockInfo Inner Class /** diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 223d89c3c9..fc69d83549 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -135,6 +135,13 @@ dispatch is now performed rather than completing the request using the error page mechanism. (markt) </fix> + <fix> + Fix WebDAV lock null (locks for non existing resources) thread safety + and removal. (remm) + </fix> + <fix> + Add periodic checking for WebDAV locks expiration. (remm) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org