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
10 changes: 10 additions & 0 deletions FlyingFox/Sources/WebSocket/WSFrameValidator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ struct WSFrameValidator: Sendable {

@Sendable
func validateFrame(_ frame: WSFrame) throws -> WSFrame? {
switch frame.opcode {
case .ping, .pong, .close:
// RFC 6455 §5.5: control frame payload MUST be ≤ 125 bytes.
guard frame.payload.count <= 125 else {
throw Error("Control frame payload exceeds 125 bytes")
}
default:
break
}

if frame.opcode == .continuation {
try appendContinuation(frame)
guard let last = last, frame.fin else {
Expand Down
25 changes: 25 additions & 0 deletions FlyingFox/Tests/WebSocket/WSFrameValidatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,31 @@ struct WSFrameValidatorTests {
}
}

@Test
func controlFrames_throwError_whenPayloadExceeds125Bytes() async {
// RFC 6455 §5.5: control frames MUST have payload length ≤ 125 bytes.
let oversized = Data(repeating: 0x41, count: 126)
await #expect(throws: WSFrameValidator.Error.self) {
try await WSFrameValidator.validate([.make(opcode: .ping, payload: oversized)]).collectAll()
}
await #expect(throws: WSFrameValidator.Error.self) {
try await WSFrameValidator.validate([.make(opcode: .pong, payload: oversized)]).collectAll()
}
await #expect(throws: WSFrameValidator.Error.self) {
try await WSFrameValidator.validate([.make(opcode: .close, payload: oversized)]).collectAll()
}
}

@Test
func controlFrames_areAccepted_whenPayloadIsAtMost125Bytes() async throws {
let maxPayload = Data(repeating: 0x41, count: 125)
let ping = WSFrame.make(opcode: .ping, payload: maxPayload)
let emptyPing = WSFrame.make(opcode: .ping)
#expect(
try await WSFrameValidator.validate([ping, emptyPing]).collectAll() == [ping, emptyPing]
)
}

@Test
func controlFrames_ThrowError_WhenNotFin() async {
await #expect(throws: WSFrameValidator.Error.self) {
Expand Down
Loading