import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
import org.eclipse.jgit.transport.UploadPack;
+import org.eclipse.jgit.transport.UploadPackInternalServerErrorException;
import org.eclipse.jgit.transport.UploadPackMayNotContinueException;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
out.close();
} catch (UploadPackMayNotContinueException e) {
- if (!e.isOutput())
+ if (!e.isOutput() && !rsp.isCommitted()) {
+ rsp.reset();
rsp.sendError(SC_SERVICE_UNAVAILABLE);
+ }
return;
+ } catch (UploadPackInternalServerErrorException e) {
+ getServletContext().log(
+ HttpServerText.get().internalErrorDuringUploadPack,
+ e.getCause());
+
} catch (IOException e) {
getServletContext().log(HttpServerText.get().internalErrorDuringUploadPack, e);
- rsp.reset();
- rsp.sendError(SC_INTERNAL_SERVER_ERROR);
+ if (!rsp.isCommitted()) {
+ rsp.reset();
+ rsp.sendError(SC_INTERNAL_SERVER_ERROR);
+ }
return;
}
}
}
}
- recvWants();
- if (wantIds.isEmpty()) {
- preUploadHook.onBeginNegotiateRound(this, wantIds, 0);
- preUploadHook.onEndNegotiateRound(this, wantIds, 0, 0, false);
- return;
- }
+ boolean sendPack;
+ try {
+ recvWants();
+ if (wantIds.isEmpty()) {
+ preUploadHook.onBeginNegotiateRound(this, wantIds, 0);
+ preUploadHook.onEndNegotiateRound(this, wantIds, 0, 0, false);
+ return;
+ }
- if (options.contains(OPTION_MULTI_ACK_DETAILED)) {
- multiAck = MultiAck.DETAILED;
- noDone = options.contains(OPTION_NO_DONE);
- } else if (options.contains(OPTION_MULTI_ACK))
- multiAck = MultiAck.CONTINUE;
- else
- multiAck = MultiAck.OFF;
+ if (options.contains(OPTION_MULTI_ACK_DETAILED)) {
+ multiAck = MultiAck.DETAILED;
+ noDone = options.contains(OPTION_NO_DONE);
+ } else if (options.contains(OPTION_MULTI_ACK))
+ multiAck = MultiAck.CONTINUE;
+ else
+ multiAck = MultiAck.OFF;
+
+ sendPack = negotiate();
+ } catch (PackProtocolException err) {
+ reportErrorDuringNegotiate(err.getMessage());
+ throw err;
+
+ } catch (UploadPackMayNotContinueException err) {
+ if (!err.isOutput() && err.getMessage() != null) {
+ try {
+ pckOut.writeString("ERR " + err.getMessage() + "\n");
+ err.setOutput();
+ } catch (Throwable err2) {
+ // Ignore this secondary failure (and not mark output).
+ }
+ }
+ throw err;
+
+ } catch (IOException err) {
+ reportErrorDuringNegotiate(JGitText.get().internalServerError);
+ throw err;
+ } catch (RuntimeException err) {
+ reportErrorDuringNegotiate(JGitText.get().internalServerError);
+ throw err;
+ } catch (Error err) {
+ reportErrorDuringNegotiate(JGitText.get().internalServerError);
+ throw err;
+ }
- if (negotiate())
+ if (sendPack)
sendPack();
}
+ private void reportErrorDuringNegotiate(String msg) {
+ try {
+ pckOut.writeString("ERR " + msg + "\n");
+ } catch (Throwable err) {
+ // Ignore this secondary failure.
+ }
+ }
+
/**
* Generate an advertisement of available refs and capabilities.
*
private ObjectId processHaveLines(List<ObjectId> peerHas, ObjectId last)
throws IOException {
- try {
- preUploadHook.onBeginNegotiateRound(this, wantIds, peerHas.size());
- } catch (UploadPackMayNotContinueException fail) {
- if (fail.getMessage() != null) {
- pckOut.writeString("ERR " + fail.getMessage() + "\n");
- fail.setOutput();
- }
- throw fail;
- }
-
+ preUploadHook.onBeginNegotiateRound(this, wantIds, peerHas.size());
if (peerHas.isEmpty())
return last;
if (wantIds.contains(id)) {
String msg = MessageFormat.format(
JGitText.get().wantNotValid, id.name());
- pckOut.writeString("ERR " + msg);
throw new PackProtocolException(msg, notFound);
}
continue;
if (!advertised.contains(obj)) {
String msg = MessageFormat.format(
JGitText.get().wantNotValid, obj.name());
- pckOut.writeString("ERR " + msg);
throw new PackProtocolException(msg);
}
sentReady = true;
}
- try {
- preUploadHook.onEndNegotiateRound(this, wantAll, //
- haveCnt, missCnt, sentReady);
- } catch (UploadPackMayNotContinueException fail) {
- if (fail.getMessage() != null) {
- pckOut.writeString("ERR " + fail.getMessage() + "\n");
- fail.setOutput();
- }
- throw fail;
- }
-
+ preUploadHook.onEndNegotiateRound(this, wantAll, haveCnt, missCnt, sentReady);
peerHas.clear();
return last;
}
"\\x" + Integer.toHexString(eof)));
}
+ if (sideband) {
+ try {
+ sendPack(true);
+ } catch (UploadPackMayNotContinueException noPack) {
+ // This was already reported on (below).
+ throw noPack;
+ } catch (IOException err) {
+ if (reportInternalServerErrorOverSideband())
+ throw new UploadPackInternalServerErrorException(err);
+ else
+ throw err;
+ } catch (RuntimeException err) {
+ if (reportInternalServerErrorOverSideband())
+ throw new UploadPackInternalServerErrorException(err);
+ else
+ throw err;
+ } catch (Error err) {
+ if (reportInternalServerErrorOverSideband())
+ throw new UploadPackInternalServerErrorException(err);
+ else
+ throw err;
+ }
+ } else {
+ sendPack(false);
+ }
+ }
+
+ private boolean reportInternalServerErrorOverSideband() {
+ try {
+ SideBandOutputStream err = new SideBandOutputStream(
+ SideBandOutputStream.CH_ERROR,
+ SideBandOutputStream.SMALL_BUF,
+ rawOut);
+ err.write(Constants.encode(JGitText.get().internalServerError));
+ err.flush();
+ return true;
+ } catch (Throwable cannotReport) {
+ // Ignore the reason. This is a secondary failure.
+ return false;
+ }
+ }
+
+ private void sendPack(final boolean sideband) throws IOException {
ProgressMonitor pm = NullProgressMonitor.INSTANCE;
OutputStream packOut = rawOut;
SideBandOutputStream msgOut = null;
--- /dev/null
+/*
+ * Copyright (C) 2011, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.IOException;
+
+/** UploadPack has already reported an error to the client. */
+public class UploadPackInternalServerErrorException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Initialize a new exception.
+ *
+ * @param why
+ * root cause.
+ */
+ public UploadPackInternalServerErrorException(Throwable why) {
+ super(why);
+ }
+}