diff options
author | Shawn Pearce <sop@google.com> | 2012-03-07 22:22:22 -0500 |
---|---|---|
committer | Gerrit Code Review @ Eclipse.org <gerrit@eclipse.org> | 2012-03-07 22:22:22 -0500 |
commit | 500e17e7d6d3c29cef0fd4651dc1cd29d7d0b8e6 (patch) | |
tree | e3bffa9389ac1e2d6e71886a6cdb1f7322b3f192 /org.eclipse.jgit.http.server/src | |
parent | 90d002c15fd2131b9f80fb9bb6f28bf691c00b5d (diff) | |
parent | 039c785d9f0eac3fcb78b9dc2bf61796b82d3401 (diff) | |
download | jgit-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.java | 133 |
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); |