swift-nio/Sources/NIOWebSocket/WebSocketErrorCodes.swift

189 lines
6.5 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2021 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import NIOCore
/// An enum that represents websocket error codes.
///
/// This enum provides names to all non-reserved code numbers,
/// to avoid users needing to remember the specific numerical values
/// of those codes.
public enum WebSocketErrorCode {
/// Indicates a normal closure, meaning that the purpose for
/// which the connection was established has been fulfilled.
/// Corresponds to code 1000.
case normalClosure
/// Ondicates that an endpoint is "going away", such as a server
/// going down or a browser having navigated away from a page.
/// Corresponds to code 1001.
case goingAway
/// Indicates that an endpoint is terminating the connection due
/// to a protocol error.
/// Corresponds to code 1002.
case protocolError
/// Indicates that an endpoint is terminating the connection
/// because it has received a type of data it cannot accept (e.g. an
/// endpoint that understands only text data may send this if it
/// receives a binary message).
/// Corresponds to code 1003.
case unacceptableData
/// Indicates that an endpoint is terminating the connection
/// because it has received data within a message that was not
/// consistent with the type of the message (e.g. non-UTF-8
/// data within a text message).
/// Corresponds to code 1007.
case dataInconsistentWithMessage
/// Indicates that an endpoint is terminating the connection
/// because it has received a message that violates its policy. This
/// is a generic status code that can be returned when there is no
/// other more suitable status code (e.g. 1003 or 1009) or if there
/// is a need to hide specific details about the policy.
/// Corresponds to code 1008.
case policyViolation
/// Indicates that an endpoint is terminating the connection
/// because it has received a message that is too big for it to
/// process.
/// Corresponds to code 1009.
case messageTooLarge
/// Indicates that an endpoint (client) is terminating the
/// connection because it has expected the server to negotiate one or
/// more extension, but the server didn't return them in the response
/// message of the WebSocket handshake. The list of extensions that
/// are needed should appear in the `reason` part of the Close frame.
/// Note that this status code is not used by the server, because it
/// can fail the WebSocket handshake instead.
/// Corresponds to code 1010.
case missingExtension
/// Indicates that a server is terminating the connection because
/// it encountered an unexpected condition that prevented it from
/// fulfilling the request.
/// Corresponds to code 1011.
case unexpectedServerError
/// We don't have a better name for this error code.
case unknown(UInt16)
/// Create an error code from a raw 16-bit integer as sent on the
/// network.
///
/// - parameters:
/// integer: The integer form of the status code.
internal init(networkInteger integer: UInt16) {
switch integer {
case 1000:
self = .normalClosure
case 1001:
self = .goingAway
case 1002:
self = .protocolError
case 1003:
self = .unacceptableData
case 1007:
self = .dataInconsistentWithMessage
case 1008:
self = .policyViolation
case 1009:
self = .messageTooLarge
case 1010:
self = .missingExtension
case 1011:
self = .unexpectedServerError
default:
self = .unknown(integer)
}
}
/// Create an error code from an integer.
///
/// Will trap if the error code is not in the valid range.
///
/// - parameters:
/// - codeNumber: The integer form of the status code.
public init(codeNumber: Int) {
self.init(networkInteger: UInt16(codeNumber))
}
}
extension WebSocketErrorCode: Equatable {}
extension ByteBuffer {
/// Read a websocket error code from a byte buffer.
///
/// This method increments the reader index.
///
/// - returns: The error code, or `nil` if there were not enough readable bytes.
public mutating func readWebSocketErrorCode() -> WebSocketErrorCode? {
return self.readInteger(as: UInt16.self).map { WebSocketErrorCode(networkInteger: $0) }
}
/// Get a websocket error code from a byte buffer.
///
/// This method does not increment the reader index, and may be used to read an error
/// code from outside the readable range of bytes.
///
/// - parameters:
/// - index: The index into the buffer to read the error code from.
/// - returns: The error code, or `nil` if there were not enough bytes at that index.
public func getWebSocketErrorCode(at index: Int) -> WebSocketErrorCode? {
return self.getInteger(at: index, as: UInt16.self).map { WebSocketErrorCode(networkInteger: $0) }
}
/// Write the given error code to the buffer.
///
/// - parameters:
/// - code: The code to write into the buffer.
public mutating func write(webSocketErrorCode code: WebSocketErrorCode) {
self.writeInteger(UInt16(webSocketErrorCode: code))
}
}
extension UInt16 {
/// Create a UInt16 corresponding to a given `WebSocketErrorCode`.
///
/// - parameters:
/// - code: The `WebSocketErrorCode`.
public init(webSocketErrorCode code: WebSocketErrorCode) {
switch code {
case .normalClosure:
self = 1000
case .goingAway:
self = 1001
case .protocolError:
self = 1002
case .unacceptableData:
self = 1003
case .dataInconsistentWithMessage:
self = 1007
case .policyViolation:
self = 1008
case .messageTooLarge:
self = 1009
case .missingExtension:
self = 1010
case .unexpectedServerError:
self = 1011
case .unknown(let i):
self = i
}
}
}