How to close the HttpServletResponse OutputStream when sending error - java

In HttpServlet.doGet(...) I get the OutputStream from the HttpServletResponse with
resp.getOutputStream();
While writing to that output stream an exception occurs, and instead of the data, I want to send an error back
resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "My error message");
How should I handle the output stream then?
I must probably close it. Does the already written data get sent to the client? Can I somehow discard that data so the client gets only the error?

The output stream will be send to client with content type as text/html.
As per the Java doc.
Sends an error response to the client using the specified status and clears the buffer. The server defaults to creating the response to look like an HTML-formatted server error page containing the specified message, setting the content type to "text/html".
If the response has already been committed, this method throws an IllegalStateException. After using this method, the response should be considered to be committed and should not be written to.
You can set error pages also for predefined response.sendError() codes in web.xml.
Edit: i have added a picture.

When some exception occurs, it will not go to client. because you send an Error to client instead of data.
From Java doc.
Sends an error response to the client using the specified status code and clearing the buffer.
so the client will not see any of the written data, and you should not care about the already written data. it will be cleaned up.

Related

Is it possible to send an ouput stream as response to a HTTP request?

Consider the case where Server B makes a HTTP request to Server A (Which is an encryption server) and get an output stream (which is encrypted). So that Server B could write with the help of this encrypted stream.
Now this encrypted output stream would be opened in Server A and closed at Server B.
Is it possible to send an output stream in HTTP response?
Is it a right way to send an output stream in response? Or are there any conventions like the output stream must be closed in the same server (or same application) where it is originated?
Yes, it's possible. That's how the file download works.
First you'll have to set the Content-Type that you're going to provide. If it's simple binary file then set it as application/octet-stream. After that get outputStream of the response and dump the file content in it.
Like below
response.setContentType("application/octet-stream");
response.setContentLength(fileSizeInBytes);//new File('myfile').length(), optional step
response.getOutputStream().write(fileBytes);//do it in chunks
#Edit
Streams are endpoints of data channels. Like an HTTP address is an endpoint to the server resource.
In case of stream our program doesn't need to know where the actual resource resides. I just need to know how to interact with the stream.
So in case of HttpServletResponse stream, data lies in your server. Client's browser (or any other client) establishes a connection with your server. When we call methods on the stream like read/write, data over this connection is sent or received. These calls in case of HttpServletResponse result in HTTP packet transfer over TCP connection.
For more information on Java Stream (or any other language with similar concept) check here.
https://docs.oracle.com/javase/tutorial/essential/io/streams.html

Redirect webpage after having sent some content

I am working with a web framework (uPortal) that is handling errors by just throwing an exception and then hanging. The framework works by rendering XML into HTML. When there is an exception, the browser recieves rendered content up to the XML template element that is failing, and then the browser just sits and waits for a timeout. Our team's theory is that the content is sent before the error occurs, which surprised me. Other frameworks I've worked with seem to finish rendering before sending content.
My question is, is there a way to redirect the browser after content has already been sent? In this case, we are in the middle of rendering the content of a <script> tag, but the error could occur potentially anywhere in the html.
My only current thought is to inject some javascript at the top of the page, and to try to change the framework's behavior to fail quickly and close the connection and add </body> and </html> tags when an error occurs. Then the above mentioned javascript would run on pageload and detect if the entire page's content was there and do a client-side redirect if not. Maybe it could look for a special hidden div at the bottom of the page.
Are there any examples of frameworks solving this problem differently or of people using similar framework working around this issue?
You must either capture the error, or capture the output in a buffer. If you can handle the exception, you can probably print a simple script tag like
<script> window.location.href = 'some_new_url';</script>
If the browser understands the doctype to be something related to HTML, it will execute that tag.
If you can capture the output in a buffer, when you handle the error you can decide to send an HTTP redirect to the browser and destroy the output buffer up to that point.
As for other frameowrks, in PHP, you can simply enable output buffering with ob_start(), which won't start sending content until the request is fully completed.
I don't know that framework, but
In http, every response has a response-code associated with it. Since the page is already half-way transferred / rendered that status code (usually "200") was sent (and received) already.
There's no way for the browser to accept another response code (like "301" for redirect) for the same response! Also the server is not able to send another response code, because the original response code was already commited and sent to the client.
Your description of the error and knowledge of the http-protocol implies that there is probably some implementation error in the framework / server components used, OR it was done deliberatly, risking the situation that you are in now...
to redirect a page , you need to set redirect information in header. but you can write header once you start writing content ( may be header is already received by client by the time you compete writing whole document )
But, you can do it in different way as below
1.let document loading complete and record if you need to redirect the page while rendering
2. add a unique request-id identifier for each page load
3. invoke ajax call with request-id ( may be rest call) to server asking if page needs to be redirected.
4. if page needs to be redirected , do so, via javascript in browser at client end.
A HTTP response consists of headers and an optional response content.
Once you have started to write the response to the socket connection you can't revert it. In your example: If you run into an error in the middle of content generation you can't add a redirect header - the header section has already be written.
The statement above is not entirely true: in HTTP chunked transfer encoding the response is sent in separate chunks. The last chunk can have an optional trailer containing entity-header fields and theoretically a redirect header. But if you can use these mechanism is a different question. For instance a servlet container may use chunked transfer encoding but does not give you an API to set the trailer.
But writing must not start immediately: For instance HttpServletResponse maintains a buffer for the response content. If you set headers and start writing the content only the buffer is filled and you still can reset the response and start all over. But once the buffer overflows the response is written to the connection and the HttpServletResponse is now committed.
Such a mechanism gives you way to deal with errors during content generation which happen when the response is not yet committed: Just reset the response and send an error message instead. You could examine your framework if it supports such an mechanism. But obviously this is not a solution for larger responses.
A second way to avoid errors during content generation is simply to make sure that they can't happen. First gather all your data needed for the response (e.g. making unsafe database calls), then in a second step generate the response - the second now step should not fail (except if you have bugs in your code).
You already mentioned a third way to handle an error, by having the client sanitize the response and take some action it errors are detected (e.g. by including a script in the generated HTML response).
The only reliable way to do this is to create a proxy HttpServletResponse object that caches the response. You'd need to give the uPortal this proxy instead of the actual HttpServletResponse, and only send the output using the real response once the processing completes / send redirect if the processing fails.
It is HTTP protocol design limitation that you cannot send HTTP redirect once output was started.
Other possible ways rely on HTML or Javascript redirects, but since you write that the error may happen at any moment, it would be difficult to print it out in a way that the browsers would reliably interpret it as redirect.

Calling getResponseCode on HttpUrlConnection before writing content throws an IOException

I'm trying to implement the following:
Open a POST connection.
Read response code.
Write content.
Read response code.
The second step throws a following exception:
Caused by: java.io.IOException: content-length promised 345286 bytes, but received 0
I understand that 'getResponseCode' will close the writing stream, but i need to find a way of how to read the response code before actually writing anything. I would like to skip the process of writing content to the request body (100 MB) due to the (for an example) 401 code.
HTTP Doesn't work like that. You need to send the full request and only then to read the response code. In your case, your response had promised a request body of 345286 bytes, but you have sent nothing.
The correct way is to do the following:
Open a POST connection.
Write content.
Read response code.
In case you want to verify that the server permits to do it (to avoid 401s) you can add a small GET request first to verify the authentication.

How can the servlet determine when an upload has been cancelled?

Here is some code on the javascript side for form-based uploads:
iframe.setAttribute('src', 'javascript:false;');
I'm using the code above to cancel an in-progress upload associated with an input element placed in an iframe.
I'm using the code below to cancel an in-progress upload sent via XHR:
myxhr.abort();
In both cases, no more bytes are sent to the servlet. The part I'm struggling with is on the servlet side. Currently, I can't figure out a way for the servlet instance to determine if the user has cancelled the upload. This is critical, otherwise the servlet will go on and process the partially uploaded file as if it is valid.
How can I determine, via the HttpServletRequest, if a user has cancelled the upload?
The POST request with the data contains the Content-Length header which tells you the size of the data that is going to be uploaded.
So when the data stops coming to your server and the size of the data received is less than expected - it would mean that the user (or some network glitch) has canceled the upload.
If the upload has been cancelled the browser will close the connection, resulting in a an IO exception on the servlet side. For example, in Tomcat it will say "Connection reset by peer" and this is a ClientAbortException. Other servers wrap the IOException differently. Point is just catch the IOException and you should be able to handle it as you wish.
Using content-length is not reliable because the HTTP spec does not require content-length headers for POSTs - or for GETs for the matter. Point is, unless you are sure your javascript XHR sets the header explicitly, this method won't work.
Alternatively you could calculate it yourself and set it to be sure, or even better append your own character stream to the end of a the posted data in the XHR, some unique string of characters, e.g. "jh923k49sk$2#%'. In the servlet, snip off the last 14 characters of the inbound message and check it against the string. If it is the same you know they didn't cancel.
I don't see how you can tell, just because a request stream has ended, whether it's done or cancelled. There would have to be a separate HTTP request to indicate cancellation that would have to include some token or ID associated with the upload, since HTTP is stateless and idempotent.

Sending an error response with com.sun.net.httpserver.HttpServer

I'm an experienced Java programmer but a newbie web developer. I'm trying to put together a simple web service using the HttpServer class that ships with JDK 1.6. From the examples I've viewed, some typical code from an HttpHandler's handle method would look something like this:
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, 0);
OutputStream responseBody = exchange.getResponseBody();
responseBody.write(createMyResponseAsBytes());
responseBody.close();
My question: What happens if I send a response header to indicate success (i.e. response code 200) and perhaps begin to stream back data and then encounter an exception, which would necessitate sending an "internal server error" response code along with some error content? In other words, what action should I take given that I've already sent a partial "success" response back to the client at the point where I encounter the exception?
200 is not sent until you either flush the stream or close it.
But once it is sent, there is nothing you can do about it.
Usually it may happen only when you have a really large amount of data and you use chunking.

Categories

Resources