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                         setDelegatingRequests( true );
    126                         setDelegatingResponses(true);
    127                         super.onResponseComplete();
    128                     }
    129                 }
    130                 catch ( IOException ioe )
    131                 {
    132                     Log.debug("WebdavListener:Complete:IOException: might not be dealing with dav server, delegate");
    133                     super.onResponseComplete();
    134                 }
    135             }
    136             else
    137             {
    138                 if (Log.isDebugEnabled())
    139                     Log.debug("WebdavListener:Not ready, calling super");
    140                 super.onResponseComplete();
    141             }
    142         }
    143         else
    144         {
    145             super.onResponseComplete();
    146         }
    147     }
    148
    149
    150
    151     public void onRequestComplete () throws IOException
    152     {
    153         _requestComplete = true;
    154         if (_needIntercept)
    155         {
    156             if ( _requestComplete && _responseComplete)
    157             {
    158                 try
    159                 {
    160                     // we have some work to do before retrying this
    161                     if ( resolveCollectionIssues() )
    162                     {
    163                         setDelegatingRequests( true );
    164                         setDelegatingResponses(true);
    165                         _requestComplete = false;
    166                         _responseComplete = false;
    167                         _destination.resend(_exchange);
    168                     }
    169                     else
    170                     {
    171                         // admit defeat but retry because someone else might have
    172                         setDelegatingRequests( true );
    173                         setDelegatingResponses(true);
    174                         super.onRequestComplete();
    175                     }
    176                 }
    177                 catch ( IOException ioe )
    178                 {
    179                     Log.debug("WebdavListener:Complete:IOException: might not be dealing with dav server, delegate");
    180                     super.onRequestComplete();
    181                 }
    182             }
    183             else
    184             {
    185                 if (Log.isDebugEnabled())
    186                     Log.debug("WebdavListener:Not ready, calling super");
    187                 super.onRequestComplete();
    188             }
    189         }
    190         else
    191         {
    192             super.onRequestComplete();
    193         }
    194     }
    195
    196
    197
    198
    199     /**
    200      * walk through the steps to try and resolve missing parent collection issues via webdav
    201      *
    202      * @return
    203      * @throws IOException
    204      */
    205     private boolean resolveCollectionIssues() throws IOException
    206     {
    207
    208         String uri = _exchange.getURI();
    209         String[] uriCollection = _exchange.getURI().split("/");
    210         int checkNum = uriCollection.length;
    211         int rewind = 0;
    212
    213         String parentUri = URIUtil.parentPath( uri );
    214         while ( !checkExists( parentUri ) )
    215         {
    216             ++rewind;
    217             parentUri = URIUtil.parentPath( parentUri );
    218         }
    219
    220         // confirm webdav is supported for this collection
    221         if ( checkWebdavSupported() )
    222         {
    223             for (int i = 0; i < rewind;)
    224             {
    225                 makeCollection(parentUri + "/" + uriCollection[checkNum - rewind - 1]);
    226                 parentUri = parentUri + "/" + uriCollection[checkNum - rewind - 1];
    227                 --rewind;
    228             }
    229         }
    230         else
    231         {
    232             return false;
    233         }
    234
    235         return true;
    236     }
    237
    238     private boolean checkExists( String uri ) throws IOException
    239     {
    240         PropfindExchange propfindExchange = new PropfindExchange();
    241         propfindExchange.setAddress( _exchange.getAddress() );
    242         propfindExchange.setMethod( HttpMethods.GET ); // PROPFIND acts wonky, just use get
    243         propfindExchange.setScheme( _exchange.getScheme() );
    244         propfindExchange.setEventListener( new SecurityListener( _destination, propfindExchange ) );
    245         propfindExchange.setConfigureListeners( false );
    246         propfindExchange.setURI( uri );
    247
    248         _destination.send( propfindExchange );
    249
    250         try
    251         {
    252             propfindExchange.waitForDone();
    253
    254             return propfindExchange.exists();
    255         }
    256         catch ( InterruptedException ie )
    257         {
    258             Log.ignore( ie );
    259             return false;
    260         }
    261     }
    262
    263     private boolean makeCollection( String uri ) throws IOException
    264     {
    265         MkcolExchange mkcolExchange = new MkcolExchange();
    266         mkcolExchange.setAddress( _exchange.getAddress() );
    267         mkcolExchange.setMethod( "MKCOL " + uri + " HTTP/1.1" );
    268         mkcolExchange.setScheme( _exchange.getScheme() );
    269         mkcolExchange.setEventListener( new SecurityListener( _destination, mkcolExchange ) );
    270         mkcolExchange.setConfigureListeners( false );
    271         mkcolExchange.setURI( uri );
    272
    273         _destination.send( mkcolExchange );
    274
    275         try
    276         {
    277             mkcolExchange.waitForDone();
    278
    279             return mkcolExchange.exists();
    280         }
    281         catch ( InterruptedException ie )
    282         {
    283             Log.ignore( ie );
    284             return false;
    285         }
    286     }
    287
    288
    289     private boolean checkWebdavSupported() throws IOException
    290     {
    291         WebdavSupportedExchange supportedExchange = new WebdavSupportedExchange();
    292         supportedExchange.setAddress( _exchange.getAddress() );
    293         supportedExchange.setMethod( HttpMethods.OPTIONS );
    294         supportedExchange.setScheme( _exchange.getScheme() );
    295         supportedExchange.setEventListener( new SecurityListener( _destination, supportedExchange ) );
    296         supportedExchange.setConfigureListeners( false );
    297         supportedExchange.setURI( _exchange.getURI() );
    298
    299         _destination.send( supportedExchange );
    300
    301         try
    302         {
    303             supportedExchange.waitTilCompletion();
    304             return supportedExchange.isWebdavSupported();
    305         }
    306         catch (InterruptedException ie )
    307         {
    308             Log.ignore( ie );
    309             return false;
    310         }
    311
    312     }
    313
    314 }