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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]