mirror of https://github.com/apache/jclouds.git
Issue 821:retry on close_notify SSLException
This commit is contained in:
parent
7b17255d95
commit
32d4dbac8a
|
@ -18,23 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.http.internal;
|
package org.jclouds.http.internal;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import com.google.common.io.NullOutputStream;
|
||||||
import static com.google.common.io.ByteStreams.copy;
|
|
||||||
import static org.jclouds.http.HttpUtils.checkRequestHasContentLengthOrChunkedEncoding;
|
|
||||||
import static org.jclouds.http.HttpUtils.wirePayloadIfEnabled;
|
|
||||||
|
|
||||||
import java.io.FilterInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
import javax.net.ssl.SSLException;
|
|
||||||
|
|
||||||
import org.jclouds.Constants;
|
import org.jclouds.Constants;
|
||||||
import org.jclouds.http.HttpCommand;
|
import org.jclouds.http.HttpCommand;
|
||||||
import org.jclouds.http.HttpCommandExecutorService;
|
import org.jclouds.http.HttpCommandExecutorService;
|
||||||
|
@ -47,10 +31,22 @@ import org.jclouds.http.IOExceptionRetryHandler;
|
||||||
import org.jclouds.http.handlers.DelegatingErrorHandler;
|
import org.jclouds.http.handlers.DelegatingErrorHandler;
|
||||||
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
import org.jclouds.rest.AuthorizationException;
|
|
||||||
import org.jclouds.util.Throwables2;
|
import org.jclouds.util.Throwables2;
|
||||||
|
|
||||||
import com.google.common.io.NullOutputStream;
|
import javax.annotation.Resource;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.io.ByteStreams.copy;
|
||||||
|
import static org.jclouds.http.HttpUtils.checkRequestHasContentLengthOrChunkedEncoding;
|
||||||
|
import static org.jclouds.http.HttpUtils.wirePayloadIfEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -171,18 +167,13 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
IOException ioe = Throwables2.getFirstThrowableOfType(e, IOException.class);
|
IOException ioe = Throwables2.getFirstThrowableOfType(e, IOException.class);
|
||||||
if (ioe != null) {
|
if (ioe != null && ioRetryHandler.shouldRetryRequest(command, ioe)) {
|
||||||
if (ioe instanceof SSLException) {
|
|
||||||
command.setException(new AuthorizationException(e.getMessage() + " connecting to "
|
|
||||||
+ command.getCurrentRequest().getRequestLine(), e));
|
|
||||||
break;
|
|
||||||
} else if (ioRetryHandler.shouldRetryRequest(command, ioe)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
command.setException(new HttpResponseException(e.getMessage() + " connecting to "
|
command.setException(new HttpResponseException(e.getMessage() + " connecting to "
|
||||||
+ command.getCurrentRequest().getRequestLine(), command, null, e));
|
+ command.getCurrentRequest().getRequestLine(), command, null, e));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
cleanup(nativeRequest);
|
cleanup(nativeRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,20 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.http;
|
package org.jclouds.http;
|
||||||
|
|
||||||
|
import static com.google.common.base.Throwables.propagate;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLException;
|
||||||
|
|
||||||
import org.jclouds.rest.BaseRestClientExpectTest;
|
import org.jclouds.rest.BaseRestClientExpectTest;
|
||||||
import org.jclouds.rest.BaseRestClientExpectTest.RegisterContext;
|
import org.jclouds.rest.BaseRestClientExpectTest.RegisterContext;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Allows us to test a client via its side effects.
|
* Allows us to test a client via its side effects.
|
||||||
|
@ -37,6 +43,33 @@ import org.testng.annotations.Test;
|
||||||
@RegisterContext(sync = IntegrationTestClient.class, async = IntegrationTestAsyncClient.class)
|
@RegisterContext(sync = IntegrationTestClient.class, async = IntegrationTestAsyncClient.class)
|
||||||
public class IntegrationTestClientExpectTest extends BaseRestClientExpectTest<IntegrationTestClient> {
|
public class IntegrationTestClientExpectTest extends BaseRestClientExpectTest<IntegrationTestClient> {
|
||||||
|
|
||||||
|
public void testRetryOnSSLExceptionClose() {
|
||||||
|
// keeps track of request count
|
||||||
|
final AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
IntegrationTestClient client = createClient(new Function<HttpRequest, HttpResponse>() {
|
||||||
|
@Override
|
||||||
|
public HttpResponse apply(HttpRequest input) {
|
||||||
|
// on first request, throw an SSL close_notify exception
|
||||||
|
if (counter.getAndIncrement() == 0)
|
||||||
|
throw propagate(new SSLException("Received close_notify during handshake"));
|
||||||
|
|
||||||
|
// on other requests, just validate and return 200
|
||||||
|
assertEquals(renderRequest(input), renderRequest(HttpRequest.builder().method("HEAD").endpoint(
|
||||||
|
URI.create("http://mock/objects/rabbit")).build()));
|
||||||
|
return HttpResponse.builder().statusCode(200).build();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// try three times, first should fail quietly due to retry logic
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
assertEquals(client.exists("rabbit"), true);
|
||||||
|
|
||||||
|
// should be an extra request relating to the retry
|
||||||
|
assertEquals(counter.get(), 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void testWhenResponseIs2xxExistsReturnsTrue() {
|
public void testWhenResponseIs2xxExistsReturnsTrue() {
|
||||||
|
|
||||||
IntegrationTestClient client = requestSendsResponse(HttpRequest.builder().method("HEAD").endpoint(
|
IntegrationTestClient client = requestSendsResponse(HttpRequest.builder().method("HEAD").endpoint(
|
||||||
|
|
Loading…
Reference in New Issue