From 45aa1edf871e7e86cbd9523146a94b911d944736 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Thu, 16 Mar 2017 12:35:47 +0100 Subject: [PATCH] Fix Undertow zero-copy-support This commit fixed the exception that occurs when a larger file is transfered using zero-copy on Undertow. Issue: SPR-15343 --- .../reactive/UndertowServerHttpResponse.java | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java index bd16c86b810..3038602d348 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java @@ -30,6 +30,7 @@ import io.undertow.server.handlers.CookieImpl; import io.undertow.util.HttpString; import org.reactivestreams.Processor; import org.reactivestreams.Publisher; +import org.xnio.channels.Channels; import org.xnio.channels.StreamSinkChannel; import reactor.core.publisher.Mono; @@ -79,24 +80,28 @@ public class UndertowServerHttpResponse extends AbstractListenerServerHttpRespon @Override public Mono writeWith(File file, long position, long count) { - applyHeaders(); - applyCookies(); - try { - StreamSinkChannel responseChannel = getUndertowExchange().getResponseChannel(); - @SuppressWarnings("resource") - FileChannel in = new FileInputStream(file).getChannel(); - long result = responseChannel.transferFrom(in, position, count); - if (result < count) { - return Mono.error(new IOException( - "Could only write " + result + " out of " + count + " bytes")); - } - else { + return doCommit(() -> { + FileChannel source = null; + try { + source = new FileInputStream(file).getChannel(); + StreamSinkChannel destination = getUndertowExchange().getResponseChannel(); + Channels.transferBlocking(destination, source, position, count); return Mono.empty(); } - } - catch (IOException ex) { - return Mono.error(ex); - } + catch (IOException ex) { + return Mono.error(ex); + } + finally { + if (source != null) { + try { + source.close(); + } + catch (IOException ex) { + // ignore + } + } + } + }); } @Override