Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
os: [macos-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- run: swift build -v

test:
Expand All @@ -26,5 +26,5 @@ jobs:
os: [macos-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- run: swift test -v
2 changes: 1 addition & 1 deletion .github/workflows/swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
name: SwiftLint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: norio-nomura/action-swiftlint@3.2.1
with:
args: --strict
2 changes: 1 addition & 1 deletion Sources/MultipartFormData/Boundary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,6 @@ extension Boundary: CustomDebugStringConvertible {

extension Boundary {
internal var _value: String {
return String(decoding: _asciiData, as: UTF8.self) // UTF-8 representation is exactly equivalent to ASCII
return String(bytes: _asciiData, encoding: .ascii) ?? ""
}
}
1 change: 1 addition & 0 deletions Sources/MultipartFormData/Internal/String+helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

extension String {
internal init(_ staticString: StaticString) {
// swiftlint:disable:next optional_data_string_conversion
self = staticString.withUTF8Buffer { String(decoding: $0, as: UTF8.self) }
}
}
3 changes: 2 additions & 1 deletion Sources/MultipartFormData/MultipartFormData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ extension MultipartFormData {

extension MultipartFormData: CustomDebugStringConvertible {
public var debugDescription: String {
return String(decoding: contentType._data + ._crlf + ._crlf + httpBody, as: UTF8.self)
let bytes: Data = contentType._data + ._crlf + ._crlf + httpBody
return String(bytes: bytes, encoding: .utf8) ?? ""
}
}
2 changes: 1 addition & 1 deletion Sources/MultipartFormData/Subpart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ extension Subpart {

extension Subpart: CustomDebugStringConvertible {
public var debugDescription: String {
return String(decoding: _data, as: UTF8.self)
return String(bytes: _data, encoding: .utf8) ?? ""
}
}

Expand Down
26 changes: 17 additions & 9 deletions Tests/MultipartFormDataTests/ContentDispositionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,36 @@ import XCTest
@testable import MultipartFormData

final class ContentDispositionTests: XCTestCase {
func testPercentEncodingError() throws {
func testUncheckedInitValid() {
XCTAssertNoThrow(try ContentDisposition(uncheckedName: "a", uncheckedFilename: "a"))

}

func testUncheckedInitInvalid() throws {
// https://stackoverflow.com/questions/33558933/why-is-the-return-value-of-string-addingpercentencoding-optional
// does not work on Linux, can still encoding there
let nonPercentEncodableString = try XCTUnwrap(String(bytes: [0xD8, 0x00] as [UInt8], encoding: .utf16BigEndian))
if nonPercentEncodableString.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) == nil {
XCTAssertThrowsError(try ContentDisposition(uncheckedName: nonPercentEncodableString, uncheckedFilename: nil))
XCTAssertThrowsError(try ContentDisposition(uncheckedName: "", uncheckedFilename: nonPercentEncodableString))
let bytes: [UInt8] = [0xD8, 0x00]

// Ensure the non-encodable string can be created, e.g. on iOS 18 it no longer works.
guard let nonPercentEncodableString = String(bytes: bytes, encoding: .utf16BigEndian) else {
throw XCTSkip("UTF16 byte encoding failed")
}

// Ensure the percent-encoding fails on the current platform, e.g. on Linux it encodes.
guard nonPercentEncodableString.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) == nil else {
throw XCTSkip("percent encoding didn't fail")
}

XCTAssertThrowsError(try ContentDisposition(uncheckedName: nonPercentEncodableString, uncheckedFilename: nil))
XCTAssertThrowsError(try ContentDisposition(uncheckedName: "", uncheckedFilename: nonPercentEncodableString))
}

func testParameters() throws {
let contentDisposition = ContentDisposition(name: "a", filename: "a")

XCTAssertEqual(contentDisposition.parameters[0], HTTPHeaderParameter("name", value: "a"))
XCTAssertEqual(contentDisposition.parameters[1], HTTPHeaderParameter("filename", value: "a"))
}

func testData() throws {
let contentDisposition = ContentDisposition(name: "a", filename: "a")

XCTAssertEqual(contentDisposition._data, Data("Content-Disposition: form-data; name=\"a\"; filename=\"a\"".utf8))
}
}
Loading