View Javadoc

    1   //========================================================================
    2   //Copyright 2008 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
    16  package org.mortbay.jetty.client.webdav;
    17
    18  import java.io.IOException;
    19
    20  import javax.servlet.http.HttpServletResponse;
    21
    22  import org.mortbay.io.Buffer;
    23  import org.mortbay.jetty.HttpMethods;
    24  import org.mortbay.jetty.client.HttpDestination;
    25  import org.mortbay.jetty.client.HttpEventListenerWrapper;
    26  import org.mortbay.jetty.client.HttpExchange;
    27  import org.mortbay.jetty.client.security.SecurityListener;
    28  import org.mortbay.log.Log;
    29  import org.mortbay.util.URIUtil;
    30
    31  /**
    32   * WebdavListener
    33   *
    34   *
    35   *
    36   *
    37   */
    38  public class WebdavListener extends HttpEventListenerWrapper
    39  {
    40      private HttpDestination _destination;
    41      private HttpExchange _exchange;
    42      private boolean _requestComplete;
    43      private boolean _responseComplete;
    44      private boolean _webdavEnabled;
    45      private boolean _needIntercept;
    46
    47      public WebdavListener(HttpDestination destination, HttpExchange ex)
    48      {
    49          // Start of sending events through to the wrapped listener
    50          // Next decision point is the onResponseStatus
    51          super(ex.getEventListener(),true);
    52          _destination=destination;
    53          _exchange=ex;
    54
    55          // We'll only enable webdav if this is a PUT request
    56          if ( HttpMethods.PUT.equalsIgnoreCase( _exchange.getMethod() ) )
    57          {
    58              _webdavEnabled = true;
    59          }
    60      }
    61
    62      public void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
    63      {
    64          if ( !_webdavEnabled )
    65          {
    66              _needIntercept = false;
    67              super.onResponseStatus(version, status, reason);
    68              return;
    69          }
    70
    71          if (Log.isDebugEnabled())
    72              Log.debug("WebdavListener:Response Status: " + status );
    73
    74          // The dav spec says that CONFLICT should be returned when the parent collection doesn't exist but I am seeing
    75          // FORBIDDEN returned instead so running with that.
    76          if ( status == HttpServletResponse.SC_CONFLICT || status == HttpServletResponse.SC_FORBIDDEN )
    77          {
    78              if ( _webdavEnabled )
    79              {
    80                  if (Log.isDebugEnabled())
    81                      Log.debug("WebdavListener:Response Status: dav enabled, taking a stab at resolving put issue" );
    82                  setDelegatingResponses( false ); // stop delegating, we can try and fix this request
    83                  _needIntercept = true;
    84              }
    85              else
    86              {
    87                  if (Log.isDebugEnabled())
    88                      Log.debug("WebdavListener:Response Status: Webdav Disabled" );
    89                  setDelegatingResponses( true ); // just make sure we delegate
    90                  setDelegatingRequests( true );
    91                  _needIntercept = false;
    92              }
    93          }
    94          else
    95          {
    96              _needIntercept = false;
    97              setDelegatingResponses( true );
    98              setDelegatingRequests( true );
    99          }
    100
    101         super.onResponseStatus(version, status, reason);
    102     }
    103
    104     public void onResponseComplete() throws IOException
    105     {
    106         _responseComplete = true;
    107         if (_needIntercept)
    108         {
    109             if ( _requestComplete && _responseComplete)
    110             {
    111                 try
    112                 {
    113                     // we have some work to do before retrying this
    114                     if ( resolveCollectionIssues() )
    115                     {
    116                         setDelegatingRequests( true );
    117                         setDelegatingResponses(true);
    118                         _requestComplete = false;
    119                         _responseComplete = false;
    120                         _destination.resend(_exchange);
    121                     }
    122                     else
    123                     {
    124                         // admit defeat but retry because someone else might have
    125                     	setDelegationResult(false);
    126                         setDelegatingRequests( true );
    127                         setDelegatingResponses(true);
    128                         super.onResponseComplete();
    129                     }
    130                 }
    131                 catch ( IOException ioe )
    132                 {
    133                     Log.debug("WebdavListener:Complete:IOException: might not be dealing with dav server, delegate");
    134                     super.onResponseComplete();
    135                 }
    136             }
    137             else
    138             {
    139                 if (Log.isDebugEnabled())
    140                     Log.debug("WebdavListener:Not ready, calling super");
    141                 super.onResponseComplete();
    142             }
    143         }
    144         else
    145         {
    146             super.onResponseComplete();
    147         }
    148     }
    149
    150
    151
    152     public void onRequestComplete () throws IOException
    153     {
    154         _requestComplete = true;
    155         if (_needIntercept)
    156         {
    157             if ( _requestComplete && _responseComplete)
    158             {
    159                 try
    160                 {
    161                     // we have some work to do before retrying this
    162                     if ( resolveCollectionIssues() )
    163                     {
    164                         setDelegatingRequests( true );
    165                         setDelegatingResponses(true);
    166                         _requestComplete = false;
    167                         _responseComplete = false;
    168                         _destination.resend(_exchange);
    169                     }
    170                     else
    171                     {
    172                         // admit defeat but retry because someone else might have
    173                         setDelegatingRequests( true );
    174                         setDelegatingResponses(true);
    175                         super.onRequestComplete();
    176                     }
    177                 }
    178                 catch ( IOException ioe )
    179                 {
    180                     Log.debug("WebdavListener:Complete:IOException: might not be dealing with dav server, delegate");
    181                     super.onRequestComplete();
    182                 }
    183             }
    184             else
    185             {
    186                 if (Log.isDebugEnabled())
    187                     Log.debug("WebdavListener:Not ready, calling super");
    188                 super.onRequestComplete();
    189             }
    190         }
    191         else
    192         {
    193             super.onRequestComplete();
    194         }
    195     }
    196
    197
    198
    199
    200     /**
    201      * walk through the steps to try and resolve missing parent collection issues via webdav
    202      *
    203      * @return
    204      * @throws IOException
    205      */
    206     private boolean resolveCollectionIssues() throws IOException
    207     {
    208
    209         String uri = _exchange.getURI();
    210         String[] uriCollection = _exchange.getURI().split("/");
    211         int checkNum = uriCollection.length;
    212         int rewind = 0;
    213
    214         String parentUri = URIUtil.parentPath( uri );
    215         while ( parentUri != null && !checkExists( parentUri ) )
    216         {
    217             ++rewind;
    218             parentUri = URIUtil.parentPath( parentUri );
    219         }
    220
    221         // confirm webdav is supported for this collection
    222         if ( checkWebdavSupported() )
    223         {
    224             for (int i = 0; i < rewind;)
    225             {
    226                 makeCollection(parentUri + "/" + uriCollection[checkNum - rewind - 1]);
    227                 parentUri = parentUri + "/" + uriCollection[checkNum - rewind - 1];
    228                 --rewind;
    229             }
    230         }
    231         else
    232         {
    233             return false;
    234         }
    235
    236         return true;
    237     }
    238
    239     private boolean checkExists( String uri ) throws IOException
    240     {
    241         PropfindExchange propfindExchange = new PropfindExchange();
    242         propfindExchange.setAddress( _exchange.getAddress() );
    243         propfindExchange.setMethod( HttpMethods.GET ); // PROPFIND acts wonky, just use get
    244         propfindExchange.setScheme( _exchange.getScheme() );
    245         propfindExchange.setEventListener( new SecurityListener( _destination, propfindExchange ) );
    246         propfindExchange.setConfigureListeners( false );
    247         propfindExchange.setURI( uri );
    248
    249         _destination.send( propfindExchange );
    250
    251         try
    252         {
    253             propfindExchange.waitForDone();
    254
    255             return propfindExchange.exists();
    256         }
    257         catch ( InterruptedException ie )
    258         {
    259             Log.ignore( ie );
    260             return false;
    261         }
    262     }
    263
    264     private boolean makeCollection( String uri ) throws IOException
    265     {
    266         MkcolExchange mkcolExchange = new MkcolExchange();
    267         mkcolExchange.setAddress( _exchange.getAddress() );
    268         mkcolExchange.setMethod( "MKCOL " + uri + " HTTP/1.1" );
    269         mkcolExchange.setScheme( _exchange.getScheme() );
    270         mkcolExchange.setEventListener( new SecurityListener( _destination, mkcolExchange ) );
    271         mkcolExchange.setConfigureListeners( false );
    272         mkcolExchange.setURI( uri );
    273
    274         _destination.send( mkcolExchange );
    275
    276         try
    277         {
    278             mkcolExchange.waitForDone();
    279
    280             return mkcolExchange.exists();
    281         }
    282         catch ( InterruptedException ie )
    283         {
    284             Log.ignore( ie );
    285             return false;
    286         }
    287     }
    288
    289
    290     private boolean checkWebdavSupported() throws IOException
    291     {
    292         WebdavSupportedExchange supportedExchange = new WebdavSupportedExchange();
    293         supportedExchange.setAddress( _exchange.getAddress() );
    294         supportedExchange.setMethod( HttpMethods.OPTIONS );
    295         supportedExchange.setScheme( _exchange.getScheme() );
    296         supportedExchange.setEventListener( new SecurityListener( _destination, supportedExchange ) );
    297         supportedExchange.setConfigureListeners( false );
    298         supportedExchange.setURI( _exchange.getURI() );
    299
    300         _destination.send( supportedExchange );
    301
    302         try
    303         {
    304             supportedExchange.waitTilCompletion();
    305             return supportedExchange.isWebdavSupported();
    306         }
    307         catch (InterruptedException ie )
    308         {
    309             Log.ignore( ie );
    310             return false;
    311         }
    312
    313     }
    314
    315 }