diff options
Diffstat (limited to 'org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java')
-rw-r--r-- | org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java | 159 |
1 files changed, 53 insertions, 106 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 d8cd61df81..bf3da4b5d0 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 @@ -1,57 +1,22 @@ /* - * Copyright (C) 2011, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2011, Google Inc. and others * - * 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 + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://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. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.http.server; +import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN; +import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; +import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND; import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER; -import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND; -import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K; import static org.eclipse.jgit.transport.GitProtocolConstants.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; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -60,16 +25,16 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.eclipse.jgit.internal.transport.parser.FirstCommand; 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. @@ -118,6 +83,7 @@ public class GitSmartHttpTools { * @param req * the current HTTP request that may have been made by Git. * @return true if the request is likely made by a Git client program. + * @since 7.0 */ public static boolean isGitClient(HttpServletRequest req) { return isInfoRefs(req) || isUploadPack(req) || isReceivePack(req); @@ -139,6 +105,7 @@ public class GitSmartHttpTools { * HTTP status code to set if the client is not a Git client. * @throws IOException * the response cannot be sent. + * @since 7.0 */ public static void sendError(HttpServletRequest req, HttpServletResponse res, int httpStatus) throws IOException { @@ -154,9 +121,9 @@ public class GitSmartHttpTools { * 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)} + * {@link org.eclipse.jgit.transport.UploadPack#upload(java.io.InputStream, OutputStream, OutputStream)} * or - * {@link ReceivePack#receive(java.io.InputStream, OutputStream, OutputStream)}. + * {@link org.eclipse.jgit.transport.ReceivePack#receive(java.io.InputStream, OutputStream, OutputStream)}. * * @param req * current request. @@ -171,6 +138,7 @@ public class GitSmartHttpTools { * response code. * @throws IOException * the response cannot be sent. + * @since 7.0 */ public static void sendError(HttpServletRequest req, HttpServletResponse res, int httpStatus, String textForGit) @@ -193,71 +161,45 @@ public class GitSmartHttpTools { } if (isInfoRefs(req)) { - sendInfoRefsError(req, res, textForGit); + sendInfoRefsError(req, res, textForGit, httpStatus); } else if (isUploadPack(req)) { - sendUploadPackError(req, res, textForGit); + sendUploadPackError(req, res, textForGit, httpStatus); } else if (isReceivePack(req)) { - sendReceivePackError(req, res, textForGit); + sendReceivePackError(req, res, textForGit, httpStatus); } else { if (httpStatus < 400) ServletUtils.consumeRequestBody(req); - res.sendError(httpStatus); + res.sendError(httpStatus, textForGit); } } private static void sendInfoRefsError(HttpServletRequest req, - HttpServletResponse res, String textForGit) throws IOException { + HttpServletResponse res, String textForGit, int httpStatus) + 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()); + send(req, res, infoRefsResultType(svc), buf.toByteArray(), httpStatus); } private static void sendUploadPackError(HttpServletRequest req, - HttpServletResponse res, String textForGit) throws IOException { + HttpServletResponse res, String textForGit, int httpStatus) + throws IOException { + // Do not use sideband. Sideband is acceptable only while packfile is + // being sent. Other places, like acknowledgement section, do not + // support sideband. Use an error packet. 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()).readString(); - 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; - } + writePacket(pckOut, textForGit); + send(req, res, UPLOAD_PACK_RESULT_TYPE, buf.toByteArray(), httpStatus); } private static void sendReceivePackError(HttpServletRequest req, - HttpServletResponse res, String textForGit) throws IOException { + HttpServletResponse res, String textForGit, int httpStatus) + throws IOException { ByteArrayOutputStream buf = new ByteArrayOutputStream(128); PacketLineOut pckOut = new PacketLineOut(buf); @@ -276,7 +218,7 @@ public class GitSmartHttpTools { writeSideBand(buf, textForGit); else writePacket(pckOut, textForGit); - send(req, res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray()); + send(req, res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray(), httpStatus); } private static boolean isReceivePackSideBand(HttpServletRequest req) { @@ -286,8 +228,9 @@ public class GitSmartHttpTools { // 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()).readString(); - ReceivePack.FirstLine parsed = new ReceivePack.FirstLine(line); - return parsed.getCapabilities().contains(CAPABILITY_SIDE_BAND_64K); + FirstCommand parsed = FirstCommand.fromLine(line); + return parsed.getCapabilities() + .containsKey(CAPABILITY_SIDE_BAND_64K); } catch (IOException e) { // Probably the connection is closed and a subsequent write will fail, but // try it just in case. @@ -297,28 +240,28 @@ public class GitSmartHttpTools { private static void writeSideBand(OutputStream out, String textForGit) throws IOException { - @SuppressWarnings("resource" /* java 7 */) - OutputStream msg = new SideBandOutputStream(CH_ERROR, SMALL_BUF, out); - msg.write(Constants.encode("error: " + textForGit)); - msg.flush(); + try (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); + pckOut.writeString("ERR " + textForGit); } private static void send(HttpServletRequest req, HttpServletResponse res, - String type, byte[] buf) throws IOException { + String type, byte[] buf, int httpStatus) throws IOException { ServletUtils.consumeRequestBody(req); - res.setStatus(HttpServletResponse.SC_OK); - res.setContentType(type); - res.setContentLength(buf.length); - OutputStream os = res.getOutputStream(); - try { + if (!res.isCommitted()) { + res.setStatus(httpStatus); + res.setContentType(type); + res.setContentLength(buf.length); + } + try (OutputStream os = res.getOutputStream()) { os.write(buf); - } finally { - os.close(); } } @@ -334,6 +277,7 @@ public class GitSmartHttpTools { * @throws IllegalArgumentException * the request is not a Git client request. See * {@link #isGitClient(HttpServletRequest)}. + * @since 7.0 */ public static String getResponseContentType(HttpServletRequest req) { if (isInfoRefs(req)) @@ -375,6 +319,7 @@ public class GitSmartHttpTools { * @param req * current request. * @return true if the request is for the /info/refs service. + * @since 7.0 */ public static boolean isInfoRefs(HttpServletRequest req) { return req.getRequestURI().endsWith(INFO_REFS_PATH) @@ -398,6 +343,7 @@ public class GitSmartHttpTools { * @param req * current request. * @return true if the request is for the /git-upload-pack handler. + * @since 7.0 */ public static boolean isUploadPack(HttpServletRequest req) { return isUploadPack(req.getRequestURI()) @@ -410,6 +356,7 @@ public class GitSmartHttpTools { * @param req * current request. * @return true if the request is for the /git-receive-pack handler. + * @since 7.0 */ public static boolean isReceivePack(HttpServletRequest req) { String uri = req.getRequestURI(); |