Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit c05f328

Browse files
Igor Dvorzhakpavelbucek
authored andcommitted
JERSEY-2728: Treat any IOExpcetion thrown from MessageBodyWorkers#writeTo(...) as a connection failure.
Change-Id: Ia7e616573c575d1c893cfe939d2e4be61f83337f
1 parent b3a64c6 commit c05f328

File tree

3 files changed

+76
-17
lines changed

3 files changed

+76
-17
lines changed

core-client/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@
153153
<artifactId>hamcrest-library</artifactId>
154154
<scope>test</scope>
155155
</dependency>
156+
157+
<dependency>
158+
<groupId>org.jmockit</groupId>
159+
<artifactId>jmockit</artifactId>
160+
<scope>test</scope>
161+
</dependency>
156162
</dependencies>
157163
<properties>
158164
<java.version>1.6</java.version>

core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141

4242
import java.io.IOException;
4343
import java.io.OutputStream;
44+
import java.lang.annotation.Annotation;
45+
import java.lang.reflect.Type;
4446
import java.net.ConnectException;
4547
import java.net.NoRouteToHostException;
4648
import java.net.SocketTimeoutException;
@@ -59,11 +61,14 @@
5961
import javax.ws.rs.core.GenericType;
6062
import javax.ws.rs.core.HttpHeaders;
6163
import javax.ws.rs.core.MediaType;
64+
import javax.ws.rs.core.MultivaluedMap;
6265
import javax.ws.rs.core.Response;
6366
import javax.ws.rs.core.Variant;
6467
import javax.ws.rs.ext.ReaderInterceptor;
6568
import javax.ws.rs.ext.WriterInterceptor;
6669

70+
import javax.net.ssl.SSLException;
71+
6772
import org.glassfish.jersey.client.internal.LocalizationMessages;
6873
import org.glassfish.jersey.internal.MapPropertiesDelegate;
6974
import org.glassfish.jersey.internal.PropertiesDelegate;
@@ -495,11 +500,24 @@ public void writeEntity() throws IOException {
495500
entityWritten = true;
496501
ensureMediaType();
497502
final GenericType<?> entityType = new GenericType(getEntityType());
503+
doWriteEntity(workers, entityType);
504+
}
505+
506+
/**
507+
* Added only to make the code testable.
508+
*
509+
* @param writeWorkers Message body workers instance used to write the entity.
510+
* @param entityType entity type.
511+
* @throws IOException when {@link MessageBodyWorkers#writeTo(Object, Class, Type, Annotation[], MediaType,
512+
* MultivaluedMap, PropertiesDelegate, OutputStream, Iterable)} throws an {@link IOException}.
513+
* This state is always regarded as connection failure.
514+
*/
515+
/* package */ void doWriteEntity(final MessageBodyWorkers writeWorkers, final GenericType<?> entityType) throws IOException {
498516
OutputStream entityStream = null;
499517
boolean connectionFailed = false;
500518
try {
501519
try {
502-
entityStream = workers.writeTo(
520+
entityStream = writeWorkers.writeTo(
503521
getEntity(),
504522
entityType.getRawType(),
505523
entityType.getType(),
@@ -510,21 +528,8 @@ public void writeEntity() throws IOException {
510528
getEntityStream(),
511529
writerInterceptors);
512530
setEntityStream(entityStream);
513-
} catch (final ConnectException ce) {
514-
// MessageBodyWorkers.writeTo() produces more general IOException, but we are only interested in specifying if
515-
// the failure was caused by connection problems or by other circumstances
516-
connectionFailed = true;
517-
throw ce;
518-
} catch (final SocketTimeoutException e) {
519-
// if MessageBodyWorkers.writeTo() fails because of non-routable target, SocketTimeOutException is thrown.
520-
// In that case, exception is rethrown and the connectionFailed flag is set to prevent the attempt to commit.
521-
// Calling commitStream() would lead to another wait time and the final timeout time would be twice as long
522-
// as described in JERSEY-1984. Depending on a system and configuration, NoRouteToHostException may be thrown
523-
// instead of SocketTimeoutException (see below).
524-
connectionFailed = true;
525-
throw e;
526-
} catch (final NoRouteToHostException e) {
527-
// to cover all the cases, also NoRouteToHostException is to be handled similarly.
531+
} catch (final IOException e) {
532+
// JERSEY-2728 - treat SSLException as connection failure
528533
connectionFailed = true;
529534
throw e;
530535
}

core-client/src/test/java/org/glassfish/jersey/client/ClientRequestTest.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
33
*
4-
* Copyright (c) 2013-2014 Oracle and/or its affiliates. All rights reserved.
4+
* Copyright (c) 2013-2015 Oracle and/or its affiliates. All rights reserved.
55
*
66
* The contents of this file are subject to the terms of either the GNU
77
* General Public License Version 2 only ("GPL") or the Common Development
@@ -39,21 +39,41 @@
3939
*/
4040
package org.glassfish.jersey.client;
4141

42+
import java.io.IOException;
43+
import java.io.OutputStream;
44+
import java.lang.annotation.Annotation;
45+
import java.lang.reflect.Type;
4246
import java.net.URI;
4347

48+
import javax.ws.rs.core.GenericType;
49+
import javax.ws.rs.core.MediaType;
50+
import javax.ws.rs.core.MultivaluedMap;
51+
import javax.ws.rs.ext.WriterInterceptor;
52+
4453
import org.glassfish.jersey.internal.MapPropertiesDelegate;
54+
import org.glassfish.jersey.internal.PropertiesDelegate;
55+
import org.glassfish.jersey.message.MessageBodyWorkers;
4556

57+
import org.junit.Assert;
4658
import org.junit.Test;
59+
import org.junit.runner.RunWith;
4760
import static org.junit.Assert.assertEquals;
4861
import static org.junit.Assert.assertFalse;
4962
import static org.junit.Assert.assertNull;
63+
import static org.junit.Assert.assertSame;
5064
import static org.junit.Assert.assertTrue;
5165

66+
import mockit.Mock;
67+
import mockit.MockUp;
68+
import mockit.Mocked;
69+
import mockit.integration.junit4.JMockit;
70+
5271
/**
5372
* {@code ClientRequest} unit tests.
5473
*
5574
* @author Marek Potociar (marek.potociar at oracle.com)
5675
*/
76+
@RunWith(JMockit.class)
5777
public class ClientRequestTest {
5878

5979
/**
@@ -136,4 +156,32 @@ public void testResolveProperty() {
136156
assertEquals("value-request", request.resolveProperty("name", "value-default"));
137157
}
138158

159+
@Test
160+
public void testSSLExceptionHandling(@Mocked MessageBodyWorkers workers, @Mocked GenericType<?> entityType)
161+
throws Exception {
162+
JerseyClient client = new JerseyClientBuilder().build();
163+
final ClientRequest request = new ClientRequest(
164+
URI.create("http://example.org"),
165+
client.getConfiguration(),
166+
new MapPropertiesDelegate());
167+
168+
final IOException ioException = new IOException("Test");
169+
new MockUp<MessageBodyWorkers>(workers) {
170+
@Mock
171+
OutputStream writeTo(Object entity, Class<?> rawType, Type type, Annotation[] annotations,
172+
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
173+
PropertiesDelegate propertiesDelegate, OutputStream entityStream,
174+
Iterable<WriterInterceptor> writerInterceptors)
175+
throws java.io.IOException, javax.ws.rs.WebApplicationException {
176+
throw ioException;
177+
}
178+
};
179+
180+
try {
181+
request.doWriteEntity(workers, entityType);
182+
Assert.fail("An IOException exception should be thrown.");
183+
} catch (IOException e) {
184+
assertSame(ioException, e);
185+
}
186+
}
139187
}

0 commit comments

Comments
 (0)