1 /* 2 * Copyright 2019 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package io.netty5.handler.codec.http.websocketx; 17 18 import java.util.Objects; 19 20 /** 21 * WebSocket status codes specified in RFC-6455. 22 * <pre> 23 * 24 * RFC-6455 The WebSocket Protocol, December 2011: 25 * <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" 26 * >https://tools.ietf.org/html/rfc6455#section-7.4.1</a> 27 * 28 * WebSocket Protocol Registries, April 2019: 29 * <a href="https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number" 30 * >https://www.iana.org/assignments/websocket/websocket.xhtml</a> 31 * 32 * 7.4.1. Defined Status Codes 33 * 34 * Endpoints MAY use the following pre-defined status codes when sending 35 * a Close frame. 36 * 37 * 1000 38 * 39 * 1000 indicates a normal closure, meaning that the purpose for 40 * which the connection was established has been fulfilled. 41 * 42 * 1001 43 * 44 * 1001 indicates that an endpoint is "going away", such as a server 45 * going down or a browser having navigated away from a page. 46 * 47 * 1002 48 * 49 * 1002 indicates that an endpoint is terminating the connection due 50 * to a protocol error. 51 * 52 * 1003 53 * 54 * 1003 indicates that an endpoint is terminating the connection 55 * because it has received a type of data it cannot accept (e.g., an 56 * endpoint that understands only text data MAY send this if it 57 * receives a binary message). 58 * 59 * 1004 60 * 61 * Reserved. The specific meaning might be defined in the future. 62 * 63 * 1005 64 * 65 * 1005 is a reserved value and MUST NOT be set as a status code in a 66 * Close control frame by an endpoint. It is designated for use in 67 * applications expecting a status code to indicate that no status 68 * code was actually present. 69 * 70 * 1006 71 * 72 * 1006 is a reserved value and MUST NOT be set as a status code in a 73 * Close control frame by an endpoint. It is designated for use in 74 * applications expecting a status code to indicate that the 75 * connection was closed abnormally, e.g., without sending or 76 * receiving a Close control frame. 77 * 78 * 1007 79 * 80 * 1007 indicates that an endpoint is terminating the connection 81 * because it has received data within a message that was not 82 * consistent with the type of the message (e.g., non-UTF-8 [RFC3629] 83 * data within a text message). 84 * 85 * 1008 86 * 87 * 1008 indicates that an endpoint is terminating the connection 88 * because it has received a message that violates its policy. This 89 * is a generic status code that can be returned when there is no 90 * other more suitable status code (e.g., 1003 or 1009) or if there 91 * is a need to hide specific details about the policy. 92 * 93 * 1009 94 * 95 * 1009 indicates that an endpoint is terminating the connection 96 * because it has received a message that is too big for it to 97 * process. 98 * 99 * 1010 100 * 101 * 1010 indicates that an endpoint (client) is terminating the 102 * connection because it has expected the server to negotiate one or 103 * more extension, but the server didn't return them in the response 104 * message of the WebSocket handshake. The list of extensions that 105 * are needed SHOULD appear in the /reason/ part of the Close frame. 106 * Note that this status code is not used by the server, because it 107 * can fail the WebSocket handshake instead. 108 * 109 * 1011 110 * 111 * 1011 indicates that a server is terminating the connection because 112 * it encountered an unexpected condition that prevented it from 113 * fulfilling the request. 114 * 115 * 1012 (IANA Registry, Non RFC-6455) 116 * 117 * 1012 indicates that the service is restarted. a client may reconnect, 118 * and if it choses to do, should reconnect using a randomized delay 119 * of 5 - 30 seconds. 120 * 121 * 1013 (IANA Registry, Non RFC-6455) 122 * 123 * 1013 indicates that the service is experiencing overload. a client 124 * should only connect to a different IP (when there are multiple for the 125 * target) or reconnect to the same IP upon user action. 126 * 127 * 1014 (IANA Registry, Non RFC-6455) 128 * 129 * The server was acting as a gateway or proxy and received an invalid 130 * response from the upstream server. This is similar to 502 HTTP Status Code. 131 * 132 * 1015 133 * 134 * 1015 is a reserved value and MUST NOT be set as a status code in a 135 * Close control frame by an endpoint. It is designated for use in 136 * applications expecting a status code to indicate that the 137 * connection was closed due to a failure to perform a TLS handshake 138 * (e.g., the server certificate can't be verified). 139 * 140 * 141 * 7.4.2. Reserved Status Code Ranges 142 * 143 * 0-999 144 * 145 * Status codes in the range 0-999 are not used. 146 * 147 * 1000-2999 148 * 149 * Status codes in the range 1000-2999 are reserved for definition by 150 * this protocol, its future revisions, and extensions specified in a 151 * permanent and readily available public specification. 152 * 153 * 3000-3999 154 * 155 * Status codes in the range 3000-3999 are reserved for use by 156 * libraries, frameworks, and applications. These status codes are 157 * registered directly with IANA. The interpretation of these codes 158 * is undefined by this protocol. 159 * 160 * 4000-4999 161 * 162 * Status codes in the range 4000-4999 are reserved for private use 163 * and thus can't be registered. Such codes can be used by prior 164 * agreements between WebSocket applications. The interpretation of 165 * these codes is undefined by this protocol. 166 * </pre> 167 * <p> 168 * While {@link WebSocketCloseStatus} is enum-like structure, its instances should NOT be compared by reference. 169 * Instead, either {@link #equals(Object)} should be used or direct comparison of {@link #code()} value. 170 */ 171 public final class WebSocketCloseStatus implements Comparable<WebSocketCloseStatus> { 172 173 public static final WebSocketCloseStatus NORMAL_CLOSURE = 174 new WebSocketCloseStatus(1000, "Bye"); 175 176 public static final WebSocketCloseStatus ENDPOINT_UNAVAILABLE = 177 new WebSocketCloseStatus(1001, "Endpoint unavailable"); 178 179 public static final WebSocketCloseStatus PROTOCOL_ERROR = 180 new WebSocketCloseStatus(1002, "Protocol error"); 181 182 public static final WebSocketCloseStatus INVALID_MESSAGE_TYPE = 183 new WebSocketCloseStatus(1003, "Invalid message type"); 184 185 public static final WebSocketCloseStatus INVALID_PAYLOAD_DATA = 186 new WebSocketCloseStatus(1007, "Invalid payload data"); 187 188 public static final WebSocketCloseStatus POLICY_VIOLATION = 189 new WebSocketCloseStatus(1008, "Policy violation"); 190 191 public static final WebSocketCloseStatus MESSAGE_TOO_BIG = 192 new WebSocketCloseStatus(1009, "Message too big"); 193 194 public static final WebSocketCloseStatus MANDATORY_EXTENSION = 195 new WebSocketCloseStatus(1010, "Mandatory extension"); 196 197 public static final WebSocketCloseStatus INTERNAL_SERVER_ERROR = 198 new WebSocketCloseStatus(1011, "Internal server error"); 199 200 public static final WebSocketCloseStatus SERVICE_RESTART = 201 new WebSocketCloseStatus(1012, "Service Restart"); 202 203 public static final WebSocketCloseStatus TRY_AGAIN_LATER = 204 new WebSocketCloseStatus(1013, "Try Again Later"); 205 206 public static final WebSocketCloseStatus BAD_GATEWAY = 207 new WebSocketCloseStatus(1014, "Bad Gateway"); 208 209 // 1004, 1005, 1006, 1015 are reserved and should never be used by user 210 //public static final WebSocketCloseStatus SPECIFIC_MEANING = register(1004, "..."); 211 212 public static final WebSocketCloseStatus EMPTY = 213 new WebSocketCloseStatus(1005, "Empty", false); 214 215 public static final WebSocketCloseStatus ABNORMAL_CLOSURE = 216 new WebSocketCloseStatus(1006, "Abnormal closure", false); 217 218 public static final WebSocketCloseStatus TLS_HANDSHAKE_FAILED = 219 new WebSocketCloseStatus(1015, "TLS handshake failed", false); 220 221 private final int statusCode; 222 private final String reasonText; 223 private String text; 224 225 public WebSocketCloseStatus(int statusCode, String reasonText) { 226 this(statusCode, reasonText, true); 227 } 228 229 public WebSocketCloseStatus(int statusCode, String reasonText, boolean validate) { 230 if (validate && !isValidStatusCode(statusCode)) { 231 throw new IllegalArgumentException( 232 "WebSocket close status code does NOT comply with RFC-6455: " + statusCode); 233 } 234 this.statusCode = statusCode; 235 this.reasonText = Objects.requireNonNull(reasonText, "reasonText"); 236 } 237 238 public int code() { 239 return statusCode; 240 } 241 242 public String reasonText() { 243 return reasonText; 244 } 245 246 /** 247 * Order of {@link WebSocketCloseStatus} only depends on {@link #code()}. 248 */ 249 @Override 250 public int compareTo(WebSocketCloseStatus o) { 251 return code() - o.code(); 252 } 253 254 /** 255 * Equality of {@link WebSocketCloseStatus} only depends on {@link #code()}. 256 */ 257 @Override 258 public boolean equals(Object o) { 259 if (this == o) { 260 return true; 261 } 262 if (null == o || getClass() != o.getClass()) { 263 return false; 264 } 265 266 WebSocketCloseStatus that = (WebSocketCloseStatus) o; 267 268 return statusCode == that.statusCode; 269 } 270 271 @Override 272 public int hashCode() { 273 return statusCode; 274 } 275 276 @Override 277 public String toString() { 278 String text = this.text; 279 if (text == null) { 280 // E.g.: "1000 Bye", "1009 Message too big" 281 this.text = text = code() + " " + reasonText(); 282 } 283 return text; 284 } 285 286 public static boolean isValidStatusCode(int code) { 287 return code < 0 || 288 1000 <= code && code <= 1003 || 289 1007 <= code && code <= 1014 || 290 3000 <= code; 291 } 292 293 public static WebSocketCloseStatus valueOf(int code) { 294 switch (code) { 295 case 1000: 296 return NORMAL_CLOSURE; 297 case 1001: 298 return ENDPOINT_UNAVAILABLE; 299 case 1002: 300 return PROTOCOL_ERROR; 301 case 1003: 302 return INVALID_MESSAGE_TYPE; 303 case 1005: 304 return EMPTY; 305 case 1006: 306 return ABNORMAL_CLOSURE; 307 case 1007: 308 return INVALID_PAYLOAD_DATA; 309 case 1008: 310 return POLICY_VIOLATION; 311 case 1009: 312 return MESSAGE_TOO_BIG; 313 case 1010: 314 return MANDATORY_EXTENSION; 315 case 1011: 316 return INTERNAL_SERVER_ERROR; 317 case 1012: 318 return SERVICE_RESTART; 319 case 1013: 320 return TRY_AGAIN_LATER; 321 case 1014: 322 return BAD_GATEWAY; 323 case 1015: 324 return TLS_HANDSHAKE_FAILED; 325 default: 326 return new WebSocketCloseStatus(code, "Close status #" + code); 327 } 328 } 329 330 }