From dfff04742f371c57f1f014c023ee90585af52ef1 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 13 Mar 2012 11:10:33 -0700 Subject: [PATCH] Enable smart HTTP transport to place EOF at end of pack When fetching over smart HTTP the InputStream that gets fed into a PackParser doesn't really support EOF at the end of the pack. It instead tries to make a new HTTP request, which fails because there is no request body currently buffered by the client. Make EOF work correctly on the end of an HTTP derived InputStream for the pack by denoting no more requests are expected as the higher level code is now consuming the pack (or side-band embedded pack). Smart HTTP support doesn't automatically enqueue execute support onto the end of the UnionInputStream, which allows the UnionInputStream to correctly reflect EOF when the HTTP response is consumed. Change-Id: I975f1ab1c81ab1c1af925716970088bc7b8d6b1a --- .../transport/BasePackFetchConnection.java | 10 ++++++ .../eclipse/jgit/transport/TransportHttp.java | 32 +++++++++++++++---- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java index 4c9c2f6f1..347fd9330 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java @@ -673,6 +673,7 @@ private void markCommon(final RevObject obj, final AckNackResult anr) } private void receivePack(final ProgressMonitor monitor) throws IOException { + onReceivePack(); InputStream input = in; if (sideband) input = new SideBandInputStream(input, monitor, getMessageWriter()); @@ -690,6 +691,15 @@ private void receivePack(final ProgressMonitor monitor) throws IOException { } } + /** + * Notification event delivered just before the pack is received from the + * network. This event can be used by RPC such as {@link TransportHttp} to + * disable its request magic and ensure the pack stream is read correctly. + */ + protected void onReceivePack() { + // By default do nothing for TCP based protocols. + } + private static class CancelledException extends Exception { private static final long serialVersionUID = 1L; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java index b323f2b5a..862d08307 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -687,6 +687,8 @@ void close() { } class SmartHttpFetchConnection extends BasePackFetchConnection { + private Service svc; + SmartHttpFetchConnection(final InputStream advertisement) throws TransportException { super(TransportHttp.this); @@ -701,9 +703,18 @@ class SmartHttpFetchConnection extends BasePackFetchConnection { protected void doFetch(final ProgressMonitor monitor, final Collection want, final Set have) throws TransportException { - final Service svc = new Service(SVC_UPLOAD_PACK); - init(svc.in, svc.out); - super.doFetch(monitor, want, have); + try { + svc = new Service(SVC_UPLOAD_PACK); + init(svc.in, svc.out); + super.doFetch(monitor, want, have); + } finally { + svc = null; + } + } + + @Override + protected void onReceivePack() { + svc.finalRequest = true; } } @@ -756,6 +767,8 @@ class Service { private final HttpExecuteStream execute; + boolean finalRequest; + final UnionInputStream in; final HttpOutputStream out; @@ -784,10 +797,14 @@ void execute() throws IOException { out.close(); if (conn == null) { - // Output hasn't started yet, because everything fit into - // our request buffer. Send with a Content-Length header. - // if (out.length() == 0) { + // Request output hasn't started yet, but more data is being + // requested. If there is no request data buffered and the + // final request was already sent, do nothing to ensure the + // caller is shown EOF on the InputStream; otherwise an + // programming error has occurred within this module. + if (finalRequest) + return; throw new TransportException(uri, JGitText.get().startingReadStageWithoutWrittenRequestDataPendingIsNotSupported); } @@ -833,7 +850,8 @@ void execute() throws IOException { } in.add(openInputStream(conn)); - in.add(execute); + if (!finalRequest) + in.add(execute); conn = null; }