Skip to content

Commit

Permalink
Fix recursion loop in decoding of a SingleValueContainer (#88)
Browse files Browse the repository at this point in the history
* Fix for recursion loop in decoding

* Update test per PR feedback
  • Loading branch information
dkolas authored Apr 13, 2023
1 parent 3a31859 commit 1adfd69
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Sources/MultipartKit/FormDataDecoder/FormDataDecoder.Decoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ extension FormDataDecoder {
let codingPath: [CodingKey]
let data: MultipartFormData
let userInfo: [CodingUserInfoKey: Any]
let previousCodingPath : [CodingKey]?
let previousType: Decodable.Type?

init(codingPath: [CodingKey], data: MultipartFormData, userInfo: [CodingUserInfoKey: Any], previousCodingPath: [CodingKey]? = nil, previousType: Decodable.Type? = nil) {
self.codingPath = codingPath
self.data = data
self.userInfo = userInfo
self.previousCodingPath = previousCodingPath
self.previousType = previousType
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ extension FormDataDecoder.Decoder: SingleValueDecodingContainer {
let part = data.part,
let Convertible = T.self as? MultipartPartConvertible.Type
else {
return try T(from: self)
guard previousCodingPath?.count != codingPath.count || previousType != T.self else {
throw DecodingError.dataCorrupted(.init(codingPath: codingPath, debugDescription: "Decoding caught in recursion loop"))
}
return try T(from: FormDataDecoder.Decoder(codingPath: codingPath, data: data, userInfo: userInfo, previousCodingPath: codingPath, previousType: T.self))
}

guard !data.hasExceededNestingDepth else {
Expand Down
14 changes: 14 additions & 0 deletions Tests/MultipartKitTests/FormDataTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -493,4 +493,18 @@ class FormDataTests: XCTestCase {
XCTAssertEqual(try FormDataEncoder().encode(license, boundary: "-"), multipart)
XCTAssertEqual(try FormDataDecoder().decode(License.self, from: multipart, boundary: "-"), license)
}

func testIncorrectlyNestedData() throws {
struct TestData : Codable {
var x: String
}
let multipart = """
---\r
Content-Disposition: form-data; name="x[not-present]"\r
\r
foo\r
-----\r
"""
XCTAssertThrowsError (try FormDataDecoder().decode(TestData.self, from: multipart, boundary: "-"))
}
}

0 comments on commit 1adfd69

Please sign in to comment.