I am trying to create a Java "Filter" which detects a custom HTTP Request Header, and inserts response headers so that the file will download automatically. The response header that is most important for this is the "Content-Type = Attachment" response header. I have created an HTTP request object that inserts the custom Header:
function myHttpObject(filePath){
function makeHttpObject() {
return new XMLHttpRequest();
}
var request = makeHttpObject();
request.open("GET", filePath, false);
request.setRequestHeader("X-Wria-Download", "PDFdownload");
request.send(null);
window.open(filePath);
console.log(request.getAllResponseHeaders());
}
This will insert the X-Wria-Download header into the request. Then I have a Java Filter which looks for that request header and should set the response header to "Content-Type=attachment"
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class Contenttypefilter implements Filter {
protected FilterConfig filterConfig;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
//noop
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//get the headers we placed in the request
//based on those request headers, set some response headers
if(req.getHeader("X-Wria-Download") != null){
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", "attachment; filename=success.pdf");
}
chain.doFilter(req,res);
}
}
And then of course the web.xml has the code to include the Filter on all jsp files.
The thing that is baffling me, is that the header is being set on the response file, but it is not downloading as it should. If I put the res.setHeader("Content-Disposition", "attachment; filename=success.pdf"); line outside the "if" statement, then it will work, but it will apply the download behavior to all JSP's which I don't want.
Why is it applying the content-disposition but not working when I have the res.setHeader in the if statement; and then working when it is outside the if statement? Any ideas for how I can get the desired behavior (only applying content disposition to jsp's that I have applied a custom request header to)?
I think your issue is related to the Filter order of execution of your Web Context
, i.e. some filters, in you web context, executes after your filter and override the header.
The Servlet Filter is an implementation of the Chain of Responsibility pattern
So you may try to:
.
...
chain.doFilter(req,res);
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//get the headers we placed in the request
//based on those request headers, set some response headers
if(req.getHeader("X-Wria-Download") != null){
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", "attachment; filename=success.pdf");
}
In this way your code will be executed after that the Servlet is called and, as explained below, if your filter is the first declared in web.xml, then the setHeader
code will be the last executed (see image below).
As you can see Filter1 (the first declared in web.xml) is the first one executed before the servlet is executed and the last one executed after the servlet is executed. So if you want to be sure to be the last Filter setting the header then declare it as Filter1.
The order of execution is determined by the order of declaration in your Deployment Descriptor (web.xml):
Servlet spec (section 6.2.4):
"The order the container uses in building the chain of filters to be applied for a particular request URI is as follows:
"1. First, the matching filter mappings in the same order that these elements appear in the deployment descriptor.
"2. Next, the matching filter mappings in the same order that these elements appear in the deployment descriptor."
So to be sure simply declare it as the first filter in your web.xml
. In this way it will be the very last filter setting the header. And, of course, set the header in your code after calling chain.doFilter
, as already said.