View Javadoc

1   //========================================================================
2   //Copyright 2006-2007 Mort Bay Consulting Pty. Ltd.
3   //------------------------------------------------------------------------
4   //Licensed under the Apache License, Version 2.0 (the "License");
5   //you may not use this file except in compliance with the License.
6   //You may obtain a copy of the License at
7   //http://www.apache.org/licenses/LICENSE-2.0
8   //Unless required by applicable law or agreed to in writing, software
9   //distributed under the License is distributed on an "AS IS" BASIS,
10  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  //See the License for the specific language governing permissions and
12  //limitations under the License.
13  //========================================================================
14  
15  package org.mortbay.jetty.client;
16  
17  import java.io.IOException;
18  import java.nio.channels.SelectionKey;
19  import java.nio.channels.SocketChannel;
20  import javax.net.ssl.SSLContext;
21  import javax.net.ssl.SSLEngine;
22  
23  import org.mortbay.component.AbstractLifeCycle;
24  import org.mortbay.io.Buffer;
25  import org.mortbay.io.Connection;
26  import org.mortbay.io.nio.IndirectNIOBuffer;
27  import org.mortbay.io.nio.SelectChannelEndPoint;
28  import org.mortbay.io.nio.SelectorManager;
29  import org.mortbay.jetty.AbstractBuffers;
30  import org.mortbay.jetty.HttpMethods;
31  import org.mortbay.jetty.HttpVersions;
32  import org.mortbay.jetty.security.SslHttpChannelEndPoint;
33  import org.mortbay.log.Log;
34  
35  class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector, Runnable
36  {
37      private final HttpClient _httpClient;
38      private SSLContext _sslContext;
39      private AbstractBuffers _sslBuffers;
40  
41      SelectorManager _selectorManager=new Manager();
42  
43      /**
44       * @param httpClient
45       */
46      SelectConnector(HttpClient httpClient)
47      {
48          _httpClient = httpClient;
49      }
50  
51      protected void doStart() throws Exception
52      {
53          _selectorManager.start();
54          _httpClient._threadPool.dispatch(this);
55      }
56  
57      protected void doStop() throws Exception
58      {
59          _selectorManager.stop();
60      }
61  
62      public void startConnection( HttpDestination destination )
63          throws IOException
64      {
65          SocketChannel channel = SocketChannel.open();
66          Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
67          channel.configureBlocking( false );
68          channel.socket().setTcpNoDelay(true);
69          channel.connect(address.toSocketAddress());
70          _selectorManager.register( channel, destination );
71      }
72  
73      public void run()
74      {
75          while (_httpClient.isRunning())
76          {
77              try
78              {
79                  _selectorManager.doSelect(0);
80              }
81              catch (Exception e)
82              {
83                  e.printStackTrace();
84              }
85          }
86      }
87  
88      class Manager extends SelectorManager
89      {
90          protected SocketChannel acceptChannel(SelectionKey key) throws IOException
91          {
92              throw new IllegalStateException();
93          }
94  
95          public boolean dispatch(Runnable task)
96          {
97              return SelectConnector.this._httpClient._threadPool.dispatch(task);
98          }
99  
100         protected void endPointOpened(SelectChannelEndPoint endpoint)
101         {
102         }
103 
104         protected void endPointClosed(SelectChannelEndPoint endpoint)
105         {
106         }
107 
108         protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
109         {
110             if (endpoint instanceof SslHttpChannelEndPoint)
111                 return new HttpConnection(_sslBuffers,endpoint,_sslBuffers.getHeaderBufferSize(),_sslBuffers.getRequestBufferSize());
112             return new HttpConnection(_httpClient,endpoint,SelectConnector.this._httpClient.getHeaderBufferSize(),SelectConnector.this._httpClient.getRequestBufferSize());
113         }
114 
115         protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
116         {
117             // key should have destination at this point (will be replaced by endpoint after this call)
118             HttpDestination dest=(HttpDestination)key.attachment();
119 
120 
121             SelectChannelEndPoint ep=null;
122 
123             if (dest.isSecure())
124             {
125                 if (dest.isProxied())
126                 {
127                     String connect = HttpMethods.CONNECT+" "+dest.getAddress()+HttpVersions.HTTP_1_0+"\r\n\r\n";
128                     // TODO need to send this over channel unencrypted and setup endpoint to ignore the 200 OK response.
129 
130                     throw new IllegalStateException("Not Implemented");
131                 }
132 
133                 SSLEngine engine=newSslEngine();
134                 ep = new SslHttpChannelEndPoint(_sslBuffers,channel,selectSet,key,engine);
135             }
136             else
137             {
138                 ep=new SelectChannelEndPoint(channel,selectSet,key);
139             }
140 
141             HttpConnection connection=(HttpConnection)ep.getConnection();
142             connection.setDestination(dest);
143             dest.onNewConnection(connection);
144             return ep;
145         }
146 
147         private synchronized SSLEngine newSslEngine() throws IOException
148         {
149             if (_sslContext==null)
150             {
151                 _sslContext = SelectConnector.this._httpClient.getSSLContext();
152             }
153 
154             SSLEngine sslEngine = _sslContext.createSSLEngine();
155             sslEngine.setUseClientMode(true);
156             sslEngine.beginHandshake();
157 
158             if (_sslBuffers==null)
159             {
160                 AbstractBuffers buffers = new AbstractBuffers()
161                 {
162                     protected Buffer newBuffer( int size )
163                     {
164                         return new IndirectNIOBuffer( size);
165                     }
166                 };
167 
168                 buffers.setHeaderBufferSize( sslEngine.getSession().getApplicationBufferSize());
169                 buffers.setRequestBufferSize( sslEngine.getSession().getApplicationBufferSize());
170                 buffers.setResponseBufferSize(sslEngine.getSession().getApplicationBufferSize());
171 
172                 try
173                 {
174                     buffers.start();
175                 }
176                 catch(Exception e)
177                 {
178                     throw new IllegalStateException(e);
179                 }
180                 _sslBuffers=buffers;
181             }
182 
183             return sslEngine;
184         }
185 
186         /* ------------------------------------------------------------ */
187         /* (non-Javadoc)
188          * @see org.mortbay.io.nio.SelectorManager#connectionFailed(java.nio.channels.SocketChannel, java.lang.Throwable, java.lang.Object)
189          */
190         protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment)
191         {
192             if (attachment instanceof HttpDestination)
193                 ((HttpDestination)attachment).onConnectionFailed(ex);
194             else
195                 Log.warn(ex);
196         }
197 
198     }
199 
200 }