Disable all default HTTP error response content in Tomcat

68,171

Solution 1

Although this doesn't respond exactly to the "not send anything" statement on the question, and on the wave of Clive Evans' answer, I found out that in tomcat you can make those too much verbose texts go away from error pages without creating a custom ErrorReportValve.

You can accomplish to this customizing ErrorReportValve through the 2 params "showReport" and "showServerInfo" on your "server.xml":

<Valve className="org.apache.catalina.valves.ErrorReportValve" showReport="false" showServerInfo="false" />

Link to official documentation.

Worked for me on tomcat 7.0.55, didn't work for me on tomcat 7.0.47 (I think because of something reported on the following link http://www.mail-archive.com/[email protected]/msg113856.html)

Solution 2

The quick, slightly dirty, but easy way of stopping Tomcat from sending any error body is to call setErrorReportValveClass against the tomcat host, with a custom error report valve which overrides report to do nothing. ie:

public class SecureErrorReportValve extends ErrorReportValve {

@Override
protected void report(Request request,Response response,Throwable throwable) {
}

}

and set it with:

  ((StandardHost) tomcat.getHost()).setErrorReportValveClass(yourErrorValveClassName);

If you want to send your message, and just think Tomcat shouldn't mess with it, you want something along the lines of:

@Override
protected void report(final Request request, final Response response, final Throwable throwable) {
    String message = response.getMessage();
    if (message != null) {
        try {
            response.getWriter().print(message);
            response.finishResponse();
        } catch (IOException e) {
        }
    }
}

Solution 3

Although it's Servlet spec compliant, for security reasons I don't want tomcat or any other Servlet container to send error details. I struggled with this as well a bit. After searching and trying, the solution can be summed up as:

  1. as others mentioned, don't use sendError(), use setStatus() instead (in Jersey framework you can choose)
  2. frameworks like e.g. Spring Security use sendError() though...
  3. write a Filter that
    a. redirects calls to sendError() to setStatus()
    b. flushes the response at the end to prevent the container from further modifying the response

A little example servlet filter doing this can be found here.

Solution 4

As Heikki said, setting the status instead of sendError() causes the Tomcat not touch the response entity/body/payload.

If you only want to send the response headers without any entity, like in my case,

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);

does the trick. With Content-Length: 0, the print() will have no effect even if used, like:

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);
response.getWriter().print("this string will be ignored due to the above line");

the client receives something like:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 0
Date: Wed, 28 Sep 2011 08:59:49 GMT

If you want to send some error message, use the setContentLength() with message length (other than zero) or you can leave it to the server

Solution 5

Configure <error-page> Elements in web.xml

Edit $CATALINA_HOME/conf/web.xml, add at the end the following <error-page>, save and restart tomcat

<web-app>

...
...
...

    <error-page>
        <error-code>404</error-code>
        <location>/404.html</location>
    </error-page>

    <error-page>
        <error-code>500</error-code>
        <location>/500.html</location>
    </error-page>

    <error-page>
        <error-code>400</error-code>
        <location>/400.html</location>
    </error-page>

</web-app>
  • It works great as I expect even though I didn't actually created a valid routes for those specified location values (e.g. /400.html)

before

enter image description here

after

enter image description here

Share:
68,171
Rob Hruska
Author by

Rob Hruska

Software Engineer for Hudl in Lincoln, NE. Come work with us!

Updated on September 07, 2021

Comments

  • Rob Hruska
    Rob Hruska over 2 years

    By default, Tomcat sends some HTML content back to the client if it encounters something like an HTTP 404. I know that via web.xml an <error-page> can be configured to customize this content.

    However, I'd just like for Tomcat to not send anything in terms of response content (I'd still like the status code, of course). Is there any way to easily configure this?

    I'm trying to avoid A) explicitly sending empty content on the response stream from my Servlet, and B) configuring custom error pages for a whole bunch of HTTP error statuses in my web.xml.

    For some background, I'm developing an HTTP API and am controlling my own response content. So for an HTTP 500, for example, I'm populating some XML content on the response containing error information. For situations like an HTTP 404, the HTTP response status is sufficient for clients, and the content tomcat is sending is unnecessary. If there's a different approach, I'm open to hearing it.

    Edit: After continued investigation, I still can't find much in the way of a solution. If someone can definitively say this is not possible, or provide a resource with evidence that it will not work, I'll accept that as an answer and try and work around it.

  • Rob Hruska
    Rob Hruska about 15 years
    I mentioned in my question that I would like to avoid configuring error pages (even if they're empty) for a bunch of statuses. If it's my only option then I guess I'll have to - but I'm looking for alternatives.
  • mckamey
    mckamey over 11 years
    This worked great! I like having a single place to control this rather than having to wrap every single response. More aspect-oriented.
  • Poni
    Poni over 11 years
    Indeed a better solution! Thanks
  • Rob Hruska
    Rob Hruska over 11 years
    Can you clarify what you mean by the behavior being "absolutely correct"? Which behavior, specifically? A link or excerpt from the Servlet specification may help. I couldn't find anything in the 3.0 specification that addressed requirements on the actual content of a response, particularly for error responses. As far as RFC2616 goes, there aren't any requirements on the entity content for any error statuses.
  • Michael-O
    Michael-O over 11 years
    Yes, of course. This is not bound to the RFC but to the Servlet spec itself. Check Servlet spec 3.0, chapters 10.9.2 and 10.9.3, Oracle's Servlet API JavaDocs for both sendError methods and my question to the Tomcat Users Mailinglist.
  • Clive Evans
    Clive Evans over 11 years
    Feel free to point to the part of the spec that says you shouldn't take the Tomcat ErrorReportValve which rewrites your message into a message containing a whole load of information you probably don't want to share with the outside world, and instead, write just your message. I'm intrigued ...
  • Javier Esteban
    Javier Esteban over 11 years
    on another note, you can write your own ErrorValve and configure it in the server.xml's <Host> element: <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" errorReportValveClass="security.MyErrorValveImpl"> see tomcat.apache.org/tomcat-7.0-doc/config/host.html
  • reallynice
    reallynice almost 10 years
    Well, more than a "quick, slightly dirt" answer, looks like the answer that really meets the needs.
  • eis
    eis over 8 years
    Working with Tomcat 8. Excellent solution!
  • mjs
    mjs over 8 years
    And now you application is tomcat dependant.
  • Clive Evans
    Clive Evans over 8 years
    If you weren't using Tomcat, you wouldn't be suffering from Tomcat leaking your information ...
  • Night Owl
    Night Owl almost 8 years
    The Tomcat docs say the <Valve /> element can go within the <Engine />, <Host /> or <Context /> elements in server.xml. For me putting the valve within the <Engine /> element didn't work but putting it inside individual <Host /> elements did. The docs also say Tomcat routes any non matching host names to the <Host /> element that is set in the defaultHost attribute of the <Engine /> element. To ensure that URLs to locations outside of your hosts/contexts are not shown the error messages compiled into Tomcat you need to make sure this <Valve /> is added your default <Host />.
  • watery
    watery almost 8 years
    +1 for pointing out that frameworks have predefined behaviour and providing an example filter, which — as I'm using Jersey — made me discover a a specific Jersey property
  • John Yeary
    John Yeary over 5 years
    I needed to add try { response.finishResponse(); } catch (IOException e) { } to the empty report() method to prevent it from producing any output.
  • maxxyme
    maxxyme almost 5 years
    Above link posted by @watery is dead as of 2019, correct link now is jersey.github.io/apidocs/latest/jersey/org/glassfish/jersey/‌​…
  • maxxyme
    maxxyme almost 5 years
    You missed the point where the OP said he's trying to avoid [..] configuring custom error pages for a whole bunch of HTTP error statuses in [his] web.xml.
  • Jossef Harush Kadouri
    Jossef Harush Kadouri almost 5 years
    Agree. Yet its helpful for those who google their way for examples. This question have good SEO rating.
  • bluish
    bluish over 2 years
    Link is dead again, better look at this answer ;)