tags:

views:

127

answers:

3

(See related question: http://stackoverflow.com/questions/162917/how-do-i-report-an-error-midway-through-a-chunked-http-repsonse-without-closing)

In my case, the #1 desire is for the browser to display an error message. No matter how uninformative.

Closing the ServletResponse outputStream obviously doesn't work. Neither does throwing an exception, even if I don't close first (tested on Tomcat 6.0.16). I think that what I want is either a RST packet, FIN in the middle of a chunk, or badly formed chunk headers.

After that I can worry about how various browsers respond.

Edited for clarification: This is for a file download, perhaps several gigabytes of binary data. I can't make certain that all of the data can be successfully read or decrypted before I have to start sending some of it.

A: 

I think you're going about it the wrong way. It seems like it would be simpler to not actually start sending the data until you're sure if will be a success or a failure. That way you can send an error message at the start if needed, instead of sending partial data that's not valid.

If you really must, you might be able to wrangle something up with JavaScript. When you get to the error, output something like this before closing the connection:

<script type="text/javascript"> alert("Processing failed!"); </script>

You might want to expand on the script, but you get the general idea. This is assuming that what's being sent back to the browser is a HTML page, you didn't specify that in the question.

davr
A: 

My own answer, after research.

Part one: There seems to be no way to convince the application servers that I tested to put an error onto the wire past the "committed" phase. The following Servlet code results in legal HTTP Chunked Transfer headers on the socket. Interestingly, in the case of WebSphere an error message is appended to the end of the stream before the end mark.

public class Servlet extends HttpServlet {
    public static final int ARRAY_SIZE = 65536;
    private static final int SEND_COUNT = 100000;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException {

        String testData = "This is a fairly long piece of test text, running on and on and on, over and over.";

        final ServletOutputStream outputStream = response.getOutputStream();
        for (int i = 0; i < SEND_COUNT; ++i) {
            outputStream.println(testData);
        }
        throw new ServletException("Break it now");
    }
}

Part two: Even if the application server was willing to either write bogus data to the wire or close the socket without a closing zero length chunk, common clients do not report an error. IE7, FF3 and cURL do not report errors in chunk encoding. This makes HTTP downloads inherently unreliable, and is contrary to the spirit if not the letter of the HTTP 1.1 RFC.

Darron
A: 

The servlet API doesn't allow it. Once the response is committed the response code has been sent. The best you can do is close the connection and log the error.

johnstok
Citation? Where does the Servlet API definition say what the container should do when my Servlet throws SomeGenericError after the commit point?I understand that it cannot change the HTTP response code that is already on the wire, but why should it write a zero length chunk before closing.
Darron
Sorry, I didn't mean the spec disallows the behaviour you want, simply that there isn't any way to achieve it with the methods available in the current version of the API.
johnstok