40

I have a situation where one of the response headers Content-Disposition has to be removed. So I thought of writing a servlet filter to do this. But I realized that the HttpServletResponse has only a setHeader() method but no method to remove it. How can I do this?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Daniel
  • 403
  • 1
  • 4
  • 4

4 Answers4

57

You can't delete headers afterwards by the standard Servlet API. Your best bet is to just prevent the header from being set. You can do this by creating a Filter which replaces the ServletResponse with a custom HttpServletResponseWrapper implementation which skips the setHeader()'s job whenever the header name is Content-Disposition.

Basically:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
        public void setHeader(String name, String value) {
            if (!name.equalsIgnoreCase("Content-Disposition")) {
                super.setHeader(name, value);
            }
        }
    });
}

Just map that filter on the URL-pattern of interest to get it to run.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • This method fails when trying to prevent "Server" header. I think it is being set by container. – itsraja Jul 02 '13 at 07:02
  • 1
    @itsraja: Indeed. You need to control it in server's own config. The filter presented above only controls the headers set by webapp during the whole process behind `chain.doFilter()`. It does not control the headers set before or after that. Which makes quite sense, by the way :) – BalusC Jul 02 '13 at 10:13
  • am trying to reset "Server" to some value for websphere server community edition, and yet to nail how to do it. – itsraja Jul 02 '13 at 10:53
  • "Server" header can not be removed but can be updated. In websphere /var/config/config.xml, , add an attribute "server" with desired value. For Tomcat, server.xml, Connector tag "server" attribute. – itsraja Jul 03 '13 at 05:09
  • 7
    One should probably override `addHeader(String name, String value)` too. – Milanka Feb 24 '16 at 13:01
  • 1
    @Milanka: There are 6 of them. Just override whatever's being used in your codebase. – BalusC Feb 24 '16 at 13:07
  • 1
    Worked for me. Just had to make sure, that this filter was run first. In my case in the webSecurityConfigurationAdapter in the configure method as first filter: httpSecurity.addFilterBefore(HeaderUnsetFilter(), HeaderWriterFilter.class); – Recek Jun 22 '17 at 11:09
  • @BalusC This filter removes header only if success response and doesn't remove the headers if error response. – Akshay Bhat 'AB' Sep 30 '19 at 15:40
  • @Akshay: that's only the case if you don't let the filter listen on FORWARD dispatcher. That's where among others the error pages run through. – BalusC Sep 30 '19 at 19:15
  • @BalusC Any way to remove Response headers in case of error response / exception? – Akshay Bhat 'AB' Oct 01 '19 at 05:42
  • @Akshay: as said, also let the filter listen on FORWARD dispatcher. – BalusC Oct 01 '19 at 10:55
4

This may not be Servlet API compliant, but setting the value to null works on GlassFish 4 and probably on Tomcat too as that is what is underneath GlassFish.

We really need to update the Servlet API specification to either add a method to allow removing headers or to officially support using setHeader with a null value.

An example where this is important is if you use a security constraint (SSL/TLS) on your web application then static resource caching is complicated by the fact that the container will automatically add headers to prevent caching (you can try to disable with disableProxyCaching and securePagesWithPragma on Tomcat/GlassFish). I've already got a servlet filter for cache control that works great for non-secure content so I would like to keep cache control all in one place and simply set Prama and Cache-Control to null to clear any container added headers.

Ryan
  • 7,499
  • 9
  • 52
  • 61
3

As the other responses. There is no way to remove a header after being set, at least not standard (glassfish lets clear a header setting it's value to null). So at the end of the day you would have two choices:

  1. Reset the response with response.reset() - This effectively removes ALL headers AND ALSO ANY BUFFERED DATA, depending on you case can be a good alternative (in my case was after authentication validation errors). If the response is already committed you'll get an IllegalStateException.

  2. Set header to empty string, clearly this doesn't remove the header. But the http specification only has some definitions for and empty value in the Accept-Encoding, TE (transfer encoding) and HOST headers, so depending in your needs you can control that in your application layer.

zb226
  • 9,586
  • 6
  • 49
  • 79
le0diaz
  • 2,488
  • 24
  • 31
1

This does not work for me using Spring 4. I'm trying to strip out the Expires response header. For every page. Like so:

public class CachingFilter implements Filter {
    private final Log logger = LogFactory.getLog(getClass());

    public CachingFilter() {}
    public void destroy() {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.debug("doFilter()");
        chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
            public void setHeader(String name, String value) {
                logger.debug("setHeader(" + name + ","+value+")");

                if (!name.equalsIgnoreCase("Expires")) {
                    super.setHeader(name, value);
                }
            }
        });
    }

    public void init(FilterConfig fConfig) throws ServletException {}
}

And here is how I add the filter:

public class AppConfig implements WebApplicationInitializer {
    private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
    private static final String DISPATCHER_SERVLET_MAPPING = "/";

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(AppContext.class);

        ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(rootContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping(DISPATCHER_SERVLET_MAPPING);

        EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);

        FilterRegistration.Dynamic noCache = servletContext.addFilter("noCacheFilter", new CachingFilter());
        noCache.addMappingForUrlPatterns(dispatcherTypes, true, "/*");

        servletContext.addListener(new ContextLoaderListener(rootContext));
    }
}

setHeader() being called for Expires and Cache-Control, but I can't override the Expires filter value, or the Cache-Control value. I can add to the Cache-Control value. It turns into an array of values if I call setHeader on Cache-Control. But I need to delete the header.

yetimoner
  • 787
  • 2
  • 9
  • 19