diff options
Diffstat (limited to 'org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java')
-rw-r--r-- | org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java | 170 |
1 files changed, 90 insertions, 80 deletions
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java index 44d4b1bcfa..3665d35c0e 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java @@ -1,55 +1,18 @@ /* - * Copyright (C) 2009-2010, Google Inc. - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2009-2010, 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 javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; -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_UNAUTHORIZED; -import static javax.servlet.http.HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE; -import static org.eclipse.jgit.http.server.ClientVersionUtil.hasChunkedEncodingRequestBug; -import static org.eclipse.jgit.http.server.ClientVersionUtil.parseVersion; +import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN; +import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; +import static jakarta.servlet.http.HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE; import static org.eclipse.jgit.http.server.GitSmartHttpTools.UPLOAD_PACK; import static org.eclipse.jgit.http.server.GitSmartHttpTools.UPLOAD_PACK_REQUEST_TYPE; import static org.eclipse.jgit.http.server.GitSmartHttpTools.UPLOAD_PACK_RESULT_TYPE; @@ -58,24 +21,29 @@ import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER; import static org.eclipse.jgit.http.server.ServletUtils.consumeRequestBody; import static org.eclipse.jgit.http.server.ServletUtils.getInputStream; import static org.eclipse.jgit.http.server.ServletUtils.getRepository; +import static org.eclipse.jgit.http.server.UploadPackErrorHandler.statusCodeForThrowable; import static org.eclipse.jgit.util.HttpSupport.HDR_USER_AGENT; import java.io.IOException; import java.text.MessageFormat; import java.util.List; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.annotations.Nullable; +import org.eclipse.jgit.errors.PackProtocolException; +import org.eclipse.jgit.http.server.UploadPackErrorHandler.UploadPackRunnable; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.transport.InternalHttpServerGlue; +import org.eclipse.jgit.transport.PacketLineOut; import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser; import org.eclipse.jgit.transport.ServiceMayNotContinueException; import org.eclipse.jgit.transport.UploadPack; @@ -117,6 +85,25 @@ class UploadPackServlet extends HttpServlet { up.setBiDirectionalPipe(false); up.sendAdvertisedRefs(pck); } finally { + // TODO(jonathantanmy): Move responsibility for closing the + // RevWalk to UploadPack, either by making it AutoCloseable + // or by making sendAdvertisedRefs clean up after itself. + up.getRevWalk().close(); + } + } + + @Override + protected void respond(HttpServletRequest req, + PacketLineOut pckOut, String serviceName) throws IOException, + ServiceNotEnabledException, ServiceNotAuthorizedException { + UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER); + try { + up.setBiDirectionalPipe(false); + up.sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut), serviceName); + } finally { + // TODO(jonathantanmy): Move responsibility for closing the + // RevWalk to UploadPack, either by making it AutoCloseable + // or by making sendAdvertisedRefs clean up after itself. up.getRevWalk().close(); } } @@ -129,6 +116,7 @@ class UploadPackServlet extends HttpServlet { this.uploadPackFactory = uploadPackFactory; } + @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; @@ -137,11 +125,10 @@ class UploadPackServlet extends HttpServlet { try { rp = uploadPackFactory.create(req, getRepository(req)); } catch (ServiceNotAuthorizedException e) { - rsp.sendError(SC_UNAUTHORIZED); + rsp.sendError(SC_UNAUTHORIZED, e.getMessage()); return; - } catch (ServiceNotEnabledException e) { - sendError(req, rsp, SC_FORBIDDEN); + sendError(req, rsp, SC_FORBIDDEN, e.getMessage()); return; } @@ -153,68 +140,91 @@ class UploadPackServlet extends HttpServlet { } } + @Override public void init(FilterConfig filterConfig) throws ServletException { // Nothing. } + @Override public void destroy() { // Nothing. } } + private final UploadPackErrorHandler handler; + + UploadPackServlet(@Nullable UploadPackErrorHandler handler) { + this.handler = handler != null ? handler + : this::defaultUploadPackHandler; + } + @Override - public void doPost(final HttpServletRequest req, - final HttpServletResponse rsp) throws IOException { + public void doPost(HttpServletRequest req, HttpServletResponse rsp) + throws IOException { if (!UPLOAD_PACK_REQUEST_TYPE.equals(req.getContentType())) { rsp.sendError(SC_UNSUPPORTED_MEDIA_TYPE); return; } - int[] version = parseVersion(req.getHeader(HDR_USER_AGENT)); - if (hasChunkedEncodingRequestBug(version, req)) { - GitSmartHttpTools.sendError(req, rsp, SC_BAD_REQUEST, "\n\n" - + HttpServerText.get().clientHas175ChunkedEncodingBug); - return; - } + UploadPackRunnable r = () -> { + upload(req, rsp); + }; + + handler.upload(req, rsp, r); + } + private void upload(HttpServletRequest req, HttpServletResponse rsp) + throws IOException, ServiceMayNotContinueException { + // to be explicitly closed by caller + @SuppressWarnings("resource") SmartOutputStream out = new SmartOutputStream(req, rsp, false) { @Override public void flush() throws IOException { doFlush(); } }; - - UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER); - try { + Repository repo = null; + try (UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER)) { up.setBiDirectionalPipe(false); rsp.setContentType(UPLOAD_PACK_RESULT_TYPE); - - up.upload(getInputStream(req), out, null); + repo = up.getRepository(); + up.uploadWithExceptionPropagation(getInputStream(req), out, null); out.close(); - } catch (ServiceMayNotContinueException e) { if (e.isOutput()) { consumeRequestBody(req); out.close(); - } else if (!rsp.isCommitted()) { - rsp.reset(); - sendError(req, rsp, SC_FORBIDDEN, e.getMessage()); } - return; - + throw e; } catch (UploadPackInternalServerErrorException e) { // Special case exception, error message was sent to client. - log(up.getRepository(), e.getCause()); + log(repo, e.getCause()); consumeRequestBody(req); out.close(); + } + } + private void defaultUploadPackHandler(HttpServletRequest req, + HttpServletResponse rsp, UploadPackRunnable r) throws IOException { + try { + r.upload(); + } catch (ServiceMayNotContinueException e) { + if (!e.isOutput() && !rsp.isCommitted()) { + rsp.reset(); + sendError(req, rsp, e.getStatusCode(), e.getMessage()); + } } catch (Throwable e) { + UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER); log(up.getRepository(), e); if (!rsp.isCommitted()) { rsp.reset(); - sendError(req, rsp, SC_INTERNAL_SERVER_ERROR); + String msg = null; + if (e instanceof PackProtocolException + || e instanceof ServiceNotEnabledException) { + msg = e.getMessage(); + } + sendError(req, rsp, statusCodeForThrowable(e), msg); } - return; } } |