Skip to content

Commit

Permalink
Add configurable max upload size. (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
Foxcapades committed Mar 6, 2023
1 parent 27184b3 commit e398777
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 15 deletions.
4 changes: 2 additions & 2 deletions lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group = "org.veupathdb.lib"
version = "1.0.2"
version = "1.1.0"

repositories {
mavenCentral()
Expand All @@ -23,7 +23,7 @@ dependencies {
implementation(kotlin("stdlib-jdk7"))
implementation(kotlin("stdlib-jdk8"))

implementation("commons-fileupload:commons-fileupload:1.4")
implementation("commons-fileupload:commons-fileupload:1.5")

implementation("org.glassfish.jersey.containers:jersey-container-grizzly2-http:3.0.8")
implementation("org.glassfish.jersey.containers:jersey-container-grizzly2-servlet:3.0.8")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.veupathdb.lib.jaxrs.raml.multipart

/**
* JaxRS Multipart Upload Global Configuration
*/
object JaxRSMultipartUpload {

/**
* Maximum allowed size for a file upload (in bytes).
*
* Defaults to 3GiB.
*/
@JvmStatic
var maxFileUploadSize = 3_221_225_472L

/**
* Maximum allowed size for an in-memory field, class, or property (in bytes).
*
* Defaults to 16MiB.
*/
@JvmStatic
var maxInMemoryFieldSize = 16_777_216L
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class MultipartMessageBodyReader : MessageBodyReader<Any> {
// Create the upload file and populate it with the contents of the stream.
return File(tmpDir, fileName).apply {
createNewFile()
outputStream().use { stream.readBodyData(it) }
outputStream().use { stream.readBodyData(CappedOutputStream(JaxRSMultipartUpload.maxFileUploadSize, it)) }
}
}

Expand Down Expand Up @@ -163,9 +163,9 @@ class MultipartMessageBodyReader : MessageBodyReader<Any> {
// Get the size of the largest valid key
val largestKeyLength = fields.keys.stream()
.map { it.toByteArray() }
.mapToInt { it.size }
.mapToLong { it.size.toLong() }
.max()
.asInt
.asLong

val inp = stream.contentToString(largestKeyLength)

Expand Down Expand Up @@ -231,7 +231,7 @@ class MultipartMessageBodyReader : MessageBodyReader<Any> {
// field.
val file = File(tmpDir, fileName).apply {
createNewFile()
outputStream().use { stream.readBodyData(it) }
CappedOutputStream(JaxRSMultipartUpload.maxFileUploadSize, outputStream()).use { stream.readBodyData(it) }
}

// Assign the file value to our temp map.
Expand Down Expand Up @@ -278,6 +278,7 @@ class MultipartMessageBodyReader : MessageBodyReader<Any> {
* Defaults to 16MiB.
*/
@JvmStatic
var maxVariableSize = 16_777_216
@Deprecated("This field is being replaced in favor of JaxRSMultipartUpload.maxInMemoryFieldSize.")
var maxVariableSize = JaxRSMultipartUpload.maxInMemoryFieldSize
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import java.io.OutputStream
* Capped Size Output Stream
*
* A simple output stream wrapper that throws an exception if more than the
* specified max number of bytes is read.
* specified max number of bytes is written.
*/
class CappedOutputStream(
private val maxBytes: Int,
private val maxBytes: Long,
private val stream: OutputStream
) : OutputStream() {
private var written = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ private const val LCContentDisp = "content-disposition"
private const val FormNamePrefix = "name="
private const val FileNamePrefix = "filename="

private const val InitialBufferSize = 8192

internal fun MultipartStream.contentToString(maxSize: Int) =
ByteArrayOutputStream(8192).let {

internal fun MultipartStream.contentToString(maxSize: Long) =
ByteArrayOutputStream(InitialBufferSize).let {
if (readBodyData(CappedOutputStream(maxSize, it)) == 0)
""
else
Expand Down Expand Up @@ -47,7 +49,7 @@ internal fun String?.parseHeaders(): Map<String, List<String>> {
return out
}

internal fun MultipartStream.readContentAsJsonNode(maxSize: Int) =
internal fun MultipartStream.readContentAsJsonNode(maxSize: Long) =
contentToString(maxSize).let {
try {
MultipartMessageBodyReader.mapper.readTree(it)
Expand Down
6 changes: 3 additions & 3 deletions test/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ dependencies {

implementation(project(":multipart-jackson-pojo"))

implementation("commons-fileupload:commons-fileupload:1.4")
implementation("commons-fileupload:commons-fileupload:1.5")

implementation("org.glassfish.jersey.containers:jersey-container-grizzly2-http:3.0.6")
implementation("org.glassfish.jersey.containers:jersey-container-grizzly2-servlet:3.0.6")
runtimeOnly("org.glassfish.jersey.inject:jersey-hk2:3.0.6")
implementation("org.glassfish.hk2:hk2-api:3.0.3")

implementation("com.fasterxml.jackson.core:jackson-databind:2.13.3")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.13.3")
implementation("com.fasterxml.jackson.core:jackson-databind:2.13.4")
implementation("com.fasterxml.jackson.core:jackson-annotations:2.13.4")

testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0")
Expand Down

0 comments on commit e398777

Please sign in to comment.