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
9 changes: 5 additions & 4 deletions Sources/MultipartFormData/Boundary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,19 @@ extension Boundary {
}
}

// MARK: - Debug
// MARK: - CustomDebugStringConvertible

extension Boundary: CustomDebugStringConvertible {
public var debugDescription: String {
return _value
return rawValue
}
}

// MARK: - Helpers
// MARK: - Data

extension Boundary {
internal var _value: String {
/// The raw string representation of a boundary.
public var rawValue: String {
return String(bytes: _asciiData, encoding: .ascii) ?? ""
}
}
4 changes: 2 additions & 2 deletions Sources/MultipartFormData/ContentType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public struct ContentType: HTTPHeaderField {
public static let name: String = "Content-Type"

public var value: String {
return mediaType._text
return mediaType.rawValue
}

/// The media type (MIME type) of the content type.
Expand All @@ -36,6 +36,6 @@ public struct ContentType: HTTPHeaderField {
extension ContentType {
internal init(boundary: Boundary) {
self.mediaType = .multipartFormData
self.parameters = [HTTPHeaderParameter("boundary", value: boundary._value)]
self.parameters = [HTTPHeaderParameter("boundary", value: boundary.rawValue)]
}
}
25 changes: 13 additions & 12 deletions Sources/MultipartFormData/HTTPHeaderField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,31 @@ public protocol HTTPHeaderField: Sendable, Hashable, CustomDebugStringConvertibl
var parameters: [HTTPHeaderParameter] { get set }
}

// MARK: - Debug
// MARK: - CustomDebugStringConvertible

extension HTTPHeaderField {
/// A textual representation of this instance, suitable for debugging.
public var debugDescription: String {
return _text
return rawValue
}
}

// MARK: - Helpers
// MARK: - Data

extension HTTPHeaderField {
internal var _value: String {
if parameters.isEmpty {
return value
}
return "\(value); \(parameters._text)"
/// The actual header field value resulting from ``value`` and ``parameters``.
public var parameterizedValue: String {
if parameters.isEmpty { return value }
return "\(value); \(parameters.rawValue)"
}

internal var _text: String {
return "\(Self.name): \(_value)"
/// The raw string representation of a header field.
public var rawValue: String {
return "\(Self.name): \(parameterizedValue)"
}

internal var _data: Data {
return Data(_text.utf8)
/// The data representation of a header field.
public var data: Data {
return Data(rawValue.utf8)
}
}
14 changes: 8 additions & 6 deletions Sources/MultipartFormData/HTTPHeaderParameter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,26 @@ public struct HTTPHeaderParameter: Sendable, Hashable {
}
}

// MARK: - Debug
// MARK: - CustomDebugStringConvertible

extension HTTPHeaderParameter: CustomDebugStringConvertible {
public var debugDescription: String {
return _text
return rawValue
}
}

// MARK: - Helpers
// MARK: - Data

extension HTTPHeaderParameter {
internal var _text: String {
/// The raw string representation of a header parameter.
public var rawValue: String {
return "\(name)=\"\(value)\""
}
}

extension Array<HTTPHeaderParameter> {
internal var _text: String {
return map(\._text).joined(separator: "; ")
/// The raw string representation of multiple header parameters.
public var rawValue: String {
return map(\.rawValue).joined(separator: "; ")
}
}
11 changes: 6 additions & 5 deletions Sources/MultipartFormData/MediaType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,24 @@ extension UTType {
/// - Parameter mediaType: The media type.
/// - Parameter supertype: Another UTType instance that the resulting type must conform to; for example, UTTypeData.
public init?(mediaType: MediaType, conformingTo supertype: UTType = .data) {
self.init(mimeType: mediaType._text, conformingTo: supertype)
self.init(mimeType: mediaType.rawValue, conformingTo: supertype)
}
}
#endif

// MARK: - Debug
// MARK: - CustomDebugStringConvertible

extension MediaType: CustomDebugStringConvertible {
public var debugDescription: String {
return _text
return rawValue
}
}

// MARK: - Helpers
// MARK: - Data

extension MediaType {
internal var _text: String {
/// The raw string representation of a media type.
public var rawValue: String {
return "\(type)/\(subtype)"
}
}
6 changes: 3 additions & 3 deletions Sources/MultipartFormData/MultipartFormData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ extension MultipartFormData {
/// This combines all the data from the subparts into one big data object.
public var httpBody: Data {
let bodyData: Data = body
.map { ._dash + boundary._asciiData + ._crlf + $0._data + ._crlf }
.map { ._dash + boundary._asciiData + ._crlf + $0.data + ._crlf }
.reduce(Data(), +)
return bodyData + ._dash + boundary._asciiData + ._dash + ._crlf
}
Expand Down Expand Up @@ -158,11 +158,11 @@ extension MultipartFormData {
}
}

// MARK: - Debug
// MARK: - CustomDebugStringConvertible

extension MultipartFormData: CustomDebugStringConvertible {
public var debugDescription: String {
let bytes: Data = contentType._data + ._crlf + ._crlf + httpBody
let bytes: Data = contentType.data + ._crlf + ._crlf + httpBody
return String(bytes: bytes, encoding: .utf8) ?? ""
}
}
13 changes: 7 additions & 6 deletions Sources/MultipartFormData/Subpart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,20 @@ extension Subpart {
}
}

// MARK: - Debug
// MARK: - CustomDebugStringConvertible

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

// MARK: - Helpers
// MARK: - Data

extension Subpart {
internal var _data: Data {
let contentTypeData: Data = contentType.map { $0._data + ._crlf } ?? Data()
return contentDisposition._data + ._crlf + contentTypeData + ._crlf + body
/// The data representation of a subpart.
public var data: Data {
let contentTypeData: Data = contentType.map { $0.data + ._crlf } ?? Data()
return contentDisposition.data + ._crlf + contentTypeData + ._crlf + body
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ extension URLRequest {
/// Updates the corresponding header field with a``HTTPHeaderField`` object.
/// - Parameter headerField: The new header field object.
public mutating func updateHeaderField<Field: HTTPHeaderField>(with headerField: Field) {
setValue(headerField._value, forHTTPHeaderField: Field.name)
setValue(headerField.parameterizedValue, forHTTPHeaderField: Field.name)
}
}
2 changes: 1 addition & 1 deletion Tests/MultipartFormDataTests/BoundaryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ final class BoundaryTests: XCTestCase {
let randomBoundary = Boundary.random()
let asciiString = String(data: randomBoundary._asciiData, encoding: .ascii)
XCTAssertNotNil(asciiString)
XCTAssertEqual(asciiString, randomBoundary._value)
XCTAssertEqual(asciiString, randomBoundary.rawValue)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/MultipartFormDataTests/ContentDispositionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ final class ContentDispositionTests: XCTestCase {

func testData() throws {
let contentDisposition = ContentDisposition(name: "a", filename: "a")
XCTAssertEqual(contentDisposition._data, Data("Content-Disposition: form-data; name=\"a\"; filename=\"a\"".utf8))
XCTAssertEqual(contentDisposition.data, Data("Content-Disposition: form-data; name=\"a\"; filename=\"a\"".utf8))
}
}
4 changes: 1 addition & 3 deletions Tests/MultipartFormDataTests/ContentTypeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@ import XCTest
final class ContentTypeTests: XCTestCase {
func testBoundaryParameters() throws {
let contentType = ContentType(boundary: try Boundary(uncheckedBoundary: "test"))

XCTAssertEqual(contentType.parameters[0], HTTPHeaderParameter("boundary", value: "test"))
}

func testData() {
let contentType = ContentType(mediaType: .textPlain, parameters: [HTTPHeaderParameter("test", value: "a")])

XCTAssertEqual(contentType._data, Data("Content-Type: text/plain; test=\"a\"".utf8))
XCTAssertEqual(contentType.data, Data("Content-Type: text/plain; test=\"a\"".utf8))
}
}
7 changes: 3 additions & 4 deletions Tests/MultipartFormDataTests/HTTPHeaderParameterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,22 @@ import XCTest
@testable import MultipartFormData

final class HTTPHeaderParameterTests: XCTestCase {
func testArrayText() {
func testArrayRawValue() {
let singleParameter = [
HTTPHeaderParameter("test", value: "a")
]
XCTAssertEqual(singleParameter._text, "test=\"a\"")
XCTAssertEqual(singleParameter.rawValue, "test=\"a\"")

let parameters = [
HTTPHeaderParameter("test", value: "a"),
HTTPHeaderParameter("test", value: "a"),
HTTPHeaderParameter("test", value: "a"),
]
XCTAssertEqual(parameters._text, "test=\"a\"; test=\"a\"; test=\"a\"")
XCTAssertEqual(parameters.rawValue, "test=\"a\"; test=\"a\"; test=\"a\"")
}

func testDebugDescription() {
let parameter = HTTPHeaderParameter("test", value: "a")

let expectedDescription = "test=\"a\""
XCTAssertEqual(parameter.debugDescription, expectedDescription)
}
Expand Down
7 changes: 2 additions & 5 deletions Tests/MultipartFormDataTests/MediaTypeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@ import UniformTypeIdentifiers
@testable import MultipartFormData

final class MediaTypeTests: XCTestCase {
func testText() {
func testRawValue() {
let mediaType = MediaType(type: "type", subtype: "subtype")
XCTAssertEqual(mediaType._text, "type/subtype")
XCTAssertEqual(mediaType.rawValue, "type/subtype")
}

func testDebugDescription() {
let mediaType = MediaType(type: "type", subtype: "subtype")

let expectedDescription = "type/subtype"
XCTAssertEqual(mediaType.debugDescription, expectedDescription)
}
Expand All @@ -29,14 +28,12 @@ final class MediaTypeTests: XCTestCase {
func testFromUTTypeConversion() throws {
let uniformType = try XCTUnwrap(UTType("public.comma-separated-values-text"))
let mediaType = try XCTUnwrap(MediaType(uniformType: uniformType))

XCTAssertEqual(mediaType, .textCsv)
}

@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
func testToUTTypeConversion() throws {
let uniformType = try XCTUnwrap(UTType(mediaType: .applicationJson))

XCTAssertEqual(uniformType.identifier, "public.json")
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion Tests/MultipartFormDataTests/MultipartFormDataTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ final class MultipartFormDataTests: XCTestCase {
func testContentType() throws {
let boundary = try Boundary(uncheckedBoundary: "test")
let multipartFormData = MultipartFormData(boundary: boundary)
XCTAssertEqual(multipartFormData.contentType._data, Data("Content-Type: multipart/form-data; boundary=\"test\"".utf8))
XCTAssertEqual(multipartFormData.contentType.data, Data("Content-Type: multipart/form-data; boundary=\"test\"".utf8))
}

func testHTTPBodyGeneration() throws {
Expand Down
2 changes: 1 addition & 1 deletion Tests/MultipartFormDataTests/SubpartTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class SubpartTests: XCTestCase {
"",
"a",
].joined(separator: "\r\n").utf8)
XCTAssertEqual(subpart._data, expectedData)
XCTAssertEqual(subpart.data, expectedData)
}

func testDebugDescription() {
Expand Down