summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.http.server/src
diff options
context:
space:
mode:
authorShawn O. Pearce <spearce@spearce.org>2011-11-30 17:36:32 -0800
committerShawn O. Pearce <spearce@spearce.org>2011-12-01 16:01:13 -0800
commitdb00632db77be8109b7aba2ffc229c354e4ee5a2 (patch)
treea8843eae5a96ef4be578ca66189030e40a005d18 /org.eclipse.jgit.http.server/src
parentac6cda955c6859d57ba1a705ac1c2786a16b8b14 (diff)
downloadjgit-db00632db77be8109b7aba2ffc229c354e4ee5a2.tar.gz
jgit-db00632db77be8109b7aba2ffc229c354e4ee5a2.zip
Discard request HTTP bodies for status code <400
The HTTP RFCs require a server to fully consume the request body before it can return a non-error status code, which is any code below 400. JGit returns most Git level errors inside of an HTTP 200 OK response, and sometimes this happens before the entire request was consumed from the servlet container. In such cases the body must be skipped or read until EOF is reached, ensuring the HTTP keep-alive semantics will work for the next request on the same TCP connection. HTTP status codes >= 400 may be returned without consuming the body, and a servlet container must set "Connection: close" in the response headers when this happens, since the state of the request body is not well defined with an early abort. With the introduction of sendError() in GitSmartHttpTools there are only a handful of locations that need to worry about the request body being consumed, so sprinkle the call in as necessary. Change-Id: I5381e110585f780c01a764df8e27c80aacf5146e
Diffstat (limited to 'org.eclipse.jgit.http.server/src')
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java17
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java2
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ServletUtils.java44
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java3
4 files changed, 59 insertions, 7 deletions
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
index 3d2aff174d..8bd1704bc4 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/GitSmartHttpTools.java
@@ -49,11 +49,11 @@ import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -184,24 +184,27 @@ public class GitSmartHttpTools {
pck.writeString("# service=" + svc + "\n");
pck.end();
pck.writeString("ERR " + textForGit);
- send(res, infoRefsResultType(svc), buf.toByteArray());
+ send(req, res, infoRefsResultType(svc), buf.toByteArray());
} else if (isUploadPack(req)) {
pck.writeString("ERR " + textForGit);
- send(res, UPLOAD_PACK_RESULT_TYPE, buf.toByteArray());
+ send(req, res, UPLOAD_PACK_RESULT_TYPE, buf.toByteArray());
} else if (isReceivePack(req)) {
pck.writeString("ERR " + textForGit);
- send(res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray());
+ send(req, res, RECEIVE_PACK_RESULT_TYPE, buf.toByteArray());
} else {
+ if (httpStatus < 400)
+ ServletUtils.consumeRequestBody(req);
res.sendError(httpStatus);
}
}
- private static void send(HttpServletResponse res, String type, byte[] buf)
- throws IOException {
+ private static void send(HttpServletRequest req, HttpServletResponse res,
+ String type, byte[] buf) throws IOException {
+ ServletUtils.consumeRequestBody(req);
res.setStatus(HttpServletResponse.SC_OK);
res.setContentType(type);
res.setContentLength(buf.length);
- ServletOutputStream os = res.getOutputStream();
+ OutputStream os = res.getOutputStream();
try {
os.write(buf);
} finally {
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 27bee85d82..c84d52b695 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
@@ -52,6 +52,7 @@ import static org.eclipse.jgit.http.server.GitSmartHttpTools.RECEIVE_PACK_REQUES
import static org.eclipse.jgit.http.server.GitSmartHttpTools.RECEIVE_PACK_RESULT_TYPE;
import static org.eclipse.jgit.http.server.GitSmartHttpTools.sendError;
import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER;
+import static org.eclipse.jgit.http.server.ServletUtils.consumeRequestBody;
import static org.eclipse.jgit.http.server.ServletUtils.getInputStream;
import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
@@ -177,6 +178,7 @@ class ReceivePackServlet extends HttpServlet {
getServletContext().log(
HttpServerText.get().internalErrorDuringReceivePack,
e.getCause());
+ consumeRequestBody(req);
out.close();
} catch (Throwable e) {
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 2114655875..91fb8cce9a 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
@@ -119,6 +119,50 @@ public final class ServletUtils {
}
/**
+ * Consume the entire request body, if one was supplied.
+ *
+ * @param req
+ * the request whose body must be consumed.
+ */
+ public static void consumeRequestBody(HttpServletRequest req) {
+ if (0 < req.getContentLength() || isChunked(req)) {
+ try {
+ consumeRequestBody(req.getInputStream());
+ } catch (IOException e) {
+ // Ignore any errors obtaining the input stream.
+ }
+ }
+ }
+
+ private static boolean isChunked(HttpServletRequest req) {
+ return "chunked".equals(req.getHeader("Transfer-Encoding"));
+ }
+
+ /**
+ * Consume the rest of the input stream and discard it.
+ *
+ * @param in
+ * the stream to discard, closed if not null.
+ */
+ public static void consumeRequestBody(InputStream in) {
+ if (in == null)
+ return;
+ try {
+ while (0 < in.skip(2048) || 0 <= in.read()) {
+ // Discard until EOF.
+ }
+ } catch (IOException err) {
+ // Discard IOException during read or skip.
+ } finally {
+ try {
+ in.close();
+ } catch (IOException err) {
+ // Discard IOException during close of input stream.
+ }
+ }
+ }
+
+ /**
* Send a plain text response to a {@code GET} or {@code HEAD} HTTP request.
* <p>
* The text response is encoded in the Git character encoding, UTF-8.
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 33bfff6d47..15ef2c7eac 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
@@ -52,6 +52,7 @@ import static org.eclipse.jgit.http.server.GitSmartHttpTools.UPLOAD_PACK_REQUEST
import static org.eclipse.jgit.http.server.GitSmartHttpTools.UPLOAD_PACK_RESULT_TYPE;
import static org.eclipse.jgit.http.server.GitSmartHttpTools.sendError;
import static org.eclipse.jgit.http.server.ServletUtils.ATTRIBUTE_HANDLER;
+import static org.eclipse.jgit.http.server.ServletUtils.consumeRequestBody;
import static org.eclipse.jgit.http.server.ServletUtils.getInputStream;
import static org.eclipse.jgit.http.server.ServletUtils.getRepository;
@@ -177,6 +178,7 @@ class UploadPackServlet extends HttpServlet {
} catch (UploadPackMayNotContinueException e) {
if (e.isOutput()) {
+ consumeRequestBody(req);
out.close();
} else if (!rsp.isCommitted()) {
rsp.reset();
@@ -189,6 +191,7 @@ class UploadPackServlet extends HttpServlet {
getServletContext().log(
HttpServerText.get().internalErrorDuringUploadPack,
e.getCause());
+ consumeRequestBody(req);
out.close();
} catch (Throwable e) {