summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.http.server/src
diff options
context:
space:
mode:
authorShawn Pearce <sop@google.com>2012-03-07 22:22:22 -0500
committerGerrit Code Review @ Eclipse.org <gerrit@eclipse.org>2012-03-07 22:22:22 -0500
commit500e17e7d6d3c29cef0fd4651dc1cd29d7d0b8e6 (patch)
treee3bffa9389ac1e2d6e71886a6cdb1f7322b3f192 /org.eclipse.jgit.http.server/src
parent90d002c15fd2131b9f80fb9bb6f28bf691c00b5d (diff)
parent039c785d9f0eac3fcb78b9dc2bf61796b82d3401 (diff)
downloadjgit-500e17e7d6d3c29cef0fd4651dc1cd29d7d0b8e6.tar.gz
jgit-500e17e7d6d3c29cef0fd4651dc1cd29d7d0b8e6.zip
Merge changes I8277fd45,I7ac4e0ae,Ib475dfc0,Ib26adf95
* changes: Try to send HTTP error messages over sideband Extract the capability parsing logic in {Upload,Receive}Pack Make capability strings in BasePack{Fetch,Push}Connection public Fix a typo in "capabilities" in ReceivePack
Diffstat (limited to 'org.eclipse.jgit.http.server/src')
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java133
1 files changed, 121 insertions, 12 deletions
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
index 8bd1704bc4..e6b287ff06 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
@@ -43,6 +43,12 @@
package org.eclipse.jgit.http.server;
+import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER;
+import static org.eclipse.jgit.transport.BasePackFetchConnection.OPTION_SIDE_BAND;
+import static org.eclipse.jgit.transport.BasePackFetchConnection.OPTION_SIDE_BAND_64K;
+import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_SIDE_BAND_64K;
+import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR;
+import static org.eclipse.jgit.transport.SideBandOutputStream.SMALL_BUF;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
@@ -58,7 +64,12 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.transport.PacketLineIn;
import org.eclipse.jgit.transport.PacketLineOut;
+import org.eclipse.jgit.transport.ReceivePack;
+import org.eclipse.jgit.transport.RequestNotYetReadException;
+import org.eclipse.jgit.transport.SideBandOutputStream;
+import org.eclipse.jgit.transport.UploadPack;
/**
* Utility functions for handling the Git-over-HTTP protocol.
@@ -141,6 +152,11 @@ public class GitSmartHttpTools {
* to a Git protocol client using an HTTP 200 OK response with the error
* embedded in the payload. If the request was not issued by a Git client,
* an HTTP response code is returned instead.
+ * <p>
+ * This method may only be called before handing off the request to
+ * {@link UploadPack#upload(java.io.InputStream, OutputStream, OutputStream)}
+ * or
+ * {@link ReceivePack#receive(java.io.InputStream, OutputStream, OutputStream)}.
*
* @param req
* current request.
@@ -176,21 +192,12 @@ public class GitSmartHttpTools {
}
}
- ByteArrayOutputStream buf = new ByteArrayOutputStream(128);
- PacketLineOut pck = new PacketLineOut(buf);
-
if (isInfoRefs(req)) {
- String svc = req.getParameter("service");
- pck.writeString("# service=" + svc + "\n");
- pck.end();
- pck.writeString("ERR " + textForGit);
- send(req, res, infoRefsResultType(svc), buf.toByteArray());
+ sendInfoRefsError(req, res, textForGit);
} else if (isUploadPack(req)) {
- pck.writeString("ERR " + textForGit);
- send(req, res, UPLOAD_PACK_RESULT_TYPE, buf.toByteArray());
+ sendUploadPackError(req, res, textForGit);
} else if (isReceivePack(req)) {
- pck.writeString("ERR " + textForGit);
- send(req, res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray());
+ sendReceivePackError(req, res, textForGit);
} else {
if (httpStatus < 400)
ServletUtils.consumeRequestBody(req);
@@ -198,6 +205,108 @@ public class GitSmartHttpTools {
}
}
+ private static void sendInfoRefsError(HttpServletRequest req,
+ HttpServletResponse res, String textForGit) throws IOException {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(128);
+ PacketLineOut pck = new PacketLineOut(buf);
+ String svc = req.getParameter("service");
+ pck.writeString("# service=" + svc + "\n");
+ pck.end();
+ pck.writeString("ERR " + textForGit);
+ send(req, res, infoRefsResultType(svc), buf.toByteArray());
+ }
+
+ private static void sendUploadPackError(HttpServletRequest req,
+ HttpServletResponse res, String textForGit) throws IOException {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(128);
+ PacketLineOut pckOut = new PacketLineOut(buf);
+
+ boolean sideband;
+ UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER);
+ if (up != null) {
+ try {
+ sideband = up.isSideBand();
+ } catch (RequestNotYetReadException e) {
+ sideband = isUploadPackSideBand(req);
+ }
+ } else
+ sideband = isUploadPackSideBand(req);
+
+ if (sideband)
+ writeSideBand(buf, textForGit);
+ else
+ writePacket(pckOut, textForGit);
+ send(req, res, UPLOAD_PACK_RESULT_TYPE, buf.toByteArray());
+ }
+
+ private static boolean isUploadPackSideBand(HttpServletRequest req) {
+ try {
+ // The client may be in a state where they have sent the sideband
+ // capability and are expecting a response in the sideband, but we might
+ // not have an UploadPack, or it might not have read any of the request.
+ // So, cheat and read the first line.
+ String line = new PacketLineIn(req.getInputStream()).readStringRaw();
+ UploadPack.FirstLine parsed = new UploadPack.FirstLine(line);
+ return (parsed.getOptions().contains(OPTION_SIDE_BAND)
+ || parsed.getOptions().contains(OPTION_SIDE_BAND_64K));
+ } catch (IOException e) {
+ // Probably the connection is closed and a subsequent write will fail, but
+ // try it just in case.
+ return false;
+ }
+ }
+
+ private static void sendReceivePackError(HttpServletRequest req,
+ HttpServletResponse res, String textForGit) throws IOException {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(128);
+ PacketLineOut pckOut = new PacketLineOut(buf);
+
+ boolean sideband;
+ ReceivePack rp = (ReceivePack) req.getAttribute(ATTRIBUTE_HANDLER);
+ if (rp != null) {
+ try {
+ sideband = rp.isSideBand();
+ } catch (RequestNotYetReadException e) {
+ sideband = isReceivePackSideBand(req);
+ }
+ } else
+ sideband = isReceivePackSideBand(req);
+
+ if (sideband)
+ writeSideBand(buf, textForGit);
+ else
+ writePacket(pckOut, textForGit);
+ send(req, res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray());
+ }
+
+ private static boolean isReceivePackSideBand(HttpServletRequest req) {
+ try {
+ // The client may be in a state where they have sent the sideband
+ // capability and are expecting a response in the sideband, but we might
+ // not have a ReceivePack, or it might not have read any of the request.
+ // So, cheat and read the first line.
+ String line = new PacketLineIn(req.getInputStream()).readStringRaw();
+ ReceivePack.FirstLine parsed = new ReceivePack.FirstLine(line);
+ return parsed.getCapabilities().contains(CAPABILITY_SIDE_BAND_64K);
+ } catch (IOException e) {
+ // Probably the connection is closed and a subsequent write will fail, but
+ // try it just in case.
+ return false;
+ }
+ }
+
+ private static void writeSideBand(OutputStream out, String textForGit)
+ throws IOException {
+ OutputStream msg = new SideBandOutputStream(CH_ERROR, SMALL_BUF, out);
+ msg.write(Constants.encode("error: " + textForGit));
+ msg.flush();
+ }
+
+ private static void writePacket(PacketLineOut pckOut, String textForGit)
+ throws IOException {
+ pckOut.writeString("error: " + textForGit);
+ }
+
private static void send(HttpServletRequest req, HttpServletResponse res,
String type, byte[] buf) throws IOException {
ServletUtils.consumeRequestBody(req);