Browse Source

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>
stable-4.8
Masaya Suzuki 8 years ago
parent
commit
3b2508b514
  1. 67
      org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

67
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_SIDE_BAND_64K;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK;
import java.io.ByteArrayOutputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -71,6 +72,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
@ -235,7 +237,7 @@ public class UploadPack {
private InputStream rawIn; private InputStream rawIn;
private OutputStream rawOut; private ResponseBufferedOutputStream rawOut;
private PacketLineIn pckIn; private PacketLineIn pckIn;
@ -644,11 +646,10 @@ public class UploadPack {
* other network connections this should be null. * other network connections this should be null.
* @throws IOException * @throws IOException
*/ */
public void upload(final InputStream input, final OutputStream output, public void upload(final InputStream input, OutputStream output,
final OutputStream messages) throws IOException { final OutputStream messages) throws IOException {
try { try {
rawIn = input; rawIn = input;
rawOut = output;
if (messages != null) if (messages != null)
msgOut = messages; msgOut = messages;
@ -656,11 +657,17 @@ public class UploadPack {
final Thread caller = Thread.currentThread(); final Thread caller = Thread.currentThread();
timer = new InterruptTimer(caller.getName() + "-Timer"); //$NON-NLS-1$ timer = new InterruptTimer(caller.getName() + "-Timer"); //$NON-NLS-1$
TimeoutInputStream i = new TimeoutInputStream(rawIn, timer); TimeoutInputStream i = new TimeoutInputStream(rawIn, timer);
TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer); @SuppressWarnings("resource")
TimeoutOutputStream o = new TimeoutOutputStream(output, timer);
i.setTimeout(timeout * 1000); i.setTimeout(timeout * 1000);
o.setTimeout(timeout * 1000); o.setTimeout(timeout * 1000);
rawIn = i; rawIn = i;
rawOut = o; output = o;
}
rawOut = new ResponseBufferedOutputStream(output);
if (biDirectionalPipe) {
rawOut.stopBuffering();
} }
pckIn = new PacketLineIn(rawIn); pckIn = new PacketLineIn(rawIn);
@ -714,6 +721,8 @@ public class UploadPack {
private void service() throws IOException { private void service() throws IOException {
boolean sendPack; 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 { try {
if (biDirectionalPipe) if (biDirectionalPipe)
sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut)); sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
@ -769,6 +778,8 @@ public class UploadPack {
throw new UploadPackInternalServerErrorException(err); throw new UploadPackInternalServerErrorException(err);
} }
throw err; throw err;
} finally {
rawOut.stopBuffering();
} }
if (sendPack) if (sendPack)
@ -1572,4 +1583,50 @@ public class UploadPack {
adv.addSymref(Constants.HEAD, head.getLeaf().getName()); 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;
}
}
}
} }

Loading…
Cancel
Save