View Javadoc

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