Skip to content

Commit

Permalink
fix: Multipart chunk content type (apollographql/apollo-ios-dev#572)
Browse files Browse the repository at this point in the history
  • Loading branch information
calvincestari authored and gh-action-runner committed Jan 8, 2025
1 parent a94ebd7 commit c17bddf
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 22 deletions.
18 changes: 6 additions & 12 deletions Sources/Apollo/MultipartResponseDeferParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct MultipartResponseDeferParser: MultipartResponseSpecificationParser {
}

private enum DataLine {
case contentHeader(type: String)
case contentHeader(directives: [String])
case json(object: JSONObject)
case unknown

Expand All @@ -32,14 +32,8 @@ struct MultipartResponseDeferParser: MultipartResponseSpecificationParser {
}

private static func parse(_ dataLine: String) -> DataLine {
var contentTypeHeader: StaticString { "content-type:" }

if dataLine.starts(with: contentTypeHeader.description) {
let contentType = (dataLine
.components(separatedBy: ":").last ?? dataLine
).trimmingCharacters(in: .whitespaces)

return .contentHeader(type: contentType)
if let directives = dataLine.parseContentTypeDirectives() {
return .contentHeader(directives: directives)
}

if
Expand All @@ -58,9 +52,9 @@ struct MultipartResponseDeferParser: MultipartResponseSpecificationParser {
static func parse(_ chunk: String) -> Result<Data?, any Error> {
for dataLine in chunk.components(separatedBy: Self.dataLineSeparator.description) {
switch DataLine(dataLine.trimmingCharacters(in: .newlines)) {
case let .contentHeader(type):
guard type == "application/json" else {
return .failure(ParsingError.unsupportedContentType(type: type))
case let .contentHeader(directives):
guard directives.contains("application/json") else {
return .failure(ParsingError.unsupportedContentType(type: directives.joined(separator: ";")))
}

case let .json(object):
Expand Down
12 changes: 12 additions & 0 deletions Sources/Apollo/MultipartResponseParsingInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,16 @@ extension String {

return nil
}

func parseContentTypeDirectives() -> [String]? {
var lowercasedContentTypeHeader: StaticString { "content-type:" }

guard lowercased().starts(with: lowercasedContentTypeHeader.description) else {
return nil
}

return dropFirst(lowercasedContentTypeHeader.description.count)
.components(separatedBy: ";")
.map({ $0.trimmingCharacters(in: .whitespaces) })
}
}
16 changes: 6 additions & 10 deletions Sources/Apollo/MultipartResponseSubscriptionParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct MultipartResponseSubscriptionParser: MultipartResponseSpecificationParser

private enum DataLine {
case heartbeat
case contentHeader(type: String)
case contentHeader(directives: [String])
case json(object: JSONObject)
case unknown

Expand All @@ -46,12 +46,8 @@ struct MultipartResponseSubscriptionParser: MultipartResponseSpecificationParser
return .heartbeat
}

if dataLine.lowercased().starts(with: contentTypeHeader.description) {
let contentType = (dataLine
.components(separatedBy: ":").last ?? dataLine
).trimmingCharacters(in: .whitespaces)

return .contentHeader(type: contentType)
if let directives = dataLine.parseContentTypeDirectives() {
return .contentHeader(directives: directives)
}

if
Expand All @@ -74,9 +70,9 @@ struct MultipartResponseSubscriptionParser: MultipartResponseSpecificationParser
// Periodically sent by the router - noop
break

case let .contentHeader(type):
guard type == "application/json" else {
return .failure(ParsingError.unsupportedContentType(type: type))
case let .contentHeader(directives):
guard directives.contains("application/json") else {
return .failure(ParsingError.unsupportedContentType(type: directives.joined(separator: ";")))
}

case let .json(object):
Expand Down

0 comments on commit c17bddf

Please sign in to comment.