Skip to content

Commit

Permalink
Prevent out of memory errors when sniffing a media type (#400)
Browse files Browse the repository at this point in the history
  • Loading branch information
mickael-menu authored Oct 2, 2023
1 parent 9580cdd commit e66cf65
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import org.readium.r2.shared.util.MessageError
import org.readium.r2.shared.util.Try
import org.readium.r2.shared.util.mediatype.MediaTypeRetriever

/**
* An [ArchiveFactory] to open local ZIP files with Java's [ZipFile].
*/
public class DefaultArchiveFactory(
private val mediaTypeRetriever: MediaTypeRetriever
) : ArchiveFactory {
Expand All @@ -28,7 +31,7 @@ public class DefaultArchiveFactory(
?.let { open(it) }
?: Try.Failure(
ArchiveFactory.Error.FormatNotSupported(
MessageError("Resource not supported because file cannot be directly access.")
MessageError("Resource not supported because file cannot be directly accessed.")
)
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.readium.r2.shared.resource

import org.readium.r2.shared.util.Url
import org.readium.r2.shared.util.getOrDefault
import org.readium.r2.shared.util.mediatype.ContainerMediaTypeSnifferContent
import org.readium.r2.shared.util.mediatype.ResourceMediaTypeSnifferContent

Expand All @@ -9,7 +10,7 @@ public class ResourceMediaTypeSnifferContent(
) : ResourceMediaTypeSnifferContent {

override suspend fun read(range: LongRange?): ByteArray? =
resource.read(range).getOrNull()
resource.safeRead(range)
}

public class ContainerMediaTypeSnifferContent(
Expand All @@ -21,6 +22,18 @@ public class ContainerMediaTypeSnifferContent(

override suspend fun read(path: String, range: LongRange?): ByteArray? =
Url.fromDecodedPath(path)?.let { url ->
container.get(url).read(range).getOrNull()
container.get(url).safeRead(range)
}
}

private suspend fun Resource.safeRead(range: LongRange?): ByteArray? {
try {
// We only read files smaller than 5MB to avoid an [OutOfMemoryError].
if (range == null && length().getOrDefault(0) > 5 * 1000 * 1000) {
return null
}
return read(range).getOrNull()
} catch (e: OutOfMemoryError) {
return null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ internal class ChannelZipContainer(
}

/**
* An [ArchiveFactory] able to open a ZIP archive served through an HTTP server.
* An [ArchiveFactory] able to open a ZIP archive served through a stream (e.g. HTTP server,
* content URI, etc.).
*/
public class ChannelZipArchiveFactory(
private val mediaTypeRetriever: MediaTypeRetriever
Expand Down

0 comments on commit e66cf65

Please sign in to comment.