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    *   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  
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.HashSet;
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 JdkNpnSslEngine 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              // Try to get the bootstrap class loader.
48              ClassLoader bootloader = ClassLoader.getSystemClassLoader().getParent();
49              if (bootloader == null) {
50                  // If failed, use the system class loader,
51                  // although it's not perfect to tell if NPN extension has been loaded.
52                  bootloader = ClassLoader.getSystemClassLoader();
53              }
54              Class.forName("sun.security.ssl.NextProtoNegoExtension", true, bootloader);
55              available = true;
56          } catch (Exception ignore) {
57              // npn-boot was not loaded.
58          }
59      }
60  
61      JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
62          super(engine);
63          checkNotNull(applicationNegotiator, "applicationNegotiator");
64  
65          if (server) {
66              final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
67                      .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
68                      "protocolListener");
69              NextProtoNego.put(engine, new ServerProvider() {
70                  @Override
71                  public void unsupported() {
72                      protocolListener.unsupported();
73                  }
74  
75                  @Override
76                  public List<String> protocols() {
77                      return applicationNegotiator.protocols();
78                  }
79  
80                  @Override
81                  public void protocolSelected(String protocol) {
82                      try {
83                          protocolListener.selected(protocol);
84                      } catch (Throwable t) {
85                          PlatformDependent.throwException(t);
86                      }
87                  }
88              });
89          } else {
90              final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
91                      .newSelector(this, new HashSet<String>(applicationNegotiator.protocols())), "protocolSelector");
92              NextProtoNego.put(engine, new ClientProvider() {
93                  @Override
94                  public boolean supports() {
95                      return true;
96                  }
97  
98                  @Override
99                  public void unsupported() {
100                     protocolSelector.unsupported();
101                 }
102 
103                 @Override
104                 public String selectProtocol(List<String> protocols) {
105                     try {
106                         return protocolSelector.select(protocols);
107                     } catch (Throwable t) {
108                         PlatformDependent.throwException(t);
109                         return null;
110                     }
111                 }
112             });
113         }
114     }
115 
116     @Override
117     public void closeInbound() throws SSLException {
118         NextProtoNego.remove(getWrappedEngine());
119         super.closeInbound();
120     }
121 
122     @Override
123     public void closeOutbound() {
124         NextProtoNego.remove(getWrappedEngine());
125         super.closeOutbound();
126     }
127 }