View Javadoc
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  
17  package io.netty.handler.ssl;
18  
19  import static io.netty.util.internal.ObjectUtil.checkNotNull;
20  import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
21  import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
22  import io.netty.util.internal.PlatformDependent;
23  
24  import java.util.LinkedHashSet;
25  import java.util.List;
26  
27  import javax.net.ssl.SSLEngine;
28  import javax.net.ssl.SSLException;
29  
30  import org.eclipse.jetty.npn.NextProtoNego;
31  import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
32  import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
33  
34  final class JettyNpnSslEngine extends JdkSslEngine {
35      private static boolean available;
36  
37      static boolean isAvailable() {
38          updateAvailability();
39          return available;
40      }
41  
42      private static void updateAvailability() {
43          if (available) {
44              return;
45          }
46          try {
47              // Always use bootstrap class loader.
48              Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null);
49              available = true;
50          } catch (Exception ignore) {
51              // npn-boot was not loaded.
52          }
53      }
54  
55      JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
56          super(engine);
57          checkNotNull(applicationNegotiator, "applicationNegotiator");
58  
59          if (server) {
60              final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
61                      .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
62                      "protocolListener");
63              NextProtoNego.put(engine, new ServerProvider() {
64                  @Override
65                  public void unsupported() {
66                      protocolListener.unsupported();
67                  }
68  
69                  @Override
70                  public List<String> protocols() {
71                      return applicationNegotiator.protocols();
72                  }
73  
74                  @Override
75                  public void protocolSelected(String protocol) {
76                      try {
77                          protocolListener.selected(protocol);
78                      } catch (Throwable t) {
79                          PlatformDependent.throwException(t);
80                      }
81                  }
82              });
83          } else {
84              final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
85                      .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
86                      "protocolSelector");
87              NextProtoNego.put(engine, new ClientProvider() {
88                  @Override
89                  public boolean supports() {
90                      return true;
91                  }
92  
93                  @Override
94                  public void unsupported() {
95                      protocolSelector.unsupported();
96                  }
97  
98                  @Override
99                  public String selectProtocol(List<String> protocols) {
100                     try {
101                         return protocolSelector.select(protocols);
102                     } catch (Throwable t) {
103                         PlatformDependent.throwException(t);
104                         return null;
105                     }
106                 }
107             });
108         }
109     }
110 
111     @Override
112     public void closeInbound() throws SSLException {
113         NextProtoNego.remove(getWrappedEngine());
114         super.closeInbound();
115     }
116 
117     @Override
118     public void closeOutbound() {
119         NextProtoNego.remove(getWrappedEngine());
120         super.closeOutbound();
121     }
122 }