Skip to content

Commit 92d43d4

Browse files
committed
WSCloseCode
1 parent 561c770 commit 92d43d4

File tree

8 files changed

+81
-16
lines changed

8 files changed

+81
-16
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//
2+
// WSCloseCode.swift
3+
// FlyingFox
4+
//
5+
// Created by Simon Whitty on 04/03/2025.
6+
// Copyright © 2025 Simon Whitty. All rights reserved.
7+
//
8+
// Distributed under the permissive MIT license
9+
// Get the latest version from here:
10+
//
11+
// https://github.com/swhitty/FlyingFox
12+
//
13+
// Permission is hereby granted, free of charge, to any person obtaining a copy
14+
// of this software and associated documentation files (the "Software"), to deal
15+
// in the Software without restriction, including without limitation the rights
16+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
// copies of the Software, and to permit persons to whom the Software is
18+
// furnished to do so, subject to the following conditions:
19+
//
20+
// The above copyright notice and this permission notice shall be included in all
21+
// copies or substantial portions of the Software.
22+
//
23+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29+
// SOFTWARE.
30+
//
31+
32+
import Foundation
33+
34+
public struct WSCloseCode: RawRepresentable, Sendable, Hashable {
35+
public var rawValue: UInt16
36+
37+
public init(rawValue: UInt16) {
38+
self.rawValue = rawValue
39+
}
40+
41+
public init(_ code: UInt16) {
42+
self.rawValue = code
43+
}
44+
}
45+
46+
public extension WSCloseCode {
47+
// The following codes are based on:
48+
// https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
49+
50+
static let normalClosure = WSCloseCode(1000)
51+
static let goingAway = WSCloseCode(1001)
52+
static let protocolError = WSCloseCode(1002)
53+
static let unsupportedData = WSCloseCode(1003)
54+
static let noStatusReceived = WSCloseCode(1005)
55+
static let abnormalClosure = WSCloseCode(1006)
56+
static let invalidFramePayloadData = WSCloseCode(1007)
57+
static let policyViolation = WSCloseCode(1008)
58+
static let messageTooBig = WSCloseCode(1009)
59+
static let mandatoryExtensionMissing = WSCloseCode(1010)
60+
static let internalServerError = WSCloseCode(1011)
61+
static let serviceRestart = WSCloseCode(1012)
62+
static let tryAgainLater = WSCloseCode(1013)
63+
static let badGateway = WSCloseCode(1014)
64+
static let tlsHandshakeFailure = WSCloseCode(1015)
65+
}

FlyingFox/Sources/WebSocket/WSFrame.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ public struct WSFrame: Sendable, Hashable {
9393
public extension WSFrame {
9494
static func close(message: String = "", mask: Mask? = nil) -> Self {
9595
close(
96-
code: message.isEmpty ? 1000 : 1002,
96+
code: message.isEmpty ? .normalClosure : .protocolError,
9797
message: message,
9898
mask: mask
9999
)
100100
}
101101

102-
static func close(code: UInt16, message: String, mask: Mask? = nil) -> Self {
103-
var payload = Data([UInt8(code >> 8), UInt8(code & 0xFF)])
102+
static func close(code: WSCloseCode, message: String, mask: Mask? = nil) -> Self {
103+
var payload = Data([UInt8(code.rawValue >> 8), UInt8(code.rawValue & 0xFF)])
104104
if let data = message.data(using: .utf8) {
105105
payload.append(contentsOf: data)
106106
}

FlyingFox/Sources/WebSocket/WSHandler.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,16 @@ public struct MessageFrameWSHandler: WSHandler {
147147
}
148148
}
149149

150-
func makeCloseCode(from payload: Data) throws -> (UInt16, String) {
150+
func makeCloseCode(from payload: Data) throws -> (WSCloseCode, String) {
151151
guard payload.count >= 2 else {
152-
return (1005, "")
152+
return (.noStatusReceived, "")
153153
}
154154

155-
let code = payload.withUnsafeBytes { $0.load(as: UInt16.self).bigEndian }
155+
let statusCode = payload.withUnsafeBytes { $0.load(as: UInt16.self).bigEndian }
156156
guard let reason = String(data: payload.dropFirst(2), encoding: .utf8) else {
157157
throw FrameError.invalid("Invalid UTF8 Sequence")
158158
}
159-
return (code, reason)
159+
return (WSCloseCode(statusCode), reason)
160160
}
161161

162162
func makeResponseFrames(for frame: WSFrame) throws -> WSFrame? {

FlyingFox/Sources/WebSocket/WSMessage.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import Foundation
3434
public enum WSMessage: @unchecked Sendable, Hashable {
3535
case text(String)
3636
case data(Data)
37-
case close(code: UInt16 = 1000, reason: String = "")
37+
case close(code: WSCloseCode = .normalClosure, reason: String = "")
3838
}
3939

4040
public protocol WSMessageHandler: Sendable {

FlyingFox/Tests/WebSocket/WSFrameTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ struct WSFrameTests {
7070
)
7171
)
7272
#expect(
73-
WSFrame.close(code: 4999, message: "Err") == .make(
73+
WSFrame.close(code: WSCloseCode(4999), message: "Err") == .make(
7474
fin: true,
7575
opcode: .close,
7676
mask: nil,
7777
payload: Data([0x13, 0x87, .ascii("E"), .ascii("r"), .ascii("r")])
7878
)
7979
)
8080
#expect(
81-
WSFrame.close(code: 4999, message: "Err", mask: .mock) == .make(
81+
WSFrame.close(code: WSCloseCode(4999), message: "Err", mask: .mock) == .make(
8282
fin: true,
8383
opcode: .close,
8484
mask: .mock,

FlyingFox/Tests/WebSocket/WSHandlerTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ struct WSHandlerTests {
6363

6464
#expect(
6565
try handler.makeMessage(for: .make(fin: true, opcode: .close, payload: payload)) ==
66-
.close(code: 4999, reason: "fish")
66+
.close(code: WSCloseCode(4999), reason: "fish")
6767
)
6868
#expect(
6969
try handler.makeMessage(for: .make(fin: true, opcode: .close)) ==
70-
.close(code: 1005, reason: "")
70+
.close(code: .noStatusReceived, reason: "")
7171
)
7272
}
7373

FlyingFox/XCTests/WebSocket/WSFrameTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ final class WSFrameTests: XCTestCase {
6565
payload: Data([0x03, 0xEA, .ascii("E"), .ascii("r"), .ascii("r")]))
6666
)
6767
XCTAssertEqual(
68-
WSFrame.close(code: 4999, message: "Err"),
68+
WSFrame.close(code: WSCloseCode(4999), message: "Err"),
6969
.make(
7070
fin: true,
7171
opcode: .close,
@@ -74,7 +74,7 @@ final class WSFrameTests: XCTestCase {
7474
)
7575
)
7676
XCTAssertEqual(
77-
WSFrame.close(code: 4999, message: "Err", mask: .mock),
77+
WSFrame.close(code: WSCloseCode(4999), message: "Err", mask: .mock),
7878
.make(
7979
fin: true,
8080
opcode: .close,

FlyingFox/XCTests/WebSocket/WSHandlerTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ final class WSHandlerTests: XCTestCase {
6565

6666
XCTAssertEqual(
6767
try handler.makeMessage(for: .make(fin: true, opcode: .close, payload: payload)),
68-
.close(code: 4999, reason: "fish")
68+
.close(code: WSCloseCode(4999), reason: "fish")
6969
)
7070
XCTAssertEqual(
7171
try handler.makeMessage(for: .make(fin: true, opcode: .close)),
72-
.close(code: 1005, reason: "")
72+
.close(code: .noStatusReceived, reason: "")
7373
)
7474
}
7575

0 commit comments

Comments
 (0)