Merge branch 'stable-4.10' into stable-4.11

* stable-4.10:
  Fix ObjectUploadListener#close
  Fix error handling in FileLfsServlet
  ObjectDownloadListener#onWritePossible: Make code spec compatible
  ObjectDownloadListener: Return from onWritePossible when data is written
  Fix IOException when LockToken#close fails

Change-Id: I28ebf6138ccd9425fc05319de78c7716f0bdd199
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
index 36dc760..c86e15b 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java
@@ -177,6 +177,11 @@
 	 */
 	protected static void sendError(HttpServletResponse rsp, int status, String message)
 			throws IOException {
+		if (rsp.isCommitted()) {
+			rsp.getOutputStream().close();
+			return;
+		}
+		rsp.reset();
 		rsp.setStatus(status);
 		try (PrintWriter writer = rsp.getWriter()) {
 			LfsGson.toJson(message, writer);
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
index ec1d3cd..ef35912 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectDownloadListener.java
@@ -80,7 +80,7 @@
 
 	private final WritableByteChannel outChannel;
 
-	private final ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
+	private ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
 
 	/**
 	 * <p>Constructor for ObjectDownloadListener.</p>
@@ -117,19 +117,26 @@
 	@Override
 	public void onWritePossible() throws IOException {
 		while (out.isReady()) {
-			if (in.read(buffer) != -1) {
-				buffer.flip();
-				outChannel.write(buffer);
-				buffer.compact();
-			} else {
-				in.close();
-				buffer.flip();
-				while (out.isReady()) {
-					if (buffer.hasRemaining()) {
-						outChannel.write(buffer);
-					} else {
+			try {
+				buffer.clear();
+				if (in.read(buffer) < 0) {
+					buffer = null;
+				} else {
+					buffer.flip();
+				}
+			} catch(Throwable t) {
+				LOG.log(Level.SEVERE, t.getMessage(), t);
+				buffer = null;
+			} finally {
+				if (buffer != null) {
+					outChannel.write(buffer);
+				} else {
+					try {
+						out.close();
+					} finally {
 						context.complete();
 					}
+					return;
 				}
 			}
 		}
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
index e4c04c1..c5b6a67 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/ObjectUploadListener.java
@@ -156,7 +156,9 @@
 			channel.close();
 			// TODO check if status 200 is ok for PUT request, HTTP foresees 204
 			// for successful PUT without response body
-			response.setStatus(HttpServletResponse.SC_OK);
+			if (!response.isCommitted()) {
+				response.setStatus(HttpServletResponse.SC_OK);
+			}
 		} finally {
 			context.complete();
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index e7126f2..56f7acb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -902,13 +902,18 @@
 
 		@Override
 		public void close() {
-			if (link.isPresent()) {
-				try {
-					Files.delete(link.get());
-				} catch (IOException e) {
-					LOG.error(MessageFormat.format(JGitText.get().closeLockTokenFailed,
-							this), e);
-				}
+			if (!link.isPresent()) {
+				return;
+			}
+			Path p = link.get();
+			if (!Files.exists(p)) {
+				return;
+			}
+			try {
+				Files.delete(p);
+			} catch (IOException e) {
+				LOG.error(MessageFormat
+						.format(JGitText.get().closeLockTokenFailed, this), e);
 			}
 		}