1 /* 2 * Copyright 2014 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 * http://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.netty.handler.ssl; 17 18 import java.util.Collections; 19 import java.util.List; 20 21 import javax.net.ssl.SSLEngine; 22 23 import static io.netty.handler.ssl.ApplicationProtocolUtil.toList; 24 import static io.netty.util.internal.ObjectUtil.checkNotNull; 25 26 /** 27 * Provides an {@link SSLEngine} agnostic way to configure a {@link ApplicationProtocolNegotiator}. 28 */ 29 public final class ApplicationProtocolConfig { 30 31 /** 32 * The configuration that disables application protocol negotiation. 33 */ 34 public static final ApplicationProtocolConfig DISABLED = new ApplicationProtocolConfig(); 35 36 private final List<String> supportedProtocols; 37 private final Protocol protocol; 38 private final SelectorFailureBehavior selectorBehavior; 39 private final SelectedListenerFailureBehavior selectedBehavior; 40 41 /** 42 * Create a new instance. 43 * @param protocol The application protocol functionality to use. 44 * @param selectorBehavior How the peer selecting the protocol should behave. 45 * @param selectedBehavior How the peer being notified of the selected protocol should behave. 46 * @param supportedProtocols The order of iteration determines the preference of support for protocols. 47 */ 48 public ApplicationProtocolConfig(Protocol protocol, SelectorFailureBehavior selectorBehavior, 49 SelectedListenerFailureBehavior selectedBehavior, Iterable<String> supportedProtocols) { 50 this(protocol, selectorBehavior, selectedBehavior, toList(supportedProtocols)); 51 } 52 53 /** 54 * Create a new instance. 55 * @param protocol The application protocol functionality to use. 56 * @param selectorBehavior How the peer selecting the protocol should behave. 57 * @param selectedBehavior How the peer being notified of the selected protocol should behave. 58 * @param supportedProtocols The order of iteration determines the preference of support for protocols. 59 */ 60 public ApplicationProtocolConfig(Protocol protocol, SelectorFailureBehavior selectorBehavior, 61 SelectedListenerFailureBehavior selectedBehavior, String... supportedProtocols) { 62 this(protocol, selectorBehavior, selectedBehavior, toList(supportedProtocols)); 63 } 64 65 /** 66 * Create a new instance. 67 * @param protocol The application protocol functionality to use. 68 * @param selectorBehavior How the peer selecting the protocol should behave. 69 * @param selectedBehavior How the peer being notified of the selected protocol should behave. 70 * @param supportedProtocols The order of iteration determines the preference of support for protocols. 71 */ 72 private ApplicationProtocolConfig( 73 Protocol protocol, SelectorFailureBehavior selectorBehavior, 74 SelectedListenerFailureBehavior selectedBehavior, List<String> supportedProtocols) { 75 this.supportedProtocols = Collections.unmodifiableList(checkNotNull(supportedProtocols, "supportedProtocols")); 76 this.protocol = checkNotNull(protocol, "protocol"); 77 this.selectorBehavior = checkNotNull(selectorBehavior, "selectorBehavior"); 78 this.selectedBehavior = checkNotNull(selectedBehavior, "selectedBehavior"); 79 80 if (protocol == Protocol.NONE) { 81 throw new IllegalArgumentException("protocol (" + Protocol.NONE + ") must not be " + Protocol.NONE + '.'); 82 } 83 if (supportedProtocols.isEmpty()) { 84 throw new IllegalArgumentException("supportedProtocols must be not empty"); 85 } 86 } 87 88 /** 89 * A special constructor that is used to instantiate {@link #DISABLED}. 90 */ 91 private ApplicationProtocolConfig() { 92 supportedProtocols = Collections.emptyList(); 93 protocol = Protocol.NONE; 94 selectorBehavior = SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL; 95 selectedBehavior = SelectedListenerFailureBehavior.ACCEPT; 96 } 97 98 /** 99 * Defines which application level protocol negotiation to use. 100 */ 101 public enum Protocol { 102 NONE, NPN, ALPN, NPN_AND_ALPN 103 } 104 105 /** 106 * Defines the most common behaviors for the peer that selects the application protocol. 107 */ 108 public enum SelectorFailureBehavior { 109 /** 110 * If the peer who selects the application protocol doesn't find a match this will result in the failing the 111 * handshake with a fatal alert. 112 * <p> 113 * For example in the case of ALPN this will result in a 114 * <a herf="https://tools.ietf.org/html/rfc7301#section-3.2">no_application_protocol(120)</a> alert. 115 */ 116 FATAL_ALERT, 117 /** 118 * If the peer who selects the application protocol doesn't find a match it will pretend no to support 119 * the TLS extension by not advertising support for the TLS extension in the handshake. This is used in cases 120 * where a "best effort" is desired to talk even if there is no matching protocol. 121 */ 122 NO_ADVERTISE, 123 /** 124 * If the peer who selects the application protocol doesn't find a match it will just select the last protocol 125 * it advertised support for. This is used in cases where a "best effort" is desired to talk even if there 126 * is no matching protocol, and the assumption is the "most general" fallback protocol is typically listed last. 127 * <p> 128 * This may be <a href="https://tools.ietf.org/html/rfc7301#section-3.2">illegal for some RFCs</a> but was 129 * observed behavior by some SSL implementations, and is supported for flexibility/compatibility. 130 */ 131 CHOOSE_MY_LAST_PROTOCOL 132 } 133 134 /** 135 * Defines the most common behaviors for the peer which is notified of the selected protocol. 136 */ 137 public enum SelectedListenerFailureBehavior { 138 /** 139 * If the peer who is notified what protocol was selected determines the selection was not matched, or the peer 140 * didn't advertise support for the TLS extension then the handshake will continue and the application protocol 141 * is assumed to be accepted. 142 */ 143 ACCEPT, 144 /** 145 * If the peer who is notified what protocol was selected determines the selection was not matched, or the peer 146 * didn't advertise support for the TLS extension then the handshake will be failed with a fatal alert. 147 */ 148 FATAL_ALERT, 149 /** 150 * If the peer who is notified what protocol was selected determines the selection was not matched, or the peer 151 * didn't advertise support for the TLS extension then the handshake will continue assuming the last protocol 152 * supported by this peer is used. This is used in cases where a "best effort" is desired to talk even if there 153 * is no matching protocol, and the assumption is the "most general" fallback protocol is typically listed last. 154 */ 155 CHOOSE_MY_LAST_PROTOCOL 156 } 157 158 /** 159 * The application level protocols supported. 160 */ 161 public List<String> supportedProtocols() { 162 return supportedProtocols; 163 } 164 165 /** 166 * Get which application level protocol negotiation to use. 167 */ 168 public Protocol protocol() { 169 return protocol; 170 } 171 172 /** 173 * Get the desired behavior for the peer who selects the application protocol. 174 */ 175 public SelectorFailureBehavior selectorFailureBehavior() { 176 return selectorBehavior; 177 } 178 179 /** 180 * Get the desired behavior for the peer who is notified of the selected protocol. 181 */ 182 public SelectedListenerFailureBehavior selectedListenerFailureBehavior() { 183 return selectedBehavior; 184 } 185 }