0

In my Java client app I'm connecting to my server using HttpsURLConnection. This works all fine, except on certain moments it does not timeout at all. I set the timeout parameters of the connection as such (to 5000 ms):

HttpsURLConnection con = (HttpsURLConnection) url.openConnection();

// timeouts
con.setConnectTimeout(5000);
con.setReadTimeout(5000);

con.setRequestMethod("put");
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestProperty("Content-length", String.valueOf(output.length()));
OutputStreamWriter os = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
BufferedWriter writer = new BufferedWriter(os);
writer.write(output);
writer.close();
os.close();

con.connect();

int respCode = con.getResponseCode();

if(respCode == 200) {
        InputStreamReader is = new InputStreamReader(con.getInputStream());
        BufferedReader br = new BufferedReader(is);
        String input;
        String respBody = "";
        while ((input = br.readLine()) != null){
            respBody += input;
        }
        br.close();
        is.close();
        this.result = respBody;
}

I'm catching all exceptions, but none is registered, so the problem cannot be an uncaught exception. The connection simply does not timeout. I waited for 3 minutes and had no response. I could reproduce the bug a few times while switching network during the execution of a request.

Also, sometimes there was a response after about a minute. Which is longer than the timeouts.

I already tried interrupting the thread on which the request is made after a timeout, disconnecting the HttpsURLConnection. But there must be a neater solution than that. I would like to know where this indefinite timeout comes from.

Any ideas?

Thanks a lot!

Zxifer
  • 413
  • 1
  • 4
  • 9
  • What URL are you connecting to? I believe the answer to your question may depend on the server you are hitting: if this server doesn't mind having an indefinite open connection, then this could explain your observations. – Tim Biegeleisen Jul 18 '16 at 13:47
  • 1
    The exception thrown in case of a time out should be [java.net.SocketTimeoutException](https://docs.oracle.com/javase/7/docs/api/java/net/SocketTimeoutException.html), which you should be already catching as it's not a runtime exception (can't see how you do that in your code though). Also note that from the [API](https://docs.oracle.com/javase/7/docs/api/java/net/URLConnection.html#setConnectTimeout%28int%29): "Some non-standard implmentation of this method may ignore the specified timeout. To see the connect timeout set, please call getConnectTimeout().". Might be a hint... – Mena Jul 18 '16 at 13:51
  • @Mena indeed, when I print the getConnectTimeout() result, I always get 0 (infinite), no matter which value I assign to it. So, we now know HttpsURLConnection has a "non-standard implementation" of the setConnectTimeout() method. But how can I restrict the infinite timeout nevertheless? – Zxifer Jul 18 '16 at 21:28
  • @Zxifer tried to answer with something. – Mena Jul 18 '16 at 21:52
  • I'm surprised this works. You haven't called `seDoOutput(true);`. You don't need to set the content length. – user207421 Jul 18 '16 at 22:06
  • @EJP I do call it, I must have forgotten to copy that part in my question. My bad. I'll edit my question. – Zxifer Jul 18 '16 at 22:55
  • Setting `doOutput` to true already sets the request method to POST. You don't need to do that yourself either. – user207421 Jul 18 '16 at 23:24

1 Answers1

1

From my comment

The exception thrown in case of a time out should be java.net.SocketTimeoutException, which you should be already catching as it's not a runtime exception (can't see how you do that in your code though).

Also note that from the API:

Some non-standard implmentation of this method may ignore the specified timeout. To see the connect timeout set, please call getConnectTimeout().

From your comment

Indeed, when I print the getConnectTimeout() result, I always get 0 (infinite), no matter which value I assign to it. So, we now know HttpsURLConnection has a "non-standard implementation" of the setConnectTimeout() method. But how can I restrict the infinite timeout nevertheless?

A quick and ugly solution

  • "Wrap around" your code establishing the connection by moving it to the call override of a Callable<String> (whose parametrized type is what I assume to be the type of your result variable).
  • From the thread currently invoking this, use a single-threaded Executor to submit your new Callable<String>.
  • Then invoke get on the Future<String>, with the timeout of your choice, and handle the TimeoutException accordingly.

A (maybe) better, long-term solution

  • Look into the implementation of the abstract class HttpsURLConnection you are dealing with, and see if there's a bug / communicate with whoever implemented it.
Mena
  • 47,782
  • 11
  • 87
  • 106
  • Thanks a lot for your reply. After digging deeper into my code, I noticed that the way I set the timeouts was incorrect. I used Java Preferences for the timeout values and these were not properly set. My code seems to work fine now, using the setConnectTimeout() and setReadTimeout(). Your quick and ugly solution nevertheless is a better solution in the sense that it also cuts short other (possibly longer) timeouts, such as Window's 21 seconds timeout as mentioned in a comment here: http://stackoverflow.com/questions/14026223/java-httpurlconnection-timeout-does-not-work – Zxifer Jul 18 '16 at 23:06
  • @Zxifer you're welcome. I guess in the end it all depends on *what* you really want to time out - using async execution idioms can be handy when it comes to a series of instructions not only enclosing the actual connection, which may be rather common, come to think of it. – Mena Jul 18 '16 at 23:11