/* | 
|
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package javax.net.ssl;  | 
|
import java.util.Arrays;  | 
|
/** | 
|
 * Instances of this class represent a server name in a Server Name | 
|
 * Indication (SNI) extension. | 
|
 * <P> | 
|
 * The SNI extension is a feature that extends the SSL/TLS protocols to | 
|
 * indicate what server name the client is attempting to connect to during | 
|
 * handshaking.  See section 3, "Server Name Indication", of <A | 
|
 * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions (RFC 6066)</A>. | 
|
 * <P> | 
|
 * {@code SNIServerName} objects are immutable.  Subclasses should not provide | 
|
 * methods that can change the state of an instance once it has been created. | 
|
 * | 
|
 * @see SSLParameters#getServerNames() | 
|
 * @see SSLParameters#setServerNames(List) | 
|
 * | 
|
 * @since 1.8 | 
|
*/  | 
|
public abstract class SNIServerName { | 
|
    // the type of the server name | 
|
private final int type;  | 
|
    // the encoded value of the server name | 
|
private final byte[] encoded;  | 
|
    // the hex digitals | 
|
private static final char[] HEXES = "0123456789ABCDEF".toCharArray();  | 
|
    /** | 
|
     * Creates an {@code SNIServerName} using the specified name type and | 
|
     * encoded value. | 
|
     * <P> | 
|
     * Note that the {@code encoded} byte array is cloned to protect against | 
|
     * subsequent modification. | 
|
     * | 
|
     * @param  type | 
|
     *         the type of the server name | 
|
     * @param  encoded | 
|
     *         the encoded value of the server name | 
|
     * | 
|
     * @throws IllegalArgumentException if {@code type} is not in the range | 
|
     *         of 0 to 255, inclusive. | 
|
     * @throws NullPointerException if {@code encoded} is null | 
|
*/  | 
|
    protected SNIServerName(int type, byte[] encoded) { | 
|
if (type < 0) {  | 
|
throw new IllegalArgumentException(  | 
|
                "Server name type cannot be less than zero"); | 
|
} else if (type > 255) {  | 
|
throw new IllegalArgumentException(  | 
|
                "Server name type cannot be greater than 255"); | 
|
}  | 
|
this.type = type;  | 
|
if (encoded == null) {  | 
|
throw new NullPointerException(  | 
|
                "Server name encoded value cannot be null"); | 
|
}  | 
|
this.encoded = encoded.clone();  | 
|
}  | 
|
    /** | 
|
     * Returns the name type of this server name. | 
|
     * | 
|
     * @return the name type of this server name | 
|
*/  | 
|
    public final int getType() { | 
|
return type;  | 
|
}  | 
|
    /** | 
|
     * Returns a copy of the encoded server name value of this server name. | 
|
     * | 
|
     * @return a copy of the encoded server name value of this server name | 
|
*/  | 
|
    public final byte[] getEncoded() { | 
|
return encoded.clone();  | 
|
}  | 
|
    /** | 
|
     * Indicates whether some other object is "equal to" this server name. | 
|
     * | 
|
     * @return true if, and only if, {@code other} is of the same class | 
|
     *         of this object, and has the same name type and | 
|
     *         encoded value as this server name. | 
|
*/  | 
|
@Override  | 
|
public boolean equals(Object other) {  | 
|
if (this == other) {  | 
|
return true;  | 
|
}  | 
|
if (this.getClass() != other.getClass()) {  | 
|
return false;  | 
|
}  | 
|
SNIServerName that = (SNIServerName)other;  | 
|
return (this.type == that.type) &&  | 
|
Arrays.equals(this.encoded, that.encoded);  | 
|
}  | 
|
    /** | 
|
     * Returns a hash code value for this server name. | 
|
     * <P> | 
|
     * The hash code value is generated using the name type and encoded | 
|
     * value of this server name. | 
|
     * | 
|
     * @return a hash code value for this server name. | 
|
*/  | 
|
@Override  | 
|
    public int hashCode() { | 
|
        int result = 17;    // 17/31: prime number to decrease collisions | 
|
result = 31 * result + type;  | 
|
result = 31 * result + Arrays.hashCode(encoded);  | 
|
return result;  | 
|
}  | 
|
    /** | 
|
     * Returns a string representation of this server name, including the server | 
|
     * name type and the encoded server name value in this | 
|
     * {@code SNIServerName} object. | 
|
     * <P> | 
|
     * The exact details of the representation are unspecified and subject | 
|
     * to change, but the following may be regarded as typical: | 
|
     * <pre> | 
|
     *     "type={@literal <name type>}, value={@literal <name value>}" | 
|
     * </pre> | 
|
     * <P> | 
|
     * In this class, the format of "{@literal <name type>}" is | 
|
     * "[LITERAL] (INTEGER)", where the optional "LITERAL" is the literal | 
|
     * name, and INTEGER is the integer value of the name type.  The format | 
|
     * of "{@literal <name value>}" is "XX:...:XX", where "XX" is the | 
|
     * hexadecimal digit representation of a byte value. For example, a | 
|
     * returned value of an pseudo server name may look like: | 
|
     * <pre> | 
|
     *     "type=(31), value=77:77:77:2E:65:78:61:6D:70:6C:65:2E:63:6E" | 
|
     * </pre> | 
|
     * or | 
|
     * <pre> | 
|
     *     "type=host_name (0), value=77:77:77:2E:65:78:61:6D:70:6C:65:2E:63:6E" | 
|
     * </pre> | 
|
     * | 
|
     * <P> | 
|
     * Please NOTE that the exact details of the representation are unspecified | 
|
     * and subject to change, and subclasses may override the method with | 
|
     * their own formats. | 
|
     * | 
|
     * @return a string representation of this server name | 
|
*/  | 
|
@Override  | 
|
public String toString() {  | 
|
if (type == StandardConstants.SNI_HOST_NAME) {  | 
|
return "type=host_name (0), value=" + toHexString(encoded);  | 
|
        } else { | 
|
return "type=(" + type + "), value=" + toHexString(encoded);  | 
|
}  | 
|
}  | 
|
    // convert byte array to hex string | 
|
private static String toHexString(byte[] bytes) {  | 
|
if (bytes.length == 0) {  | 
|
            return "(empty)"; | 
|
}  | 
|
StringBuilder sb = new StringBuilder(bytes.length * 3 - 1);  | 
|
boolean isInitial = true;  | 
|
for (byte b : bytes) {  | 
|
if (isInitial) {  | 
|
isInitial = false;  | 
|
            } else { | 
|
sb.append(':');  | 
|
}  | 
|
int k = b & 0xFF;  | 
|
sb.append(HEXES[k >>> 4]);  | 
|
sb.append(HEXES[k & 0xF]);  | 
|
}  | 
|
return sb.toString();  | 
|
}  | 
|
}  | 
|