1867087bbSShawn O. Pearce /* 2*5c5f7c6bSMatthias Sohn * Copyright (C) 2011, Google Inc. and others 3867087bbSShawn O. Pearce * 4*5c5f7c6bSMatthias Sohn * This program and the accompanying materials are made available under the 5*5c5f7c6bSMatthias Sohn * terms of the Eclipse Distribution License v. 1.0 which is available at 6*5c5f7c6bSMatthias Sohn * https://www.eclipse.org/org/documents/edl-v10.php. 7867087bbSShawn O. Pearce * 8*5c5f7c6bSMatthias Sohn * SPDX-License-Identifier: BSD-3-Clause 9867087bbSShawn O. Pearce */ 10867087bbSShawn O. Pearce 11867087bbSShawn O. Pearce package org.eclipse.jgit.http.server; 12867087bbSShawn O. Pearce 13867087bbSShawn O. Pearce import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; 14867087bbSShawn O. Pearce import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; 15867087bbSShawn O. Pearce import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; 16a45cfee7SDavid Pursehouse import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER; 17a45cfee7SDavid Pursehouse import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K; 18a45cfee7SDavid Pursehouse import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR; 19a45cfee7SDavid Pursehouse import static org.eclipse.jgit.transport.SideBandOutputStream.SMALL_BUF; 20867087bbSShawn O. Pearce 21867087bbSShawn O. Pearce import java.io.ByteArrayOutputStream; 22867087bbSShawn O. Pearce import java.io.IOException; 23db00632dSShawn O. Pearce import java.io.OutputStream; 24867087bbSShawn O. Pearce import java.util.Arrays; 25867087bbSShawn O. Pearce import java.util.Collections; 26867087bbSShawn O. Pearce import java.util.List; 27867087bbSShawn O. Pearce 28867087bbSShawn O. Pearce import javax.servlet.http.HttpServletRequest; 29867087bbSShawn O. Pearce import javax.servlet.http.HttpServletResponse; 30867087bbSShawn O. Pearce 310d9e4867SMichael Keppler import org.eclipse.jgit.internal.transport.parser.FirstCommand; 32867087bbSShawn O. Pearce import org.eclipse.jgit.lib.Constants; 33039c785dSDave Borowitz import org.eclipse.jgit.transport.PacketLineIn; 34867087bbSShawn O. Pearce import org.eclipse.jgit.transport.PacketLineOut; 35039c785dSDave Borowitz import org.eclipse.jgit.transport.ReceivePack; 36039c785dSDave Borowitz import org.eclipse.jgit.transport.RequestNotYetReadException; 37039c785dSDave Borowitz import org.eclipse.jgit.transport.SideBandOutputStream; 38867087bbSShawn O. Pearce 39867087bbSShawn O. Pearce /** 40867087bbSShawn O. Pearce * Utility functions for handling the Git-over-HTTP protocol. 41867087bbSShawn O. Pearce */ 42867087bbSShawn O. Pearce public class GitSmartHttpTools { 43867087bbSShawn O. Pearce private static final String INFO_REFS = Constants.INFO_REFS; 44867087bbSShawn O. Pearce 45867087bbSShawn O. Pearce /** Name of the git-upload-pack service. */ 46867087bbSShawn O. Pearce public static final String UPLOAD_PACK = "git-upload-pack"; 47867087bbSShawn O. Pearce 48867087bbSShawn O. Pearce /** Name of the git-receive-pack service. */ 49867087bbSShawn O. Pearce public static final String RECEIVE_PACK = "git-receive-pack"; 50867087bbSShawn O. Pearce 51867087bbSShawn O. Pearce /** Content type supplied by the client to the /git-upload-pack handler. */ 52867087bbSShawn O. Pearce public static final String UPLOAD_PACK_REQUEST_TYPE = 53867087bbSShawn O. Pearce "application/x-git-upload-pack-request"; 54867087bbSShawn O. Pearce 55867087bbSShawn O. Pearce /** Content type returned from the /git-upload-pack handler. */ 56867087bbSShawn O. Pearce public static final String UPLOAD_PACK_RESULT_TYPE = 57867087bbSShawn O. Pearce "application/x-git-upload-pack-result"; 58867087bbSShawn O. Pearce 59867087bbSShawn O. Pearce /** Content type supplied by the client to the /git-receive-pack handler. */ 60867087bbSShawn O. Pearce public static final String RECEIVE_PACK_REQUEST_TYPE = 61867087bbSShawn O. Pearce "application/x-git-receive-pack-request"; 62867087bbSShawn O. Pearce 63867087bbSShawn O. Pearce /** Content type returned from the /git-receive-pack handler. */ 64867087bbSShawn O. Pearce public static final String RECEIVE_PACK_RESULT_TYPE = 65867087bbSShawn O. Pearce "application/x-git-receive-pack-result"; 66867087bbSShawn O. Pearce 67867087bbSShawn O. Pearce /** Git service names accepted by the /info/refs?service= handler. */ 68867087bbSShawn O. Pearce public static final List<String> VALID_SERVICES = 69867087bbSShawn O. Pearce Collections.unmodifiableList(Arrays.asList(new String[] { 70867087bbSShawn O. Pearce UPLOAD_PACK, RECEIVE_PACK })); 71867087bbSShawn O. Pearce 72867087bbSShawn O. Pearce private static final String INFO_REFS_PATH = "/" + INFO_REFS; 73867087bbSShawn O. Pearce private static final String UPLOAD_PACK_PATH = "/" + UPLOAD_PACK; 74867087bbSShawn O. Pearce private static final String RECEIVE_PACK_PATH = "/" + RECEIVE_PACK; 75867087bbSShawn O. Pearce 76867087bbSShawn O. Pearce private static final List<String> SERVICE_SUFFIXES = 77867087bbSShawn O. Pearce Collections.unmodifiableList(Arrays.asList(new String[] { 78867087bbSShawn O. Pearce INFO_REFS_PATH, UPLOAD_PACK_PATH, RECEIVE_PACK_PATH })); 79867087bbSShawn O. Pearce 80867087bbSShawn O. Pearce /** 81867087bbSShawn O. Pearce * Check a request for Git-over-HTTP indicators. 82867087bbSShawn O. Pearce * 83867087bbSShawn O. Pearce * @param req 84867087bbSShawn O. Pearce * the current HTTP request that may have been made by Git. 85867087bbSShawn O. Pearce * @return true if the request is likely made by a Git client program. 86867087bbSShawn O. Pearce */ isGitClient(HttpServletRequest req)87867087bbSShawn O. Pearce public static boolean isGitClient(HttpServletRequest req) { 88867087bbSShawn O. Pearce return isInfoRefs(req) || isUploadPack(req) || isReceivePack(req); 89867087bbSShawn O. Pearce } 90867087bbSShawn O. Pearce 91867087bbSShawn O. Pearce /** 92867087bbSShawn O. Pearce * Send an error to the Git client or browser. 93867087bbSShawn O. Pearce * <p> 94867087bbSShawn O. Pearce * Server implementors may use this method to send customized error messages 95867087bbSShawn O. Pearce * to a Git protocol client using an HTTP 200 OK response with the error 96867087bbSShawn O. Pearce * embedded in the payload. If the request was not issued by a Git client, 97867087bbSShawn O. Pearce * an HTTP response code is returned instead. 98867087bbSShawn O. Pearce * 99867087bbSShawn O. Pearce * @param req 100867087bbSShawn O. Pearce * current request. 101867087bbSShawn O. Pearce * @param res 102867087bbSShawn O. Pearce * current response. 103867087bbSShawn O. Pearce * @param httpStatus 104867087bbSShawn O. Pearce * HTTP status code to set if the client is not a Git client. 105867087bbSShawn O. Pearce * @throws IOException 106867087bbSShawn O. Pearce * the response cannot be sent. 107867087bbSShawn O. Pearce */ sendError(HttpServletRequest req, HttpServletResponse res, int httpStatus)108867087bbSShawn O. Pearce public static void sendError(HttpServletRequest req, 109867087bbSShawn O. Pearce HttpServletResponse res, int httpStatus) throws IOException { 110867087bbSShawn O. Pearce sendError(req, res, httpStatus, null); 111867087bbSShawn O. Pearce } 112867087bbSShawn O. Pearce 113867087bbSShawn O. Pearce /** 114867087bbSShawn O. Pearce * Send an error to the Git client or browser. 115867087bbSShawn O. Pearce * <p> 116867087bbSShawn O. Pearce * Server implementors may use this method to send customized error messages 117867087bbSShawn O. Pearce * to a Git protocol client using an HTTP 200 OK response with the error 118867087bbSShawn O. Pearce * embedded in the payload. If the request was not issued by a Git client, 119867087bbSShawn O. Pearce * an HTTP response code is returned instead. 120039c785dSDave Borowitz * <p> 121039c785dSDave Borowitz * This method may only be called before handing off the request to 1223b00041cSMatthias Sohn * {@link org.eclipse.jgit.transport.UploadPack#upload(java.io.InputStream, OutputStream, OutputStream)} 123039c785dSDave Borowitz * or 1243b00041cSMatthias Sohn * {@link org.eclipse.jgit.transport.ReceivePack#receive(java.io.InputStream, OutputStream, OutputStream)}. 125867087bbSShawn O. Pearce * 126867087bbSShawn O. Pearce * @param req 127867087bbSShawn O. Pearce * current request. 128867087bbSShawn O. Pearce * @param res 129867087bbSShawn O. Pearce * current response. 130867087bbSShawn O. Pearce * @param httpStatus 131867087bbSShawn O. Pearce * HTTP status code to set if the client is not a Git client. 132867087bbSShawn O. Pearce * @param textForGit 133867087bbSShawn O. Pearce * plain text message to display on the user's console. This is 134867087bbSShawn O. Pearce * shown only if the client is likely to be a Git client. If null 135867087bbSShawn O. Pearce * or the empty string a default text is chosen based on the HTTP 136867087bbSShawn O. Pearce * response code. 137867087bbSShawn O. Pearce * @throws IOException 138867087bbSShawn O. Pearce * the response cannot be sent. 139867087bbSShawn O. Pearce */ sendError(HttpServletRequest req, HttpServletResponse res, int httpStatus, String textForGit)140867087bbSShawn O. Pearce public static void sendError(HttpServletRequest req, 141867087bbSShawn O. Pearce HttpServletResponse res, int httpStatus, String textForGit) 142867087bbSShawn O. Pearce throws IOException { 143867087bbSShawn O. Pearce if (textForGit == null || textForGit.length() == 0) { 144867087bbSShawn O. Pearce switch (httpStatus) { 145867087bbSShawn O. Pearce case SC_FORBIDDEN: 146867087bbSShawn O. Pearce textForGit = HttpServerText.get().repositoryAccessForbidden; 147867087bbSShawn O. Pearce break; 148867087bbSShawn O. Pearce case SC_NOT_FOUND: 149867087bbSShawn O. Pearce textForGit = HttpServerText.get().repositoryNotFound; 150867087bbSShawn O. Pearce break; 151867087bbSShawn O. Pearce case SC_INTERNAL_SERVER_ERROR: 152867087bbSShawn O. Pearce textForGit = HttpServerText.get().internalServerError; 153867087bbSShawn O. Pearce break; 154867087bbSShawn O. Pearce default: 155867087bbSShawn O. Pearce textForGit = "HTTP " + httpStatus; 156867087bbSShawn O. Pearce break; 157867087bbSShawn O. Pearce } 158867087bbSShawn O. Pearce } 159867087bbSShawn O. Pearce 160867087bbSShawn O. Pearce if (isInfoRefs(req)) { 161039c785dSDave Borowitz sendInfoRefsError(req, res, textForGit); 162867087bbSShawn O. Pearce } else if (isUploadPack(req)) { 163039c785dSDave Borowitz sendUploadPackError(req, res, textForGit); 164867087bbSShawn O. Pearce } else if (isReceivePack(req)) { 165039c785dSDave Borowitz sendReceivePackError(req, res, textForGit); 166867087bbSShawn O. Pearce } else { 167db00632dSShawn O. Pearce if (httpStatus < 400) 168db00632dSShawn O. Pearce ServletUtils.consumeRequestBody(req); 169e8d4f259SMasaya Suzuki res.sendError(httpStatus, textForGit); 170867087bbSShawn O. Pearce } 171867087bbSShawn O. Pearce } 172867087bbSShawn O. Pearce sendInfoRefsError(HttpServletRequest req, HttpServletResponse res, String textForGit)173039c785dSDave Borowitz private static void sendInfoRefsError(HttpServletRequest req, 174039c785dSDave Borowitz HttpServletResponse res, String textForGit) throws IOException { 175039c785dSDave Borowitz ByteArrayOutputStream buf = new ByteArrayOutputStream(128); 176039c785dSDave Borowitz PacketLineOut pck = new PacketLineOut(buf); 177039c785dSDave Borowitz String svc = req.getParameter("service"); 178039c785dSDave Borowitz pck.writeString("# service=" + svc + "\n"); 179039c785dSDave Borowitz pck.end(); 180039c785dSDave Borowitz pck.writeString("ERR " + textForGit); 181039c785dSDave Borowitz send(req, res, infoRefsResultType(svc), buf.toByteArray()); 182039c785dSDave Borowitz } 183039c785dSDave Borowitz sendUploadPackError(HttpServletRequest req, HttpServletResponse res, String textForGit)184039c785dSDave Borowitz private static void sendUploadPackError(HttpServletRequest req, 185039c785dSDave Borowitz HttpServletResponse res, String textForGit) throws IOException { 1862d4196b9SMasaya Suzuki // Do not use sideband. Sideband is acceptable only while packfile is 1872d4196b9SMasaya Suzuki // being sent. Other places, like acknowledgement section, do not 1882d4196b9SMasaya Suzuki // support sideband. Use an error packet. 189039c785dSDave Borowitz ByteArrayOutputStream buf = new ByteArrayOutputStream(128); 190039c785dSDave Borowitz PacketLineOut pckOut = new PacketLineOut(buf); 191039c785dSDave Borowitz writePacket(pckOut, textForGit); 192039c785dSDave Borowitz send(req, res, UPLOAD_PACK_RESULT_TYPE, buf.toByteArray()); 193039c785dSDave Borowitz } 194039c785dSDave Borowitz sendReceivePackError(HttpServletRequest req, HttpServletResponse res, String textForGit)195039c785dSDave Borowitz private static void sendReceivePackError(HttpServletRequest req, 196039c785dSDave Borowitz HttpServletResponse res, String textForGit) throws IOException { 197039c785dSDave Borowitz ByteArrayOutputStream buf = new ByteArrayOutputStream(128); 198039c785dSDave Borowitz PacketLineOut pckOut = new PacketLineOut(buf); 199039c785dSDave Borowitz 200039c785dSDave Borowitz boolean sideband; 201039c785dSDave Borowitz ReceivePack rp = (ReceivePack) req.getAttribute(ATTRIBUTE_HANDLER); 202039c785dSDave Borowitz if (rp != null) { 203039c785dSDave Borowitz try { 204039c785dSDave Borowitz sideband = rp.isSideBand(); 205039c785dSDave Borowitz } catch (RequestNotYetReadException e) { 206039c785dSDave Borowitz sideband = isReceivePackSideBand(req); 207039c785dSDave Borowitz } 208039c785dSDave Borowitz } else 209039c785dSDave Borowitz sideband = isReceivePackSideBand(req); 210039c785dSDave Borowitz 211039c785dSDave Borowitz if (sideband) 212039c785dSDave Borowitz writeSideBand(buf, textForGit); 213039c785dSDave Borowitz else 214039c785dSDave Borowitz writePacket(pckOut, textForGit); 215039c785dSDave Borowitz send(req, res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray()); 216039c785dSDave Borowitz } 217039c785dSDave Borowitz isReceivePackSideBand(HttpServletRequest req)218039c785dSDave Borowitz private static boolean isReceivePackSideBand(HttpServletRequest req) { 219039c785dSDave Borowitz try { 220039c785dSDave Borowitz // The client may be in a state where they have sent the sideband 221039c785dSDave Borowitz // capability and are expecting a response in the sideband, but we might 222039c785dSDave Borowitz // not have a ReceivePack, or it might not have read any of the request. 223039c785dSDave Borowitz // So, cheat and read the first line. 224c1ed9483SShawn O. Pearce String line = new PacketLineIn(req.getInputStream()).readString(); 2250d9e4867SMichael Keppler FirstCommand parsed = FirstCommand.fromLine(line); 226039c785dSDave Borowitz return parsed.getCapabilities().contains(CAPABILITY_SIDE_BAND_64K); 227039c785dSDave Borowitz } catch (IOException e) { 228039c785dSDave Borowitz // Probably the connection is closed and a subsequent write will fail, but 229039c785dSDave Borowitz // try it just in case. 230039c785dSDave Borowitz return false; 231039c785dSDave Borowitz } 232039c785dSDave Borowitz } 233039c785dSDave Borowitz writeSideBand(OutputStream out, String textForGit)234039c785dSDave Borowitz private static void writeSideBand(OutputStream out, String textForGit) 235039c785dSDave Borowitz throws IOException { 236f5614e03SDavid Pursehouse try (OutputStream msg = new SideBandOutputStream(CH_ERROR, SMALL_BUF, 237f5614e03SDavid Pursehouse out)) { 238039c785dSDave Borowitz msg.write(Constants.encode("error: " + textForGit)); 239039c785dSDave Borowitz msg.flush(); 240039c785dSDave Borowitz } 241f5614e03SDavid Pursehouse } 242039c785dSDave Borowitz writePacket(PacketLineOut pckOut, String textForGit)243039c785dSDave Borowitz private static void writePacket(PacketLineOut pckOut, String textForGit) 244039c785dSDave Borowitz throws IOException { 2452d4196b9SMasaya Suzuki pckOut.writeString("ERR " + textForGit); 246039c785dSDave Borowitz } 247039c785dSDave Borowitz send(HttpServletRequest req, HttpServletResponse res, String type, byte[] buf)248db00632dSShawn O. Pearce private static void send(HttpServletRequest req, HttpServletResponse res, 249db00632dSShawn O. Pearce String type, byte[] buf) throws IOException { 250db00632dSShawn O. Pearce ServletUtils.consumeRequestBody(req); 251867087bbSShawn O. Pearce res.setStatus(HttpServletResponse.SC_OK); 252867087bbSShawn O. Pearce res.setContentType(type); 253867087bbSShawn O. Pearce res.setContentLength(buf.length); 2546722f692SDavid Pursehouse try (OutputStream os = res.getOutputStream()) { 255867087bbSShawn O. Pearce os.write(buf); 256867087bbSShawn O. Pearce } 257867087bbSShawn O. Pearce } 258867087bbSShawn O. Pearce 259867087bbSShawn O. Pearce /** 260867087bbSShawn O. Pearce * Get the response Content-Type a client expects for the request. 261867087bbSShawn O. Pearce * <p> 262867087bbSShawn O. Pearce * This method should only be invoked if 263867087bbSShawn O. Pearce * {@link #isGitClient(HttpServletRequest)} is true. 264867087bbSShawn O. Pearce * 265867087bbSShawn O. Pearce * @param req 266867087bbSShawn O. Pearce * current request. 267867087bbSShawn O. Pearce * @return the Content-Type the client expects. 268867087bbSShawn O. Pearce * @throws IllegalArgumentException 269867087bbSShawn O. Pearce * the request is not a Git client request. See 270867087bbSShawn O. Pearce * {@link #isGitClient(HttpServletRequest)}. 271867087bbSShawn O. Pearce */ getResponseContentType(HttpServletRequest req)272867087bbSShawn O. Pearce public static String getResponseContentType(HttpServletRequest req) { 273867087bbSShawn O. Pearce if (isInfoRefs(req)) 274867087bbSShawn O. Pearce return infoRefsResultType(req.getParameter("service")); 275867087bbSShawn O. Pearce else if (isUploadPack(req)) 276867087bbSShawn O. Pearce return UPLOAD_PACK_RESULT_TYPE; 277867087bbSShawn O. Pearce else if (isReceivePack(req)) 278867087bbSShawn O. Pearce return RECEIVE_PACK_RESULT_TYPE; 279867087bbSShawn O. Pearce else 280867087bbSShawn O. Pearce throw new IllegalArgumentException(); 281867087bbSShawn O. Pearce } 282867087bbSShawn O. Pearce infoRefsResultType(String svc)283867087bbSShawn O. Pearce static String infoRefsResultType(String svc) { 284867087bbSShawn O. Pearce return "application/x-" + svc + "-advertisement"; 285867087bbSShawn O. Pearce } 286867087bbSShawn O. Pearce 287867087bbSShawn O. Pearce /** 288867087bbSShawn O. Pearce * Strip the Git service suffix from a request path. 289867087bbSShawn O. Pearce * 290867087bbSShawn O. Pearce * Generally the suffix is stripped by the {@code SuffixPipeline} handling 291867087bbSShawn O. Pearce * the request, so this method is rarely needed. 292867087bbSShawn O. Pearce * 293867087bbSShawn O. Pearce * @param path 294867087bbSShawn O. Pearce * the path of the request. 295867087bbSShawn O. Pearce * @return the path up to the last path component before the service suffix; 296867087bbSShawn O. Pearce * the path as-is if it contains no service suffix. 297867087bbSShawn O. Pearce */ stripServiceSuffix(String path)298867087bbSShawn O. Pearce public static String stripServiceSuffix(String path) { 299867087bbSShawn O. Pearce for (String suffix : SERVICE_SUFFIXES) { 300867087bbSShawn O. Pearce if (path.endsWith(suffix)) 301867087bbSShawn O. Pearce return path.substring(0, path.length() - suffix.length()); 302867087bbSShawn O. Pearce } 303867087bbSShawn O. Pearce return path; 304867087bbSShawn O. Pearce } 305867087bbSShawn O. Pearce 306867087bbSShawn O. Pearce /** 307867087bbSShawn O. Pearce * Check if the HTTP request was for the /info/refs?service= Git handler. 308867087bbSShawn O. Pearce * 309867087bbSShawn O. Pearce * @param req 310867087bbSShawn O. Pearce * current request. 311867087bbSShawn O. Pearce * @return true if the request is for the /info/refs service. 312867087bbSShawn O. Pearce */ isInfoRefs(HttpServletRequest req)313867087bbSShawn O. Pearce public static boolean isInfoRefs(HttpServletRequest req) { 314867087bbSShawn O. Pearce return req.getRequestURI().endsWith(INFO_REFS_PATH) 315867087bbSShawn O. Pearce && VALID_SERVICES.contains(req.getParameter("service")); 316867087bbSShawn O. Pearce } 317867087bbSShawn O. Pearce 318867087bbSShawn O. Pearce /** 319867087bbSShawn O. Pearce * Check if the HTTP request path ends with the /git-upload-pack handler. 320867087bbSShawn O. Pearce * 321867087bbSShawn O. Pearce * @param pathOrUri 322867087bbSShawn O. Pearce * path or URI of the request. 323867087bbSShawn O. Pearce * @return true if the request is for the /git-upload-pack handler. 324867087bbSShawn O. Pearce */ isUploadPack(String pathOrUri)325867087bbSShawn O. Pearce public static boolean isUploadPack(String pathOrUri) { 326867087bbSShawn O. Pearce return pathOrUri != null && pathOrUri.endsWith(UPLOAD_PACK_PATH); 327867087bbSShawn O. Pearce } 328867087bbSShawn O. Pearce 329867087bbSShawn O. Pearce /** 330867087bbSShawn O. Pearce * Check if the HTTP request was for the /git-upload-pack Git handler. 331867087bbSShawn O. Pearce * 332867087bbSShawn O. Pearce * @param req 333867087bbSShawn O. Pearce * current request. 334867087bbSShawn O. Pearce * @return true if the request is for the /git-upload-pack handler. 335867087bbSShawn O. Pearce */ isUploadPack(HttpServletRequest req)336867087bbSShawn O. Pearce public static boolean isUploadPack(HttpServletRequest req) { 337867087bbSShawn O. Pearce return isUploadPack(req.getRequestURI()) 338867087bbSShawn O. Pearce && UPLOAD_PACK_REQUEST_TYPE.equals(req.getContentType()); 339867087bbSShawn O. Pearce } 340867087bbSShawn O. Pearce 341867087bbSShawn O. Pearce /** 342867087bbSShawn O. Pearce * Check if the HTTP request was for the /git-receive-pack Git handler. 343867087bbSShawn O. Pearce * 344867087bbSShawn O. Pearce * @param req 345867087bbSShawn O. Pearce * current request. 346867087bbSShawn O. Pearce * @return true if the request is for the /git-receive-pack handler. 347867087bbSShawn O. Pearce */ isReceivePack(HttpServletRequest req)348867087bbSShawn O. Pearce public static boolean isReceivePack(HttpServletRequest req) { 349867087bbSShawn O. Pearce String uri = req.getRequestURI(); 350867087bbSShawn O. Pearce return uri != null && uri.endsWith(RECEIVE_PACK_PATH) 351867087bbSShawn O. Pearce && RECEIVE_PACK_REQUEST_TYPE.equals(req.getContentType()); 352867087bbSShawn O. Pearce } 353867087bbSShawn O. Pearce GitSmartHttpTools()354867087bbSShawn O. Pearce private GitSmartHttpTools() { 355867087bbSShawn O. Pearce } 356867087bbSShawn O. Pearce } 357