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 }