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.client;
20  
21  import java.io.IOException;
22  import java.util.List;
23  import java.util.Map;
24  
25  import javax.net.ssl.SSLEngine;
26  
27  import org.eclipse.jetty.io.AbstractConnection;
28  import org.eclipse.jetty.io.ClientConnectionFactory;
29  import org.eclipse.jetty.io.Connection;
30  import org.eclipse.jetty.io.EndPoint;
31  import org.eclipse.jetty.io.RuntimeIOException;
32  import org.eclipse.jetty.npn.NextProtoNego;
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 NPNClientConnection extends AbstractConnection implements NextProtoNego.ClientProvider
38  {
39      private final Logger LOG = Log.getLogger(getClass());
40      private final SPDYClient client;
41      private final ClientConnectionFactory connectionFactory;
42      private final SSLEngine engine;
43      private final Map<String, Object> context;
44      private volatile boolean completed;
45  
46      public NPNClientConnection(EndPoint endPoint, SPDYClient client, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map<String, Object> context)
47      {
48          super(endPoint, client.getFactory().getExecutor());
49          this.client = client;
50          this.connectionFactory = connectionFactory;
51          this.engine = sslEngine;
52          this.context = context;
53          NextProtoNego.put(engine, this);
54      }
55  
56      @Override
57      public void onOpen()
58      {
59          super.onOpen();
60          try
61          {
62              getEndPoint().flush(BufferUtil.EMPTY_BUFFER);
63              if (completed)
64                  replaceConnection();
65              else
66                  fillInterested();
67          }
68          catch(IOException e)
69          {
70              throw new RuntimeIOException(e);
71          }
72      }
73  
74      @Override
75      public void onFillable()
76      {
77          while (true)
78          {
79              int filled = fill();
80              if (filled == 0 && !completed)
81                  fillInterested();
82              if (filled <= 0 || completed)
83                  break;
84          }
85          if (completed)
86              replaceConnection();
87      }
88  
89      private int fill()
90      {
91          try
92          {
93              return getEndPoint().fill(BufferUtil.EMPTY_BUFFER);
94          }
95          catch (IOException x)
96          {
97              LOG.debug(x);
98              NextProtoNego.remove(engine);
99              close();
100             return -1;
101         }
102     }
103 
104     @Override
105     public boolean supports()
106     {
107         return true;
108     }
109 
110     @Override
111     public void unsupported()
112     {
113         NextProtoNego.remove(engine);
114         completed = true;
115     }
116 
117     @Override
118     public String selectProtocol(List<String> protocols)
119     {
120         NextProtoNego.remove(engine);
121         completed = true;
122         return client.selectProtocol(protocols);
123     }
124 
125     private void replaceConnection()
126     {
127         EndPoint endPoint = getEndPoint();
128         try
129         {
130             Connection oldConnection = endPoint.getConnection();
131             Connection newConnection = connectionFactory.newConnection(endPoint, context);
132             ClientConnectionFactory.Helper.replaceConnection(oldConnection, newConnection);
133         }
134         catch (Throwable x)
135         {
136             LOG.debug(x);
137             close();
138         }
139     }
140 }