Hi, I am uploading assets to AEM's servlet, but before the file reaches servlet, I want to intercept it with a filter and scan it.
All details aside, I am unable to extract file from ServletRequest.
Here is my filter:
@Component
@SlingServletFilter(scope = {SlingServletFilterScope.REQUEST},
pattern = ".*createasset.html",
methods = {"POST"})
public class UploadFileFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;
//try to download multipart file...
chain.doFilter(request, slingResponse);
}
@Override
public void destroy() {
}
}
I can't read input stream directly in filter, because it has already been read.
I have tried solution from this post:
But request.getRequestParameterMap() always return empty map. Is it because I try to access parameters in a filter, not a servlet?
Do you know any working way to download multipart file in a filter?
Solved! Go to Solution.
Views
Replies
Total Likes
Views
Replies
Total Likes
As I stated in the other thread - Sling Has its own way in a Servlet to read the InputStream. That code works to read a file in a Sling Servlet. I have never tried to capture it within a filter. Lets see if other community members have.
Views
Replies
Total Likes
Since you have the same request object in the filter servlet, you should be able to access the inputstream, download it to a local file and scan it.
Are you not able to find the input stream in your filter ? what is the error thrown ?
Views
Replies
Total Likes
When I request.getInputStream() I get error saying that input data has already been read, which, as far as I know, is the expected behaviour in AEM servlets and filters.
Views
Replies
Total Likes
Views
Replies
Total Likes
Hi, thank you for answering!
Using the code you posted, I get and error inside CreateAssetServlet.java:
22.01.2019 11:54:39.041 *ERROR* [] [] [85.222.102.38 [1548158078795] POST /content/dam/catalogs/myfolder.createasset.html HTTP/1.1] org.apache.sling.engine.impl.SlingMainServlet service: Uncaught Problem handling the request
org.apache.commons.fileupload.FileItemStream$ItemSkippedException: null
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:896)
at java.io.InputStream.read(InputStream.java:101)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2146)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:2102)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2123)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:2078)
at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:721)
at com.day.cq.dam.core.impl.StreamedRequestParameter.<init>(StreamedRequestParameter.java:45)
at com.day.cq.dam.core.impl.servlet.CreateAssetServlet.doPost(CreateAssetServlet.java:247)
at org.apache.sling.api.servlets.SlingAllMethodsServlet.mayService(SlingAllMethodsServlet.java:146)
at org.apache.sling.api.servlets.SlingSafeMethodsServlet.service(SlingSafeMethodsServlet.java:342)
at org.apache.sling.api.servlets.SlingSafeMethodsServlet.service(SlingSafeMethodsServlet.java:374)
at org.apache.sling.engine.impl.request.RequestData.service(RequestData.java:552)
at org.apache.sling.engine.impl.filter.SlingComponentFilterChain.render(SlingComponentFilterChain.java:44)
This is my code in my filter:
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (!(request instanceof SlingHttpServletRequest)
|| !(response instanceof SlingHttpServletResponse)) {
chain.doFilter(request, response);
return;
}
final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
if (!StringUtils.equals("POST", slingRequest.getMethod())
|| !isCreateAssetRequest(slingRequest)) {
chain.doFilter(request, response);
return;
}
Iterator<Part> partsIter = (Iterator) request.getAttribute("request-parts-iterator");
if ((partsIter == null) || !partsIter.hasNext()) {
chain.doFilter(request, response);
return;
}
List<Part> parts = new ArrayList<>();
while (partsIter.hasNext()) {
Part part = partsIter.next();
String tmpDir = System.getProperty(TEMPORARY_DIRECTORY);
File tmpFile = new File(tmpDir + "/temp-upload-asset.tmp");
FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(part.getInputStream(), baos);
fileOutputStream.write(baos.toByteArray());
fileOutputStream.close();
parts.add(part);
}
request.setAttribute("request-parts-iterator", parts.iterator());
chain.doFilter(request, response);
}
Views
Replies
Total Likes
FileItemStream$ItemSkippedException would happen if you try to use the stream outside the context/block where it was initially read/opened.
I'll test the code later & revert..
Views
Replies
Total Likes
Below is the code that worked for me. I've highlighted couple of changes that I did in DecryptAssetsFilter shared in that link:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!(request instanceof SlingHttpServletRequest) || !(response instanceof SlingHttpServletResponse)) {
chain.doFilter(request, response);
return;
}
final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
if (!StringUtils.equals("POST", slingRequest.getMethod()) || !isCreateAssetRequest(slingRequest)) {
chain.doFilter(request, response);
return;
}
log.info("Decoding create asset request - " + slingRequest.getRequestURI());
List parts = (ArrayList) slingRequest.getParts();
if ((parts == null) || parts.size() == 0) {
chain.doFilter(request, response);
return;
}
List<Part> otherParts = new ArrayList<Part>();
Part part = null;
for (int i = 0; i < parts.size() - 1; i++) {
part = (Part) parts.get(i);
otherParts.add(new EAEMDecryptRequestPart(part));
}
chain.doFilter(request, response);
}
private boolean isCreateAssetRequest(SlingHttpServletRequest slingRequest) {
String[] selectors = slingRequest.getRequestPathInfo().getSelectors();
if (ArrayUtils.isEmpty(selectors) || (selectors.length > 1)) {
return false;
}
return selectors[0].equals("createasset");
}
public void destroy() {
}
private static class EAEMDecryptRequestPart implements Part {
private final Part part;
private final InputStream inputStream;
private static final String TEMP_PREFIX = "eaem_decrypt_";
public EAEMDecryptRequestPart(Part part) throws IOException {
this.part = part;
if (!isFilePart(part)) {
this.inputStream = new ByteArrayInputStream(IOUtils.toByteArray(part.getInputStream()));
} else {
this.inputStream = this.getDecodedStream(part);
}
}
private InputStream getDecodedStream(Part part) throws IOException {
File tmpFile = File.createTempFile(TEMP_PREFIX, ".tmp");
// byte[] decoded =
// Base64.getDecoder().decode(IOUtils.toByteArray(part.getInputStream())); //use decode, if the input file is encoded
byte[] decoded = IOUtils.toByteArray(part.getInputStream());
FileOutputStream decodedStream = new FileOutputStream(tmpFile);
decodedStream.write(decoded);
decodedStream.close();
return new FileInputStream(tmpFile);
}
private boolean isFilePart(Part part) {
return StringUtils.isNotEmpty(part.getName());
}
public InputStream getInputStream() throws IOException {
return inputStream;
}
public String getContentType() {
return part.getContentType();
}
public String getName() {
return part.getName();
}
public long getSize() {
return 0;
}
public void write(String s) throws IOException {
throw new UnsupportedOperationException(
"Writing parts directly to disk is not supported by this implementation, use getInputStream instead");
}
public void delete() throws IOException {
}
public String getHeader(String headerName) {
return part.getHeader(headerName);
}
public Collection<String> getHeaders(String headerName) {
return part.getHeaders(headerName);
}
public Collection<String> getHeaderNames() {
return part.getHeaderNames();
}
public String getSubmittedFileName() {
return part.getName();
}
private <T> Collection<T> toCollection(Iterator<T> i) {
if (i == null) {
return Collections.emptyList();
} else {
List<T> c = new ArrayList<T>();
while (i.hasNext()) {
c.add(i.next());
}
return c;
}
}
}
}
Views
Replies
Total Likes
Hello, unfortunatelly my SlingHttpServletRequest does not have getParts() method. Mine comes from com.adobe.aem:uber-jar:apis:6.3.3
Anyway, I have tried the code that you previously posted from:
https://experience-aem.blogspot.com/2018/11/aem-6420-file-de…
And it seems to work now, except I cant extract code from getDecodedStream method, or else it will throw, the exception I have described above, inside CreateAsserServlet.
Views
Replies
Total Likes
Are you not able to get the byte array/write stream to a file? Process the stream as byte array or as a file, do the scan and return the results accordingly.
getParts() is available in AEM 6.3. You could still use other ways to get the parts.
SlingHttpServletRequest ("The Adobe AEM Quickstart and Web Application.")
authenticate, changeSessionId, getAuthType, getContextPath, getCookies, getDateHeader, getHeader, getHeaderNames, getHeaders, getIntHeader, getMethod, getPart, getParts, getPathInfo, getPathTranslated, getQueryString, getRemoteUser, getRequestedSessionId, getRequestURI, getRequestURL, getServletPath, getSession, getSession, getUserPrincipal, isRequestedSessionIdFromCookie, isRequestedSessionIdFromUrl, isRequestedSessionIdFromURL, isRequestedSessionIdValid, isUserInRole, login, logout, upgrade
Views
Replies
Total Likes
Views
Likes
Replies