View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server;
20  
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import javax.net.ssl.SSLEngine;
26  
27  import org.eclipse.jetty.io.AbstractConnection;
28  import org.eclipse.jetty.io.Connection;
29  import org.eclipse.jetty.io.EndPoint;
30  import org.eclipse.jetty.io.ssl.SslConnection;
31  
32  public abstract class NegotiatingServerConnectionFactory extends AbstractConnectionFactory
33  {
34      public static void checkProtocolNegotiationAvailable()
35      {
36          if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN"))
37              throw new IllegalStateException("No ALPN classes available");
38      }
39  
40      private static boolean isAvailableInBootClassPath(String className)
41      {
42          try
43          {
44              Class<?> klass = ClassLoader.getSystemClassLoader().loadClass(className);
45              if (klass.getClassLoader() != null)
46                  throw new IllegalStateException(className + " must be on JVM boot classpath");
47              return true;
48          }
49          catch (ClassNotFoundException x)
50          {
51              return false;
52          }
53      }
54  
55      private final List<String> negotiatedProtocols;
56      private String defaultProtocol;
57  
58      public NegotiatingServerConnectionFactory(String protocol, String... negotiatedProtocols)
59      {
60          super(protocol);
61          this.negotiatedProtocols = new ArrayList<>();
62          if (negotiatedProtocols != null)
63          {
64              // Trim the values, as they may come from XML configuration.
65              for (String p : negotiatedProtocols)
66              {
67                  p = p.trim();
68                  if (!p.isEmpty())
69                      this.negotiatedProtocols.add(p.trim());
70              }
71          }
72      }
73  
74      public String getDefaultProtocol()
75      {
76          return defaultProtocol;
77      }
78  
79      public void setDefaultProtocol(String defaultProtocol)
80      {
81          // Trim the value, as it may come from XML configuration.
82          String dft = defaultProtocol == null ? "" : defaultProtocol.trim();
83          this.defaultProtocol = dft.isEmpty() ? null : dft;
84      }
85  
86      public List<String> getNegotiatedProtocols()
87      {
88          return negotiatedProtocols;
89      }
90      
91      @Override
92      public Connection newConnection(Connector connector, EndPoint endPoint)
93      {
94          List<String> negotiated = this.negotiatedProtocols;
95          if (negotiated.isEmpty())
96          {
97              // Generate list of protocols that we can negotiate
98              negotiated = new ArrayList<>(connector.getProtocols());
99              for (Iterator<String> i = negotiated.iterator();i.hasNext();)
100             {
101                 String protocol = i.next();
102                 // exclude SSL and negotiating protocols
103                 ConnectionFactory f = connector.getConnectionFactory(protocol);
104                
105                 if ((f instanceof SslConnectionFactory) ||
106                     (f instanceof NegotiatingServerConnectionFactory))
107                 {
108                     i.remove();
109                 }
110             }
111         }
112 
113         // if default protocol is not set, then it is the first protocol given
114         String dft = defaultProtocol;
115         if (dft == null && !negotiated.isEmpty())
116             dft = negotiated.get(0);
117 
118         SSLEngine engine = null;
119         EndPoint ep = endPoint;
120         while (engine == null && ep != null)
121         {
122             // TODO make more generic
123             if (ep instanceof SslConnection.DecryptedEndPoint)
124                 engine = ((SslConnection.DecryptedEndPoint)ep).getSslConnection().getSSLEngine();
125             else
126                 ep = null;
127         }
128 
129         return configure(newServerConnection(connector, endPoint, engine, negotiated, dft), connector, endPoint);
130     }
131 
132     protected abstract AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol);
133 
134     @Override
135     public String toString()
136     {
137         return String.format("%s@%x{%s,%s,%s}", getClass().getSimpleName(), hashCode(), getProtocols(), getDefaultProtocol(), getNegotiatedProtocols());
138     }
139 }