Sending an error response after servlet response has been written to - java

I am writing a data transfer application using a servlet and would like to be able to send an error response if a problem occurs after the servlet response has been written to. Is that possible?
My issue is that I will be sending large compressed csv files that are created from data read from a database. Everything is done with streams so it is possible that an error could occur in the creation of the csv file after the servlet response has been written to. I have seen it happen.
I've noticed that this is only a problem after the servlet OutputStream has been flushed. If it has not been flushed I can send an error response but not after. Since I am dealing with large amounts of data it is not feasible to send everything in one go.

I am writing a data transfer application using a servlet and would like to be able to send an error response if a problem occurs after the servlet response has been written to. Is that possible?
Not from the server side on. The server cannot take the already flushed bytes back from the client. This is a point of no return. I assume that this concerns a different exception than IOException on the response's Writer or OutputStream.
If it were HTML (even though this is a poor practice; HTML belongs in JSP), you could print some JS code which forces a location change like so:
try {
writer.write(someHtml);
} catch (SomeException e) {
writer.write("<script>window.location = 'error.jsp';</script>");
// ...
}
But this is not possible in non-HTML responses. You'd really need to buffer the entire response in memory or on (temp) disk beforehand. If buffering went flawlessly, then you can pipe it to the response again.
try {
processAndSaveInMemoryOrTempDiskFile(someData, byteArrayOrFileLocation);
} catch (SomeException e) {
throw new ServletException(e, "Processing some data failed.");
}
copyFromMemoryOrTempDiskToResponse(byteArrayOrFileLocation, writer);

Related

Send different types of objects using Java in single call

First of all, I'm not sure whether this could be possible or not. I'm flushing bytes of data as PDF to the browser. Now the requirement is, I want to generate the pdf and also send one more extra object to be sent . Is it possible?
I've written something like this, but the result object is not getting as response.
YBUtil.GeneratePdf(response,documentBytes, "Bureau");
result.setStatus("SUCCESS");
return result; --> I want to pass this object as well
GeneratePdf method
public static void GeneratePdf(HttpServletResponse response, byte[] documentBytes, String fileName){
response.setHeader("Content-Disposition", "inline;filename="+fileName+".pdf");
response.setContentType("application/pdf");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, postcheck=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setContentLength(documentBytes.length);
ServletOutputStream out = null;
try {
out = response.getOutputStream();
out.write(documentBytes);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
In principle, this is more about the HTTP protocol than about Java.
HTTP is designed to send requests, with one optional request body sent along, and to receive a response in reaction, with one optional response body sent along. One. Not more than that.
When dealing with typical text stuff, you can send/respond a text-like format such as XML, JSON or web forms, that contain all the stuff you want it to contain. But when you want to receive/send a file, it's binary stuff and it must be sent as-is, alongside metadata that tell the file's type and name.
Now when you want to send/receive more than just a file, it looks like you're stuck. Well no. Look up multipart/form-data and realize you can use something similar for an HTTP response. Just like an email would.
Java can be programmed to respond with a multipart response. However, it is a bit of work to program, and I haven't really found an effective library that will success in helping me do it.
I have done this by sending a DTO object that will contain bytes(for pdf, this parsing of pdf is done on client side) and other values added to the DTO which are necessary.

File upload handling and buffering internals with Jersey API

How does Jersey handle receiving files from a client (e.g. web application)?
I've looked around for a longer while and cannot seem to get the answers I need.
Let's say that I have an exposed Jersey endpoint that consumes a multipart data form with a file that looks pretty much like this:
#POST
public Response upload(#FormDataParam("file") InputStream inputStream,
#FormDataParam("file") FormDataContentDisposition fileDetails { ... }
I've noticed that if I try to upload the file, the endpoint is not called until the uploading is finished. Does Jersey attempt to read and buffer (memory? disk?) an entire file before handling it for further processing? Does it mean that the inputStream source and size is already known when the processing of endpoint logic starts (because it was already read)?
And finally, is it possible to handle it in a "as comes" manner, without waiting with further actions for whole file to be uploaded first?

How to close the HttpServletResponse OutputStream when sending error

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.

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.

No images displayed when website called from self written webserver

I have Java webserver (no standard software ... self written). Everything seems to work fine, but when I try to call a page that contains pictures, those pictures are not displayed. Do I have to send images with the output stream to the client? Am I missing an extra step?
As there is too much code to post it here, here is a little outline what happens or is supposed to happen:
1. client logs in
2. client gets a session id and so on
3. the client is connected with an output stream
4. we built the response with the HTML-Code for a certain 'GET'-request
5. look what the GET-request is all about
6. send html response || file || image (not working yet)
So much for the basic outline ...
It sends css-files and stuff, but I still have a problem with images!
Does anybody have an idea? How can I send images from a server to a browser?
Thanks.
I check requests from the client and responses from the server with charles. It sends the files (like css or js) fine, but doesn't with images: though the status is "200 OK" the transfer-encoding is chunked ... I have no idea what that means!? Does anybody know?
EDIT:
Here is the file-reading code:
try{
File requestedFile = new File( file );
PrintStream out = new PrintStream( this.getHttpExchange().getResponseBody() );
// File wird geschickt:
InputStream in = new FileInputStream( requestedFile );
byte content[] = new byte[(int)requestedFile.length()];
in.read( content );
try{
// some header stuff
out.write( content );
}
catch( Exception e ){
e.printStackTrace();
}
in.close();
if(out!=null){
out.close();
System.out.println( "FILE " + uri + " SEND!" );
}
}
catch ( /*all exceptions*/ ) {
// catch it ...
}
Your browser will send separate GET image.png HTTP 1.1 requests to your server, you should handle these file-gets too. There is no good way to embed and image browser-independent in HTML, only the <img src="data:base64codedimage"> protocol handler is available in some browsers.
As you create your HTML response, you can include the contents of the external js/css files directly between <script></script> and <style></style> tags.
Edit: I advise to use Firebug for further diagnostics.
Are you certain that you send out the correct MIME type for the files?
If you need a tiny OpenSource webserver to be inspired by, then have a look at http://www.acme.com/java/software/Acme.Serve.Serve.html which serves us well for ad-hoc server needs.
Do I have to send those external files
or images with the output stream to
the client?
The client will make separate requests for those files, which your server will have to serve. However, those requests can arrive over the same persisten connection (a.k.a. keepalive). The two most likely reasons for your problem:
The client tries to send multiple requests over a persistent connection (which is the default with HTTP 1.1) and your server is not handling this correctly. The easiest way to avoid this is to send a Connection: close header with the response.
The client tries to open a separate connection and your server isn't handling it correctly.
Edit:
There's a problem with this line:
in.read( content );
This method is not guaranteed to fill the array; it will read an arbitrary number of bytes and return that number. You have to use it in a loop to make sure everything is read. Since you have to do a loop anyway, it's a good idea to use a smaller array as a buffer to avoid keeping the whole file in memory and running into an OutOfMemoryError with large files.
Proabably step #4 is where you are going wrong:
// 4. we built the response with the HTML-Code for a certain 'GET'-request
Some of the requests will be a 'GET /css/styles.css' or 'GET /js/main.js' or 'GET /images/header.jpg'. Make sure you stream those files in those circumstances - try loading those URLs directly.
Images (and css/js files) are requested by the browser as completely separate GET requests to the page, so there's definitely no need to "send those ... with the output stream". So if you're getting pages served up ok, but images aren't being loaded, my first guess would be that you're not setting your response headers appropriately (for example, setting the Content-Type of the response to text/html), so the browser isn't interpreting it as a proper page & therefore not loading the images.
Some other things to try if that doesn't work:
Check if you can access an image directly
Use something like firebug or fiddler to check whether the browser is actually requesting the image/css/js files & that all your request/response headers look ok
Use an existing web server!

Categories

Resources