You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2026/09/27 14:09:48 UTC
(tapestry-5) branch master updated: Improving context asset handling
This is an automated email from the ASF dual-hosted git repository.
thiagohp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/master by this push:
new e9e0b7e7a Improving context asset handling
e9e0b7e7a is described below
commit e9e0b7e7ad589ac9dd433168d34145620ffa0f9f
Author: Thiago H. de Paula Figueiredo <th...@arsmachina.com.br>
AuthorDate: Sun Sep 27 11:09:38 2026 -0300
Improving context asset handling
---
.../assets/ContextAssetRequestHandler.java | 42 ++++++++++++++++++++--
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java
index 1ba8e007f..5f30c37ed 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ContextAssetRequestHandler.java
@@ -20,6 +20,8 @@ import org.apache.tapestry5.http.services.Response;
import org.apache.tapestry5.internal.services.ResourceStreamer;
import org.apache.tapestry5.services.ContextAssetProtectionRule;
import org.apache.tapestry5.services.assets.AssetRequestHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.regex.Pattern;
@@ -32,6 +34,8 @@ import java.util.regex.Pattern;
*/
public class ContextAssetRequestHandler implements AssetRequestHandler
{
+ private final static Logger LOGGER = LoggerFactory.getLogger(ContextAssetRequestHandler.class);
+
private final ResourceStreamer resourceStreamer;
private final Resource rootContextResource;
@@ -52,18 +56,50 @@ public class ContextAssetRequestHandler implements AssetRequestHandler
{
ChecksumPath path = new ChecksumPath(resourceStreamer, null, extraPath);
- if (illegal.matcher(path.resourcePath).matches())
+ // Resolve the resource first, then check the protection rule against the
+ // fully-normalized path that will actually be loaded and streamed (Resource#getPath()).
+ final Resource resource;
+
+ try
+ {
+ resource = rootContextResource.forFile(path.resourcePath);
+ }
+ catch (IllegalStateException ex)
+ {
+ // The path normalized to a location above the context root (a "../" escape).
+ // Fail closed: treat it as blocked rather than surfacing it as a server error.
+ if (LOGGER.isWarnEnabled())
+ {
+ LOGGER.warn("Blocked request for context asset '" + path.resourcePath +
+ "': " + ex.getMessage());
+ }
+ return false;
+ }
+
+ final String resourcePath = resource.getPath();
+
+ if (illegal.matcher(resourcePath).matches())
{
+ if (LOGGER.isWarnEnabled())
+ {
+ LOGGER.warn("Blocked request for context asset '" + resourcePath +
+ "': the path resolves to a protected location (WEB-INF, META-INF or a template).");
+ }
return false;
}
// TAP5-2835: Allow custom protection rules mirroring ClasspathAssetProtectionRule
- if (contextAssetProtectionRule.block(path.resourcePath))
+ if (contextAssetProtectionRule.block(resourcePath))
{
+ if (LOGGER.isWarnEnabled())
+ {
+ LOGGER.warn("Blocked request for context asset '" + resourcePath +
+ "'. Contribute a new ContextAssetProtectionRule if you need this asset to be publicly accessible.");
+ }
return false;
}
- return path.stream(rootContextResource.forFile(path.resourcePath));
+ return path.stream(resource);
}
}