From f93a6a72290d475d080b1e76de58a21934422e90 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 19 Sep 2012 17:33:07 -0700 Subject: [PATCH 1/2] Compress large /info/refs responses on HTTP Enable streaming compression for any response that is bigger than the 32 KiB buffer used by SmartOutputStream. This is useful on the info/refs file which can have many branches and tags listed, and is often bigger than 32 KiB, but also compresses by at least 50%. Disable streaming compression on large git-upload-pack responses, as these are usually highly compressed Git pack data. Trying to compress these with gzip will only waste CPU time and additional transfer space with the gzip wrapper. Small git-upload-pack data is usually text based negotiation responses and can be squeezed smaller with a little bit of CPU usage. Change-Id: Ia13e63ed334f594d5e1ab53a97240eb2e8f550e2 --- .../eclipse/jgit/http/server/InfoRefsServlet.java | 3 ++- .../jgit/http/server/ReceivePackServlet.java | 2 +- .../jgit/http/server/SmartOutputStream.java | 15 +++++++++++---- .../jgit/http/server/SmartServiceInfoRefs.java | 2 +- .../jgit/http/server/UploadPackServlet.java | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java index ffaa13153..52f928548 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/InfoRefsServlet.java @@ -72,7 +72,8 @@ class InfoRefsServlet extends HttpServlet { final Repository db = getRepository(req); final OutputStreamWriter out = new OutputStreamWriter( - new SmartOutputStream(req, rsp), Constants.CHARSET); + new SmartOutputStream(req, rsp, true), + Constants.CHARSET); final RefAdvertiser adv = new RefAdvertiser() { @Override protected void writeOne(final CharSequence line) throws 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 10cadd7bb..3d6c35b0b 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 @@ -171,7 +171,7 @@ class ReceivePackServlet extends HttpServlet { return; } - SmartOutputStream out = new SmartOutputStream(req, rsp) { + SmartOutputStream out = new SmartOutputStream(req, rsp, true) { @Override public void flush() throws IOException { doFlush(); diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartOutputStream.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartOutputStream.java index c39b78900..145c63bca 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartOutputStream.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/SmartOutputStream.java @@ -70,22 +70,29 @@ class SmartOutputStream extends TemporaryBuffer { private static final int LIMIT = 32 * 1024; private final HttpServletRequest req; - private final HttpServletResponse rsp; - + private boolean compressStream; private boolean startedOutput; SmartOutputStream(final HttpServletRequest req, - final HttpServletResponse rsp) { + final HttpServletResponse rsp, + boolean compressStream) { super(LIMIT); this.req = req; this.rsp = rsp; + this.compressStream = compressStream; } @Override protected OutputStream overflow() throws IOException { startedOutput = true; - return rsp.getOutputStream(); + + OutputStream out = rsp.getOutputStream(); + if (compressStream && acceptsGzipEncoding(req)) { + rsp.setHeader(HDR_CONTENT_ENCODING, ENCODING_GZIP); + out = new GZIPOutputStream(out); + } + return out; } public void close() throws IOException { 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 907b328db..481075377 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 @@ -122,7 +122,7 @@ abstract class SmartServiceInfoRefs implements Filter { throws IOException { final HttpServletRequest req = (HttpServletRequest) request; final HttpServletResponse res = (HttpServletResponse) response; - final SmartOutputStream buf = new SmartOutputStream(req, res); + final SmartOutputStream buf = new SmartOutputStream(req, res, true); try { res.setContentType(infoRefsResultType(svc)); 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 046db4576..c5272b55e 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 @@ -172,7 +172,7 @@ class UploadPackServlet extends HttpServlet { return; } - SmartOutputStream out = new SmartOutputStream(req, rsp) { + SmartOutputStream out = new SmartOutputStream(req, rsp, false) { @Override public void flush() throws IOException { doFlush(); From b3e8f29fe9f578e11ad322c94a4bd2dd6cfb6eb0 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 19 Sep 2012 19:19:20 -0700 Subject: [PATCH 2/2] Use '406 Not Acceptable' when info/refs is disabled Instead of a confusing 403 Forbidden error indicating the dumb file service is disabled on this server, use 406 Not Acceptable to mean the client sent a request for content (the plain info/refs file) that this server does not want to provide. The stock C Git client will report HTTP 406 error if it predates 1.6.6 or something goes wrong with the smart request and it tried falling back to the dumb request. This may help to debug cases where a broken proxy server exists between the client and the server and has mangled a prior smart info/refs response. Change-Id: Ic2b78ba9502e4bbdff7cc3ba1fd284cf7616412b --- .../src/org/eclipse/jgit/http/server/GitFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 980d246d2..529b8391f 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 @@ -225,7 +225,7 @@ public class GitFilter extends MetaFilter { refs = refs.through(new AsIsFileFilter(asIs)); refs.with(new InfoRefsServlet()); } else - refs.with(new ErrorServlet(HttpServletResponse.SC_FORBIDDEN)); + refs.with(new ErrorServlet(HttpServletResponse.SC_NOT_ACCEPTABLE)); if (asIs != AsIsFileService.DISABLED) { final IsLocalFilter mustBeLocal = new IsLocalFilter();