Skip to content

MultipartResponseParsing.DataLineIterator.next() produces infinite loop in some cases #3608

@frehulfd

Description

@frehulfd

Summary

In certain configurations during multipart body message passing, in this case a subscription, if a new chunk only has one CRLF at the end, the DataLineIterator will return the same DataLine forever.

Relevant Source:

guard let separatorRange = data.firstRange(of: Self.DataLineSeparator) else {
return data
}

Version

2.0.2

Steps to reproduce the behavior

Example stream:

--graphql
content-type: application/json

{}
--graphql
content-type: application/json

{"payload":{"data":{"conversationNewMessage":{"__typename":"ConversationNewMessagePayload","message":{"__typename":"ConversationMessage","text":"This is a Test122","conversationId":"don-chat-id"}}},"extensions":{"cost":{"config-graphql-api":{"actualQueryCost":1,"maxQueryCost":200,"requestedQueryCost":6}}}}}
--graphql
content-type: application/json

{}
--graphql
content-type: application/json

{}
--graphql
content-type: application/json

{}
--graphql
content-type: application/json

{"payload":{"data":null,"errors":[{"message":"the connection has been closed because it hasn't heartbeat for a while","extensions":{"code":"SUBSCRIPTION_HEARTBEAT_ERROR"}}],"extensions":{"cost":{"config-graphql-api":{"actualQueryCost":1,"maxQueryCost":200,"requestedQueryCost":6}}}}}
--graphql--

Parsing will loop infinitely on the first heartbeat.

Should probably be something like:

guard let separatorRange = data.firstRange(of: Self.DataLineSeparator) else {
    let fullData = data
    data = Data()
    return fullData
}

Logs

Anything else?

No response

Metadata

Metadata

Assignees

Labels

bugGenerally incorrect behaviorneeds investigationplanned-nextSlated to be included in the next release

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions