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  
21  import javax.net.ssl.SSLContext;
22  import javax.net.ssl.SSLEngine;
23  
24  import org.mortbay.component.AbstractLifeCycle;
25  import org.mortbay.io.Buffer;
26  import org.mortbay.io.Buffers;
27  import org.mortbay.io.Connection;
28  import org.mortbay.io.nio.IndirectNIOBuffer;
29  import org.mortbay.io.nio.SelectChannelEndPoint;
30  import org.mortbay.io.nio.SelectorManager;
31  import org.mortbay.jetty.AbstractBuffers;
32  import org.mortbay.jetty.HttpMethods;
33  import org.mortbay.jetty.HttpVersions;
34  import org.mortbay.jetty.security.SslHttpChannelEndPoint;
35  import org.mortbay.log.Log;
36  
37  class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector, Runnable
38  {
39      private final HttpClient _httpClient;
40      private SSLContext _sslContext;
41      private AbstractBuffers _sslBuffers;
42  
43      SelectorManager _selectorManager=new Manager();
44  
45      /**
46       * @param httpClient
47       */
48      SelectConnector(HttpClient httpClient)
49      {
50          _httpClient = httpClient;
51      }
52  
53      protected void doStart() throws Exception
54      {
55          _selectorManager.start();
56          _httpClient._threadPool.dispatch(this);
57      }
58  
59      protected void doStop() throws Exception
60      {
61          _selectorManager.stop();
62      }
63  
64      public void startConnection( HttpDestination destination )
65          throws IOException
66      {
67          SocketChannel channel = SocketChannel.open();
68          Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
69          channel.configureBlocking( false );
70          channel.connect(address.toSocketAddress());
71          channel.socket().setSoTimeout( _httpClient.getSoTimeout());
72          _selectorManager.register( channel, destination );
73      }
74  
75      public void run()
76      {
77          while (_httpClient.isRunning())
78          {
79              try
80              {
81                  _selectorManager.doSelect(0);
82              }
83              catch (Exception e)
84              {
85                  e.printStackTrace();
86              }
87          }
88      }
89  
90      class Manager extends SelectorManager
91      {
92          protected SocketChannel acceptChannel(SelectionKey key) throws IOException
93          {
94              throw new IllegalStateException();
95          }
96  
97          public boolean dispatch(Runnable task)
98          {
99              return SelectConnector.this._httpClient._threadPool.dispatch(task);
100         }
101 
102         protected void endPointOpened(SelectChannelEndPoint endpoint)
103         {
104         }
105 
106         protected void endPointClosed(SelectChannelEndPoint endpoint)
107         {
108         }
109 
110         protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
111         {
112             if (endpoint instanceof SslHttpChannelEndPoint)
113                 return new HttpConnection(_sslBuffers,endpoint,_sslBuffers.getHeaderBufferSize(),_sslBuffers.getRequestBufferSize());
114             return new HttpConnection(_httpClient,endpoint,SelectConnector.this._httpClient.getHeaderBufferSize(),SelectConnector.this._httpClient.getRequestBufferSize());
115         }
116 
117         protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
118         {
119             // key should have destination at this point (will be replaced by endpoint after this call)
120             HttpDestination dest=(HttpDestination)key.attachment();
121 
122 
123             SelectChannelEndPoint ep=null;
124 
125             if (dest.isSecure())
126             {
127                 if (dest.isProxied())
128                 {
129                     String connect = HttpMethods.CONNECT+" "+dest.getAddress()+HttpVersions.HTTP_1_0+"\r\n\r\n";
130                     // TODO need to send this over channel unencrypted and setup endpoint to ignore the 200 OK response.
131 
132                     throw new IllegalStateException("Not Implemented");
133                 }
134 
135                 SSLEngine engine=newSslEngine();
136                 ep = new SslHttpChannelEndPoint(_sslBuffers,channel,selectSet,key,engine);
137             }
138             else
139             {
140                 ep=new SelectChannelEndPoint(channel,selectSet,key);
141             }
142 
143             HttpConnection connection=(HttpConnection)ep.getConnection();
144             connection.setDestination(dest);
145             dest.onNewConnection(connection);
146             return ep;
147         }
148 
149         private synchronized SSLEngine newSslEngine() throws IOException
150         {
151             if (_sslContext==null)
152             {
153                 _sslContext = SelectConnector.this._httpClient.getSSLContext();
154             }
155 
156             SSLEngine sslEngine = _sslContext.createSSLEngine();
157             sslEngine.setUseClientMode(true);
158             sslEngine.beginHandshake();
159 
160             if (_sslBuffers==null)
161             {
162                 AbstractBuffers buffers = new AbstractBuffers()
163                 {
164                     protected Buffer newBuffer( int size )
165                     {
166                         return new IndirectNIOBuffer( size);
167                     }
168                 };
169 
170                 buffers.setHeaderBufferSize( sslEngine.getSession().getApplicationBufferSize());
171                 buffers.setRequestBufferSize( sslEngine.getSession().getApplicationBufferSize());
172                 buffers.setResponseBufferSize(sslEngine.getSession().getApplicationBufferSize());
173 
174                 try
175                 {
176                     buffers.start();
177                 }
178                 catch(Exception e)
179                 {
180                     throw new IllegalStateException(e);
181                 }
182                 _sslBuffers=buffers;
183             }
184 
185             return sslEngine;
186         }
187 
188         /* ------------------------------------------------------------ */
189         /* (non-Javadoc)
190          * @see org.mortbay.io.nio.SelectorManager#connectionFailed(java.nio.channels.SocketChannel, java.lang.Throwable, java.lang.Object)
191          */
192         protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment)
193         {
194             if (attachment instanceof HttpDestination)
195                 ((HttpDestination)attachment).onConnectionFailed(ex);
196             else
197                 Log.warn(ex);
198         }
199 
200     }
201 
202 }