From ac78c175231979c7c5ab361980a233edee7626df Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Sat, 26 Feb 2022 12:46:50 +0100 Subject: [PATCH] [sideband] Ensure last bit of progress channel is written If the last sideband progress message didn't end in \r or \n, there may still be a buffered message at the end of a fetch or push. Ensure that message gets written, too, even if it may be only partial. Bug: 575629 Change-Id: I38edccb5cffb89e00e468480b43c7d951fb63e8e Signed-off-by: Thomas Wolf --- .../transport/SideBandInputStreamTest.java | 17 ++++++++++++++ .../transport/BasePackFetchConnection.java | 15 ++++++++---- .../transport/BasePackPushConnection.java | 8 +++++-- .../jgit/transport/SideBandInputStream.java | 23 ++++++++++++++++++- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java index 497f584b5..7ac83195f 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandInputStreamTest.java @@ -79,6 +79,8 @@ public void progressPartial() throws IOException { init(packet("message")); assertTrue(sideband.read() < 0); assertEquals("", messages.toString()); + sideband.drainMessages(); + assertEquals("message\n", messages.toString()); } @Test @@ -128,6 +130,8 @@ public void progressPartialCR() throws IOException { init(packet("message 0%\rmessage 100%")); assertTrue(sideband.read() < 0); assertEquals("message 0%\r", messages.toString()); + sideband.drainMessages(); + assertEquals("message 0%\rmessage 100%\n", messages.toString()); } @Test @@ -135,6 +139,8 @@ public void progressPartialLF() throws IOException { init(packet("message 0%\nmessage 100%")); assertTrue(sideband.read() < 0); assertEquals("message 0%\n", messages.toString()); + sideband.drainMessages(); + assertEquals("message 0%\nmessage 100%\n", messages.toString()); } @Test @@ -142,6 +148,8 @@ public void progressPartialCRLF() throws IOException { init(packet("message 0%\r\nmessage 100%")); assertTrue(sideband.read() < 0); assertEquals("message 0%\r\n", messages.toString()); + sideband.drainMessages(); + assertEquals("message 0%\r\nmessage 100%\n", messages.toString()); } @Test @@ -152,6 +160,8 @@ public void progressPartialSplitCR() throws IOException { assertEquals("", messages.toString()); assertTrue(sideband.read() < 0); assertEquals("message 0%\r", messages.toString()); + sideband.drainMessages(); + assertEquals("message 0%\rmessage 100%\n", messages.toString()); } @Test @@ -162,6 +172,8 @@ public void progressPartialSplitLF() throws IOException { assertEquals("", messages.toString()); assertTrue(sideband.read() < 0); assertEquals("message 0%\n", messages.toString()); + sideband.drainMessages(); + assertEquals("message 0%\nmessage 100%\n", messages.toString()); } @Test @@ -172,6 +184,8 @@ public void progressPartialSplitCRLF() throws IOException { assertEquals("", messages.toString()); assertTrue(sideband.read() < 0); assertEquals("message 0%\r\n", messages.toString()); + sideband.drainMessages(); + assertEquals("message 0%\r\nmessage 100%\n", messages.toString()); } @Test @@ -197,6 +211,9 @@ public void progressInterleavedPartial() throws IOException { assertEquals("message 0%\r", messages.toString()); assertTrue(sideband.read() < 0); assertEquals("message 0%\rmessage 10%\r", messages.toString()); + sideband.drainMessages(); + assertEquals("message 0%\rmessage 10%\rmessage 100%\n", + messages.toString()); } private String packet(String data) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java index f48e1e68c..3f167ccce 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2008, 2010 Google Inc. * Copyright (C) 2008, Robin Rosenberg - * Copyright (C) 2008, 2020 Shawn O. Pearce and others + * Copyright (C) 2008, 2022 Shawn O. Pearce and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -1004,9 +1004,12 @@ private void receivePack(final ProgressMonitor monitor, OutputStream outputStream) throws IOException { onReceivePack(); InputStream input = in; - if (sideband) - input = new SideBandInputStream(input, monitor, getMessageWriter(), - outputStream); + SideBandInputStream sidebandIn = null; + if (sideband) { + sidebandIn = new SideBandInputStream(input, monitor, + getMessageWriter(), outputStream); + input = sidebandIn; + } try (ObjectInserter ins = local.newObjectInserter()) { PackParser parser = ins.newPackParser(input); @@ -1015,6 +1018,10 @@ private void receivePack(final ProgressMonitor monitor, parser.setLockMessage(lockMessage); packLock = parser.parse(monitor); ins.flush(); + } finally { + if (sidebandIn != null) { + sidebandIn.drainMessages(); + } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java index b87a85d93..b7be59d6f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2008, Marek Zawirski - * Copyright (C) 2008, Shawn O. Pearce and others + * Copyright (C) 2008, 2022 Shawn O. Pearce and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -194,10 +194,11 @@ protected void doPush(final ProgressMonitor monitor, // the other data channels. // int b = in.read(); - if (0 <= b) + if (0 <= b) { throw new TransportException(uri, MessageFormat.format( JGitText.get().expectedEOFReceived, Character.valueOf((char) b))); + } } } } catch (TransportException e) { @@ -205,6 +206,9 @@ protected void doPush(final ProgressMonitor monitor, } catch (Exception e) { throw new TransportException(uri, e.getMessage(), e); } finally { + if (in instanceof SideBandInputStream) { + ((SideBandInputStream) in).drainMessages(); + } close(); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java index 8a8d977ed..96c7be5b9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandInputStream.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2008, Robin Rosenberg - * Copyright (C) 2008, Shawn O. Pearce and others + * Copyright (C) 2008, 2022 Shawn O. Pearce and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -28,6 +28,8 @@ import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Unmultiplexes the data portion of a side-band channel. @@ -46,6 +48,10 @@ * @since 4.11 */ public class SideBandInputStream extends InputStream { + + private static final Logger LOG = LoggerFactory + .getLogger(SideBandInputStream.class); + static final int CH_DATA = 1; static final int CH_PROGRESS = 2; static final int CH_ERROR = 3; @@ -210,6 +216,21 @@ private void beginTask(int totalWorkUnits) { monitor.beginTask(remote(currentTask), totalWorkUnits); } + /** + * Forces any buffered progress messages to be written. + */ + void drainMessages() { + if (!progressBuffer.isEmpty()) { + try { + progress("\n"); //$NON-NLS-1$ + } catch (IOException e) { + // Just log; otherwise this IOException might hide a real + // TransportException + LOG.error(e.getMessage(), e); + } + } + } + private static String remote(String msg) { String prefix = JGitText.get().prefixRemote; StringBuilder r = new StringBuilder(prefix.length() + msg.length() + 1);