aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorShawn Pearce <spearce@spearce.org>2016-07-04 22:10:55 -0700
committerShawn Pearce <spearce@spearce.org>2016-07-05 09:18:41 -0700
commitb57d060408bcc58b2afbce671b2e68a07e90d7d9 (patch)
treededa1cb30512b1dcae986988583fd60ea995adf8 /org.eclipse.jgit
parent61d444305e1a70fbfae47d2c691d064b83eef59e (diff)
downloadjgit-b57d060408bcc58b2afbce671b2e68a07e90d7d9.tar.gz
jgit-b57d060408bcc58b2afbce671b2e68a07e90d7d9.zip
push: Report fatal server errors during pack writing
If the push client has requested side-band support the server can signal a fatal error parsing the pack using the error channel (3) and then hang up. This may cause the PackWriter to fail to write to data onto the network socket, which throws a misleading error back up to the application and the user. During a write failure poll the input to see if the side band system can parse out an error message off channel 3. This should be fast as there will either be an error present in the buffer, or the remote will also have hung-up on the side band channel. In the case of a hang-up just rethrow the original IOException as its a network error. This roughly matches what C git does; once commands are sent and the packer is started a new thread runs in the background to decode any possible server error during unpacking on the remote peer Change-Id: Idb37a4a122a565ec4b59130e08c27d963ba09395
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java52
1 files changed, 51 insertions, 1 deletions
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 9b8ba8098f..0cbbdc77e3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -47,6 +47,7 @@ package org.eclipse.jgit.transport;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.Collection;
@@ -317,7 +318,12 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen
writer.setReuseValidatingObjects(false);
writer.setDeltaBaseAsOffset(capableOfsDelta);
writer.preparePack(monitor, newObjects, remoteObjects);
- writer.writePack(monitor, monitor, out);
+
+ OutputStream packOut = out;
+ if (capableSideBand) {
+ packOut = new CheckingSideBandOutputStream(in, out);
+ }
+ writer.writePack(monitor, monitor, packOut);
packTransferTime = writer.getStatistics().getTimeWriting();
}
@@ -397,4 +403,48 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen
timeoutIn.setTimeout(oldTimeout);
}
}
+
+ private static class CheckingSideBandOutputStream extends OutputStream {
+ private final InputStream in;
+ private final OutputStream out;
+
+ CheckingSideBandOutputStream(InputStream in, OutputStream out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ write(new byte[] { (byte) b });
+ }
+
+ @Override
+ public void write(byte[] buf, int ptr, int cnt) throws IOException {
+ try {
+ out.write(buf, ptr, cnt);
+ } catch (IOException e) {
+ throw checkError(e);
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ try {
+ out.flush();
+ } catch (IOException e) {
+ throw checkError(e);
+ }
+ }
+
+ private IOException checkError(IOException e1) {
+ try {
+ in.read();
+ } catch (TransportException e2) {
+ return e2;
+ } catch (IOException e2) {
+ return e1;
+ }
+ return e1;
+ }
+ }
}