Skip to content

Instantly share code, notes, and snippets.

@cpilsworth
Last active May 11, 2023 16:19
Show Gist options
  • Save cpilsworth/cb006177cbc51585708dc414bc7d668e to your computer and use it in GitHub Desktop.
Save cpilsworth/cb006177cbc51585708dc414bc7d668e to your computer and use it in GitHub Desktop.
Cloud Storage Direct Asset Download URL generator
package com.chrisp.rde.core.servlets;
import org.apache.commons.lang3.StringUtils;
import org.apache.jackrabbit.api.binary.BinaryDownload;
import org.apache.jackrabbit.api.binary.BinaryDownloadOptions;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.servlets.OptingServlet;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletResourceTypes;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Binary;
import javax.jcr.Node;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component(service = {Servlet.class})
@SlingServletResourceTypes(
resourceTypes = "dam/Asset",
methods = "GET",
selectors = "woi"
)
/**
* Returns a redirect to the cloud storage of the underlying original asset when `woi` selector added.
* e.g. https://author-p31359-e934772.adobeaemcloud.com/content/dam/xxxx/sample.jpg.woi/image.png
*/
public class ImageSignedUrlRedirectServlet extends SlingSafeMethodsServlet implements OptingServlet {
private static final Logger log = LoggerFactory.getLogger(ImageSignedUrlRedirectServlet.class);
public static final String DEFAULT_FILENAME_PATTERN = "(image|img)\\.(.+)";
private final Pattern lastSuffixPattern = Pattern.compile(DEFAULT_FILENAME_PATTERN);
private String cacheHeader;
/**
* Only accept requests that.
* - Are not null
* - Have a suffix
* - Whose first suffix segment is a registered transform name
* - Whose last suffix matches the image file name pattern
*
* @param request SlingRequest object
* @return true if the Servlet should handle the request
*/
@Override
public final boolean accepts(final SlingHttpServletRequest request) {
if (request == null) {
return false;
}
final String suffix = request.getRequestPathInfo().getSuffix();
if (StringUtils.isBlank(suffix)) {
return false;
}
final String lastSuffix = PathInfoUtil.getLastSuffixSegment(request);
final Matcher matcher = lastSuffixPattern.matcher(lastSuffix);
return matcher.matches();
}
@Override
protected final void doGet(final SlingHttpServletRequest request, final SlingHttpServletResponse response) throws
ServletException, IOException {
final Resource resource = request.getResource();
if (!isAsset(resource)) {
response.setStatus(404);
return;
}
try {
Resource rendition = resource.getChild("jcr:content/renditions/original");
Node ntFile = rendition.adaptTo(Node.class);
Node ntResource = ntFile.getNode("jcr:content");
Binary binary = ntResource.getProperty("jcr:data").getBinary();
if (binary instanceof BinaryDownload) {
BinaryDownload binaryDownload = (BinaryDownload) binary;
BinaryDownloadOptions.BinaryDownloadOptionsBuilder builder = BinaryDownloadOptions.builder()
.withFileName(ntFile.getName())
.withMediaType(ntResource.getProperty("jcr:mimeType").getString());
if (ntResource.hasProperty("jcr:encoding")) {
builder.withCharacterEncoding(ntResource.getProperty("jcr:encoding").getString());
}
// if you need to prevent the browser from potentially executing the response
// (for example js, flash, html), you can enforce a download with this option
// builder.withDispositionTypeAttachment();
final URI uri = binaryDownload.getURI(builder.build());
log.info("redirect: {}", uri);
response.sendRedirect(uri.toString());
}
} catch (Throwable e) {
log.error("Exception fetching signed url", e);
response.setStatus(500);
}
}
public static boolean isAsset(Resource resource) {
return null != resource && "dam:Asset".equals(resource.getResourceType());
}
protected void activate(Map<String, Object> properties) {
// this.cacheHeader = properties.get("cacheControl").toString();
}
}
/*
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2013 Adobe
* %%
* Licensed 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.
* #L%
*/
package com.chrisp.rde.core.servlets;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.request.RequestPathInfo;
import org.osgi.annotation.versioning.ProviderType;
/**
* Util class to help with parsing URIs and PathInfos.
*/
@ProviderType
public final class PathInfoUtil {
private PathInfoUtil() {
}
/**
* Get a named Query Parameter from the Request.
*
* @param request
* @param key
* @return
*/
public static String getQueryParam(final SlingHttpServletRequest request, final String key) {
return request.getParameter(key);
}
/**
* Get a named Query Parameter from the Request.
*
* @param request
* @param key
* @param dfault Value to return if Query Parameter value is blank
* @return
*/
public static String getQueryParam(final SlingHttpServletRequest request, final String key, final String dfault) {
String tmp = request.getParameter(key);
if (StringUtils.isBlank(tmp)) {
return dfault;
}
return tmp;
}
/**
* Gets the selector at the supplied index.
* <p>
* Given: /content/page.selA.selB.html
* <br>
* getSelector(request, 0) // --&gt; "selA"
* <br>
* getSelector(request, 1) // --&gt; "selB"
*
* @param request
* @param index
* @return null if selector cannot be found at the specified index
*/
public static String getSelector(final SlingHttpServletRequest request, final int index) {
return getSelector(request, index, null);
}
/**
* <p>
* Gets the selector at the supplied index, using a default if
* there is no selector at that index.
* </p><p>
* Given: /content/page.selA.html
* <br>
* getSelector(request, 0, "default") // --&gt; "selA"
* <br>
* getSelector(request, 1, "default2") // --&gt; "default2"
* </p>
*
* @param request the request
* @param index the index
* @param defaultValue the default value
* @return the selector value or the default
*/
public static String getSelector(final SlingHttpServletRequest request,
final int index, final String defaultValue) {
RequestPathInfo pathInfo = request.getRequestPathInfo();
if (pathInfo == null) {
return null;
}
String[] selectors = pathInfo.getSelectors();
if (selectors == null) {
return null;
}
if (index >= 0 && index < selectors.length) {
return selectors[index];
} else {
return defaultValue;
}
}
/**
* Gets the suffixes as an array; each segment is the text between the /'s.
*
* /segment-0/segment-1/segment-2
*
* @param request
* @return and array of the suffix segments or empty array
*/
public static String[] getSuffixSegments(final SlingHttpServletRequest request) {
RequestPathInfo pathInfo = request.getRequestPathInfo();
if (pathInfo == null || pathInfo.getSuffix() == null) {
return new String[] {};
}
return StringUtils.split(pathInfo.getSuffix(), '/');
}
/**
* <p>
* Gets the suffix segment at the supplied index.
* </p><p>
* Given: /content/page.html/suffixA/suffixB
* <br>
* getSuffixSegment(request, 0) // --&gt; "suffixA"
* <br>
* getSuffixSegment(request, 1) // --&gt; "suffixB"
* </p>
*
* @param request
* @param index
* @return null if suffix segment cannot be found at the specified index
*/
public static String getSuffixSegment(final SlingHttpServletRequest request, int index) {
final String[] suffixes = getSuffixSegments(request);
if (index >= 0 && index < suffixes.length) {
return suffixes[index];
} else {
return null;
}
}
/**
* Get the entire suffix.
*
* @param request
* @return Returns null if Request's pathInfo or Suffix is null
*/
public static String getSuffix(final SlingHttpServletRequest request) {
RequestPathInfo pathInfo = request.getRequestPathInfo();
if (pathInfo == null || pathInfo.getSuffix() == null) {
return null;
}
return pathInfo.getSuffix();
}
/**
* Get the first suffix segment.
*
* @param request
* @return the String in the first suffix segment or null if no suffix
*/
public static String getFirstSuffixSegment(final SlingHttpServletRequest request) {
return getSuffixSegment(request, 0);
}
/**
* Gets the last suffix segment.
*
* @param request
* @return the String in the last suffix segment or null if no suffix
*/
public static String getLastSuffixSegment(final SlingHttpServletRequest request) {
final String[] suffixes = getSuffixSegments(request);
if (suffixes.length < 1) {
return null;
} else {
return suffixes[suffixes.length - 1];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment