How to detect if Tomcat http connection timedout [duplicate] - java

How can I detect that the client side of a tomcat servlet request has disconnected? I've read that I should do a response.getOutputStream().print(), then a response.getOutputStream().flush() and catch an IOException, but is there a way I can detect this without writing any data?
EDIT:
The servlet sends out a data stream that doesn't necessarily end, but doesn't necessarily have any data flowing through it (it's a stream of real time events). I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera). If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?

is there a way I can detect this
without writing any data?
No because there isn't a way in TCP/IP to detect it without writing any data.
Don't worry about it. Just complete the request actions and write the response. If the client has disappeared, that will cause an IOException: connection reset, which will be thrown into the servlet container. Nothing you have to do about that.

I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera).
There the finally block is for. It will be executed regardless of the outcome. E.g.
OutputStream output = null;
try {
output = response.getOutputStream();
// ...
output.flush();
// ...
} finally {
// Do your cleanup here.
}
If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?
Depends on how you're reading from it and how much of request body is already in server memory. In case of normal form encoded requests, whenever you call getParameter() beforehand, it will usually be fully parsed and stored in server memory. Calling the getInputStream() won't be useful at all. Better do it on the response instead.

Have you tried to flush the buffer of the response:
response.flushBuffer();
Seems to throw an IOException when the client disconnected.

Related

Why is it important to read the response body of an HTTP request?

Learning about HTTP requests in Java. I'd like to know if reading the response body is essential to keeping a connection alive.
Here's an example code block (which posts a message to some URL):
private void writeToConnection(String url, String msg) throws IOException {
try {
HttpURLConnection connection = open(url);
// "Try with resources"
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(connection.getOutputStream()))) {
writer.write(msg);
}
// Why do I need this line?
IOUtils.readStringFromStream(connection.getInputStream());
int code = connection.getResponseCode();
System.out.println(String.format("Returned response code %d.", code));
} catch (IOException e) {
e.printStackTrace();
}
}
Why is it necessary to read the input stream? The method readStringFromStream is returning a string but the string is not being assigned to anything. Does this ensure the connection stays alive? If so, how does the connection stay alive when the first line in the method opens a new connection? If the next batch of data to be written invokes this method, wouldn't that discard the old connection and open a new one?
I believe the intent of this code is indeed to consume the response body so that the connection can be reused. However, I'm not sure that this approach is correct; it is also likely to depend on the version of Java you are using.
First, it should suffice to get the connection's InputStream and close it; behind the scenes, the body still needs to be read, but closing the stream signals to the connection handler that the application wants to skip the body, and the handler can read and discard the content before putting the connection into a cache for re-use.
However, depending on the status, there could be an error stream instead of an input stream. Even in this case, the body needs to be consumed before the connection can be re-used, but many applications (like this one) don't bother reading the body of an error message. Since Java 7, however, if the error body is small enough, it will be consumed and buffered automatically.
Behind the scenes, a connection cache is used to retain open connections. Although the method names suggest a new connection is opened every time, in fact the cache is first checked for an open connection.

Detect client disconnect in Tomcat [duplicate]

How can I detect that the client side of a tomcat servlet request has disconnected? I've read that I should do a response.getOutputStream().print(), then a response.getOutputStream().flush() and catch an IOException, but is there a way I can detect this without writing any data?
EDIT:
The servlet sends out a data stream that doesn't necessarily end, but doesn't necessarily have any data flowing through it (it's a stream of real time events). I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera). If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?
is there a way I can detect this
without writing any data?
No because there isn't a way in TCP/IP to detect it without writing any data.
Don't worry about it. Just complete the request actions and write the response. If the client has disappeared, that will cause an IOException: connection reset, which will be thrown into the servlet container. Nothing you have to do about that.
I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera).
There the finally block is for. It will be executed regardless of the outcome. E.g.
OutputStream output = null;
try {
output = response.getOutputStream();
// ...
output.flush();
// ...
} finally {
// Do your cleanup here.
}
If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?
Depends on how you're reading from it and how much of request body is already in server memory. In case of normal form encoded requests, whenever you call getParameter() beforehand, it will usually be fully parsed and stored in server memory. Calling the getInputStream() won't be useful at all. Better do it on the response instead.
Have you tried to flush the buffer of the response:
response.flushBuffer();
Seems to throw an IOException when the client disconnected.

Does Spring MVC has something like CancellationToken? [duplicate]

How can I detect that the client side of a tomcat servlet request has disconnected? I've read that I should do a response.getOutputStream().print(), then a response.getOutputStream().flush() and catch an IOException, but is there a way I can detect this without writing any data?
EDIT:
The servlet sends out a data stream that doesn't necessarily end, but doesn't necessarily have any data flowing through it (it's a stream of real time events). I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera). If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?
is there a way I can detect this
without writing any data?
No because there isn't a way in TCP/IP to detect it without writing any data.
Don't worry about it. Just complete the request actions and write the response. If the client has disappeared, that will cause an IOException: connection reset, which will be thrown into the servlet container. Nothing you have to do about that.
I need to actually detect when the client disconnects because I have some cleanup I have to do at that point (resources to release, etcetera).
There the finally block is for. It will be executed regardless of the outcome. E.g.
OutputStream output = null;
try {
output = response.getOutputStream();
// ...
output.flush();
// ...
} finally {
// Do your cleanup here.
}
If I have the HttpServletRequest available, will trying to read from that throw an IOException if the client disconnects?
Depends on how you're reading from it and how much of request body is already in server memory. In case of normal form encoded requests, whenever you call getParameter() beforehand, it will usually be fully parsed and stored in server memory. Calling the getInputStream() won't be useful at all. Better do it on the response instead.
Have you tried to flush the buffer of the response:
response.flushBuffer();
Seems to throw an IOException when the client disconnected.

Do I need to flush the servlet outputstream?

Do I need to "flush" the OutputStream from the HttpServletResponse?
I already saw from to Should I close the servlet outputstream? that I don't need to close it, but it's not clear if I need to flush it. Should I expect it from the container as well?
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
byte[] response = getResponse();
String responseType = getResponseType();
response.setContentLength(response.length);
response.setContentType(responseType);
response.getOutputStream().write(response);
response.getOutputStream().flush(); // yes/no/why?
}
You don't need to. The servletcontainer will flush and close it for you. The close by the way already implicitly calls flush.
See also chapter 5.6 of Servlet 3.1 specification:
5.6 Closure of Response Object
When a response is closed, the container must immediately flush all remaining
content in the response buffer to the client. The following events indicate that the servlet has satisfied the request and that the response object is to be closed:
The termination of the service method of the servlet.
The amount of content specified in the setContentLength or
setContentLengthLong method of the response has been greater than zero and
has been written to the response.
The sendError method is called.
The sendRedirect method is called.
The complete method on AsyncContext is called.
Calling flush while still running the servlet's service is usually only beneficial when you have multiple writers on the same stream and you want to switch of the writer (e.g. file with mixed binary/character data), or when you want to keep the stream pointer open for an uncertain time (e.g. a logfile).
Guess that the same answer you got in your other question applies here: if it is your stream, flush and close it. Otherwise the stream creator should be doing it, unless otherwise stated.
To point out an insidious exception to the rule “no need to flush”: Working with IBM WebSphere Application Server and using the response Writer (rather than the OutputStream) I found that I had to flush it; otherwise a final portion of my response data was lost. I suppose that IBM's HttpServletResponse class does indeed flush the OutputStream but uses a separate buffer for the Writer and does not flush it. Other application servers seem to do this.
So if you send your response data to the Writer it is safer to flush it. But there is no need to flush the OutputStream into the bargain.
(I would have posted this as a comment but lack the reputation to do it.)
java.lang.Object
extended byjava.io.Writer
extended byjavax.servlet.jsp.JspWriter
close
public abstract void close()
throws IOException
Close the stream, flushing it first.
This method needs not be invoked explicitly for the initial JspWriter as the code generated by the JSP container will automatically include a call to close().
Closing a previously-closed stream, unlike flush(), has no effect.
Throws:
IOException - If an I/O error occurs
============================
So, DO NOT close the output stream explicitly.

Why is the end of the input stream never reached using Java Sockets?

I am writing a simple proxy in Java. I am having trouble reading the entirety of a given request into a byte array. Specifically, in the following loop, the call to 'read' blocks even though the client has sent all the data that it will (that is, the end of stream is never reached). As I can't be sure that it is time to start writing output until I've read the entirety of the input, this is causing a bit of trouble. If I kill the connection to the server, the end of stream is finally reached, and everything goes off without a hitch (all of the data from the client, in this case Firefox requesting www.google.com, has been read by the server, and it is able to process it as required, though obviously it can't send anything back to the client).
public static void copyStream(InputStream is, OutputStream os) throws IOException
{
int read = 0;
byte[] buffer = new byte[BUFFER_SIZE];
while((read = is.read(buffer, 0, BUFFER_SIZE)) != -1)
{
os.write(buffer, 0, read);
}
return;
}
The InputStream comes from the client socket (getInputStream(), then buffered) directly; the OutputStream is a ByteArrayOutputStream.
What am I doing wrong?
Typically in HTTP the Content-Length header indicates how much data you're supposed to read from the stream. Basically it tells you how many bytes follow the double-newline (actually double-\r\n) that indicates the end of the HTTP headers. See W3C for more info...
If there is no Content-Length header sent, you could try interrupting the read after a certain amount of time passes with no data sent over the connection, although that's definitely not preferable.
(I'm assuming that you're going to be processing the data you're reading somehow, otherwise you could just write out each byte as you read it)
HTTP 1.1, supported by all modern browsers, has a feature called "keep-alive", or "persistent connections", in which clients are allowed by default to reuse a HTTP 1.1 connection to a server for several requests (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html).
So if you are pointing FF to http://www.google.com, the connection to www.google.com:80 will remain open for a while, even if the first request has been completed. You thus can not know if all the data has been sent without a basic understanding of HTTP protocol by your application.
You can somehow circumvent that by using a timeout on the connection, hoping the client is not stuck somewhere and that silence actually means the end of the data block.
An other way would be to rewrite server response headers, to advertise your proxy as HTTP 1.0 compliant, and not 1.1, thus forbidding the client to use persistent connections.
Keep in mind that not all connections will have a Content-Length header; some may be using Transfer-Encoding: chunked where the content length is encoded and included as part of the body.

Categories

Resources