The doc explains that the HttpServletResponse#sendError() method throws an IOException if an input or output exception occurs (DRY ;).
I couldn't find any scenario that makes this method throw that exception, is there any?
HTTP is sent over TCP so you can safely assume that somewhere in the underlying HttpServletRequest and HttpServletResponse there is a SocketInputStream and a SocketOutputStream.
If a user closes their browser or the network goes down client-side or server-side, then the server won't be able to receive requests or send responses. If the disconnection happens while the server was in the process of sendError(), then an IOException will occur while writing to the SocketOutputStream.
Related
Encountered some code doing this inside a servlet:
while ((read = request.getInputStream().read(bytes)) != -1)
buffer.write(bytes, 0, read);
While in most cases, request.getInputStream() is just returning a field somewhere, I was thinking there might be dynamic wrappers or such that could get into a bad state.
Is there anything written in the docs about doing such a thing that I can use as a case for pulling the getInputStream() code out of the loop?
It's ok to call getInputStream() multiple times, the Servlet Specification only prohibits using it together with getReader(). As per the ServletRequest#getInputStream() method javadoc:
Retrieves the body of the request as binary data using a ServletInputStream. Either this method or getReader() may be called to read the body, not both.
Returns:
a ServletInputStream object containing the body of the request
Throws:
IllegalStateException - if the getReader() method has already been called for this request
IOException - if an input or output exception occurred
A particular Servlet implementation is free to return a wrapper object but at the end of the day one is supposed to always expect ServletInputStream can throw throw IOException at some point (e.g. connection reset).
If we take Apache Tomcat as an example, the HTTP connection handling logic is in AbstractProtocol.ConnectionHandler.process() method and is very defensive. The cleanup code for the HTTP connection and the underlying socket runs after catch(Throwable ) so application error shouldn't interfere with resource cleanup.
I am using Apache Tomcat 8.0.33.
I was going through Java documentation about RemoteEndpoint.Basic
which says that sendText(String text) blocks until all of the message
has been transmitted.
But I noticed that when the client loses internet connection and
sendText() method is called on the server side, it doesn't thrown an
IOException immediately and the method returns normally.
IOException is thrown later and the onError() method is called.
Is
this a normal behaviour? Shouldn't the sendText() method block until
all the message has been transmitted successfully or throw an
IOException immediately if there's any problem?
Yes, this behavior is normal.
Depending on how the client disconnects, there server might not know and the message will sit in the network buffer until the network stack figures out that
the client has gone away.
From Socket documentation:
shutdownInput
public void shutdownInput()
throws IOException
Places the input stream for this socket at "end of stream". Any data sent to the input stream side of the socket is acknowledged and then silently discarded.
If you read from a socket input stream after invoking shutdownInput() on the socket, the stream will return EOF.
In order to test interaction between clients in a server, I've written some client bots.
These bots generate somewhat random client requests. Since these only write to the server, they have no need for the input stream, they do not need to read the updates the server sends. This is the main body of code for the bots:
private void runWriteBot(PrintWriter out) throws IOException {
//socket.shutdownInput();
String request;
System.out.println("Write bot ready.");
while (!quit) {
request = randomRequest();
out.println(request);
sleep();
}
}
If I uncomment the shutdownInput, an exception is thrown in the server's client handler:
Connection reset
I wasn't expecting an exception to be thrown on the other side of the socket. The documentation suggests (to me, at least) that anything sent by the other side will just be silently discarded, causing no interference with the other end's activity, ie without having the other side throw an exception.
Can I just ignore what the server sends, or should I drain what comes to the input stream?
Is there any automagic way of doing it, or do I need to regularly read and ignore?
The behaviour when you call shutdownInput() is platform-dependent.
BSD Unix will silently discard any further input.
Linux will keep buffering the input, which will eventually block the sender, or cause him to get EAGAIN/EWOULDBLOCK if he is in non-blocking mode.
Windows will reset the connection if any further data arrives.
This is determined by the platform, not by Java.
I don't see any need for calling shutdownInput() in most situations. The only thing it is really useful for is unblocking a read. In your situation you are going to have to read the server responses.
I'm doing a GET request with the apache HttpClient. Is there a way to detect when the server disconnects while reading from the InputStream?
EOS on the input stream (read() returning -1, readLine() returning null, readXXX() throwing EOFException for any other XXX) is the primary mechanism, otherwise an IOException, typically 'connection reset'. Very rarely you may see a SocketException. If you are using read timeouts, a SocketTimeoutException.
Sure, check out the Exception Handling section of the docs.
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.