Skip to content

Commit 85f2f50

Browse files
Carter Kozakvelo
authored andcommitted
Response is closed after decoder fails (OpenFeign#668)
Previously a decoder failure resulting in an exception would fail to close responses when "doNotCloseAfterDecode" was enabled.
1 parent 7670103 commit 85f2f50

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

core/src/main/java/feign/SynchronousMethodHandler.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,14 @@ Object executeAndDecode(RequestTemplate template) throws Throwable {
131131
if (void.class == metadata.returnType()) {
132132
return null;
133133
} else {
134+
Object result = decode(response);
134135
shouldClose = closeAfterDecode;
135-
return decode(response);
136+
return result;
136137
}
137138
} else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
139+
Object result = decode(response);
138140
shouldClose = closeAfterDecode;
139-
return decode(response);
141+
return result;
140142
} else {
141143
throw errorDecoder.decode(metadata.configKey(), response);
142144
}

core/src/test/java/feign/FeignBuilderTest.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import org.junit.Test;
2222

2323
import java.io.IOException;
24+
import java.io.InputStream;
25+
import java.io.Reader;
2426
import java.lang.reflect.InvocationHandler;
2527
import java.lang.reflect.Method;
2628
import java.lang.reflect.Type;
@@ -29,6 +31,7 @@
2931
import java.util.Iterator;
3032
import java.util.List;
3133
import java.util.Map;
34+
import java.util.concurrent.atomic.AtomicBoolean;
3235
import java.util.concurrent.atomic.AtomicInteger;
3336

3437
import feign.codec.Decoder;
@@ -349,6 +352,75 @@ public Object next() {
349352
assertEquals(1, server.getRequestCount());
350353
}
351354

355+
/**
356+
* When {@link Feign.Builder#doNotCloseAfterDecode()} is enabled an an exception
357+
* is thrown from the {@link Decoder}, the response should be closed.
358+
*/
359+
@Test
360+
public void testDoNotCloseAfterDecodeDecoderFailure() throws Exception {
361+
server.enqueue(new MockResponse().setBody("success!"));
362+
363+
String url = "http://localhost:" + server.getPort();
364+
Decoder angryDecoder = new Decoder() {
365+
@Override
366+
public Object decode(Response response, Type type) throws IOException {
367+
throw new IOException("Failed to decode the response");
368+
}
369+
};
370+
371+
final AtomicBoolean closed = new AtomicBoolean();
372+
TestInterface api = Feign.builder()
373+
.client(new Client() {
374+
Client client = new Client.Default(null, null);
375+
@Override
376+
public Response execute(Request request, Request.Options options) throws IOException {
377+
final Response original = client.execute(request, options);
378+
return Response.builder()
379+
.status(original.status())
380+
.headers(original.headers())
381+
.reason(original.reason())
382+
.request(original.request())
383+
.body(new Response.Body() {
384+
@Override
385+
public Integer length() {
386+
return original.body().length();
387+
}
388+
389+
@Override
390+
public boolean isRepeatable() {
391+
return original.body().isRepeatable();
392+
}
393+
394+
@Override
395+
public InputStream asInputStream() throws IOException {
396+
return original.body().asInputStream();
397+
}
398+
399+
@Override
400+
public Reader asReader() throws IOException {
401+
return original.body().asReader();
402+
}
403+
404+
@Override
405+
public void close() throws IOException {
406+
closed.set(true);
407+
original.body().close();
408+
}
409+
})
410+
.build();
411+
}
412+
})
413+
.decoder(angryDecoder)
414+
.doNotCloseAfterDecode()
415+
.target(TestInterface.class, url);
416+
try {
417+
api.decodedLazyPost();
418+
fail("Expected an exception");
419+
} catch (FeignException expected) {
420+
}
421+
assertTrue("Responses must be closed when the decoder fails", closed.get());
422+
}
423+
352424
interface TestInterface {
353425
@RequestLine("GET")
354426
Response getNoPath();

0 commit comments

Comments
 (0)