Skip to content

Commit

Permalink
fix(Multipart): Create InputStream only when the body is filled (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
rudyfremont authored Mar 20, 2023
1 parent a5a5e07 commit cf14135
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 13 deletions.
32 changes: 20 additions & 12 deletions Sources/SimpleHTTP/MultipartForm/MultipartFormData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,30 @@ enum Boundary {

struct BodyPart {
let headers: [Header]
let stream: InputStream
let length: Int
let stream: () throws -> InputStream

var hasInitialBoundary = false
var hasFinalBoundary = false

init(headers: [Header], stream: InputStream, length: Int) {
private init(headers: [Header], stream: @escaping () throws -> InputStream, length: Int) {
self.headers = headers
self.stream = stream
self.length = length
self.stream = stream
}

init(headers: [Header], url: URL, length: Int) {
let stream: () throws -> InputStream = {
guard let stream = InputStream(url: url) else {
throw MultipartFormData.Error.inputStreamCreationFailed(url)
}
return stream
}
self.init(headers: headers, stream: stream, length: length)
}

init(headers: [Header], data: Data) {
self.init(headers: headers, stream: { InputStream(data: data) }, length: data.count)
}
}

Expand Down Expand Up @@ -126,12 +141,7 @@ public struct MultipartFormData {
}

let length = fileSize.intValue

guard let stream = InputStream(url: url) else {
throw MultipartFormData.Error.inputStreamCreationFailed(url)
}

bodyParts.append(BodyPart(headers: headers, stream: stream, length: length))
bodyParts.append(BodyPart(headers: headers, url: url, length: length))
}

/// Creates a body part from the data and add it to the instance.
Expand All @@ -150,10 +160,8 @@ public struct MultipartFormData {
/// - mimeType: MIME type associated to the data in the `Content-Type` HTTPHeader.
public mutating func add(data: Data, name: String, fileName: String? = nil, mimeType: String? = nil) {
let headers = defineBodyPartHeader(name: name, fileName: fileName, mimeType: mimeType)
let stream = InputStream(data: data)
let length = data.count

bodyParts.append(BodyPart(headers: headers, stream: stream, length: length))
bodyParts.append(BodyPart(headers: headers, data: data))
}

private func defineBodyPartHeader(name: String, fileName: String?, mimeType: String?) -> [Header] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ struct MultipartFormDataEncoder {
}

encoded.append(try encodeBodyPart(headers: bodyPart.headers))
encoded.append(try encodeBodyPart(stream: bodyPart.stream, length: bodyPart.length))
encoded.append(try encodeBodyPart(stream: bodyPart.stream(), length: bodyPart.length))

if bodyPart.hasFinalBoundary {
encoded.append(Boundary.data(for: .final, boundary: boundary))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,18 @@ class MultipartFormDataEncoderTests: XCTestCase {
XCTAssertEqual(encodedData, expectedData)
}

func test_encode_encoreMultiPartFormDataTwice_notThrow() throws {
let boundary = "boundary"
var multipart = MultipartFormData(boundary: boundary)

let data = "I'm pjechris, Nice to meet you"
let name1 = "data"
multipart.add(data: Data(data.utf8), name: name1)

var encoder = MultipartFormDataEncoder(body: multipart)
_ = try encoder.encode()

XCTAssertNoThrow(_ = try encoder.encode())
}

}

0 comments on commit cf14135

Please sign in to comment.