All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sling.scripting.sightly.engine.ResourceResolution Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*******************************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package org.apache.sling.scripting.sightly.engine;

import javax.servlet.Servlet;

import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.jetbrains.annotations.NotNull;

/**
 * Utility class which is used by the HTL engine & extensions to resolve resources.
 */
public final class ResourceResolution {

    /**
     * Maximum number of iterations that can be performed when searching for a resource in
     * the resource superType chain
     */
    private static final int RECURSION_LIMIT = 100;

    /**
     * 

* Resolves a resource from the search path relative to the {@code base} resource by traversing the {@code sling:resourceSuperType} * chain. *

*

* Since this method will traverse the {@code sling:resourceSuperType} chain, the {@code ResourceResolver} used for resolving the * {@code base} resource should be able to read the super type resources. *

* * @param base the base resource from which to start the lookup * @param path the relative path to the resource; if the path is absolute the {@code Resource} identified by this path will be * returned * @return the resource identified by the relative {@code path} or {@code null} if no resource was found * @throws java.lang.UnsupportedOperationException if the resource is not in the resource resolver's search path * @throws java.lang.IllegalStateException if the number of steps necessary to search for the resource on the resource * superType chain has reached the maximum limit * @see ResourceResolver#getSearchPath() */ public static Resource getResourceFromSearchPath(Resource base, String path) { if (base == null || path == null) { return null; } if (path.startsWith("/")) { Resource resource = getScriptResource(base.getResourceResolver(), path); if (resource != null) { return searchPathChecked(resource); } } Resource internalBase; if ("nt:file".equals(base.getResourceType()) || base.adaptTo(Servlet.class) != null) { internalBase = base.getParent(); } else { internalBase = base; } return resolveComponentInternal(internalBase, path); } /** *

* Resolves the resource accessed by a {@code request}. Since the {@code request} can use an anonymous {@code ResourceResolver}, the * passed {@code resolver} parameter should have read access rights to resources from the search path. *

* * @param resolver a {@link ResourceResolver} that has read access rights to resources from the search path * @param request the request * @return the resource identified by the {@code request} or {@code null} if no resource was found */ public static Resource getResourceForRequest(ResourceResolver resolver, SlingHttpServletRequest request) { if (resolver == null || request == null) { return null; } String resourceType = request.getResource().getResourceType(); if (StringUtils.isNotEmpty(resourceType)) { return getScriptResource(resolver, resourceType); } return null; } /** * Resolve the resource in the specified component * * @param base The resource for the component. It can be null if path is absolute * @param path the path to the resource * @return the retrieved resource or null if no resource was found * @throws java.lang.UnsupportedOperationException if the resource is not in the resource resolver's search path * @throws java.lang.IllegalStateException if more than {@link ResourceResolution#RECURSION_LIMIT} steps were * necessary to search for the resource on the resource superType chain */ private static Resource resolveComponentInternal(Resource base, String path) { if (base == null || path == null) { throw new NullPointerException("Arguments cannot be null"); } Resource resource = recursiveResolution(base, path); if (resource == null) { resource = locateInSearchPath(base.getResourceResolver(), path); } return resource != null ? searchPathChecked(resource) : null; } private static Resource recursiveResolution(Resource base, String path) { ResourceResolver resolver = base.getResourceResolver(); for (int iteration = 0; iteration < RECURSION_LIMIT; iteration++) { Resource resource = null; if (path.startsWith("/")) { resource = getScriptResource(resolver, path); } else { String normalizedPath = ResourceUtil.normalize(base.getPath() + "/" + path); if (normalizedPath != null) { resource = getScriptResource(resolver, normalizedPath); } } if (resource != null) { return resource; } base = findSuperComponent(base); if (base == null) { return null; } } //at this point we have reached recursion limit throw new IllegalStateException("Searching for resource in component chain took more than " + RECURSION_LIMIT + " steps"); } private static Resource locateInSearchPath(ResourceResolver resourceResolver, String path) { for (String searchPath : resourceResolver.getSearchPath()) { String fullPath = ResourceUtil.normalize(searchPath + path); if (fullPath != null) { Resource resource = resourceResolver.getResource(fullPath); if (resource != null && resource.getPath().startsWith(searchPath)) { //prevent path traversal attack return resource; } } } return null; } private static boolean isInSearchPath(Resource resource) { String resourcePath = resource.getPath(); ResourceResolver resolver = resource.getResourceResolver(); for (String path : resolver.getSearchPath()) { if (resourcePath.startsWith(path)) { return true; } } return false; } private static Resource findSuperComponent(Resource base) { ResourceResolver resolver = base.getResourceResolver(); String superType = resolver.getParentResourceType(base); if (superType == null) { return null; } return getScriptResource(resolver, superType); } private static Resource searchPathChecked(Resource resource) { if (!isInSearchPath(resource)) { throw new UnsupportedOperationException("Access to resource " + resource.getPath() + " is denied, since the resource does not" + " reside on the search path"); } return resource; } private static Resource getScriptResource(@NotNull ResourceResolver resourceResolver, @NotNull String path) { if (path.startsWith("/")) { return resourceResolver.getResource(path); } else { for (String searchPath : resourceResolver.getSearchPath()) { String resourcePath = ResourceUtil.normalize(searchPath + path); if (resourcePath != null) { Resource resource = resourceResolver.getResource(resourcePath); if (resource != null) { return resource; } } } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy