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 class GitFilter extends MetaFilter { 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 class GitFilter extends MetaFilter { 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.HttpServlet; 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 @@ class ReceivePackServlet extends HttpServlet { } } + @Nullable + private final ReceivePackErrorHandler handler; + + ReceivePackServlet(@Nullable ReceivePackErrorHandler handler) { + this.handler = handler; + } + /** {@inheritDoc} */ @Override public void doPost(final HttpServletRequest req, @@ -178,34 +186,42 @@ class ReceivePackServlet extends HttpServlet { }; ReceivePack rp = (ReceivePack) req.getAttribute(ATTRIBUTE_HANDLER); - try { - 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(); - - } 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); + rp.setBiDirectionalPipe(false); + rsp.setContentType(RECEIVE_PACK_RESULT_TYPE); + + 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 (Throwable e) { + log(rp.getRepository(), e); + if (!rsp.isCommitted()) { + rsp.reset(); + sendError(req, rsp, SC_INTERNAL_SERVER_ERROR); + } + return; } - return; } }