From 75ec5b746dcaabbd0448dcffb8e3d2ed0d0f3943 Mon Sep 17 00:00:00 2001 From: Masaya Suzuki Date: Fri, 8 Nov 2019 10:48:03 -0800 Subject: [PATCH] server: Add a custom error handler Same as UploadPack, add a custom error handler. Change-Id: I9c708aa5a22e01214c1d997fa6f72f4b8bf814f0 Signed-off-by: Masaya Suzuki --- .../eclipse/jgit/http/server/GitFilter.java | 15 ++++- .../http/server/ReceivePackErrorHandler.java | 60 +++++++++++++++++ .../jgit/http/server/ReceivePackServlet.java | 64 ++++++++++++------- 3 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackErrorHandler.java diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java index e9462eeb4..06970a769 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java @@ -96,6 +96,8 @@ public class GitFilter extends MetaFilter { private ReceivePackFactory receivePackFactory = new DefaultReceivePackFactory(); + private ReceivePackErrorHandler receivePackErrorHandler; + private final List uploadPackFilters = new LinkedList<>(); private final List receivePackFilters = new LinkedList<>(); @@ -189,6 +191,17 @@ public void setReceivePackFactory(ReceivePackFactory f) { this.receivePackFactory = f != null ? f : (ReceivePackFactory)ReceivePackFactory.DISABLED; } + /** + * Set a custom error handler for git-receive-pack. + * + * @param h + * A custom error handler for git-receive-pack. + */ + public void setReceivePackErrorHandler(ReceivePackErrorHandler h) { + assertNotInitialized(); + this.receivePackErrorHandler = h; + } + /** * Add receive-pack filter * @@ -233,7 +246,7 @@ public void init(FilterConfig filterConfig) throws ServletException { b = b.through(new ReceivePackServlet.Factory(receivePackFactory)); for (Filter f : receivePackFilters) b = b.through(f); - b.with(new ReceivePackServlet()); + b.with(new ReceivePackServlet(receivePackErrorHandler)); } ServletBinder refs = serve("*/" + Constants.INFO_REFS); diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackErrorHandler.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackErrorHandler.java new file mode 100644 index 000000000..ee66cb102 --- /dev/null +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackErrorHandler.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019, Google LLC and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.http.server; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jgit.transport.ReceivePack; +import org.eclipse.jgit.transport.ServiceMayNotContinueException; + +/** + * Handle git-receive-pack errors. + * + *

+ * This is an entry point for customizing an error handler for git-receive-pack. + * Right before calling {@link ReceivePack#receiveWithExceptionPropagation}, + * JGit will call this handler if specified through {@link GitFilter}. The + * implementation of this handler is responsible for calling + * {@link ReceivePackRunnable} and handling exceptions for clients. + * + *

+ * If a custom handler is not specified, JGit will use the default error + * handler. + * + * @since 5.6 + */ +public interface ReceivePackErrorHandler { + /** + * @param req + * The HTTP request + * @param rsp + * The HTTP response + * @param r + * A continuation that handles a git-receive-pack request. + * @throws IOException + */ + void receive(HttpServletRequest req, HttpServletResponse rsp, + ReceivePackRunnable r) throws IOException; + + /** Process a git-receive-pack request. */ + public interface ReceivePackRunnable { + /** + * See {@link ReceivePack#receiveWithExceptionPropagation}. + * + * @throws ServiceMayNotContinueException + * @throws IOException + */ + void receive() throws ServiceMayNotContinueException, IOException; + } + +} diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java index aed36560a..eb130d0a2 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java @@ -71,6 +71,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.errors.UnpackException; @@ -161,6 +162,13 @@ public void destroy() { } } + @Nullable + private final ReceivePackErrorHandler handler; + + ReceivePackServlet(@Nullable ReceivePackErrorHandler handler) { + this.handler = handler; + } + /** {@inheritDoc} */ @Override public void doPost(final HttpServletRequest req, @@ -178,34 +186,42 @@ public void flush() throws IOException { }; ReceivePack rp = (ReceivePack) req.getAttribute(ATTRIBUTE_HANDLER); - try { - rp.setBiDirectionalPipe(false); - rsp.setContentType(RECEIVE_PACK_RESULT_TYPE); + rp.setBiDirectionalPipe(false); + rsp.setContentType(RECEIVE_PACK_RESULT_TYPE); - rp.receive(getInputStream(req), out, null); - out.close(); - } catch (CorruptObjectException e ) { - // This should be already reported to the client. - getServletContext().log(MessageFormat.format( - HttpServerText.get().receivedCorruptObject, - e.getMessage(), - ServletUtils.identify(rp.getRepository()))); - consumeRequestBody(req); - out.close(); + if (handler != null) { + handler.receive(req, rsp, () -> { + rp.receiveWithExceptionPropagation(getInputStream(req), out, + null); + out.close(); + }); + } else { + try { + rp.receive(getInputStream(req), out, null); + out.close(); + } catch (CorruptObjectException e ) { + // This should be already reported to the client. + getServletContext().log(MessageFormat.format( + HttpServerText.get().receivedCorruptObject, + e.getMessage(), + ServletUtils.identify(rp.getRepository()))); + consumeRequestBody(req); + out.close(); - } catch (UnpackException | PackProtocolException e) { - // This should be already reported to the client. - log(rp.getRepository(), e.getCause()); - consumeRequestBody(req); - out.close(); + } catch (UnpackException | PackProtocolException e) { + // This should be already reported to the client. + log(rp.getRepository(), e.getCause()); + consumeRequestBody(req); + out.close(); - } catch (Throwable e) { - log(rp.getRepository(), e); - if (!rsp.isCommitted()) { - rsp.reset(); - sendError(req, rsp, SC_INTERNAL_SERVER_ERROR); + } catch (Throwable e) { + log(rp.getRepository(), e); + if (!rsp.isCommitted()) { + rsp.reset(); + sendError(req, rsp, SC_INTERNAL_SERVER_ERROR); + } + return; } - return; } }