Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce2011-03-15 21:00:43 +0000
committerShawn O. Pearce2011-04-01 21:40:33 +0000
commitaf3562f7f70a9017f6f90d266f2b2a6fc3b361ad (patch)
tree68762a6733c2e3053b1e4b4fdcf0af96c4cc2a5c /org.eclipse.jgit.http.server
parent8ac65d33ed7a94f77cb066271669feebf9b882fc (diff)
downloadjgit-af3562f7f70a9017f6f90d266f2b2a6fc3b361ad.tar.gz
jgit-af3562f7f70a9017f6f90d266f2b2a6fc3b361ad.tar.xz
jgit-af3562f7f70a9017f6f90d266f2b2a6fc3b361ad.zip
Allow application filters on smart HTTP operations
Permit applications embedding GitServlet to wrap the info/refs?service=$name and /$name operations with a servlet Filter. To help applications inspect state of the operation, expose the UploadPack or ReceivePack object into a request attribute. This can be useful for logging, or to implement throttling of requests like Gerrit Code Review uses to prevent server overload. Change-Id: Ib8773c14e2b7a650769bd578aad745e6651210cb Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Diffstat (limited to 'org.eclipse.jgit.http.server')
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java53
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java81
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java3
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java71
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java84
5 files changed, 228 insertions, 64 deletions
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java
index 9be5fa7e9f..caa84e46ba 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitServlet.java
@@ -45,7 +45,10 @@ package org.eclipse.jgit.http.server;
import java.io.File;
import java.text.MessageFormat;
+import java.util.LinkedList;
+import java.util.List;
+import javax.servlet.Filter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -55,9 +58,9 @@ import org.eclipse.jgit.http.server.glue.ErrorServlet;
import org.eclipse.jgit.http.server.glue.MetaServlet;
import org.eclipse.jgit.http.server.glue.RegexGroupFilter;
import org.eclipse.jgit.http.server.glue.ServletBinder;
+import org.eclipse.jgit.http.server.resolver.AsIsFileService;
import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory;
import org.eclipse.jgit.http.server.resolver.DefaultUploadPackFactory;
-import org.eclipse.jgit.http.server.resolver.AsIsFileService;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.UploadPack;
@@ -114,6 +117,10 @@ public class GitServlet extends MetaServlet {
private ReceivePackFactory<HttpServletRequest> receivePackFactory = new DefaultReceivePackFactory();
+ private final List<Filter> uploadPackFilters = new LinkedList<Filter>();
+
+ private final List<Filter> receivePackFilters = new LinkedList<Filter>();
+
/**
* New servlet that will load its base directory from {@code web.xml}.
* <p>
@@ -161,6 +168,17 @@ public class GitServlet extends MetaServlet {
}
/**
+ * @param filter
+ * filter to apply before any of the UploadPack operations. The
+ * UploadPack instance is available in the request attribute
+ * {@link ServletUtils#ATTRIBUTE_HANDLER}.
+ */
+ public void addUploadPackFilter(Filter filter) {
+ assertNotInitialized();
+ uploadPackFilters.add(filter);
+ }
+
+ /**
* @param f
* the factory to construct and configure a {@link ReceivePack}
* session when a push is requested by a client.
@@ -171,6 +189,17 @@ public class GitServlet extends MetaServlet {
this.receivePackFactory = f != null ? f : (ReceivePackFactory<HttpServletRequest>)ReceivePackFactory.DISABLED;
}
+ /**
+ * @param filter
+ * filter to apply before any of the ReceivePack operations. The
+ * ReceivePack instance is available in the request attribute
+ * {@link ServletUtils#ATTRIBUTE_HANDLER}.
+ */
+ public void addReceivePackFilter(Filter filter) {
+ assertNotInitialized();
+ receivePackFilters.add(filter);
+ }
+
private void assertNotInitialized() {
if (initialized)
throw new IllegalStateException(HttpServerText.get().alreadyInitializedByContainer);
@@ -189,23 +218,29 @@ public class GitServlet extends MetaServlet {
initialized = true;
if (uploadPackFactory != UploadPackFactory.DISABLED) {
- serve("*/git-upload-pack")//
- .with(new UploadPackServlet(uploadPackFactory));
+ ServletBinder b = serve("*/git-upload-pack");
+ b = b.through(new UploadPackServlet.Factory(uploadPackFactory));
+ for (Filter f : uploadPackFilters)
+ b = b.through(f);
+ b.with(new UploadPackServlet());
}
if (receivePackFactory != ReceivePackFactory.DISABLED) {
- serve("*/git-receive-pack")//
- .with(new ReceivePackServlet(receivePackFactory));
+ ServletBinder b = serve("*/git-receive-pack");
+ b = b.through(new ReceivePackServlet.Factory(receivePackFactory));
+ for (Filter f : receivePackFilters)
+ b = b.through(f);
+ b.with(new ReceivePackServlet());
}
ServletBinder refs = serve("*/" + Constants.INFO_REFS);
if (uploadPackFactory != UploadPackFactory.DISABLED) {
- refs = refs.through(//
- new UploadPackServlet.InfoRefs(uploadPackFactory));
+ refs = refs.through(new UploadPackServlet.InfoRefs(
+ uploadPackFactory, uploadPackFilters));
}
if (receivePackFactory != ReceivePackFactory.DISABLED) {
- refs = refs.through(//
- new ReceivePackServlet.InfoRefs(receivePackFactory));
+ refs = refs.through(new ReceivePackServlet.InfoRefs(
+ receivePackFactory, receivePackFilters));
}
if (asIs != AsIsFileService.DISABLED) {
refs = refs.through(new IsLocalFilter());
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 bb4ae19e78..69b5aec25e 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
@@ -47,11 +47,19 @@ 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.ServletUtils.ATTRIBUTE_HANDLER;
import static org.eclipse.jgit.http.server.ServletUtils.getInputStream;
import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
import java.io.IOException;
-
+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;
@@ -72,18 +80,27 @@ class ReceivePackServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
static class InfoRefs extends SmartServiceInfoRefs {
- private final ReceivePackFactory receivePackFactory;
+ private final ReceivePackFactory<HttpServletRequest> receivePackFactory;
- InfoRefs(final ReceivePackFactory receivePackFactory) {
- super("git-receive-pack");
+ InfoRefs(ReceivePackFactory<HttpServletRequest> receivePackFactory,
+ List<Filter> filters) {
+ super("git-receive-pack", filters);
this.receivePackFactory = receivePackFactory;
}
@Override
- protected void advertise(HttpServletRequest req, Repository db,
+ protected void begin(HttpServletRequest req, Repository db)
+ throws IOException, ServiceNotEnabledException,
+ ServiceNotAuthorizedException {
+ ReceivePack rp = receivePackFactory.create(req, db);
+ req.setAttribute(ATTRIBUTE_HANDLER, rp);
+ }
+
+ @Override
+ protected void advertise(HttpServletRequest req,
PacketLineOutRefAdvertiser pck) throws IOException,
ServiceNotEnabledException, ServiceNotAuthorizedException {
- ReceivePack rp = receivePackFactory.create(req, db);
+ ReceivePack rp = (ReceivePack) req.getAttribute(ATTRIBUTE_HANDLER);
try {
rp.sendAdvertisedRefs(pck);
} finally {
@@ -92,10 +109,44 @@ class ReceivePackServlet extends HttpServlet {
}
}
- private final ReceivePackFactory receivePackFactory;
+ static class Factory implements Filter {
+ private final ReceivePackFactory<HttpServletRequest> receivePackFactory;
- ReceivePackServlet(final ReceivePackFactory receivePackFactory) {
- this.receivePackFactory = receivePackFactory;
+ Factory(ReceivePackFactory<HttpServletRequest> receivePackFactory) {
+ this.receivePackFactory = receivePackFactory;
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse rsp = (HttpServletResponse) response;
+ ReceivePack rp;
+ try {
+ rp = receivePackFactory.create(req, getRepository(req));
+ } catch (ServiceNotAuthorizedException e) {
+ rsp.sendError(SC_UNAUTHORIZED);
+ return;
+
+ } catch (ServiceNotEnabledException e) {
+ rsp.sendError(SC_FORBIDDEN);
+ return;
+ }
+
+ try {
+ req.setAttribute(ATTRIBUTE_HANDLER, rp);
+ chain.doFilter(req, rsp);
+ } finally {
+ req.removeAttribute(ATTRIBUTE_HANDLER);
+ }
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // Nothing.
+ }
+
+ public void destroy() {
+ // Nothing.
+ }
}
@Override
@@ -106,9 +157,8 @@ class ReceivePackServlet extends HttpServlet {
return;
}
- final Repository db = getRepository(req);
+ ReceivePack rp = (ReceivePack) req.getAttribute(ATTRIBUTE_HANDLER);
try {
- final ReceivePack rp = receivePackFactory.create(req, db);
rp.setBiDirectionalPipe(false);
rsp.setContentType(RSP_TYPE);
@@ -120,15 +170,6 @@ class ReceivePackServlet extends HttpServlet {
};
rp.receive(getInputStream(req), out, null);
out.close();
-
- } catch (ServiceNotAuthorizedException e) {
- rsp.sendError(SC_UNAUTHORIZED);
- return;
-
- } catch (ServiceNotEnabledException e) {
- rsp.sendError(SC_FORBIDDEN);
- return;
-
} catch (IOException e) {
getServletContext().log(HttpServerText.get().internalErrorDuringReceivePack, e);
rsp.sendError(SC_INTERNAL_SERVER_ERROR);
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
index 4e47c95ad0..2114655875 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java
@@ -71,6 +71,9 @@ public final class ServletUtils {
/** Request attribute which stores the {@link Repository} instance. */
public static final String ATTRIBUTE_REPOSITORY = "org.eclipse.jgit.Repository";
+ /** Request attribute storing either UploadPack or ReceivePack. */
+ public static final String ATTRIBUTE_HANDLER = "org.eclipse.jgit.transport.UploadPackOrReceivePack";
+
/**
* Get the selected repository from the request.
*
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
index f9be95f04e..7152c88ed5 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartServiceInfoRefs.java
@@ -45,9 +45,11 @@ package org.eclipse.jgit.http.server;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER;
import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
import java.io.IOException;
+import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@@ -68,8 +70,11 @@ import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
abstract class SmartServiceInfoRefs implements Filter {
private final String svc;
- SmartServiceInfoRefs(final String service) {
+ private final Filter[] filters;
+
+ SmartServiceInfoRefs(final String service, final List<Filter> filters) {
this.svc = service;
+ this.filters = filters.toArray(new Filter[filters.size()]);
}
public void init(FilterConfig config) throws ServletException {
@@ -83,31 +88,71 @@ abstract class SmartServiceInfoRefs implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
final HttpServletRequest req = (HttpServletRequest) request;
+ final HttpServletResponse rsp = (HttpServletResponse) response;
if (svc.equals(req.getParameter("service"))) {
- final HttpServletResponse rsp = (HttpServletResponse) response;
+ final Repository db = getRepository(req);
try {
- final Repository db = getRepository(req);
- rsp.setContentType("application/x-" + svc + "-advertisement");
-
- final SmartOutputStream buf = new SmartOutputStream(req, rsp);
- final PacketLineOut out = new PacketLineOut(buf);
- out.writeString("# service=" + svc + "\n");
- out.end();
- advertise(req, db, new PacketLineOutRefAdvertiser(out));
- buf.close();
+ begin(req, db);
} catch (ServiceNotAuthorizedException e) {
rsp.sendError(SC_UNAUTHORIZED);
-
+ return;
} catch (ServiceNotEnabledException e) {
rsp.sendError(SC_FORBIDDEN);
+ return;
+ }
+
+ try {
+ if (filters.length == 0)
+ service(req, response);
+ else
+ new Chain().doFilter(request, response);
+ } finally {
+ req.removeAttribute(ATTRIBUTE_HANDLER);
}
} else {
chain.doFilter(request, response);
}
}
- protected abstract void advertise(HttpServletRequest req, Repository db,
+ private void service(ServletRequest request, ServletResponse response)
+ throws IOException {
+ final HttpServletRequest req = (HttpServletRequest) request;
+ final HttpServletResponse rsp = (HttpServletResponse) response;
+ try {
+ rsp.setContentType("application/x-" + svc + "-advertisement");
+
+ final SmartOutputStream buf = new SmartOutputStream(req, rsp);
+ final PacketLineOut out = new PacketLineOut(buf);
+ out.writeString("# service=" + svc + "\n");
+ out.end();
+ advertise(req, new PacketLineOutRefAdvertiser(out));
+ buf.close();
+ } catch (ServiceNotAuthorizedException e) {
+ rsp.sendError(SC_UNAUTHORIZED);
+
+ } catch (ServiceNotEnabledException e) {
+ rsp.sendError(SC_FORBIDDEN);
+ }
+ }
+
+ protected abstract void begin(HttpServletRequest req, Repository db)
+ throws IOException, ServiceNotEnabledException,
+ ServiceNotAuthorizedException;
+
+ protected abstract void advertise(HttpServletRequest req,
PacketLineOutRefAdvertiser pck) throws IOException,
ServiceNotEnabledException, ServiceNotAuthorizedException;
+
+ private class Chain implements FilterChain {
+ private int filterIdx;
+
+ public void doFilter(ServletRequest req, ServletResponse rsp)
+ throws IOException, ServletException {
+ if (filterIdx < filters.length)
+ filters[filterIdx++].doFilter(req, rsp, this);
+ else
+ service(req, rsp);
+ }
+ }
}
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 ff5e5d53c8..192adc56b4 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
@@ -47,18 +47,26 @@ 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.ServletUtils.ATTRIBUTE_HANDLER;
import static org.eclipse.jgit.http.server.ServletUtils.getInputStream;
import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
import java.io.IOException;
-
+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 org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.UploadPack;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
+import org.eclipse.jgit.transport.UploadPack;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.transport.resolver.UploadPackFactory;
@@ -72,18 +80,27 @@ class UploadPackServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
static class InfoRefs extends SmartServiceInfoRefs {
- private final UploadPackFactory uploadPackFactory;
+ private final UploadPackFactory<HttpServletRequest> uploadPackFactory;
- InfoRefs(final UploadPackFactory uploadPackFactory) {
- super("git-upload-pack");
+ InfoRefs(UploadPackFactory<HttpServletRequest> uploadPackFactory,
+ List<Filter> filters) {
+ super("git-upload-pack", filters);
this.uploadPackFactory = uploadPackFactory;
}
@Override
- protected void advertise(HttpServletRequest req, Repository db,
+ protected void begin(HttpServletRequest req, Repository db)
+ throws IOException, ServiceNotEnabledException,
+ ServiceNotAuthorizedException {
+ UploadPack up = uploadPackFactory.create(req, db);
+ req.setAttribute(ATTRIBUTE_HANDLER, up);
+ }
+
+ @Override
+ protected void advertise(HttpServletRequest req,
PacketLineOutRefAdvertiser pck) throws IOException,
ServiceNotEnabledException, ServiceNotAuthorizedException {
- UploadPack up = uploadPackFactory.create(req, db);
+ UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER);
try {
up.sendAdvertisedRefs(pck);
} finally {
@@ -92,10 +109,44 @@ class UploadPackServlet extends HttpServlet {
}
}
- private final UploadPackFactory uploadPackFactory;
+ static class Factory implements Filter {
+ private final UploadPackFactory<HttpServletRequest> uploadPackFactory;
+
+ Factory(UploadPackFactory<HttpServletRequest> uploadPackFactory) {
+ this.uploadPackFactory = uploadPackFactory;
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse rsp = (HttpServletResponse) response;
+ UploadPack rp;
+ try {
+ rp = uploadPackFactory.create(req, getRepository(req));
+ } catch (ServiceNotAuthorizedException e) {
+ rsp.sendError(SC_UNAUTHORIZED);
+ return;
+
+ } catch (ServiceNotEnabledException e) {
+ rsp.sendError(SC_FORBIDDEN);
+ return;
+ }
+
+ try {
+ req.setAttribute(ATTRIBUTE_HANDLER, rp);
+ chain.doFilter(req, rsp);
+ } finally {
+ req.removeAttribute(ATTRIBUTE_HANDLER);
+ }
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // Nothing.
+ }
- UploadPackServlet(final UploadPackFactory uploadPackFactory) {
- this.uploadPackFactory = uploadPackFactory;
+ public void destroy() {
+ // Nothing.
+ }
}
@Override
@@ -106,9 +157,8 @@ class UploadPackServlet extends HttpServlet {
return;
}
- final Repository db = getRepository(req);
+ UploadPack up = (UploadPack) req.getAttribute(ATTRIBUTE_HANDLER);
try {
- final UploadPack up = uploadPackFactory.create(req, db);
up.setBiDirectionalPipe(false);
rsp.setContentType(RSP_TYPE);
@@ -121,16 +171,6 @@ class UploadPackServlet extends HttpServlet {
up.upload(getInputStream(req), out, null);
out.close();
- } catch (ServiceNotAuthorizedException e) {
- rsp.reset();
- rsp.sendError(SC_UNAUTHORIZED);
- return;
-
- } catch (ServiceNotEnabledException e) {
- rsp.reset();
- rsp.sendError(SC_FORBIDDEN);
- return;
-
} catch (IOException e) {
getServletContext().log(HttpServerText.get().internalErrorDuringUploadPack, e);
rsp.reset();

Back to the top