summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.http.server/src/org/eclipse
diff options
context:
space:
mode:
authorMasaya Suzuki <masayasuzuki@google.com>2019-08-06 12:02:23 -0700
committerMasaya Suzuki <masayasuzuki@google.com>2019-10-09 10:25:54 -0700
commitabedaf0d3854f319d0df839851c0e95909aec06a (patch)
treea6b2d959fb7d4335209f73b331afdd2b94f1a152 /org.eclipse.jgit.http.server/src/org/eclipse
parentb8d9734c0268446cddac281ec762808ac369538e (diff)
downloadjgit-abedaf0d3854f319d0df839851c0e95909aec06a.tar.gz
jgit-abedaf0d3854f319d0df839851c0e95909aec06a.zip
http: Allow specifying a custom error handler for UploadPack
By abstracting the error handler, this lets a user customize the error handler for UploadPack. A customized error handler can show a custom error message to the clients based on the exception thrown from the hook, create a monitoring system for server errors, or do custom logging. Change-Id: Idd3b87d6bd471fef807c0cf1183e904b2886157e Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>
Diffstat (limited to 'org.eclipse.jgit.http.server/src/org/eclipse')
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitFilter.java15
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java59
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java71
3 files changed, 118 insertions, 27 deletions
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 1c5e7ec598..e9462eeb4c 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
@@ -92,6 +92,8 @@ public class GitFilter extends MetaFilter {
private UploadPackFactory<HttpServletRequest> uploadPackFactory = new DefaultUploadPackFactory();
+ private UploadPackErrorHandler uploadPackErrorHandler;
+
private ReceivePackFactory<HttpServletRequest> receivePackFactory = new DefaultReceivePackFactory();
private final List<Filter> uploadPackFilters = new LinkedList<>();
@@ -150,6 +152,17 @@ public class GitFilter extends MetaFilter {
}
/**
+ * Set a custom error handler for git-upload-pack.
+ *
+ * @param h
+ * A custom error handler for git-upload-pack.
+ */
+ public void setUploadPackErrorHandler(UploadPackErrorHandler h) {
+ assertNotInitialized();
+ this.uploadPackErrorHandler = h;
+ }
+
+ /**
* Add upload-pack filter
*
* @param filter
@@ -212,7 +225,7 @@ public class GitFilter extends MetaFilter {
b = b.through(new UploadPackServlet.Factory(uploadPackFactory));
for (Filter f : uploadPackFilters)
b = b.through(f);
- b.with(new UploadPackServlet());
+ b.with(new UploadPackServlet(uploadPackErrorHandler));
}
if (receivePackFactory != ReceivePackFactory.DISABLED) {
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java
new file mode 100644
index 0000000000..03be0873b0
--- /dev/null
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackErrorHandler.java
@@ -0,0 +1,59 @@
+/*
+ * 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.ServiceMayNotContinueException;
+import org.eclipse.jgit.transport.UploadPack;
+
+/**
+ * Handle git-upload-pack errors.
+ *
+ * <p>
+ * This is an entry point for customizing an error handler for git-upload-pack.
+ * Right before calling {@link UploadPack#uploadWithExceptionPropagation}, JGit
+ * will call this handler if specified through {@link GitFilter}. The
+ * implementation of this handler is responsible for calling
+ * {@link UploadPackRunnable} and handling exceptions for clients.
+ *
+ * <p>
+ * If a custom handler is not specified, JGit will use the default error
+ * handler.
+ *
+ * @since 5.6
+ */
+public interface UploadPackErrorHandler {
+ /**
+ * @param req
+ * The HTTP request
+ * @param rsp
+ * The HTTP response
+ * @param r
+ * A continuation that handles a git-upload-pack request.
+ * @throws IOException
+ */
+ void upload(HttpServletRequest req, HttpServletResponse rsp,
+ UploadPackRunnable r) throws IOException;
+
+ /** Process a git-upload-pack request. */
+ public interface UploadPackRunnable {
+ /**
+ * See {@link UploadPack#uploadWithExceptionPropagation}.
+ *
+ * @throws ServiceMayNotContinueException
+ * @throws IOException
+ */
+ void upload() throws ServiceMayNotContinueException, IOException;
+ }
+}
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 0f4037144a..54561e0cfc 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
@@ -70,7 +70,8 @@ import javax.servlet.ServletResponse;
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.http.server.UploadPackErrorHandler.UploadPackRunnable;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.InternalHttpServerGlue;
import org.eclipse.jgit.transport.PacketLineOut;
@@ -181,53 +182,71 @@ class UploadPackServlet extends HttpServlet {
}
}
+ private final UploadPackErrorHandler handler;
+
+ UploadPackServlet(@Nullable UploadPackErrorHandler handler) {
+ this.handler = handler != null ? handler
+ : this::defaultUploadPackHandler;
+ }
+
/** {@inheritDoc} */
@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;
}
- SmartOutputStream out = new SmartOutputStream(req, rsp, false) {
- @Override
- public void flush() throws IOException {
- doFlush();
- }
- };
+ UploadPackRunnable r = () -> {
+ UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER);
+ @SuppressWarnings("resource")
+ SmartOutputStream out = new SmartOutputStream(req, rsp, false) {
+ @Override
+ public void flush() throws IOException {
+ doFlush();
+ }
+ };
- UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER);
- try {
up.setBiDirectionalPipe(false);
rsp.setContentType(UPLOAD_PACK_RESULT_TYPE);
- up.upload(getInputStream(req), out, null);
- out.close();
-
- } catch (ServiceMayNotContinueException e) {
- if (e.isOutput()) {
+ try {
+ up.upload(getInputStream(req), out, null);
+ out.close();
+ } catch (ServiceMayNotContinueException e) {
+ if (e.isOutput()) {
+ consumeRequestBody(req);
+ out.close();
+ }
+ throw e;
+ } catch (UploadPackInternalServerErrorException e) {
+ // Special case exception, error message was sent to client.
+ log(up.getRepository(), e.getCause());
consumeRequestBody(req);
out.close();
- } else if (!rsp.isCommitted()) {
- rsp.reset();
- sendError(req, rsp, e.getStatusCode(), e.getMessage());
}
- return;
+ };
- } catch (UploadPackInternalServerErrorException e) {
- // Special case exception, error message was sent to client.
- log(up.getRepository(), e.getCause());
- consumeRequestBody(req);
- out.close();
+ handler.upload(req, rsp, r);
+ }
+ 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);
}
- return;
}
}