Skip to content

Commit

Permalink
Merge pull request #277 from Microsoft/feature/ssl_exception_retry
Browse files Browse the repository at this point in the history
 #270 Retry transient ssl exceptions
  • Loading branch information
guperrot authored Dec 9, 2016
2 parents 359e961 + 646632e commit 80c98c4
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.security.cert.CertPathValidatorException;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import static com.microsoft.azure.mobile.ingestion.http.HttpUtils.isRecoverableError;
import static junit.framework.Assert.assertFalse;
Expand Down Expand Up @@ -39,5 +43,11 @@ public void isRecoverableErrorTest() {
assertFalse(isRecoverableError(new HttpException(413)));
assertTrue(isRecoverableError(new HttpException(429)));
assertTrue(isRecoverableError(new HttpException(401)));
assertTrue(isRecoverableError(new SSLException("Write error: ssl=0x59c28f90: I/O error during system call, Connection timed out")));
assertFalse(isRecoverableError(new SSLHandshakeException("java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.")));
assertFalse(isRecoverableError(new SSLException(null, new CertPathValidatorException("Trust anchor for certification path not found."))));
assertFalse(isRecoverableError(new SSLException("java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty")));
assertTrue(isRecoverableError(new SSLException("Read error: ssl=0x9dd07200: I/O error during system call, Connection reset by peer")));
assertTrue(isRecoverableError(new SSLException("SSL handshake aborted: ssl=0x1cc160: I/O error during system call, Connection reset by peer")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,60 @@
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.regex.Pattern;

import javax.net.ssl.SSLException;

/**
* HTTP utilities.
*/
public final class HttpUtils {

/**
* Types of exception that can be retried, no matter what the details are. Sub-classes are included.
*/
private static final Class[] RECOVERABLE_EXCEPTIONS = {
EOFException.class,
InterruptedIOException.class,
SocketException.class,
UnknownHostException.class
};

/**
* Some transient exceptions can only be detected by interpreting the message...
*/
private static Pattern CONNECTION_ISSUE_PATTERN = Pattern.compile("connection (time|reset)");

@VisibleForTesting
HttpUtils() {
}

/**
* Check whether an exception/error describes a recoverable error or not.
*
* @param t exception or error.
* @return true if the exception/error should be retried, false otherwise.
*/
public static boolean isRecoverableError(Throwable t) {

/* Check HTTP exception details. */
if (t instanceof HttpException) {
HttpException exception = (HttpException) t;
int code = exception.getStatusCode();
return code >= 500 || code == 408 || code == 429 || code == 401;
}

/* Check for a generic exception to retry. */
for (Class<?> type : RECOVERABLE_EXCEPTIONS)
if (type.isAssignableFrom(t.getClass()))
return true;

/* Check corner cases. */
if (t instanceof SSLException) {
String message = t.getMessage();
if (message != null && CONNECTION_ISSUE_PATTERN.matcher(message.toLowerCase()).find())
return true;
}
return false;
}
}

0 comments on commit 80c98c4

Please sign in to comment.