Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java filter failing to set response headers

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)?

like image 696
Sol Slay Avatar asked Nov 19 '12 20:11

Sol Slay


2 Answers

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:

  • Set the headers after the call to chain.doFilter:

.

...

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).

  • make sure that your filter is the last to be executed after the Servlet is executed, i.e. it should be the first servlet Filter declared as explained here:

enter image description here

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.

like image 80
Tony Rad Avatar answered Nov 17 '22 20:11

Tony Rad


Assuming you use a response wrapper as described here by others, the whole secret is when to call getWriter() on the original response! That's because the response object ignores all headers added AFTER you asked for a writer!

So, make sure you add all your headers Before you call getWriter(). Here is my recommended sequence for doFilter():

  1. Create a response wrapper

  2. chain.doFilter (origRequest, wrapper);

  3. Assign all required headers to the original (!) Response

  4. Get writer from original response

  5. Copy the wrapper's content to this writer

like image 36
Adi Degani Avatar answered Nov 17 '22 19:11

Adi Degani