This is an automated email from the ASF dual-hosted git repository. remm pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push: new cbfc2b7131 Reorganize and javadoc cbfc2b7131 is described below commit cbfc2b713125b4b472abcd97d70c33ab0508db73 Author: remm <r...@apache.org> AuthorDate: Tue Oct 22 17:36:32 2024 +0200 Reorganize and javadoc No functional change. --- .../apache/catalina/servlets/WebdavServlet.java | 449 +++++++++++---------- 1 file changed, 235 insertions(+), 214 deletions(-) diff --git a/java/org/apache/catalina/servlets/WebdavServlet.java b/java/org/apache/catalina/servlets/WebdavServlet.java index dc4ffa744d..971fb5a20b 100644 --- a/java/org/apache/catalina/servlets/WebdavServlet.java +++ b/java/org/apache/catalina/servlets/WebdavServlet.java @@ -260,6 +260,7 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen // --------------------------------------------------------- Public Methods + @Override public void init() throws ServletException { @@ -320,8 +321,113 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } } + // ------------------------------------------------------ Protected Methods + + /** + * Copy resource. This should be overridden by subclasses to provide useful behavior. The default implementation + * prevents setting protected properties (anything from the DAV: namespace), and sets 507 for a set attempt on dead + * properties. + * + * @param source the copy source path + * @param dest the copy destination path + */ + protected void copyResource(String source, String dest) { + } + + + /** + * Delete specified resource. This should be overridden by subclasses to provide useful behavior. The default + * implementation prevents setting protected properties (anything from the DAV: namespace), and sets 507 for a set + * attempt on dead properties. + * + * @param path the path of the resource to delete + */ + protected void deleteResource(String path) { + unlockResource(path, null); + } + + + /** + * Generate propfind XML fragments for dead properties. This should be overridden by subclasses to provide useful + * behavior. The default implementation prevents setting protected properties (anything from the DAV: namespace), + * and sets 507 for a set attempt on dead properties. + * + * @param path the resource path + * @param property the dead property, if null then all dead properties must be written + * @param nameOnly true if only the property name element should be generated + * @param generatedXML the current generated XML for the PROPFIND response + * + * @return true if property was specified and a corresponding dead property was found on the resource, false + * otherwise + */ + protected boolean propfindResource(String path, Node property, boolean nameOnly, XMLWriter generatedXML) { + if (nameOnly) { + generatedXML.writeElement("D", "displayname", XMLWriter.NO_CONTENT); + } else if (property == null) { + String resourceName = path; + int lastSlash = path.lastIndexOf('/'); + if (lastSlash != -1) { + resourceName = resourceName.substring(lastSlash + 1); + } + generatedXML.writeElement("D", "displayname", XMLWriter.OPENING); + generatedXML.writeData(resourceName); + generatedXML.writeElement("D", "displayname", XMLWriter.CLOSING); + } else { + String davName = getDAVNode(property); + if ("displayname".equals(davName)) { + String resourceName = path; + int lastSlash = path.lastIndexOf('/'); + if (lastSlash != -1) { + resourceName = resourceName.substring(lastSlash + 1); + } + generatedXML.writeElement("D", "displayname", XMLWriter.OPENING); + generatedXML.writeData(resourceName); + generatedXML.writeElement("D", "displayname", XMLWriter.CLOSING); + } + } + return false; + } + + + /** + * Apply proppatch to the specified path. This should be overridden by subclasses to provide useful behavior. The + * default implementation prevents setting protected properties (anything from the DAV: namespace), and sets 507 for + * a set attempt on dead properties. + * + * @param path the resource path on which to apply the proppatch + * @param operations the set and remove to apply, the final status codes of the result should be set on each + * operation + */ + protected void proppatchResource(String path, ArrayList<ProppatchOperation> operations) { + boolean setProperty = false; + boolean protectedProperty = false; + // Check for the protected properties + for (ProppatchOperation operation : operations) { + if (operation.getUpdateType() == PropertyUpdateType.SET) { + setProperty = true; + } + if (operation.getProtectedProperty()) { + protectedProperty = true; + operation.setStatusCode(HttpServletResponse.SC_FORBIDDEN); + } + } + if (protectedProperty) { + for (ProppatchOperation operation : operations) { + if (!operation.getProtectedProperty()) { + operation.setStatusCode(WebdavStatus.SC_FAILED_DEPENDENCY); + } + } + } else if (setProperty) { + // No dead property support + for (ProppatchOperation operation : operations) { + operation.setStatusCode(WebdavStatus.SC_INSUFFICIENT_STORAGE); + } + } + } + + /** * Return JAXP document builder instance. * @@ -346,9 +452,6 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } - /** - * Handles the special WebDAV methods. - */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -399,19 +502,6 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } - /** - * Checks whether a given path refers to a resource under <code>WEB-INF</code> or <code>META-INF</code>. - * - * @param path the full path of the resource being accessed - * - * @return <code>true</code> if the resource specified is under a special path - */ - private boolean isSpecialPath(final String path) { - return !allowSpecialPaths && (path.toUpperCase(Locale.ENGLISH).startsWith("/WEB-INF") || - path.toUpperCase(Locale.ENGLISH).startsWith("/META-INF")); - } - - @Override protected boolean checkIfHeaders(HttpServletRequest request, HttpServletResponse response, WebResource resource) throws IOException { @@ -565,75 +655,41 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } - private String getEncodedPath(String path, WebResource resource, HttpServletRequest request) { - String href = getPathPrefix(request); - if ((href.endsWith("/")) && (path.startsWith("/"))) { - href += path.substring(1); - } else { - href += path; - } - if (resource != null && resource.isDirectory() && (!href.endsWith("/"))) { - href += "/"; - } - - return rewriteUrl(href); - } - - private String getUriPrefix(HttpServletRequest request) { - return request.getScheme() + "://" + request.getServerName(); - } - - private String getPathFromHref(String href, HttpServletRequest req) { - - if (href == null || href.isEmpty()) { - return null; - } - - URI hrefUri; - try { - hrefUri = new URI(href); - } catch (URISyntaxException e) { - return null; - } + @Override + protected String determineMethodsAllowed(HttpServletRequest req) { - String hrefPath = hrefUri.getPath(); + WebResource resource = resources.getResource(getRelativePath(req)); - // Avoid path traversals - if (!hrefPath.equals(RequestUtil.normalize(hrefPath))) { - return null; - } + // These methods are always allowed. They may return a 404 (not a 405) + // if the resource does not exist. + StringBuilder methodsAllowed = new StringBuilder("OPTIONS, GET, POST, HEAD"); - if (hrefUri.isAbsolute()) { - if (!req.getServerName().equals(hrefUri.getHost())) { - return null; + if (!readOnly) { + methodsAllowed.append(", DELETE"); + if (!resource.isDirectory()) { + methodsAllowed.append(", PUT"); } } - if (hrefPath.length() > 1 && hrefPath.endsWith("/")) { - hrefPath = hrefPath.substring(0, hrefPath.length() - 1); - } - - // Verify context path - String reqContextPath = getPathPrefix(req); - if (!hrefPath.startsWith(reqContextPath + "/")) { - return null; + // Trace - assume disabled unless we can prove otherwise + if (req instanceof RequestFacade && ((RequestFacade) req).getAllowTrace()) { + methodsAllowed.append(", TRACE"); } - // Remove context path & servlet path - hrefPath = hrefPath.substring(reqContextPath.length()); + methodsAllowed.append(", LOCK, UNLOCK, PROPPATCH, COPY, MOVE"); - if (debug > 0) { - log(href + " Href path: " + hrefPath); + if (listings) { + methodsAllowed.append(", PROPFIND"); } - // Protect special subdirectories - if (isSpecialPath(hrefPath)) { - return null; + if (!resource.exists()) { + methodsAllowed.append(", MKCOL"); } - return hrefPath; + return methodsAllowed.toString(); } + @Override protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.addHeader("DAV", "1,2"); @@ -994,43 +1050,6 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } - /** - * Apply proppatch to the specified path. This should be overridden by subclasses to provide useful behavior. The - * default implementation prevents setting protected properties (anything from the DAV: namespace), and sets 507 for - * a set attempt on dead properties. - * - * @param path the resource path on which to apply the proppatch - * @param operations the set and remove to apply, the final status codes of the result should be set on each - * operation - */ - protected void proppatchResource(String path, ArrayList<ProppatchOperation> operations) { - boolean setProperty = false; - boolean protectedProperty = false; - // Check for the protected properties - for (ProppatchOperation operation : operations) { - if (operation.getUpdateType() == PropertyUpdateType.SET) { - setProperty = true; - } - if (operation.getProtectedProperty()) { - protectedProperty = true; - operation.setStatusCode(HttpServletResponse.SC_FORBIDDEN); - } - } - if (protectedProperty) { - for (ProppatchOperation operation : operations) { - if (!operation.getProtectedProperty()) { - operation.setStatusCode(WebdavStatus.SC_FAILED_DEPENDENCY); - } - } - } else if (setProperty) { - // No dead property support - for (ProppatchOperation operation : operations) { - operation.setStatusCode(WebdavStatus.SC_INSUFFICIENT_STORAGE); - } - } - } - - /** * MKCOL Method. * @@ -1673,8 +1692,95 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } } + // -------------------------------------------------------- Private Methods + + /** + * Checks whether a given path refers to a resource under <code>WEB-INF</code> or <code>META-INF</code>. + * + * @param path the full path of the resource being accessed + * + * @return <code>true</code> if the resource specified is under a special path + */ + private boolean isSpecialPath(final String path) { + return !allowSpecialPaths && (path.toUpperCase(Locale.ENGLISH).startsWith("/WEB-INF") || + path.toUpperCase(Locale.ENGLISH).startsWith("/META-INF")); + } + + + private String getEncodedPath(String path, WebResource resource, HttpServletRequest request) { + String href = getPathPrefix(request); + if ((href.endsWith("/")) && (path.startsWith("/"))) { + href += path.substring(1); + } else { + href += path; + } + if (resource != null && resource.isDirectory() && (!href.endsWith("/"))) { + href += "/"; + } + + return rewriteUrl(href); + } + + + private String getUriPrefix(HttpServletRequest request) { + return request.getScheme() + "://" + request.getServerName(); + } + + + private String getPathFromHref(String href, HttpServletRequest req) { + + if (href == null || href.isEmpty()) { + return null; + } + + URI hrefUri; + try { + hrefUri = new URI(href); + } catch (URISyntaxException e) { + return null; + } + + String hrefPath = hrefUri.getPath(); + + // Avoid path traversals + if (!hrefPath.equals(RequestUtil.normalize(hrefPath))) { + return null; + } + + if (hrefUri.isAbsolute()) { + if (!req.getServerName().equals(hrefUri.getHost())) { + return null; + } + } + + if (hrefPath.length() > 1 && hrefPath.endsWith("/")) { + hrefPath = hrefPath.substring(0, hrefPath.length() - 1); + } + + // Verify context path + String reqContextPath = getPathPrefix(req); + if (!hrefPath.startsWith(reqContextPath + "/")) { + return null; + } + + // Remove context path & servlet path + hrefPath = hrefPath.substring(reqContextPath.length()); + + if (debug > 0) { + log(href + " Href path: " + hrefPath); + } + + // Protect special subdirectories + if (isSpecialPath(hrefPath)) { + return null; + } + + return hrefPath; + } + + /** * Check to see if a resource is currently write locked. The method will look at the "If" header to make sure the * client has demonstrated knowledge of the appropriate lock tokens. @@ -2024,16 +2130,6 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen return true; } - /** - * Copy resource. This should be overridden by subclasses to provide useful behavior. The default implementation - * prevents setting protected properties (anything from the DAV: namespace), and sets 507 for a set attempt on dead - * properties. - * - * @param source the copy source path - * @param dest the copy destination path - */ - protected void copyResource(String source, String dest) { - } /** * Delete a resource. @@ -2125,17 +2221,6 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen return true; } - /** - * Delete specified resource. This should be overridden by subclasses to provide useful behavior. The default - * implementation prevents setting protected properties (anything from the DAV: namespace), and sets 507 for a set - * attempt on dead properties. - * - * @param path the path of the resource to delete - */ - protected void deleteResource(String path) { - unlockResource(path, null); - } - private void unlockResource(String path, String lockToken) { LockInfo lock = resourceLocks.get(path); if (lock != null) { @@ -2158,6 +2243,7 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } } + /** * Deletes a collection. * @@ -2491,48 +2577,6 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } - /** - * Generate propfind XML fragments for dead properties. This should be overridden by subclasses to provide useful - * behavior. The default implementation prevents setting protected properties (anything from the DAV: namespace), - * and sets 507 for a set attempt on dead properties. - * - * @param path the resource path - * @param property the dead property, if null then all dead properties must be written - * @param nameOnly true if only the property name element should be generated - * @param generatedXML the current generated XML for the PROPFIND response - * - * @return true if property was specified and a corresponding dead property was found on the resource, false - * otherwise - */ - protected boolean propfindResource(String path, Node property, boolean nameOnly, XMLWriter generatedXML) { - if (nameOnly) { - generatedXML.writeElement("D", "displayname", XMLWriter.NO_CONTENT); - } else if (property == null) { - String resourceName = path; - int lastSlash = path.lastIndexOf('/'); - if (lastSlash != -1) { - resourceName = resourceName.substring(lastSlash + 1); - } - generatedXML.writeElement("D", "displayname", XMLWriter.OPENING); - generatedXML.writeData(resourceName); - generatedXML.writeElement("D", "displayname", XMLWriter.CLOSING); - } else { - String davName = getDAVNode(property); - if ("displayname".equals(davName)) { - String resourceName = path; - int lastSlash = path.lastIndexOf('/'); - if (lastSlash != -1) { - resourceName = resourceName.substring(lastSlash + 1); - } - generatedXML.writeElement("D", "displayname", XMLWriter.OPENING); - generatedXML.writeData(resourceName); - generatedXML.writeElement("D", "displayname", XMLWriter.CLOSING); - } - } - return false; - } - - /** * Print the lock discovery information associated with a path. * @@ -2591,41 +2635,6 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } - @Override - protected String determineMethodsAllowed(HttpServletRequest req) { - - WebResource resource = resources.getResource(getRelativePath(req)); - - // These methods are always allowed. They may return a 404 (not a 405) - // if the resource does not exist. - StringBuilder methodsAllowed = new StringBuilder("OPTIONS, GET, POST, HEAD"); - - if (!readOnly) { - methodsAllowed.append(", DELETE"); - if (!resource.isDirectory()) { - methodsAllowed.append(", PUT"); - } - } - - // Trace - assume disabled unless we can prove otherwise - if (req instanceof RequestFacade && ((RequestFacade) req).getAllowTrace()) { - methodsAllowed.append(", TRACE"); - } - - methodsAllowed.append(", LOCK, UNLOCK, PROPPATCH, COPY, MOVE"); - - if (listings) { - methodsAllowed.append(", PROPFIND"); - } - - if (!resource.exists()) { - methodsAllowed.append(", MKCOL"); - } - - return methodsAllowed.toString(); - } - - private static String getDAVNode(Node node) { if (DEFAULT_NAMESPACE.equals(node.getNamespaceURI())) { return node.getLocalName(); @@ -2754,6 +2763,7 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen // --------------------------------------------- WebdavResolver Inner Class + /** * Work around for XML parsers that don't fully respect * {@link DocumentBuilderFactory#setExpandEntityReferences(boolean)} when called with <code>false</code>. External @@ -2773,61 +2783,72 @@ public class WebdavServlet extends DefaultServlet implements PeriodicEventListen } } - enum PropertyUpdateType { - SET, - REMOVE - } + // ----------------------------------------- ProppatchOperation Inner Class + /** + * Represents a PROPPATCH sub operation to be performed. + */ protected static class ProppatchOperation { private final PropertyUpdateType updateType; private final Node propertyNode; private final boolean protectedProperty; private int statusCode = HttpServletResponse.SC_OK; + /** + * PROPPATCH operation constructor. + * @param updateType the update type, either SET or REMOVE + * @param propertyNode the XML node that contains the property name (and value if SET) + */ public ProppatchOperation(PropertyUpdateType updateType, Node propertyNode) { this.updateType = updateType; this.propertyNode = propertyNode; String davName = getDAVNode(propertyNode); + // displayname and getcontentlanguage are the DAV: properties that should not be protected protectedProperty = davName != null && (!(davName.equals("displayname") || davName.equals("getcontentlanguage"))); } /** - * @return the updateType + * @return the updateType for this operation */ public PropertyUpdateType getUpdateType() { return this.updateType; } /** - * @return the propertyNode + * @return the propertyNode the XML node that contains the property name (and value if SET) */ public Node getPropertyNode() { return this.propertyNode; } /** - * @return the statusCode + * @return the statusCode the statusCode to set as a result of the operation */ public int getStatusCode() { return this.statusCode; } /** - * @param statusCode the statusCode to set + * @param statusCode the statusCode to set as a result of the operation */ public void setStatusCode(int statusCode) { this.statusCode = statusCode; } /** - * @return the protectedProperty + * @return <code>true</code> if the property is protected */ public boolean getProtectedProperty() { return this.protectedProperty; } } + enum PropertyUpdateType { + SET, + REMOVE + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org