Browse Source

Merge changes Ieebbd671,I0e3e9456,Ia8d72e31

* changes:
  UploadPack: Create a method that propagates an exception as-is
  UploadPack: Consolidate the sideband handling code to one place
  UploadPack: Introduce ErrorWriter
next
Terry Parker 5 years ago committed by Gerrit Code Review @ Eclipse.org
parent
commit
6bd9bc23b7
  1. 228
      org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

228
org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java

@ -44,6 +44,7 @@
package org.eclipse.jgit.transport; package org.eclipse.jgit.transport;
import static java.util.Collections.unmodifiableMap; import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.requireNonNull;
import static org.eclipse.jgit.lib.Constants.R_TAGS; import static org.eclipse.jgit.lib.Constants.R_TAGS;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REF_IN_WANT; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REF_IN_WANT;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SERVER_OPTION; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SERVER_OPTION;
@ -282,6 +283,8 @@ public class UploadPack {
private OutputStream msgOut = NullOutputStream.INSTANCE; private OutputStream msgOut = NullOutputStream.INSTANCE;
private ErrorWriter errOut = new PackProtocolErrorWriter();
/** /**
* Refs eligible for advertising to the client, set using * Refs eligible for advertising to the client, set using
* {@link #setAdvertisedRefs}. * {@link #setAdvertisedRefs}.
@ -756,9 +759,59 @@ public class UploadPack {
/** /**
* Execute the upload task on the socket. * Execute the upload task on the socket.
* *
* <p>If the client passed extra parameters (e.g., "version=2") through a * <p>
* side channel, the caller must call setExtraParameters first to supply * Same as {@link #uploadWithExceptionPropagation} except that the thrown
* them. * exceptions are handled in the method, and the error messages are sent to
* the clients.
*
* <p>
* Call this method if the caller does not have an error handling mechanism.
* Call {@link #uploadWithExceptionPropagation} if the caller wants to have
* its own error handling mechanism.
*
* @param input
* @param output
* @param messages
* @throws java.io.IOException
*/
public void upload(InputStream input, OutputStream output,
@Nullable OutputStream messages) throws IOException {
try {
uploadWithExceptionPropagation(input, output, messages);
} catch (ServiceMayNotContinueException err) {
if (!err.isOutput() && err.getMessage() != null) {
try {
errOut.writeError(err.getMessage());
} catch (IOException e) {
err.addSuppressed(e);
throw err;
}
err.setOutput();
}
throw err;
} catch (IOException | RuntimeException | Error err) {
if (rawOut != null) {
String msg = err instanceof PackProtocolException
? err.getMessage()
: JGitText.get().internalServerError;
try {
errOut.writeError(msg);
} catch (IOException e) {
err.addSuppressed(e);
throw err;
}
throw new UploadPackInternalServerErrorException(err);
}
throw err;
}
}
/**
* Execute the upload task on the socket.
*
* <p>
* If the client passed extra parameters (e.g., "version=2") through a side
* channel, the caller must call setExtraParameters first to supply them.
* *
* @param input * @param input
* raw input to read client commands from. Caller must ensure the * raw input to read client commands from. Caller must ensure the
@ -772,15 +825,20 @@ public class UploadPack {
* through. When run over SSH this should be tied back to the * through. When run over SSH this should be tied back to the
* standard error channel of the command execution. For most * standard error channel of the command execution. For most
* other network connections this should be null. * other network connections this should be null.
* @throws java.io.IOException * @throws ServiceMayNotContinueException
* thrown if one of the hooks throws this.
* @throws IOException
* thrown if the server or the client I/O fails, or there's an
* internal server error.
*/ */
public void upload(InputStream input, OutputStream output, public void uploadWithExceptionPropagation(InputStream input,
@Nullable OutputStream messages) throws IOException { OutputStream output, @Nullable OutputStream messages)
PacketLineOut pckOut = null; throws ServiceMayNotContinueException, IOException {
try { try {
rawIn = input; rawIn = input;
if (messages != null) if (messages != null) {
msgOut = messages; msgOut = messages;
}
if (timeout > 0) { if (timeout > 0) {
final Thread caller = Thread.currentThread(); final Thread caller = Thread.currentThread();
@ -800,42 +858,12 @@ public class UploadPack {
} }
pckIn = new PacketLineIn(rawIn); pckIn = new PacketLineIn(rawIn);
pckOut = new PacketLineOut(rawOut); PacketLineOut pckOut = new PacketLineOut(rawOut);
if (useProtocolV2()) { if (useProtocolV2()) {
serviceV2(pckOut); serviceV2(pckOut);
} else { } else {
service(pckOut); service(pckOut);
} }
} catch (UploadPackInternalServerErrorException err) {
// UploadPackInternalServerErrorException is a special exception
// that indicates an error is already written to the client. Do
// nothing.
throw err;
} catch (ServiceMayNotContinueException err) {
if (!err.isOutput() && err.getMessage() != null && pckOut != null) {
try {
pckOut.writeString("ERR " + err.getMessage() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (IOException e) {
err.addSuppressed(e);
throw err;
}
err.setOutput();
}
throw err;
} catch (IOException | RuntimeException | Error err) {
if (pckOut != null) {
String msg = err instanceof PackProtocolException
? err.getMessage()
: JGitText.get().internalServerError;
try {
pckOut.writeString("ERR " + msg + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (IOException e) {
err.addSuppressed(e);
throw err;
}
throw new UploadPackInternalServerErrorException(err);
}
throw err;
} finally { } finally {
msgOut = NullOutputStream.INSTANCE; msgOut = NullOutputStream.INSTANCE;
walk.close(); walk.close();
@ -2114,54 +2142,42 @@ public class UploadPack {
Set<String> caps = req.getClientCapabilities(); Set<String> caps = req.getClientCapabilities();
boolean sideband = caps.contains(OPTION_SIDE_BAND) boolean sideband = caps.contains(OPTION_SIDE_BAND)
|| caps.contains(OPTION_SIDE_BAND_64K); || caps.contains(OPTION_SIDE_BAND_64K);
if (sideband) { if (sideband) {
try { errOut = new SideBandErrorWriter();
sendPack(true, req, accumulator, allTags, unshallowCommits,
deepenNots, pckOut); int bufsz = SideBandOutputStream.SMALL_BUF;
} catch (ServiceMayNotContinueException err) { if (req.getClientCapabilities().contains(OPTION_SIDE_BAND_64K)) {
String message = err.getMessage(); bufsz = SideBandOutputStream.MAX_BUF;
if (message == null) { }
message = JGitText.get().internalServerError; OutputStream packOut = new SideBandOutputStream(
} SideBandOutputStream.CH_DATA, bufsz, rawOut);
try {
reportInternalServerErrorOverSideband(message); ProgressMonitor pm = NullProgressMonitor.INSTANCE;
} catch (IOException e) { if (!req.getClientCapabilities().contains(OPTION_NO_PROGRESS)) {
err.addSuppressed(e); msgOut = new SideBandOutputStream(
throw err; SideBandOutputStream.CH_PROGRESS, bufsz, rawOut);
} pm = new SideBandProgressMonitor(msgOut);
throw new UploadPackInternalServerErrorException(err);
} catch (IOException | RuntimeException | Error err) {
try {
reportInternalServerErrorOverSideband(
JGitText.get().internalServerError);
} catch (IOException e) {
err.addSuppressed(e);
throw err;
}
throw new UploadPackInternalServerErrorException(err);
} }
sendPack(pm, pckOut, packOut, req, accumulator, allTags,
unshallowCommits, deepenNots);
pckOut.end();
} else { } else {
sendPack(false, req, accumulator, allTags, unshallowCommits, deepenNots, sendPack(NullProgressMonitor.INSTANCE, pckOut, rawOut, req,
pckOut); accumulator, allTags, unshallowCommits, deepenNots);
} }
} }
private void reportInternalServerErrorOverSideband(String message)
throws IOException {
@SuppressWarnings("resource" /* java 7 */)
SideBandOutputStream err = new SideBandOutputStream(
SideBandOutputStream.CH_ERROR, SideBandOutputStream.SMALL_BUF,
rawOut);
err.write(Constants.encode(message));
err.flush();
}
/** /**
* Send the requested objects to the client. * Send the requested objects to the client.
* *
* @param sideband * @param pm
* whether to wrap the pack in side-band pkt-lines, interleaved * progress monitor
* with progress messages and errors. * @param pckOut
* PacketLineOut that shares the output with packOut
* @param packOut
* packfile output
* @param req * @param req
* request being processed * request being processed
* @param accumulator * @param accumulator
@ -2173,35 +2189,14 @@ public class UploadPack {
* shallow commits on the client that are now becoming unshallow * shallow commits on the client that are now becoming unshallow
* @param deepenNots * @param deepenNots
* objects that the client specified using --shallow-exclude * objects that the client specified using --shallow-exclude
* @param pckOut
* output writer
* @throws IOException * @throws IOException
* if an error occurred while generating or writing the pack. * if an error occurred while generating or writing the pack.
*/ */
private void sendPack(final boolean sideband, private void sendPack(ProgressMonitor pm, PacketLineOut pckOut,
FetchRequest req, OutputStream packOut, FetchRequest req,
PackStatistics.Accumulator accumulator, PackStatistics.Accumulator accumulator,
@Nullable Collection<Ref> allTags, @Nullable Collection<Ref> allTags, List<ObjectId> unshallowCommits,
List<ObjectId> unshallowCommits, List<ObjectId> deepenNots) throws IOException {
List<ObjectId> deepenNots,
PacketLineOut pckOut) throws IOException {
ProgressMonitor pm = NullProgressMonitor.INSTANCE;
OutputStream packOut = rawOut;
if (sideband) {
int bufsz = SideBandOutputStream.SMALL_BUF;
if (req.getClientCapabilities().contains(OPTION_SIDE_BAND_64K))
bufsz = SideBandOutputStream.MAX_BUF;
packOut = new SideBandOutputStream(SideBandOutputStream.CH_DATA,
bufsz, rawOut);
if (!req.getClientCapabilities().contains(OPTION_NO_PROGRESS)) {
msgOut = new SideBandOutputStream(
SideBandOutputStream.CH_PROGRESS, bufsz, rawOut);
pm = new SideBandProgressMonitor(msgOut);
}
}
if (wantAll.isEmpty()) { if (wantAll.isEmpty()) {
preUploadHook.onSendPack(this, wantIds, commonBase); preUploadHook.onSendPack(this, wantIds, commonBase);
} else { } else {
@ -2344,9 +2339,6 @@ public class UploadPack {
} }
pw.close(); pw.close();
} }
if (sideband)
pckOut.end();
} }
private static void findSymrefs( private static void findSymrefs(
@ -2411,4 +2403,28 @@ public class UploadPack {
} }
} }
} }
private interface ErrorWriter {
void writeError(String message) throws IOException;
}
private class SideBandErrorWriter implements ErrorWriter {
@Override
public void writeError(String message) throws IOException {
@SuppressWarnings("resource" /* java 7 */)
SideBandOutputStream err = new SideBandOutputStream(
SideBandOutputStream.CH_ERROR,
SideBandOutputStream.SMALL_BUF, requireNonNull(rawOut));
err.write(Constants.encode(message));
err.flush();
}
}
private class PackProtocolErrorWriter implements ErrorWriter {
@Override
public void writeError(String message) throws IOException {
new PacketLineOut(requireNonNull(rawOut))
.writeString("ERR " + message + '\n'); //$NON-NLS-1$
}
}
} }

Loading…
Cancel
Save