diff --git a/nuxeo-jsf/nuxeo-platform-ui-web/src/main/java/org/nuxeo/ecm/platform/ui/web/rest/FancyURLFilter.java b/nuxeo-jsf/nuxeo-platform-ui-web/src/main/java/org/nuxeo/ecm/platform/ui/web/rest/FancyURLFilter.java
index 7f8b76a..7dda3bb 100644
--- a/nuxeo-jsf/nuxeo-platform-ui-web/src/main/java/org/nuxeo/ecm/platform/ui/web/rest/FancyURLFilter.java
+++ b/nuxeo-jsf/nuxeo-platform-ui-web/src/main/java/org/nuxeo/ecm/platform/ui/web/rest/FancyURLFilter.java
@@ -131,6 +131,7 @@ public class FancyURLFilter implements Filter {
         } catch (IOException e) {
             String url = httpRequest.getRequestURL().toString();
             if (ExceptionHelper.isClientAbortError(e)) {
+                ExceptionHelper.logClientAbort(e);
                 log.debug(String.format("Client disconnected from URL %s : %s",
                         url, e.getMessage()));
             } else {
@@ -139,6 +140,7 @@ public class FancyURLFilter implements Filter {
         } catch (ServletException e) {
             String url = httpRequest.getRequestURL().toString();
             if (ExceptionHelper.isClientAbortError(e)) {
+                ExceptionHelper.logClientAbort(e);
                 log.debug(String.format("Client disconnected from URL %s : %s",
                         url, e.getMessage()));
             } else {
diff --git a/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/ui/web/download/DownloadServlet.java b/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/ui/web/download/DownloadServlet.java
index 828ea50..06977e3 100644
--- a/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/ui/web/download/DownloadServlet.java
+++ b/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/ui/web/download/DownloadServlet.java
@@ -330,7 +330,7 @@ public class DownloadServlet extends HttpServlet {
 
     public void handleClientDisconnect(IOException ioe) throws IOException {
         if (ExceptionHelper.isClientAbortError(ioe)) {
-            log.debug("Client disconnected: " + ioe.getMessage());
+            ExceptionHelper.logClientAbort(ioe);
         } else {
             // this is a real unexpected problem, let the traditional error
             // management handle this case
diff --git a/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/exceptionhandling/ExceptionHelper.java b/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/exceptionhandling/ExceptionHelper.java
index 971ae25..522ced1 100644
--- a/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/exceptionhandling/ExceptionHelper.java
+++ b/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/exceptionhandling/ExceptionHelper.java
@@ -18,18 +18,26 @@
 
 package org.nuxeo.ecm.platform.web.common.exceptionhandling;
 
-import java.net.SocketException;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
 
 import javax.servlet.ServletException;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.nuxeo.ecm.core.api.DocumentSecurityException;
 
 public class ExceptionHelper {
 
+    private static final Log log = LogFactory.getLog(ExceptionHelper.class);
+
+    // tomcat catalina
     private static final String CLIENT_ABORT_EXCEPTION = "ClientAbortException";
 
+    // jetty (with CamelCase "Eof")
+    private static final String EOF_EXCEPTION = "EofException";
+
     private ExceptionHelper() {
     }
 
@@ -72,25 +80,26 @@ public class ExceptionHelper {
     }
 
     public static boolean isClientAbortError(Throwable t) {
-        if (t == null) {
-            return false;
-        } else if (t instanceof SocketException
-                || t.getCause() instanceof SocketException) {
-            return true;
-        } else {
-            // handle all IOException that are ClientAbortException by looking
-            // at their class name since the package name is not the same for
-            // jboss, glassfish, tomcat and jetty and we don't want to add
-            // implementation specific build dependencies to this project
-            if (CLIENT_ABORT_EXCEPTION.equals(t.getClass().getSimpleName())) {
-                return true;
-            }
-            Throwable cause = t.getCause();
-            if (cause != null
-                    && CLIENT_ABORT_EXCEPTION.equals(cause.getClass().getSimpleName())) {
-                return true;
+        int loops = 20; // no infinite loop
+        while (t != null && loops > 0) {
+            if (t instanceof IOException) {
+                // handle all IOException that are ClientAbortException by looking
+                // at their class name since the package name is not the same for
+                // jboss, glassfish, tomcat and jetty and we don't want to add
+                // implementation specific build dependencies to this project
+                String name = t.getClass().getSimpleName();
+                if (CLIENT_ABORT_EXCEPTION.equals(name) || EOF_EXCEPTION.equals(name)) {
+                    return true;
+                }
             }
+            loops--;
+            t = t.getCause();
         }
         return false;
     }
+
+    public static void logClientAbort(Exception e) {
+        log.warn("Client disconnected: " + unwrapException(e).getMessage());
+    }
+
 }
diff --git a/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/requestcontroller/filter/BufferingServletOutputStream.java b/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/requestcontroller/filter/BufferingServletOutputStream.java
index 679fbf2..c0dc2e0 100644
--- a/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/requestcontroller/filter/BufferingServletOutputStream.java
+++ b/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/requestcontroller/filter/BufferingServletOutputStream.java
@@ -207,6 +207,7 @@ public class BufferingServletOutputStream extends ServletOutputStream {
             }
             log.debug("buffered bytes: " + len);
         }
+        boolean clientAbort = false;
         try {
             if (memory != null) {
                 memory.writeTo(outputStream);
@@ -221,10 +222,9 @@ public class BufferingServletOutputStream extends ServletOutputStream {
                     try {
                         IOUtils.copy(in, outputStream);
                     } catch (IOException e) {
-                        Throwable unwrappedError = ExceptionHelper.unwrapException(e);
-                        if (ExceptionHelper.isClientAbortError(unwrappedError)) {
-                            log.warn("Client disconnected: "
-                                    + unwrappedError.getMessage());
+                        if (ExceptionHelper.isClientAbortError(e)) {
+                            ExceptionHelper.logClientAbort(e);
+                            clientAbort = true;
                         } else {
                             throw e;
                         }
@@ -236,9 +236,11 @@ public class BufferingServletOutputStream extends ServletOutputStream {
                 }
             }
         } catch (IOException e) {
-            Throwable unwrappedError = ExceptionHelper.unwrapException(e);
-            if (ExceptionHelper.isClientAbortError(unwrappedError)) {
-                log.warn("Client disconnected : " + unwrappedError.getMessage());
+            if (ExceptionHelper.isClientAbortError(e)) {
+                if (!clientAbort) {
+                    ExceptionHelper.logClientAbort(e);
+                    clientAbort = true;
+                }
             } else {
                 throw e;
             }
@@ -251,10 +253,10 @@ public class BufferingServletOutputStream extends ServletOutputStream {
                     outputStream.flush();
                 }
             } catch (IOException e) {
-                Throwable unwrappedError = ExceptionHelper.unwrapException(e);
-                if (ExceptionHelper.isClientAbortError(unwrappedError)) {
-                    log.warn("Client disconnected : "
-                            + unwrappedError.getMessage());
+                if (ExceptionHelper.isClientAbortError(e)) {
+                    if (!clientAbort) {
+                        ExceptionHelper.logClientAbort(e);
+                    }
                 } else {
                     throw e;
                 }
diff --git a/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/requestcontroller/filter/NuxeoRequestControllerFilter.java b/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/requestcontroller/filter/NuxeoRequestControllerFilter.java
index f5fd79b..3590a91 100644
--- a/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/requestcontroller/filter/NuxeoRequestControllerFilter.java
+++ b/nuxeo-services/nuxeo-platform-web-common/src/main/java/org/nuxeo/ecm/platform/web/common/requestcontroller/filter/NuxeoRequestControllerFilter.java
@@ -144,10 +144,8 @@ public class NuxeoRequestControllerFilter implements Filter {
             try {
                 chain.doFilter(request, response);
             } catch (ServletException e) {
-                Throwable unwrappedError = ExceptionHelper.unwrapException(e);
-                if (ExceptionHelper.isClientAbortError(unwrappedError)) {
-                    log.warn("Client disconnected: "
-                            + unwrappedError.getMessage());
+                if (ExceptionHelper.isClientAbortError(e)) {
+                    ExceptionHelper.logClientAbort(e);
                 } else {
                     throw e;
                 }
@@ -184,10 +182,8 @@ public class NuxeoRequestControllerFilter implements Filter {
                 }
                 TransactionHelper.setTransactionRollbackOnly();
             }
-            Throwable unwrappedError = ExceptionHelper.unwrapException(e);
-            if (ExceptionHelper.isClientAbortError(unwrappedError)) {
-                log.warn("Client disconnected: "
-                        + unwrappedError.getMessage());
+            if (ExceptionHelper.isClientAbortError(e)) {
+                ExceptionHelper.logClientAbort(e);
             } else {
                 log.error(
                     doFormatLogMessage(httpRequest,
diff --git a/nuxeo-webengine/nuxeo-webengine-core/src/main/java/org/nuxeo/ecm/webengine/model/io/FileWriter.java b/nuxeo-webengine/nuxeo-webengine-core/src/main/java/org/nuxeo/ecm/webengine/model/io/FileWriter.java
index 4e3edf0..52296f0 100644
--- a/nuxeo-webengine/nuxeo-webengine-core/src/main/java/org/nuxeo/ecm/webengine/model/io/FileWriter.java
+++ b/nuxeo-webengine/nuxeo-webengine-core/src/main/java/org/nuxeo/ecm/webengine/model/io/FileWriter.java
@@ -60,14 +60,9 @@ public class FileWriter implements MessageBodyWriter<File> {
             in = new FileInputStream(t);
             FileUtils.copy(in, entityStream);
             entityStream.flush();
-        } catch (Throwable e) {
-            Throwable unwrappedError = ExceptionHelper.unwrapException(e);
-            if (ExceptionHelper.isClientAbortError(unwrappedError)) {
-                // ignore but log as warn
-                log.warn(unwrappedError.getMessage());
-            } else if (unwrappedError instanceof IOException) {
-                // can be a broken pipe => do not display the whole stack trace
-                log.error(unwrappedError.getMessage());
+        } catch (RuntimeException | IOException e) {
+            if (ExceptionHelper.isClientAbortError(e)) {
+                ExceptionHelper.logClientAbort(e);
             } else {
                 throw WebException.wrap("Failed to render resource", e);
             }
