I use <mvc:resources /> to host Asciidoctor-generated HTML content in few webapps. Those webapps are deployed to different contexts on an Apache Tomcat 8.5 instance. The documentation must be able to reference the entire URL for documentation purpose. Since this is statically generated, I cannot inject the webapp context URL, for obvious reasons. Those HTML files contain a {contextUrl} placeholder and with the following snippet the interpolation happens.

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.resource.ResourceTransformer;
import org.springframework.web.servlet.resource.ResourceTransformerChain;
import org.springframework.web.servlet.resource.TransformedResource;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

public class ContextUrlResourceTransformer implements ResourceTransformer {

    private static final Logger logger = LoggerFactory
            .getLogger(ContextUrlResourceTransformer.class);

    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    private final Collection<String> extensions;

    public ContextUrlResourceTransformer() {
        this.extensions = new HashSet<>();
        extensions.add("html");
        extensions.add("yaml");
    }

    @Override
    public Resource transform(HttpServletRequest request, Resource resource,
            ResourceTransformerChain transformerChain) throws IOException {

        resource = transformerChain.transform(request, resource);

        String filename = resource.getFilename();
        if (!extensions.contains(StringUtils.getFilenameExtension(filename))) {
            return resource;
        }

        logger.trace("Transforming: {}", resource);

        byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
        String content = new String(bytes, DEFAULT_CHARSET);

        if (!content.contains("{contextUrl}")) {
            logger.trace("No {contextUrl} placeholders found.");
            return resource;
        }

        ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromContextPath(request);

        String contextUrl = builder.build().toUriString();
        content = content.replace("{contextUrl}", contextUrl);

        return new TransformedResource(resource, content.getBytes(DEFAULT_CHARSET));
    }
````

followed by:
```xml
    <mvc:resources mapping="/**" location="/" cache-period="86400">
        <mvc:resource-chain resource-cache="true">
            <mvc:transformers>
                <beans:bean
                    class="...ContextUrlResourceTransformer" />
            </mvc:transformers>
        </mvc:resource-chain>
    </mvc:resources>

This is conceptually similar to the CssLinkResourceTransformer, but for suited for general text formats. Please add such a resource tranformer upstream, I guess many would require something like this. Feel free to reuse and modify my code for upstream.

I am on Spring Framework 5.3.14.

Comment From: bclozel

Hello @michael-o

While conceptually similar to CssLinkResourceTransformer, this is a rather different use case. CSS resource transformation is well defined and targets a common use case for web applications.

What you're describing here and in #27931 sound like the following use case: hosting static HTML files and partially implementing templating engine features. For this, we'd rather advise our community to use a proper templating engine or a processor in the static html generator that supports this case.

We're happy to support custom implementations through this infrastructure, but I don't think we're going to officially support this implementation in Spring Framework. I'm declining this issue and #27931 as a result, I hope you'll understand our position. Thanks for your contribution!

Comment From: michael-o

@bclozel I do understand your position, but a static site generator won't solve a runtime problem for me and a template engine is overkill for such a case. Sad, then I will keep those private. I am still surprised that I am the only one requiring this.

Comment From: bclozel

We can always reconsider if we get more demand for this. Note that manually dealing with substitutions in HTML content exposes you to the usual templating engine challenges: encoding, malicious injection, etc.