View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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.spdy.server;
20  
21  import java.io.IOException;
22  import java.util.List;
23  
24  import javax.net.ssl.SSLEngine;
25  import javax.net.ssl.SSLEngineResult;
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.npn.NextProtoNego;
31  import org.eclipse.jetty.server.ConnectionFactory;
32  import org.eclipse.jetty.server.Connector;
33  import org.eclipse.jetty.util.BufferUtil;
34  import org.eclipse.jetty.util.log.Log;
35  import org.eclipse.jetty.util.log.Logger;
36  
37  public class NextProtoNegoServerConnection extends AbstractConnection implements NextProtoNego.ServerProvider
38  {
39      private final Logger LOG = Log.getLogger(getClass());
40      private final Connector connector;
41      private final SSLEngine engine;
42      private final List<String> protocols;
43      private final String defaultProtocol;
44      private String nextProtocol; // No need to be volatile: it is modified and read by the same thread
45  
46      public NextProtoNegoServerConnection(EndPoint endPoint, SSLEngine engine, Connector connector, List<String>protocols, String defaultProtocol)
47      {
48          super(endPoint, connector.getExecutor());
49          this.connector = connector;
50          this.protocols = protocols;
51          this.defaultProtocol = defaultProtocol;
52          this.engine = engine;
53          NextProtoNego.put(engine, this);
54      }
55  
56      @Override
57      public void onOpen()
58      {
59          super.onOpen();
60          fillInterested();
61      }
62  
63      @Override
64      public void onFillable()
65      {
66          while (true)
67          {
68              int filled = fill();
69              if (filled == 0 && nextProtocol == null)
70                  fillInterested();
71              if (filled <= 0 || nextProtocol != null)
72                  break;
73          }
74  
75          if (nextProtocol == null && engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
76          {
77              // The client sent the NPN extension, but did not send the NextProtocol
78              // message with the chosen protocol so we need to close
79              LOG.debug("{} missing next protocol. SSLEngine: {}", this, engine);
80              close();
81          }
82  
83          if (nextProtocol != null)
84          {
85              ConnectionFactory connectionFactory = connector.getConnectionFactory(nextProtocol);
86              EndPoint endPoint = getEndPoint();
87              Connection oldConnection = endPoint.getConnection();
88              oldConnection.onClose();
89              Connection connection = connectionFactory.newConnection(connector, endPoint);
90              LOG.debug("{} switching from {} to {}", this, oldConnection, connection);
91              endPoint.setConnection(connection);
92              getEndPoint().getConnection().onOpen();
93          }
94      }
95  
96      private int fill()
97      {
98          try
99          {
100             return getEndPoint().fill(BufferUtil.EMPTY_BUFFER);
101         }
102         catch (IOException x)
103         {
104             LOG.debug(x);
105             NextProtoNego.remove(engine);
106             getEndPoint().close();
107             return -1;
108         }
109     }
110 
111     @Override
112     public void unsupported()
113     {
114         protocolSelected(defaultProtocol);
115     }
116 
117     @Override
118     public List<String> protocols()
119     {
120         return protocols;
121     }
122 
123     @Override
124     public void protocolSelected(String protocol)
125     {
126         LOG.debug("{} protocol selected {}", this, protocol);
127         nextProtocol = protocol != null ? protocol : defaultProtocol;
128         NextProtoNego.remove(engine);
129     }
130 }