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