Fixed issue (noticed with upgraded Jetty): When FreemarkerServlet was used with the TemplateExceptionHandler.DEBUG_HANDLER or HTML_DEBUG_HANDLER, on Jetty the response web page was possibly empty or partial, as Jetty has abruptly closed the connection after we flushed the HTTP response with status code 200, and yet thrown an exception. Now in this situation we only log the exception, but don't throw it. (Production system should always use RETHROW_HANDLER, and this change has no effect there.)
diff --git a/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java b/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java
index 6ceeeb9..e8a3899 100644
--- a/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java
+++ b/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java
@@ -883,13 +883,29 @@
                 }
             }
         } catch (TemplateException e) {
+            boolean suppressServletException;
+
             final TemplateExceptionHandler teh = config.getTemplateExceptionHandler();
             // Ensure that debug handler responses aren't rolled back:
             if (teh == TemplateExceptionHandler.HTML_DEBUG_HANDLER || teh == TemplateExceptionHandler.DEBUG_HANDLER
-                    || teh.getClass().getName().indexOf("Debug") != -1) {
+                    || teh.getClass().getName().contains("Debug")) {
                 response.flushBuffer();
+
+                // Apparently, if the status is 200, yet the servlet throw an exception, Jetty (9.4.53) closes the
+                // connection, so the developer possibly won't see the debug error page (or not all of it).
+                suppressServletException = true;
+            } else {
+                suppressServletException = false;
             }
-            throw newServletExceptionWithFreeMarkerLogging("Error executing FreeMarker template", e);
+
+            if (suppressServletException) {
+                logSerlvetExceptionWithFreemarkerLog("Error executing FreeMarker template", e);
+                log("Error executing FreeMarker template. " +
+                        "Servlet-level exception was suppressed to show debug page with HTTP 200. " +
+                        "See earlier FreeMarker log message for details!");
+            } else {
+                throw newServletExceptionWithFreeMarkerLogging("Error executing FreeMarker template", e);
+            }
         }
     }
 
@@ -937,13 +953,7 @@
     }
 
     private ServletException newServletExceptionWithFreeMarkerLogging(String message, Throwable cause) throws ServletException {
-        if (cause instanceof TemplateException) {
-            // For backward compatibility, we log into the same category as Environment did when
-            // log_template_exceptions was true.
-            LOG_RT.error(message, cause);
-        } else {
-            LOG.error(message, cause);
-        }
+        logSerlvetExceptionWithFreemarkerLog(message, cause);
 
         ServletException e = new ServletException(message, cause);
         try {
@@ -955,7 +965,17 @@
         }
         throw e;
     }
-    
+
+    private static void logSerlvetExceptionWithFreemarkerLog(String message, Throwable cause) {
+        if (cause instanceof TemplateException) {
+            // For backward compatibility, we log into the same category as Environment did when
+            // log_template_exceptions was true.
+            LOG_RT.error(message, cause);
+        } else {
+            LOG.error(message, cause);
+        }
+    }
+
     @SuppressFBWarnings(value={ "MSF_MUTABLE_SERVLET_FIELD", "DC_DOUBLECHECK" }, justification="Performance trick")
     private void logWarnOnObjectWrapperMismatch() {
         // Deliberately uses double check locking.
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index e8f98da..4b4dc4b 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -30088,6 +30088,19 @@
             </listitem>
 
             <listitem>
+              <para>When <literal>FreemarkerServlet</literal> was used with
+              the <literal>TemplateExceptionHandler.DEBUG_HANDLER</literal> or
+              <literal>HTML_DEBUG_HANDLER</literal>, on Jetty the response web
+              page was possibly empty or partial, as the Jetty has abruptly
+              closed the connection after we flushed the HTTP response with
+              status code 200, and yet thrown an exception. Now in this
+              situation we only log the exception, but don't throw it.
+              (Production system should always use
+              <literal>RETHROW_HANDLER</literal>, and this change has no
+              effect there.)</para>
+            </listitem>
+
+            <listitem>
               <para>We don't generate RMIC stub classes for
               <literal>freemarker.debug.impl.Rmi*Impl</literal> classes
               anymore. Almost nobody uses that API, but if you do, you