You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by re...@apache.org on 2026/08/10 13:12:45 UTC
(sling-org-apache-sling-resourceresolver) 01/01: SLING-13288: logging of 'invalid' vanity paths - prototype
This is an automated email from the ASF dual-hosted git repository.
reschke pushed a commit to branch SLING-13288
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git
commit 02a24765edcffd3dcc2a2be7b2bbe3a92d65a977
Author: Julian Reschke <ju...@gmx.de>
AuthorDate: Mon Aug 10 14:12:16 2026 +0100
SLING-13288: logging of 'invalid' vanity paths - prototype
---
.../impl/mapping/VanityPathHandler.java | 52 +++++++++++++++++++---
.../impl/mapping/VanityPathMapEntriesTest.java | 30 ++++++++++---
2 files changed, 70 insertions(+), 12 deletions(-)
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathHandler.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathHandler.java
index bd96990d..c69fa0f0 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathHandler.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathHandler.java
@@ -44,6 +44,7 @@ import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.resource.path.Path;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -79,6 +80,9 @@ public class VanityPathHandler {
private final Logger log = LoggerFactory.getLogger(VanityPathHandler.class);
+ // keep track of some dubious vanityPaths for diagnostics (thus size-limited)
+ private static final int MAX_REPORT_DUBIOUS_VANITY_PATHS = 50;
+
private final MapConfigurationProvider factory;
private byte[] vanityBloomFilter;
@@ -193,10 +197,12 @@ public class VanityPathHandler {
try (ResourceResolver resolver =
factory.getServiceResourceResolver(factory.getServiceUserAuthenticationInfo("mapping"))) {
+ List<String> dubiousPaths = new ArrayList<>();
+
StopWatch sw = StopWatch.createStarted();
log.debug("vanity path initialization - start");
- vanityTargets = loadVanityPaths(resolver);
+ vanityTargets = loadVanityPaths(resolver, dubiousPaths);
// process pending events
VanityPathHandler.this.drain.accept("draining vanity path event queue (during cache initialization)");
@@ -228,7 +234,7 @@ public class VanityPathHandler {
boolean updateTheCache = isAllVanityPathEntriesCached()
|| vanityCounter.longValue() < this.factory.getMaxCachedVanityPathEntries();
- return null != loadVanityPath(resource, resolveMapsMap, vanityTargets, updateTheCache, true);
+ return null != loadVanityPath(resource, resolveMapsMap, vanityTargets, updateTheCache, true, new ArrayList<>());
}
private String getMapEntryRedirect(final MapEntry mapEntry) {
@@ -410,11 +416,11 @@ public class VanityPathHandler {
&& (this.factory.isMaxCachedVanityPathEntriesStartup()
|| this.isAllVanityPathEntriesCached()
|| vanityCounter.longValue() < this.factory.getMaxCachedVanityPathEntries())) {
- loadVanityPath(resource, resolveMapsMap, vanityTargets, true, true);
+ loadVanityPath(resource, resolveMapsMap, vanityTargets, true, true, new ArrayList<>());
entryMap = resolveMapsMap;
} else {
final Map<String, List<String>> targetPaths = new HashMap<>();
- loadVanityPath(resource, entryMap, targetPaths, true, false);
+ loadVanityPath(resource, entryMap, targetPaths, true, false, new ArrayList<>());
}
}
}
@@ -461,11 +467,27 @@ public class VanityPathHandler {
return true;
}
+ private String diagnoseDubiousValidVanityPath(String resource, String path) {
+ String reason = "";
+ if (path == null) {
+ reason = "null path";
+ } else if (!path.startsWith("/")) {
+ reason = "not an absolute path";
+ } else if (path.contains("//")) {
+ reason = "empty path segment";
+ }
+
+ return reason.isEmpty() ? "" : String.format("Dubious vanity on '%s', value '%s': %s", resource, path, reason);
+ }
+
/**
* Load vanity paths - search for all nodes (except under /jcr:system)
* having a sling:vanityPath property
+ * <p>
+ * Also collect diagnostics about vanity paths that appear to be broken.
*/
- private Map<String, List<String>> loadVanityPaths(ResourceResolver resolver) {
+ private Map<String, List<String>> loadVanityPaths(
+ @NotNull ResourceResolver resolver, @NotNull List<String> dubiousVanityPaths) {
final Map<String, List<String>> targetPaths = new ConcurrentHashMap<>();
final String baseQueryString =
"SELECT [sling:vanityPath], [sling:redirect], [sling:redirectStatus]" + " FROM [nt:base]" + " WHERE "
@@ -496,7 +518,7 @@ public class VanityPathHandler {
countInScope += 1;
final boolean addToCache = isAllVanityPathEntriesCached()
|| vanityCounter.longValue() < this.factory.getMaxCachedVanityPathEntries();
- loadVanityPath(resource, resolveMapsMap, targetPaths, addToCache, true);
+ loadVanityPath(resource, resolveMapsMap, targetPaths, addToCache, true, dubiousVanityPaths);
}
}
@@ -521,6 +543,14 @@ public class VanityPathHandler {
}
}
+ // warn about dubious vanity paths
+
+ if (dubiousVanityPaths.size() >= MAX_REPORT_DUBIOUS_VANITY_PATHS) {
+ log.warn("There are {} dubious vanity paths; excerpt: {}", dubiousVanityPaths.size(), dubiousVanityPaths);
+ } else if (!dubiousVanityPaths.isEmpty()) {
+ log.warn("There are {} dubious vanity paths: {}", dubiousVanityPaths.size(), dubiousVanityPaths);
+ }
+
this.vanityResourcesOnStartup.set(count);
return targetPaths;
@@ -543,7 +573,8 @@ public class VanityPathHandler {
final Map<String, List<MapEntry>> entryMap,
final Map<String, List<String>> targetPaths,
boolean addToCache,
- boolean updateCounter) {
+ boolean updateCounter,
+ final List<String> dubiousVanityPaths) {
if (!isValidVanityPath(resource.getPath())) {
return null;
@@ -561,6 +592,13 @@ public class VanityPathHandler {
}
for (final String pVanityPath : pVanityPaths) {
+
+ // collect vanity path values that seem to be broken
+ final String diagnostics = diagnoseDubiousValidVanityPath(resource.getPath(), pVanityPath);
+ if (!diagnostics.isEmpty() && dubiousVanityPaths.size() > MAX_REPORT_DUBIOUS_VANITY_PATHS) {
+ dubiousVanityPaths.add(diagnostics);
+ }
+
final String[] result = this.getVanityPathDefinition(resource.getPath(), pVanityPath);
if (result != null) {
// redirect target is the node providing the sling:vanityPath
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathMapEntriesTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathMapEntriesTest.java
index 05706e03..32f7e2c3 100644
--- a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathMapEntriesTest.java
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/VanityPathMapEntriesTest.java
@@ -229,11 +229,12 @@ public class VanityPathMapEntriesTest extends AbstractMappingMapEntriesTest {
method.invoke(mapEntries, ctx, bool);
}
- private static void loadVanityPaths(MapEntries mapEntries, ResourceResolver resourceResolver)
+ private static void loadVanityPaths(MapEntries mapEntries, ResourceResolver resourceResolver, List<String> dubious)
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
- Method method = VanityPathHandler.class.getDeclaredMethod("loadVanityPaths", ResourceResolver.class);
+ Method method =
+ VanityPathHandler.class.getDeclaredMethod("loadVanityPaths", ResourceResolver.class, List.class);
method.setAccessible(true);
- method.invoke(mapEntries.vph, resourceResolver);
+ method.invoke(mapEntries.vph, resourceResolver, dubious);
}
@Override
@@ -267,6 +268,25 @@ public class VanityPathMapEntriesTest extends AbstractMappingMapEntriesTest {
assertNotNull(vanityMap.get("/" + containerName + "/" + oneMore));
}
+ @Test
+ public void test_simple_dubious_vanity_path() {
+ String vanityPath = "";
+ String containerName = "foo";
+ String childName = "child";
+ String oneMore = "one-more";
+ prepareMapEntriesForVanityPath(false, false, containerName, childName, oneMore, vanityPath);
+
+ initializeVanityPaths();
+
+ Map<String, List<String>> vanityMap = mapEntries.getVanityPathMappings();
+ assertNotNull(vanityMap);
+ assertEquals(
+ "/" + vanityPath,
+ vanityMap.get("/" + containerName + "/" + childName).get(0));
+ assertEquals(2, vanityMap.size());
+ assertNotNull(vanityMap.get("/" + containerName + "/" + oneMore));
+ }
+
// see SLING-12620
@Test
public void test_simple_vanity_path_support_with_null_parent() {
@@ -1046,7 +1066,7 @@ public class VanityPathMapEntriesTest extends AbstractMappingMapEntriesTest {
}
});
- loadVanityPaths(mapEntries, resourceResolver);
+ loadVanityPaths(mapEntries, resourceResolver, new ArrayList<>());
assertEquals(2, getVanityCounter(mapEntries).longValue());
}
@@ -1068,7 +1088,7 @@ public class VanityPathMapEntriesTest extends AbstractMappingMapEntriesTest {
}
});
- loadVanityPaths(mapEntries, resourceResolver);
+ loadVanityPaths(mapEntries, resourceResolver, new ArrayList<>());
assertEquals(2, getVanityCounter(mapEntries).longValue());
}