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