New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Default max body size for streaming request body collection #2312
Changes from 15 commits
18910f0
a86288f
f297a9b
baa184c
eb89bf7
aa6bdec
8b32960
713bb1b
d130d05
e949d4d
21d1dc3
b55cf05
0024074
deb0284
b09b40a
86e817d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import Foundation | ||
|
||
/// Represents a number of bytes: | ||
/// | ||
/// let bytes: ByteCount = "1mb" | ||
/// print(bytes.value) // 1048576 | ||
/// | ||
/// let bytes: ByteCount = 1_000_000 | ||
/// print(bytes.value) // 1000000 | ||
|
||
/// let bytes: ByteCount = "2kb" | ||
/// print(bytes.value) // 2048 | ||
public struct ByteCount: Equatable { | ||
/// The value in Bytes | ||
public let value: Int | ||
|
||
public init(value: Int) { | ||
self.value = value | ||
} | ||
} | ||
|
||
extension ByteCount: ExpressibleByIntegerLiteral { | ||
/// Initializes the `ByteCount` with the raw byte count | ||
/// - Parameter value: The number of bytes | ||
public init(integerLiteral value: Int) { | ||
self.value = value | ||
} | ||
} | ||
|
||
extension ByteCount: ExpressibleByStringLiteral { | ||
/// Initializes the `ByteCount` via a descriptive string. Available suffixes are: | ||
/// `kb`, `mb`, `gb`, `tb` | ||
/// - Parameter value: The string value (`1mb`) | ||
public init(stringLiteral value: String) { | ||
// Short path if it's an int wrapped in a string | ||
if let intValue = Int(value) { | ||
self.value = intValue | ||
return | ||
} | ||
|
||
let validSuffixes = [ | ||
"kb": 10, | ||
"mb": 20, | ||
"gb": 30, | ||
"tb": 40 | ||
] | ||
|
||
for suffix in validSuffixes { | ||
guard value.hasSuffix(suffix.key) else { continue } | ||
guard let stringIntValue = value.components(separatedBy: suffix.key).first else { | ||
fatalError("Invalid string format") | ||
} | ||
|
||
guard let intValue = Int(stringIntValue) else { | ||
fatalError("Invalid int value: \(stringIntValue)") | ||
} | ||
|
||
self.value = intValue << suffix.value | ||
return | ||
} | ||
|
||
// Assert failure here because all cases are handled in the above loop | ||
fatalError("Could not parse byte count string: \(value)") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -95,7 +95,7 @@ final class ServerTests: XCTestCase { | |
|
||
let payload = [UInt8].random(count: 1 << 20) | ||
|
||
app.on(.POST, "payload", body: .collect(maxSize: nil)) { req -> HTTPStatus in | ||
app.on(.POST, "payload", body: .collect(maxSize: "1gb")) { req -> HTTPStatus in | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Passing
I don't think so since I view the current behavior as a bug.
I don't think so as this opens your server up to an easy attack vector. If you really want to get around this you can use |
||
guard let data = req.body.data else { | ||
throw Abort(.internalServerError) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we make this a little fuzzier? Such as lowercasing the input before splitting it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, lowercasing is a good idea. Maybe removing whitespace too?