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>
This commit is contained in:
parent
27b05c7d71
commit
3b2508b514
|
@ -58,6 +58,7 @@
|
|||
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.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 Set<String> getOptions() {
|
|||
|
||||
private InputStream rawIn;
|
||||
|
||||
private OutputStream rawOut;
|
||||
private ResponseBufferedOutputStream rawOut;
|
||||
|
||||
private PacketLineIn pckIn;
|
||||
|
||||
|
@ -644,11 +646,10 @@ public boolean isSideBand() throws RequestNotYetReadException {
|
|||
* 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 void upload(final InputStream input, final OutputStream output,
|
|||
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 @@ private Map<String, Ref> getAdvertisedOrDefaultRefs() throws IOException {
|
|||
|
||||
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 @@ else if (requestValidator instanceof AnyRequestValidator)
|
|||
throw new UploadPackInternalServerErrorException(err);
|
||||
}
|
||||
throw err;
|
||||
} finally {
|
||||
rawOut.stopBuffering();
|
||||
}
|
||||
|
||||
if (sendPack)
|
||||
|
@ -1572,4 +1583,50 @@ private static void findSymrefs(
|
|||
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…
Reference in New Issue