Browse Source

FileLfsServlet: Include error message in response body

According to the specification [1], the error response body must
include the error message in json format.

[1] https://github.com/github/git-lfs/blob/master/docs/api/v1/http-v1-batch.md#response-errors

Change-Id: I79e7a841d230fdedefa53b9c6d2d477e81e1f9e6
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
tags/v4.5.0.201609210915-r
David Pursehouse 7 years ago
parent
commit
e27eab26e2

+ 17
- 10
org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/DownloadTest.java View File

public void testDownloadInvalidPathInfo() public void testDownloadInvalidPathInfo()
throws ClientProtocolException, IOException { throws ClientProtocolException, IOException {
String TEXT = "test"; String TEXT = "test";
AnyLongObjectId id = putContent(TEXT);
String id = putContent(TEXT).name().substring(0, 60);
Path f = Paths.get(getTempDirectory().toString(), "download"); Path f = Paths.get(getTempDirectory().toString(), "download");
try { try {
getContent(id.name().substring(0, 60), f);
getContent(id, f);
fail("expected RuntimeException"); fail("expected RuntimeException");
} catch (RuntimeException e) { } catch (RuntimeException e) {
assertEquals("Status: 422 Unprocessable Entity",
e.getMessage());
String error = String.format(
"Invalid pathInfo '/%s' does not match '/{SHA-256}'", id);
assertEquals(formatErrorMessage(422, error), e.getMessage());
} }
} }


public void testDownloadInvalidId() public void testDownloadInvalidId()
throws ClientProtocolException, IOException { throws ClientProtocolException, IOException {
String TEXT = "test"; String TEXT = "test";
AnyLongObjectId id = putContent(TEXT);
String id = putContent(TEXT).name().replace('f', 'z');
Path f = Paths.get(getTempDirectory().toString(), "download"); Path f = Paths.get(getTempDirectory().toString(), "download");
try { try {
getContent(id.name().replace('f', 'z'), f);
getContent(id, f);
fail("expected RuntimeException"); fail("expected RuntimeException");
} catch (RuntimeException e) { } catch (RuntimeException e) {
assertEquals("Status: 422 Unprocessable Entity",
e.getMessage());
String error = String.format("Invalid id: : %s", id);
assertEquals(formatErrorMessage(422, error), e.getMessage());
} }
} }


getContent(id, f); getContent(id, f);
fail("expected RuntimeException"); fail("expected RuntimeException");
} catch (RuntimeException e) { } catch (RuntimeException e) {
assertEquals("Status: 404 Not Found",
e.getMessage());
String error = String.format("Object '%s' not found", id.getName());
assertEquals(formatErrorMessage(404, error), e.getMessage());
} }
} }


FileUtils.delete(f.toFile(), FileUtils.RETRY); FileUtils.delete(f.toFile(), FileUtils.RETRY);


} }

@SuppressWarnings("boxing")
private String formatErrorMessage(int status, String message) {
return String.format("Status: %d {\n \"message\": \"%s\"\n}", status,
message);
}
} }

+ 16
- 2
org.eclipse.jgit.lfs.server.test/tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java View File

import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;


import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
StatusLine statusLine = response.getStatusLine(); StatusLine statusLine = response.getStatusLine();
int status = statusLine.getStatusCode(); int status = statusLine.getStatusCode();
if (statusLine.getStatusCode() >= 400) { if (statusLine.getStatusCode() >= 400) {
throw new RuntimeException("Status: " + status + " "
+ statusLine.getReasonPhrase());
String error;
try {
BufferedInputStream bis = new BufferedInputStream(
response.getEntity().getContent());
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int result = bis.read();
while (result != -1) {
buf.write((byte) result);
result = bis.read();
}
error = buf.toString();
} catch (IOException e) {
error = statusLine.getReasonPhrase();
}
throw new RuntimeException("Status: " + status + " " + error);
} }
assertEquals(200, status); assertEquals(200, status);
} }

+ 29
- 3
org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsServlet.java View File

package org.eclipse.jgit.lfs.server.fs; package org.eclipse.jgit.lfs.server.fs;


import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter;
import java.text.MessageFormat; import java.text.MessageFormat;


import javax.servlet.AsyncContext; import javax.servlet.AsyncContext;
import org.eclipse.jgit.lfs.lib.LongObjectId; import org.eclipse.jgit.lfs.lib.LongObjectId;
import org.eclipse.jgit.lfs.server.internal.LfsServerText; import org.eclipse.jgit.lfs.server.internal.LfsServerText;


import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/** /**
* Servlet supporting upload and download of large objects as defined by the * Servlet supporting upload and download of large objects as defined by the
* GitHub Large File Storage extension API extending git to allow separate * GitHub Large File Storage extension API extending git to allow separate


private final long timeout; private final long timeout;


private static Gson gson = createGson();

/** /**
* @param repository * @param repository
* the repository storing the large objects * the repository storing the large objects
if (obj != null) { if (obj != null) {
if (repository.getSize(obj) == -1) { if (repository.getSize(obj) == -1) {
sendError(rsp, HttpStatus.SC_NOT_FOUND, MessageFormat sendError(rsp, HttpStatus.SC_NOT_FOUND, MessageFormat
.format(LfsServerText.get().objectNotFound, obj));
.format(LfsServerText.get().objectNotFound,
obj.getName()));
return; return;
} }
AsyncContext context = req.startAsync(); AsyncContext context = req.startAsync();
} }
} }


static class Error {
String message;

Error(String m) {
this.message = m;
}
}

static void sendError(HttpServletResponse rsp, int status, String message) static void sendError(HttpServletResponse rsp, int status, String message)
throws IOException { throws IOException {
rsp.setStatus(status); rsp.setStatus(status);
// TODO return message in response body in json format as specified in
// https://github.com/github/git-lfs/blob/master/docs/api/v1/http-v1-batch.md
PrintWriter writer = rsp.getWriter();
gson.toJson(new Error(message), writer);
writer.flush();
writer.close();
rsp.flushBuffer(); rsp.flushBuffer();
} }

private static Gson createGson() {
GsonBuilder gb = new GsonBuilder()
.setFieldNamingPolicy(
FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting().disableHtmlEscaping();
return gb.create();
}
} }

Loading…
Cancel
Save