/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * http://glassfish.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package javax.websocket; import java.io.UnsupportedEncodingException; /** * A class encapsulating the reason why a web socket has been closed, or why it is being asked to * close. Note the acceptable uses of codes and reason phrase are defined in more detail by * RFC 6455. * * @author dannycoward */ public class CloseReason { private final CloseReason.CloseCode closeCode; private final String reasonPhrase; /** * Creates a reason for closing a web socket connection with the given * code and reason phrase. * * @param closeCode the close code, may not be {@code null} * @param reasonPhrase the reason phrase, may be {@code null}. */ public CloseReason(CloseReason.CloseCode closeCode, String reasonPhrase) { if (closeCode == null) { throw new IllegalArgumentException("closeCode cannot be null"); } try { if (reasonPhrase != null && reasonPhrase.getBytes("UTF-8").length > 123) { throw new IllegalArgumentException("Reason Phrase cannot exceed 123 UTF-8 encoded bytes: " + reasonPhrase); } } catch (UnsupportedEncodingException uee) { throw new IllegalStateException(uee); } this.closeCode = closeCode; this.reasonPhrase = "".equals(reasonPhrase) ? null : reasonPhrase; } /** * The Close code associated with this CloseReason. * * @return the close code. */ public CloseReason.CloseCode getCloseCode() { return this.closeCode; } /** * The reason phrase associated with this CloseReason. * * @return the reason phrase. If there is no reason phrase, this returns * the empty string */ public String getReasonPhrase() { return (this.reasonPhrase == null) ? "" : this.reasonPhrase; } /** * Converts the CloseReason to a debug-friendly string. The exact format * is not defined by the specification and may change in future releases. * * @return A String representation of this CloseReason */ public String toString() { return (this.reasonPhrase == null) ? "CloseReason[" + this.closeCode.getCode() + "]" : "CloseReason[" + this.closeCode.getCode() + "," + reasonPhrase + "]"; } /** * A marker interface for the close codes. This interface may be * implemented by enumerations that contain web socket close codes, for * example enumerations that contain all the in use close codes as of * web socket 1.0, or an enumeration that contains close codes * that are currently reserved for special use by the web socket * specification. */ public interface CloseCode { /** * Returns the code number, for example the integer '1000' for normal closure. * * @return the code number */ int getCode(); } /** * An Enumeration of status codes for a web socket close that * are defined in the specification. */ public enum CloseCodes implements CloseReason.CloseCode { /** * 1000 indicates a normal closure, meaning that the purpose for * which the connection was established has been fulfilled. */ NORMAL_CLOSURE(1000), /** * 1001 indicates that an endpoint is "going away", such as a server * going down or a browser having navigated away from a page. */ GOING_AWAY(1001), /** * 1002 indicates that an endpoint is terminating the connection due * to a protocol error. */ PROTOCOL_ERROR(1002), /** * 1003 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). */ CANNOT_ACCEPT(1003), /** * Reserved. The specific meaning might be defined in the future. */ RESERVED(1004), /** * 1005 is a reserved value and MUST NOT be set as a status code in a * Close control frame by an endpoint. It is designated for use in * applications expecting a status code to indicate that no status * code was actually present. */ NO_STATUS_CODE(1005), /** * 1006 is a reserved value and MUST NOT be set as a status code in a * Close control frame by an endpoint. It is designated for use in * applications expecting a status code to indicate that the * connection was closed abnormally, e.g., without sending or * receiving a Close control frame. */ CLOSED_ABNORMALLY(1006), /** * 1007 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). */ NOT_CONSISTENT(1007), /** * 1008 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. */ VIOLATED_POLICY(1008), /** * 1009 indicates that an endpoint is terminating the connection * because it has received a message that is too big for it to * process. */ TOO_BIG(1009), /** * 1010 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. */ NO_EXTENSION(1010), /** * 1011 indicates that a server is terminating the connection because * it encountered an unexpected condition that prevented it from * fulfilling the request. */ UNEXPECTED_CONDITION(1011), /** * 1012 indicates that the service will be restarted. */ SERVICE_RESTART(1012), /** * 1013 indicates that the service is experiencing overload */ TRY_AGAIN_LATER(1013), /** * 1015 is a reserved value and MUST NOT be set as a status code in a * Close control frame by an endpoint. It is designated for use in * applications expecting a status code to indicate that the * connection was closed due to a failure to perform a TLS handshake * (e.g., the server certificate can't be verified). */ TLS_HANDSHAKE_FAILURE(1015); /** * Creates a CloseCode from the given int code number. This method throws * an IllegalArgumentException if the int is not one of the * * @param code the integer code number * @return a new CloseCode with the given code number * @throws IllegalArgumentException if the code is not a valid close code */ public static CloseReason.CloseCode getCloseCode(final int code) { if (code < 1000 || code > 4999) { throw new IllegalArgumentException("Invalid code: " + code); } switch (code) { case 1000: return CloseReason.CloseCodes.NORMAL_CLOSURE; case 1001: return CloseReason.CloseCodes.GOING_AWAY; case 1002: return CloseReason.CloseCodes.PROTOCOL_ERROR; case 1003: return CloseReason.CloseCodes.CANNOT_ACCEPT; case 1004: return CloseReason.CloseCodes.RESERVED; case 1005: return CloseReason.CloseCodes.NO_STATUS_CODE; case 1006: return CloseReason.CloseCodes.CLOSED_ABNORMALLY; case 1007: return CloseReason.CloseCodes.NOT_CONSISTENT; case 1008: return CloseReason.CloseCodes.VIOLATED_POLICY; case 1009: return CloseReason.CloseCodes.TOO_BIG; case 1010: return CloseReason.CloseCodes.NO_EXTENSION; case 1011: return CloseReason.CloseCodes.UNEXPECTED_CONDITION; case 1012: return CloseReason.CloseCodes.SERVICE_RESTART; case 1013: return CloseReason.CloseCodes.TRY_AGAIN_LATER; case 1015: return CloseReason.CloseCodes.TLS_HANDSHAKE_FAILURE; } return new CloseReason.CloseCode() { @Override public int getCode() { return code; } }; } CloseCodes(int code) { this.code = code; } /** * Return the code number of this status code. * * @return the code. */ @Override public int getCode() { return code; } private int code; } }