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 }