View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 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.io.IOException;
22  import java.util.List;
23  import javax.net.ssl.SSLEngine;
24  import javax.net.ssl.SSLEngineResult;
25  
26  import org.eclipse.jetty.io.AbstractConnection;
27  import org.eclipse.jetty.io.Connection;
28  import org.eclipse.jetty.io.EndPoint;
29  import org.eclipse.jetty.util.BufferUtil;
30  import org.eclipse.jetty.util.log.Log;
31  import org.eclipse.jetty.util.log.Logger;
32  
33  public abstract class NegotiatingServerConnection extends AbstractConnection
34  {
35      private static final Logger LOG = Log.getLogger(NegotiatingServerConnection.class);
36  
37      private final Connector connector;
38      private final SSLEngine engine;
39      private final List<String> protocols;
40      private final String defaultProtocol;
41      private String protocol; // No need to be volatile: it is modified and read by the same thread
42  
43      protected NegotiatingServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol)
44      {
45          super(endPoint, connector.getExecutor());
46          this.connector = connector;
47          this.protocols = protocols;
48          this.defaultProtocol = defaultProtocol;
49          this.engine = engine;
50      }
51  
52      protected List<String> getProtocols()
53      {
54          return protocols;
55      }
56  
57      protected String getDefaultProtocol()
58      {
59          return defaultProtocol;
60      }
61  
62      protected SSLEngine getSSLEngine()
63      {
64          return engine;
65      }
66  
67      protected String getProtocol()
68      {
69          return protocol;
70      }
71  
72      protected void setProtocol(String protocol)
73      {
74          this.protocol = protocol;
75      }
76  
77      @Override
78      public void onOpen()
79      {
80          super.onOpen();
81          fillInterested();
82      }
83  
84      @Override
85      public void onFillable()
86      {
87          int filled = fill();
88  
89          if (filled == 0)
90          {
91              if (protocol == null)
92              {
93                  if (engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
94                  {
95                      // Here the SSL handshake is finished, but the protocol has not been negotiated.
96                      if (LOG.isDebugEnabled())
97                          LOG.debug("{} could not negotiate protocol, SSLEngine: {}", this, engine);
98                      close();
99                  }
100                 else
101                 {
102                     // Here the SSL handshake is not finished yet but we filled 0 bytes,
103                     // so we need to read more.
104                     fillInterested();
105                 }
106             }
107             else
108             {
109                 ConnectionFactory connectionFactory = connector.getConnectionFactory(protocol);
110                 if (connectionFactory == null)
111                 {
112                     if (LOG.isDebugEnabled())
113                         LOG.debug("{} application selected protocol '{}', but no correspondent {} has been configured",
114                             this, protocol, ConnectionFactory.class.getName());
115                     close();
116                 }
117                 else
118                 {
119                     EndPoint endPoint = getEndPoint();
120                     Connection oldConnection = endPoint.getConnection();
121                     Connection newConnection = connectionFactory.newConnection(connector, endPoint);
122                     if (LOG.isDebugEnabled())
123                         LOG.debug("{} switching from {} to {}", this, oldConnection, newConnection);
124                     oldConnection.onClose();
125                     endPoint.setConnection(newConnection);
126                     getEndPoint().getConnection().onOpen();
127                 }
128             }
129         }
130         else if (filled < 0)
131         {
132             // Something went bad, we need to close.
133             if (LOG.isDebugEnabled())
134                 LOG.debug("{} closing on client close", this);
135             close();
136         }
137         else
138         {
139             // Must never happen, since we fill using an empty buffer
140             throw new IllegalStateException();
141         }
142     }
143 
144     private int fill()
145     {
146         try
147         {
148             return getEndPoint().fill(BufferUtil.EMPTY_BUFFER);
149         }
150         catch (IOException x)
151         {
152             LOG.debug(x);
153             close();
154             return -1;
155         }
156     }
157 
158     @Override
159     public void close()
160     {
161         // Gentler close for SSL.
162         getEndPoint().shutdownOutput();
163         super.close();
164     }
165 }