Merge branch 'develop' into review_build_process
[pub/Android/ownCloud.git] / src / eu / alefzero / webdav / WebdavClient.java
index 0b3cf81..65a8f00 100644 (file)
 
 package eu.alefzero.webdav;
 
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.httpclient.Credentials;
-import org.apache.commons.httpclient.HostConfiguration;
+import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.HttpConnectionManager;
 import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.HttpMethodBase;
-import org.apache.commons.httpclient.HttpState;
 import org.apache.commons.httpclient.HttpVersion;
+import org.apache.commons.httpclient.URI;
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 import org.apache.commons.httpclient.auth.AuthPolicy;
 import org.apache.commons.httpclient.auth.AuthScope;
-import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.cookie.CookiePolicy;
 import org.apache.commons.httpclient.methods.HeadMethod;
-import org.apache.commons.httpclient.methods.PutMethod;
 import org.apache.commons.httpclient.params.HttpMethodParams;
 import org.apache.http.HttpStatus;
 import org.apache.http.params.CoreProtocolPNames;
-import org.apache.jackrabbit.webdav.client.methods.DavMethod;
-import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
 
 import com.owncloud.android.Log_OC;
+import com.owncloud.android.MainApp;
 
 import com.owncloud.android.network.BearerAuthScheme;
 import com.owncloud.android.network.BearerCredentials;
@@ -55,12 +50,16 @@ import com.owncloud.android.network.BearerCredentials;
 import android.net.Uri;
 
 public class WebdavClient extends HttpClient {
+    private static final int MAX_REDIRECTIONS_COUNT = 3;
+    
     private Uri mUri;
     private Credentials mCredentials;
+    private boolean mFollowRedirects;
+    private String mSsoSessionCookie;
+    private String mAuthTokenType;
     final private static String TAG = "WebdavClient";
-    private static final String USER_AGENT = "Android-ownCloud";
+    public static final String USER_AGENT = "Android-ownCloud";
     
-    private OnDatatransferProgressListener mDataTransferListener;
     static private byte[] sExhaustBuffer = new byte[1024];
     
     /**
@@ -71,6 +70,9 @@ public class WebdavClient extends HttpClient {
         Log_OC.d(TAG, "Creating WebdavClient");
         getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
         getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
+        mFollowRedirects = true;
+        mSsoSessionCookie = null;
+        mAuthTokenType = MainApp.getAuthTokenTypePass();
     }
 
     public void setBearerCredentials(String accessToken) {
@@ -82,6 +84,8 @@ public class WebdavClient extends HttpClient {
         
         mCredentials = new BearerCredentials(accessToken);
         getState().setCredentials(AuthScope.ANY, mCredentials);
+        mSsoSessionCookie = null;
+        mAuthTokenType = MainApp.getAuthTokenTypeAccessToken();
     }
 
     public void setBasicCredentials(String username, String password) {
@@ -92,138 +96,24 @@ public class WebdavClient extends HttpClient {
         getParams().setAuthenticationPreemptive(true);
         mCredentials = new UsernamePasswordCredentials(username, password);
         getState().setCredentials(AuthScope.ANY, mCredentials);
+        mSsoSessionCookie = null;
+        mAuthTokenType = MainApp.getAuthTokenTypePass();
     }
     
-    /**
-     * Downloads a file in remoteFilepath to the local targetPath.
-     * 
-     * @param remoteFilepath    Path to the file in the remote server, URL DECODED. 
-     * @param targetFile        Local path to save the downloaded file.
-     * @return                  'True' when the file is successfully downloaded.
-     */
-    public boolean downloadFile(String remoteFilePath, File targetFile) {
-        boolean ret = false;
-        GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));
-
-        try {
-            int status = executeMethod(get);
-            if (status == HttpStatus.SC_OK) {
-                targetFile.createNewFile();
-                BufferedInputStream bis = new BufferedInputStream(
-                        get.getResponseBodyAsStream());
-                FileOutputStream fos = new FileOutputStream(targetFile);
-
-                byte[] bytes = new byte[4096];
-                int readResult;
-                while ((readResult = bis.read(bytes)) != -1) {
-                    if (mDataTransferListener != null)
-                        mDataTransferListener.onTransferProgress(readResult);
-                    fos.write(bytes, 0, readResult);
-                }
-                fos.close();
-                ret = true;
-            } else {
-                exhaustResponse(get.getResponseBodyAsStream());
-            }
-            Log_OC.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":""));
-            
-        } catch (Exception e) {
-            logException(e, "dowloading " + remoteFilePath);
-            
-        } finally {
-            if (!ret && targetFile.exists()) {
-                targetFile.delete();
-            }
-            get.releaseConnection();    // let the connection available for other methods
-        }
-        return ret;
+    public void setSsoSessionCookie(String accessToken) {
+        getParams().setAuthenticationPreemptive(false);
+        getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
+        mSsoSessionCookie = accessToken;
+        mCredentials = null;
+        mAuthTokenType = MainApp.getAuthTokenTypeSamlSessionCookie();
     }
     
     
     /**
-     * Deletes a remote file via webdav
-     * @param remoteFilePath       Remote file path of the file to delete, in URL DECODED format.
-     * @return
-     */
-    public boolean deleteFile(String remoteFilePath) {
-        boolean ret = false;
-        DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));
-        try {
-            int status = executeMethod(delete);
-            ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT);
-            exhaustResponse(delete.getResponseBodyAsStream());
-            
-            Log_OC.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status +  (!ret?"(FAIL)":""));
-            
-        } catch (Exception e) {
-            logException(e, "deleting " + remoteFilePath);
-            
-        } finally {
-            delete.releaseConnection();    // let the connection available for other methods
-        }
-        return ret;
-    }
-
-    
-    public void setDataTransferProgressListener(OnDatatransferProgressListener listener) {
-        mDataTransferListener = listener;
-    }
-    
-    /**
-     * Creates or update a file in the remote server with the contents of a local file.
-     * 
-     * @param localFile         Path to the local file to upload.
-     * @param remoteTarget      Remote path to the file to create or update, URL DECODED
-     * @param contentType       MIME type of the file.
-     * @return                  Status HTTP code returned by the server.
-     * @throws IOException      When a transport error that could not be recovered occurred while uploading the file to the server.
-     * @throws HttpException    When a violation of the HTTP protocol occurred. 
-     */
-    public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException {
-        int status = -1;
-        PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget));
-        
-        try {
-            File f = new File(localFile);
-            FileRequestEntity entity = new FileRequestEntity(f, contentType);
-            entity.addDatatransferProgressListener(mDataTransferListener);
-            put.setRequestEntity(entity);
-            status = executeMethod(put);
-            
-            exhaustResponse(put.getResponseBodyAsStream());
-            
-        } finally {
-            put.releaseConnection();    // let the connection available for other methods
-        }
-        return status;
-    }
-    
-    /**
-     * Tries to log in to the current URI, with the current credentials
-     * 
-     * @return A {@link HttpStatus}-Code of the result. SC_OK is good.
-     */
-    public int tryToLogin() {
-        int status = 0;
-        HeadMethod head = new HeadMethod(mUri.toString());
-        try {
-            status = executeMethod(head);
-            boolean result = status == HttpStatus.SC_OK;
-            Log_OC.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":""));
-            exhaustResponse(head.getResponseBodyAsStream());
-            
-        } catch (Exception e) {
-            logException(e, "trying to login at " + mUri.toString());
-            
-        } finally {
-            head.releaseConnection();
-        }
-        return status;
-    }
-
-    /**
      * Check if a file exists in the OC server
      * 
+     * TODO replace with ExistenceOperation
+     * 
      * @return              'true' if the file exists; 'false' it doesn't exist
      * @throws  Exception   When the existence could not be determined
      */
@@ -270,6 +160,45 @@ public class WebdavClient extends HttpClient {
             getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
         }
     }
+    
+    
+    @Override
+    public int executeMethod(HttpMethod method) throws IOException, HttpException {
+        boolean customRedirectionNeeded = false;
+        try {
+            method.setFollowRedirects(mFollowRedirects);
+        } catch (Exception e) {
+            //if (mFollowRedirects) Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + " method, custom redirection will be used if needed");
+            customRedirectionNeeded = mFollowRedirects;
+        }
+        if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) {
+            method.setRequestHeader("Cookie", mSsoSessionCookie);
+        }
+        int status = super.executeMethod(method);
+        int redirectionsCount = 0;
+        while (customRedirectionNeeded &&
+                redirectionsCount < MAX_REDIRECTIONS_COUNT &&
+                (   status == HttpStatus.SC_MOVED_PERMANENTLY || 
+                    status == HttpStatus.SC_MOVED_TEMPORARILY ||
+                    status == HttpStatus.SC_TEMPORARY_REDIRECT)
+                ) {
+            
+            Header location = method.getResponseHeader("Location");
+            if (location != null) {
+                Log_OC.d(TAG,  "Location to redirect: " + location.getValue());
+                method.setURI(new URI(location.getValue(), true));
+                status = super.executeMethod(method);
+                redirectionsCount++;
+                
+            } else {
+                Log_OC.d(TAG,  "No location to redirect!");
+                status = HttpStatus.SC_NOT_FOUND;
+            }
+        }
+        
+        return status;
+    }
+
 
     /**
      * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
@@ -289,25 +218,6 @@ public class WebdavClient extends HttpClient {
     }
 
     /**
-     * Logs an exception triggered in a HTTP request. 
-     * 
-     * @param e         Caught exception.
-     * @param doing     Suffix to add at the end of the logged message.
-     */
-    private void logException(Exception e, String doing) {
-        if (e instanceof HttpException) {
-            Log_OC.e(TAG, "HTTP violation while " + doing, e);
-
-        } else if (e instanceof IOException) {
-            Log_OC.e(TAG, "Unrecovered transport exception while " + doing, e);
-
-        } else {
-            Log_OC.e(TAG, "Unexpected exception while " + doing, e);
-        }
-    }
-
-    
-    /**
      * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.
      */
     public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
@@ -327,18 +237,20 @@ public class WebdavClient extends HttpClient {
         return mUri;
     }
 
-    @Override\r
-    public int executeMethod(HostConfiguration hostconfig, final HttpMethod method, final HttpState state) throws IOException, HttpException  {\r
-        if (mCredentials instanceof BearerCredentials) {\r
-            method.getHostAuthState().setAuthScheme(AuthPolicy.getAuthScheme(BearerAuthScheme.AUTH_POLICY));\r
-            method.getHostAuthState().setAuthAttempted(true);\r
-        }\r
-        return super.executeMethod(hostconfig, method, state);\r
-    }\r
-\r
-    \r
     public final Credentials getCredentials() {\r
         return mCredentials;\r
-    }\r
-\r
+    }
+    
+    public final String getSsoSessionCookie() {
+        return mSsoSessionCookie;
+    }
+
+    public void setFollowRedirects(boolean followRedirects) {
+        mFollowRedirects = followRedirects;
+    }
+
+    public String getAuthTokenType() {
+        return mAuthTokenType;
+    }
+
 }