TaskThunk#run: ignore SshChannelClosedException

As recommended by Thomas Wolf in [1] ignore SshChannelClosedException
when flushing the task's output and error streams. JGit commands like
UploadPack flush these streams already. When TaskThunk tries to flush
them again SshChannelClosedException is thrown and leads to an
internal server error:

[SSH git-upload-pack /xxx.git (xxx)] ERROR com.google.gerrit.sshd.BaseCommand :
  Internal server error (user xxx account xx) during git-upload-pack '/xxx.git'
org.apache.sshd.common.channel.exception.SshChannelClosedException:
    write(ChannelOutputStream SSH_MSG_CHANNEL_DATA) len=17 - channel already closed
  at org.apache.sshd.common.channel.ChannelOutputStream.write(ChannelOutputStream.java:132)
  at org.eclipse.jgit.transport.UploadPack$ResponseBufferedOutputStream.write(UploadPack.java:2495)
  at org.eclipse.jgit.transport.SideBandOutputStream.writeBuffer(SideBandOutputStream.java:141)
  at org.eclipse.jgit.transport.SideBandOutputStream.flushBuffer(SideBandOutputStream.java:94)
  at org.eclipse.jgit.transport.SideBandOutputStream.flush(SideBandOutputStream.java:100)
  at org.eclipse.jgit.transport.PacketLineOut.writePacket(PacketLineOut.java:157)
  at org.eclipse.jgit.transport.PacketLineOut.writePacket(PacketLineOut.java:133)
  at org.eclipse.jgit.transport.PacketLineOut.writeString(PacketLineOut.java:119)
  at org.eclipse.jgit.transport.RefAdvertiser$PacketLineOutRefAdvertiser.writeOne(RefAdvertiser.java:125)
  at org.eclipse.jgit.transport.RefAdvertiser.send(RefAdvertiser.java:306)
  at org.eclipse.jgit.transport.UploadPack.lsRefsV2(UploadPack.java:1133)
  at org.eclipse.jgit.transport.UploadPack.serveOneCommandV2(UploadPack.java:1347)
  at org.eclipse.jgit.transport.UploadPack.serviceV2(UploadPack.java:1398)
  at org.eclipse.jgit.transport.UploadPack.uploadWithExceptionPropagation(UploadPack.java:859)
  at org.eclipse.jgit.transport.UploadPack.upload(UploadPack.java:769)
  at com.google.gerrit.sshd.commands.Upload.runImpl(Upload.java:101)
  at com.google.gerrit.sshd.AbstractGitCommand.service(AbstractGitCommand.java:109)
  at com.google.gerrit.sshd.AbstractGitCommand$1.run(AbstractGitCommand.java:74)
  at com.google.gerrit.sshd.BaseCommand$TaskThunk.run(BaseCommand.java:491)
  at com.google.gerrit.server.logging.LoggingContextAwareRunnable.run(LoggingContextAwareRunnable.java:113)
  at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
  at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
  at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
  at com.google.gerrit.server.git.WorkQueue$Task.run(WorkQueue.java:612)
  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
  at java.base/java.lang.Thread.run(Thread.java:829)
  org.apache.sshd.common.channel.exception.SshChannelClosedException:
      write SSH_MSG_CHANNEL_DATA) len=4 - channel already closed
    at org.apache.sshd.common.channel.ChannelOutputStream.write(ChannelOutputStream.java:132)
    at org.eclipse.jgit.transport.UploadPack$ResponseBufferedOutputStream.write(UploadPack.java:2495)
    at org.eclipse.jgit.transport.PacketLineOut.writePacket(PacketLineOut.java:157)
    at org.eclipse.jgit.transport.PacketLineOut.writePacket(PacketLineOut.java:133)
    at org.eclipse.jgit.transport.PacketLineOut.writeString(PacketLineOut.java:119)
    at org.eclipse.jgit.transport.UploadPack$PackProtocolErrorWriter.writeError(UploadPack.java:2536)
    at org.eclipse.jgit.transport.UploadPack.upload(UploadPack.java:787)
    ...

[1] https://bugs.eclipse.org/bugs/show_bug.cgi?id=565854

Release-Notes: Fix internal server error caused by double flush in BaseCommand.TaskThunk
Change-Id: I66a650c30228bcbab2d9fb01449010dda53faba9
diff --git a/java/com/google/gerrit/sshd/BaseCommand.java b/java/com/google/gerrit/sshd/BaseCommand.java
index 2c373c5..75b08e7 100644
--- a/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/java/com/google/gerrit/sshd/BaseCommand.java
@@ -55,6 +55,7 @@
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.channel.exception.SshChannelClosedException;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.channel.ChannelSession;
@@ -499,19 +500,11 @@
             throw new UnloggedFailure(1, e.getMessage() + " no such change");
           }
 
-          out.flush();
-          err.flush();
+          flushIgnoreSCCE(out);
+          flushIgnoreSCCE(err);
         } catch (Throwable e) {
-          try {
-            out.flush();
-          } catch (Exception e2) {
-            // Ignored
-          }
-          try {
-            err.flush();
-          } catch (Exception e2) {
-            // Ignored
-          }
+          flushIgnoreException(out);
+          flushIgnoreException(err);
           rc = handleError(e);
         } finally {
           try {
@@ -524,6 +517,22 @@
       }
     }
 
+    private void flushIgnoreSCCE(OutputStream os) throws IOException {
+      try {
+        os.flush();
+      } catch (SshChannelClosedException e) {
+        // Ignore - command implementation flushed stream already
+      }
+    }
+
+    private void flushIgnoreException(OutputStream os) {
+      try {
+        os.flush();
+      } catch (Exception e) {
+        // Ignore
+      }
+    }
+
     @Override
     public String toString() {
       return taskName;