Skip to content

Commit 1adfd69

Browse files
authored
Fix recursion loop in decoding of a SingleValueContainer (#88)
* Fix for recursion loop in decoding * Update test per PR feedback
1 parent 3a31859 commit 1adfd69

File tree

3 files changed

+28
-1
lines changed

3 files changed

+28
-1
lines changed

Sources/MultipartKit/FormDataDecoder/FormDataDecoder.Decoder.swift

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ extension FormDataDecoder {
33
let codingPath: [CodingKey]
44
let data: MultipartFormData
55
let userInfo: [CodingUserInfoKey: Any]
6+
let previousCodingPath : [CodingKey]?
7+
let previousType: Decodable.Type?
8+
9+
init(codingPath: [CodingKey], data: MultipartFormData, userInfo: [CodingUserInfoKey: Any], previousCodingPath: [CodingKey]? = nil, previousType: Decodable.Type? = nil) {
10+
self.codingPath = codingPath
11+
self.data = data
12+
self.userInfo = userInfo
13+
self.previousCodingPath = previousCodingPath
14+
self.previousType = previousType
15+
}
616
}
717
}
818

Sources/MultipartKit/FormDataDecoder/FormDataDecoder.SingleValueContainer.swift

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ extension FormDataDecoder.Decoder: SingleValueDecodingContainer {
88
let part = data.part,
99
let Convertible = T.self as? MultipartPartConvertible.Type
1010
else {
11-
return try T(from: self)
11+
guard previousCodingPath?.count != codingPath.count || previousType != T.self else {
12+
throw DecodingError.dataCorrupted(.init(codingPath: codingPath, debugDescription: "Decoding caught in recursion loop"))
13+
}
14+
return try T(from: FormDataDecoder.Decoder(codingPath: codingPath, data: data, userInfo: userInfo, previousCodingPath: codingPath, previousType: T.self))
1215
}
1316

1417
guard !data.hasExceededNestingDepth else {

Tests/MultipartKitTests/FormDataTests.swift

+14
Original file line numberDiff line numberDiff line change
@@ -493,4 +493,18 @@ class FormDataTests: XCTestCase {
493493
XCTAssertEqual(try FormDataEncoder().encode(license, boundary: "-"), multipart)
494494
XCTAssertEqual(try FormDataDecoder().decode(License.self, from: multipart, boundary: "-"), license)
495495
}
496+
497+
func testIncorrectlyNestedData() throws {
498+
struct TestData : Codable {
499+
var x: String
500+
}
501+
let multipart = """
502+
---\r
503+
Content-Disposition: form-data; name="x[not-present]"\r
504+
\r
505+
foo\r
506+
-----\r
507+
"""
508+
XCTAssertThrowsError (try FormDataDecoder().decode(TestData.self, from: multipart, boundary: "-"))
509+
}
496510
}

0 commit comments

Comments
 (0)