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 }