From c1a9b2ae8be6b0826b62021fe82a53de8783ea21 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 14 Sep 2011 15:31:42 -0700 Subject: [PATCH] Fix smart HTTP client stream alignment errors The client's use of UnionInputStream was broken when combined with a 8192 byte buffer used by PackParser. A smart HTTP client connection always pushes in the execute stateless RPC input stream after the data stream has ended from the remote peer. At the end of the pack, PackParser asked to fill a 8192 byte buffer, but if only e.g. 1000 bytes remained UnionInputStream went to the next stream and asked it for input, which triggered a new RPC, and failed because there was nothing pending in the request buffer. Change UnionInputStream to only return what it consumed from a single InputStream without invoking the next InputStream, just in case that second InputStream happens to be one of these magical ones that generates an RPC invocation. Change-Id: I0e51a8e6fea1647e4d2e08ac9cfc69c2945ce4cb Signed-off-by: Shawn O. Pearce --- .../jgit/util/io/UnionInputStreamTest.java | 28 +++++++++++++------ .../eclipse/jgit/transport/TransportHttp.java | 5 ---- .../jgit/util/io/UnionInputStream.java | 7 ++++- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java index 5fd6816ec..9fb323c4d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java @@ -106,13 +106,21 @@ public class UnionInputStreamTest { u.add(new ByteArrayInputStream(new byte[] { 4, 5 })); final byte[] r = new byte[5]; - assertEquals(5, u.read(r, 0, 5)); - assertTrue(Arrays.equals(new byte[] { 1, 0, 2, 3, 4 }, r)); + assertEquals(3, u.read(r, 0, 5)); + assertTrue(Arrays.equals(new byte[] { 1, 0, 2, }, slice(r, 3))); assertEquals(1, u.read(r, 0, 5)); - assertEquals(5, r[0]); + assertEquals(3, r[0]); + assertEquals(2, u.read(r, 0, 5)); + assertTrue(Arrays.equals(new byte[] { 4, 5, }, slice(r, 2))); assertEquals(-1, u.read(r, 0, 5)); } + private static byte[] slice(byte[] in, int len) { + byte[] r = new byte[len]; + System.arraycopy(in, 0, r, 0, len); + return r; + } + @Test public void testArrayConstructor() throws IOException { final UnionInputStream u = new UnionInputStream( @@ -121,10 +129,12 @@ public class UnionInputStreamTest { new ByteArrayInputStream(new byte[] { 4, 5 })); final byte[] r = new byte[5]; - assertEquals(5, u.read(r, 0, 5)); - assertTrue(Arrays.equals(new byte[] { 1, 0, 2, 3, 4 }, r)); + assertEquals(3, u.read(r, 0, 5)); + assertTrue(Arrays.equals(new byte[] { 1, 0, 2, }, slice(r, 3))); assertEquals(1, u.read(r, 0, 5)); - assertEquals(5, r[0]); + assertEquals(3, r[0]); + assertEquals(2, u.read(r, 0, 5)); + assertTrue(Arrays.equals(new byte[] { 4, 5, }, slice(r, 2))); assertEquals(-1, u.read(r, 0, 5)); } @@ -143,9 +153,9 @@ public class UnionInputStreamTest { u.add(new ByteArrayInputStream(new byte[] { 3 })); u.add(new ByteArrayInputStream(new byte[] { 4, 5 })); assertEquals(0, u.skip(0)); - assertEquals(4, u.skip(4)); - assertEquals(4, u.read()); - assertEquals(1, u.skip(5)); + assertEquals(3, u.skip(3)); + assertEquals(3, u.read()); + assertEquals(2, u.skip(5)); assertEquals(0, u.skip(5)); assertEquals(-1, u.read()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java index 43ad98985..1b78fcfc9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -851,11 +851,6 @@ public class TransportHttp extends HttpTransport implements WalkTransport, } class HttpExecuteStream extends InputStream { - public int available() throws IOException { - execute(); - return 0; - } - public int read() throws IOException { execute(); return -1; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java index f0183717a..0df3775f1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/UnionInputStream.java @@ -148,8 +148,11 @@ public class UnionInputStream extends InputStream { len -= n; } else if (in == EOF) return 0 < cnt ? cnt : -1; - else + else { pop(); + if (0 < cnt) + break; + } } return cnt; } @@ -180,6 +183,8 @@ public class UnionInputStream extends InputStream { final int r = in.read(); if (r < 0) { pop(); + if (0 < cnt) + break; } else { cnt += 1; len -= 1;