Building42 / Telegraph

Secure Web Server for iOS, tvOS and macOS

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

WebSocket finishing messages that aren't final

Joebayld opened this issue · comments

I've been tracing a bug with the WebSocketParser and I think I've found where it's at. In my app, the client is sending a lot of data quickly to the server, causing some packets to be fragmented. The issue I've found is that telegraph is calling the finishedMessage method on messages that aren't marked final. This is resulting in broken JSON on my app.

When examining the incoming data I can see the split data frames. The WebSocketParser should see that a packet is not final and wait till a message is marked final before firing that message to the delegate. It should just append any packets payload that follows the non-final packet.

I've added this small piece of code to the parser for debugging and it results in a crash.

      case .payload:
        // For now we can only support payloads that can fit into a Data object,
        // if the payload is any bigger we should probably offload it to a temporary file
        let payloadSafeLength = payloadLength > Int.max ? Int.max : Int(payloadLength)

        // Is this the first payload byte?
        if payload.isEmpty {
          payload.reserveCapacity(payloadSafeLength)
        }
        
        // Append the byte we already read
        payload.append(byte)

        // Append any payload bytes available in the stream
        let payloadBytesToRead = payloadSafeLength - payload.count
        payload.append(stream.read(count: payloadBytesToRead))

        // Is the payload complete?
        if payload.count == payloadSafeLength {

            // Are we finished with the packet? <---- THIS IS WHERE THE ISSUE IS
            if !message.finBit {
                fatalError("endOfMessage set when we never recieved the final packet!")
            }
            nextPart = .endOfMessage
        }

Let me know your thoughts and I can take a stab at fixing this.

Ah I just realized this could be intentional as I could check the message.finBit on the delegate call. But then the weird part is that the .continuationFrame is sent as binary (when it is a continuation of the original textFrame)

Nice work on tracking down the issue! The WebSocket implementation of Telegraph is quite basic. You're quite likely to run into a few issues here and there if you use more advanced options.

I'm not quite sure if it should be Telegraph's responsibility to combine the fragmented messages. We could have a look at how other web servers handle that. Maybe the nicest solution would be to have a setting where you can control if Telegraph will automatically handle it for you, and perhaps that should be on by default.