From 2c171413b3cc711102c59ef771f6fa1d091ad8f1 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 15 Nov 2023 12:40:01 +0100 Subject: [PATCH 1/3] fix(fileutils): Add `readBytesFromFile` for use in Hybrid SDKs --- CHANGELOG.md | 1 + sentry/api/sentry.api | 1 + .../java/io/sentry/SentryEnvelopeItem.java | 43 +------------- .../main/java/io/sentry/util/FileUtils.java | 56 +++++++++++++++++++ 4 files changed, 59 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54d8e895bbe..1745a0b6351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - (Internal) Extract Android Profiler and Measurements for Hybrid SDKs ([#3016](https://github.com/getsentry/sentry-java/pull/3016)) - Ensure DSN uses http/https protocol ([#3044](https://github.com/getsentry/sentry-java/pull/3044)) +- (Internal) Add `readBytesFromFile` for use in Hybrid SDKs ([#3052](https://github.com/getsentry/sentry-java/pull/3052)) ### Features diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 4272f044b4d..97b20df850d 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -4365,6 +4365,7 @@ public final class io/sentry/util/ExceptionUtils { public final class io/sentry/util/FileUtils { public fun ()V public static fun deleteRecursively (Ljava/io/File;)Z + public static fun readBytesFromFile (Ljava/lang/String;J)[B public static fun readText (Ljava/io/File;)Ljava/lang/String; } diff --git a/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java index 61a78199423..ca50a8ac61d 100644 --- a/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java @@ -1,5 +1,6 @@ package io.sentry; +import static io.sentry.util.FileUtils.readBytesFromFile; import static io.sentry.vendor.Base64.NO_PADDING; import static io.sentry.vendor.Base64.NO_WRAP; @@ -304,48 +305,6 @@ private static void ensureAttachmentSizeLimit( return new SentryEnvelopeItem(itemHeader, () -> cachedItem.getBytes()); } - private static byte[] readBytesFromFile(String pathname, long maxFileLength) - throws SentryEnvelopeException { - try { - File file = new File(pathname); - - if (!file.isFile()) { - throw new SentryEnvelopeException( - String.format( - "Reading the item %s failed, because the file located at the path is not a file.", - pathname)); - } - - if (!file.canRead()) { - throw new SentryEnvelopeException( - String.format("Reading the item %s failed, because can't read the file.", pathname)); - } - - if (file.length() > maxFileLength) { - throw new SentryEnvelopeException( - String.format( - "Dropping item, because its size located at '%s' with %d bytes is bigger " - + "than the maximum allowed size of %d bytes.", - pathname, file.length(), maxFileLength)); - } - - try (FileInputStream fileInputStream = new FileInputStream(pathname); - BufferedInputStream inputStream = new BufferedInputStream(fileInputStream); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - byte[] bytes = new byte[1024]; - int length; - int offset = 0; - while ((length = inputStream.read(bytes)) != -1) { - outputStream.write(bytes, offset, length); - } - return outputStream.toByteArray(); - } - } catch (IOException | SecurityException exception) { - throw new SentryEnvelopeException( - String.format("Reading the item %s failed.\n%s", pathname, exception.getMessage())); - } - } - public static @NotNull SentryEnvelopeItem fromClientReport( final @NotNull ISerializer serializer, final @NotNull ClientReport clientReport) throws IOException { diff --git a/sentry/src/main/java/io/sentry/util/FileUtils.java b/sentry/src/main/java/io/sentry/util/FileUtils.java index b5d4df8c16a..1ff6f20126d 100644 --- a/sentry/src/main/java/io/sentry/util/FileUtils.java +++ b/sentry/src/main/java/io/sentry/util/FileUtils.java @@ -1,7 +1,10 @@ package io.sentry.util; +import java.io.BufferedInputStream; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import org.jetbrains.annotations.ApiStatus; @@ -60,4 +63,57 @@ public static boolean deleteRecursively(@Nullable File file) { } return contentBuilder.toString(); } + + /** + * Reads the content of a path into a byte array. If the path is does not exists, + * it's not a file, can't be read or is larger than max size allowed IOException + * is thrown. Do not use with large files, as the byte array is kept in memory! + * + * @param pathname file to read + * @return a byte array containing all the content of the file + * @throws IOException In case of error reading the file + */ + public static byte[] readBytesFromFile(String pathname, long maxFileLength) + throws IOException, SecurityException { + File file = new File(pathname); + + if (!file.exists()) { + throw new IOException( + String.format( + "File '%s' doesn't exists", + file.getName())); + } + + if (!file.isFile()) { + throw new IOException( + String.format( + "Reading path %s failed, because it's not a file.", + pathname)); + } + + if (!file.canRead()) { + throw new IOException( + String.format("Reading the item %s failed, because can't read the file.", pathname)); + } + + if (file.length() > maxFileLength) { + throw new IOException( + String.format( + "Reading file failed, because size located at '%s' with %d bytes is bigger " + + "than the maximum allowed size of %d bytes.", + pathname, file.length(), maxFileLength)); + } + + try (FileInputStream fileInputStream = new FileInputStream(pathname); + BufferedInputStream inputStream = new BufferedInputStream(fileInputStream); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] bytes = new byte[1024]; + int length; + int offset = 0; + while ((length = inputStream.read(bytes)) != -1) { + outputStream.write(bytes, offset, length); + } + return outputStream.toByteArray(); + } + } } From 58e96bf716f0e91df0842d5a2d1e0907a977b109 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Wed, 15 Nov 2023 11:45:14 +0000 Subject: [PATCH 2/3] Format code --- .../java/io/sentry/SentryEnvelopeItem.java | 2 -- .../main/java/io/sentry/util/FileUtils.java | 31 ++++++++----------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java index ca50a8ac61d..acd6b36aa91 100644 --- a/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java @@ -10,13 +10,11 @@ import io.sentry.util.JsonSerializationUtils; import io.sentry.util.Objects; import io.sentry.vendor.Base64; -import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; diff --git a/sentry/src/main/java/io/sentry/util/FileUtils.java b/sentry/src/main/java/io/sentry/util/FileUtils.java index 1ff6f20126d..73b83713c77 100644 --- a/sentry/src/main/java/io/sentry/util/FileUtils.java +++ b/sentry/src/main/java/io/sentry/util/FileUtils.java @@ -65,48 +65,43 @@ public static boolean deleteRecursively(@Nullable File file) { } /** - * Reads the content of a path into a byte array. If the path is does not exists, - * it's not a file, can't be read or is larger than max size allowed IOException - * is thrown. Do not use with large files, as the byte array is kept in memory! + * Reads the content of a path into a byte array. If the path is does not exists, it's not a file, + * can't be read or is larger than max size allowed IOException is thrown. Do not use with large + * files, as the byte array is kept in memory! * * @param pathname file to read * @return a byte array containing all the content of the file * @throws IOException In case of error reading the file */ public static byte[] readBytesFromFile(String pathname, long maxFileLength) - throws IOException, SecurityException { + throws IOException, SecurityException { File file = new File(pathname); if (!file.exists()) { - throw new IOException( - String.format( - "File '%s' doesn't exists", - file.getName())); + throw new IOException(String.format("File '%s' doesn't exists", file.getName())); } if (!file.isFile()) { throw new IOException( - String.format( - "Reading path %s failed, because it's not a file.", - pathname)); + String.format("Reading path %s failed, because it's not a file.", pathname)); } if (!file.canRead()) { throw new IOException( - String.format("Reading the item %s failed, because can't read the file.", pathname)); + String.format("Reading the item %s failed, because can't read the file.", pathname)); } if (file.length() > maxFileLength) { throw new IOException( - String.format( - "Reading file failed, because size located at '%s' with %d bytes is bigger " - + "than the maximum allowed size of %d bytes.", - pathname, file.length(), maxFileLength)); + String.format( + "Reading file failed, because size located at '%s' with %d bytes is bigger " + + "than the maximum allowed size of %d bytes.", + pathname, file.length(), maxFileLength)); } try (FileInputStream fileInputStream = new FileInputStream(pathname); - BufferedInputStream inputStream = new BufferedInputStream(fileInputStream); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + BufferedInputStream inputStream = new BufferedInputStream(fileInputStream); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { byte[] bytes = new byte[1024]; int length; int offset = 0; From 0a318043386c9b35c572d66afdef2595f22c9375 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 15 Nov 2023 17:17:56 +0100 Subject: [PATCH 3/3] fix tests --- .../test/java/io/sentry/JsonSerializerTest.kt | 2 +- .../java/io/sentry/SentryEnvelopeItemTest.kt | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sentry/src/test/java/io/sentry/JsonSerializerTest.kt b/sentry/src/test/java/io/sentry/JsonSerializerTest.kt index 3d07b3e37c6..62c2c53526f 100644 --- a/sentry/src/test/java/io/sentry/JsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/JsonSerializerTest.kt @@ -1037,7 +1037,7 @@ class JsonSerializerTest { .log( eq(SentryLevel.ERROR), eq("Failed to create envelope item. Dropping it."), - any() + any() ) } diff --git a/sentry/src/test/java/io/sentry/SentryEnvelopeItemTest.kt b/sentry/src/test/java/io/sentry/SentryEnvelopeItemTest.kt index 926277751ac..98178976510 100644 --- a/sentry/src/test/java/io/sentry/SentryEnvelopeItemTest.kt +++ b/sentry/src/test/java/io/sentry/SentryEnvelopeItemTest.kt @@ -13,6 +13,7 @@ import org.mockito.kotlin.whenever import java.io.BufferedWriter import java.io.ByteArrayOutputStream import java.io.File +import java.io.IOException import java.io.OutputStreamWriter import java.nio.charset.Charset import kotlin.test.AfterTest @@ -120,7 +121,7 @@ class SentryEnvelopeItemTest { val item = SentryEnvelopeItem.fromAttachment(fixture.serializer, fixture.options.logger, attachment, fixture.maxAttachmentSize) - assertFailsWith( + assertFailsWith( "Reading the attachment ${attachment.pathname} failed, because the file located at " + "the path is not a file." ) { @@ -140,7 +141,7 @@ class SentryEnvelopeItemTest { val item = SentryEnvelopeItem.fromAttachment(fixture.serializer, fixture.options.logger, attachment, fixture.maxAttachmentSize) - assertFailsWith( + assertFailsWith( "Reading the attachment ${attachment.pathname} failed, " + "because can't read the file." ) { @@ -163,7 +164,7 @@ class SentryEnvelopeItemTest { val item = SentryEnvelopeItem.fromAttachment(fixture.serializer, fixture.options.logger, attachment, fixture.maxAttachmentSize) - assertFailsWith("Reading the attachment ${attachment.pathname} failed.") { + assertFailsWith("Reading the attachment ${attachment.pathname} failed.") { item.data } @@ -244,12 +245,12 @@ class SentryEnvelopeItemTest { file.writeBytes(fixture.bytesTooBig) val attachment = Attachment(file.path) - val exception = assertFailsWith { + val exception = assertFailsWith { SentryEnvelopeItem.fromAttachment(fixture.serializer, fixture.options.logger, attachment, fixture.maxAttachmentSize).data } assertEquals( - "Dropping item, because its size located at " + + "Reading file failed, because size located at " + "'${fixture.pathname}' with ${file.length()} bytes is bigger than the maximum " + "allowed size of ${fixture.maxAttachmentSize} bytes.", exception.message @@ -317,7 +318,7 @@ class SentryEnvelopeItemTest { } file.writeBytes(fixture.bytes) file.setReadable(false) - assertFailsWith("Dropping profiling trace data, because the file ${file.path} doesn't exists") { + assertFailsWith("Dropping profiling trace data, because the file ${file.path} doesn't exists") { SentryEnvelopeItem.fromProfilingTrace(profilingTraceData, fixture.maxAttachmentSize, mock()).data } } @@ -344,12 +345,12 @@ class SentryEnvelopeItemTest { whenever(it.traceFile).thenReturn(file) } - val exception = assertFailsWith { + val exception = assertFailsWith { SentryEnvelopeItem.fromProfilingTrace(profilingTraceData, fixture.maxAttachmentSize, mock()).data } assertEquals( - "Dropping item, because its size located at " + + "Reading file failed, because size located at " + "'${fixture.pathname}' with ${file.length()} bytes is bigger than the maximum " + "allowed size of ${fixture.maxAttachmentSize} bytes.", exception.message