diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java index 2c4577603..6d5eec1df 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java @@ -77,6 +77,17 @@ interface MailboxApi { List getFiles(MailboxProperties properties, String folderId) throws IOException, ApiException; + /** + * Used by owner and contacts to retrieve a file. + *

+ * Returns 200 OK if successful with the files' raw bytes + * in the response body. + * + * @param file the empty file the response bytes will be written into. + */ + void getFile(MailboxProperties properties, String folderId, + String fileId, File file) throws IOException, ApiException; + @Immutable @JsonSerialize class MailboxContact { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java index 83efd7ed5..751600ad4 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiImpl.java @@ -11,6 +11,7 @@ import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -28,6 +29,7 @@ import okhttp3.ResponseBody; import static com.fasterxml.jackson.databind.MapperFeature.BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES; import static java.util.Objects.requireNonNull; import static okhttp3.internal.Util.EMPTY_REQUEST; +import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.bramble.util.StringUtils.fromHexString; @NotNullByDefault @@ -206,6 +208,19 @@ class MailboxApiImpl implements MailboxApi { } } + @Override + public void getFile(MailboxProperties properties, String folderId, + String fileId, File file) throws IOException, ApiException { + String path = "/files/" + folderId + "/" + fileId; + Response response = sendGetRequest(properties, path); + if (response.code() != 200) throw new ApiException(); + + ResponseBody body = response.body(); + if (body == null) throw new ApiException(); + FileOutputStream outputStream = new FileOutputStream(file); + copyAndClose(body.byteStream(), outputStream); + } + /* Helper Functions */ private Response sendGetRequest(MailboxProperties properties, String path) diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiTest.java index 87707df7f..4c0c53b44 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiTest.java @@ -25,12 +25,14 @@ import okhttp3.OkHttpClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; +import okio.Buffer; import static java.util.Collections.singletonList; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.briarproject.bramble.test.TestUtils.getContactId; import static org.briarproject.bramble.test.TestUtils.getMailboxSecret; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; +import static org.briarproject.bramble.test.TestUtils.readBytes; import static org.briarproject.bramble.test.TestUtils.writeBytes; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.junit.Assert.assertArrayEquals; @@ -533,6 +535,53 @@ public class MailboxApiTest extends BrambleTestCase { assertToken(request9, token); } + @Test + public void testGetFile() throws Exception { + String name = getMailboxSecret(); + File file1 = folder.newFile(); + File file2 = folder.newFile(); + File file3 = folder.newFile(); + byte[] bytes = getRandomBytes(1337); + + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setBody(new Buffer().write(bytes))); + server.enqueue(new MockResponse().setResponseCode(401)); + server.enqueue(new MockResponse().setResponseCode(500)); + server.start(); + String baseUrl = getBaseUrl(server); + MailboxProperties properties = + new MailboxProperties(baseUrl, token, true); + + // file gets downloaded as expected + api.getFile(properties, contactOutboxId, name, file1); + RecordedRequest request1 = server.takeRequest(); + assertEquals("/files/" + contactOutboxId + "/" + name, + request1.getPath()); + assertEquals("GET", request1.getMethod()); + assertToken(request1, token); + assertArrayEquals(bytes, readBytes(file1)); + + // request is not successful + assertThrows(ApiException.class, () -> + api.getFile(properties, contactOutboxId, name, file2)); + RecordedRequest request2 = server.takeRequest(); + assertEquals("/files/" + contactOutboxId + "/" + name, + request2.getPath()); + assertEquals("GET", request1.getMethod()); + assertToken(request2, token); + assertEquals(0, readBytes(file2).length); + + // server error + assertThrows(ApiException.class, () -> + api.getFile(properties, contactOutboxId, name, file3)); + RecordedRequest request3 = server.takeRequest(); + assertEquals("/files/" + contactOutboxId + "/" + name, + request3.getPath()); + assertEquals("GET", request1.getMethod()); + assertToken(request3, token); + assertEquals(0, readBytes(file3).length); + } + private String getBaseUrl(MockWebServer server) { String baseUrl = server.url("").toString(); return baseUrl.substring(0, baseUrl.length() - 1);