diff options
author | Masaya Suzuki <masayasuzuki@google.com> | 2017-03-31 13:54:02 -0700 |
---|---|---|
committer | Masaya Suzuki <masayasuzuki@google.com> | 2017-04-04 10:52:49 -0700 |
commit | 3b2508b51467c3cb0541c004488eaabae2842f9e (patch) | |
tree | fd04477f94ebb703d26228f3abeb6c48f0716fff /org.eclipse.jgit | |
parent | 27b05c7d719754427a97c141b44bec7de3acb8db (diff) | |
download | jgit-3b2508b51467c3cb0541c004488eaabae2842f9e.tar.gz jgit-3b2508b51467c3cb0541c004488eaabae2842f9e.zip |
Buffer the response until request parsing has done
This is a continuation from https://git.eclipse.org/r/#/c/4716/. For a
non-bidirectional request, we need to consume the request before writing
any response. In UploadPack, we write "shallow"/"unshallow" responses
before parsing "have" lines. This has happened not to be a problem most
of the time in the smart HTTP protocol because the underlying
InputStream has a 32 KiB buffer in SmartOutputStream.
Change-Id: I7c61659e7c4e8bd49a8b17e2fe9be67bb32933d3
Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java | 67 |
1 files changed, 62 insertions, 5 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index 58fdd25745..6b16f550d9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -58,6 +58,7 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK; +import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -71,6 +72,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; @@ -235,7 +237,7 @@ public class UploadPack { private InputStream rawIn; - private OutputStream rawOut; + private ResponseBufferedOutputStream rawOut; private PacketLineIn pckIn; @@ -644,11 +646,10 @@ public class UploadPack { * other network connections this should be null. * @throws IOException */ - public void upload(final InputStream input, final OutputStream output, + public void upload(final InputStream input, OutputStream output, final OutputStream messages) throws IOException { try { rawIn = input; - rawOut = output; if (messages != null) msgOut = messages; @@ -656,11 +657,17 @@ public class UploadPack { final Thread caller = Thread.currentThread(); timer = new InterruptTimer(caller.getName() + "-Timer"); //$NON-NLS-1$ TimeoutInputStream i = new TimeoutInputStream(rawIn, timer); - TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer); + @SuppressWarnings("resource") + TimeoutOutputStream o = new TimeoutOutputStream(output, timer); i.setTimeout(timeout * 1000); o.setTimeout(timeout * 1000); rawIn = i; - rawOut = o; + output = o; + } + + rawOut = new ResponseBufferedOutputStream(output); + if (biDirectionalPipe) { + rawOut.stopBuffering(); } pckIn = new PacketLineIn(rawIn); @@ -714,6 +721,8 @@ public class UploadPack { private void service() throws IOException { boolean sendPack; + // If it's a non-bidi request, we need to read the entire request before + // writing a response. Buffer the response until then. try { if (biDirectionalPipe) sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut)); @@ -769,6 +778,8 @@ public class UploadPack { throw new UploadPackInternalServerErrorException(err); } throw err; + } finally { + rawOut.stopBuffering(); } if (sendPack) @@ -1572,4 +1583,50 @@ public class UploadPack { adv.addSymref(Constants.HEAD, head.getLeaf().getName()); } } + + private static class ResponseBufferedOutputStream extends OutputStream { + private final OutputStream rawOut; + + private OutputStream out; + @Nullable + private ByteArrayOutputStream buffer; + + ResponseBufferedOutputStream(OutputStream rawOut) { + this.rawOut = rawOut; + this.out = this.buffer = new ByteArrayOutputStream(); + } + + @Override + public void write(int b) throws IOException { + out.write(b); + } + + @Override + public void write(byte b[]) throws IOException { + out.write(b); + } + + @Override + public void write(byte b[], int off, int len) throws IOException { + out.write(b, off, len); + } + + @Override + public void flush() throws IOException { + out.flush(); + } + + @Override + public void close() throws IOException { + out.close(); + } + + void stopBuffering() throws IOException { + if (buffer != null) { + buffer.writeTo(rawOut); + buffer = null; + out = rawOut; + } + } + } } |