Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 639cb7ea authored by masensio's avatar masensio
Browse files

Merge pull request #70 from owncloud/keep_permanent_redirection_in_existence_check

Get that ExistenceCheckRemoteOperation remembers the sequence of foll…
parents e48aa9c3 41dcc337
Loading
Loading
Loading
Loading
+45 −40
Original line number Original line Diff line number Diff line
@@ -49,13 +49,14 @@ import android.net.Uri;


import com.owncloud.android.lib.common.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials;
import com.owncloud.android.lib.common.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.common.utils.Log_OC;


public class OwnCloudClient extends HttpClient {
public class OwnCloudClient extends HttpClient {
	
	
    private static final String TAG = OwnCloudClient.class.getSimpleName();
    private static final String TAG = OwnCloudClient.class.getSimpleName();
    private static final int MAX_REDIRECTIONS_COUNT = 3;
    public static final int MAX_REDIRECTIONS_COUNT = 3;
    private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
    private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
    private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true;
    private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true;
    
    
@@ -173,8 +174,8 @@ public class OwnCloudClient extends HttpClient {
     * @param readTimeout           Timeout to set for data reception
     * @param readTimeout           Timeout to set for data reception
     * @param connectionTimeout     Timeout to set for connection establishment
     * @param connectionTimeout     Timeout to set for connection establishment
     */
     */
    public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) 
    public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws IOException {
    		throws HttpException, IOException {

        int oldSoTimeout = getParams().getSoTimeout();
        int oldSoTimeout = getParams().getSoTimeout();
        int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
        int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
        try {
        try {
@@ -193,22 +194,16 @@ public class OwnCloudClient extends HttpClient {
    }
    }




    /**
     * Requests the received method.
     *
     * Executes the method through the inherited HttpClient.executedMethod(method).
     *
     * @param method                HTTP method request.
     */
    @Override
    @Override
    public int executeMethod(HttpMethod method) throws IOException, HttpException {
    public int executeMethod(HttpMethod method) throws IOException {
        try {	// just to log 
	        boolean customRedirectionNeeded = false;
	        
        try {
        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;
	        }

            // Update User Agent
            // Update User Agent
            HttpParams params = method.getParams();
            HttpParams params = method.getParams();
            String userAgent = OwnCloudClientManagerFactory.getUserAgent();
            String userAgent = OwnCloudClientManagerFactory.getUserAgent();
@@ -219,11 +214,12 @@ public class OwnCloudClient extends HttpClient {


//	        logCookiesAtRequest(method.getRequestHeaders(), "before");
//	        logCookiesAtRequest(method.getRequestHeaders(), "before");
//	        logCookiesAtState("before");
//	        logCookiesAtState("before");
            method.setFollowRedirects(false);


            int status = super.executeMethod(method);
            int status = super.executeMethod(method);


	        if (customRedirectionNeeded) {
            if (mFollowRedirects) {
	        	status = patchRedirection(status, method);
                status = followRedirection(method).getLastStatus();
            }
            }


//	        logCookiesAtRequest(method.getRequestHeaders(), "after");
//	        logCookiesAtRequest(method.getRequestHeaders(), "after");
@@ -233,13 +229,16 @@ public class OwnCloudClient extends HttpClient {
            return status;
            return status;


        } catch (IOException e) {
        } catch (IOException e) {
        	Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e);
            //Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e);
            throw e;
            throw e;
        }
        }
    }
    }


	private int patchRedirection(int status, HttpMethod method) throws HttpException, IOException {

	public RedirectionPath followRedirection(HttpMethod method) throws IOException {
        int redirectionsCount = 0;
        int redirectionsCount = 0;
        int status = method.getStatusCode();
        RedirectionPath result = new RedirectionPath(status, MAX_REDIRECTIONS_COUNT);
        while (redirectionsCount < MAX_REDIRECTIONS_COUNT &&
        while (redirectionsCount < MAX_REDIRECTIONS_COUNT &&
                (   status == HttpStatus.SC_MOVED_PERMANENTLY || 
                (   status == HttpStatus.SC_MOVED_PERMANENTLY || 
                    status == HttpStatus.SC_MOVED_TEMPORARILY ||
                    status == HttpStatus.SC_MOVED_TEMPORARILY ||
@@ -254,18 +253,20 @@ public class OwnCloudClient extends HttpClient {
                Log_OC.d(TAG + " #" + mInstanceNumber,  
                Log_OC.d(TAG + " #" + mInstanceNumber,  
                		"Location to redirect: " + location.getValue());
                		"Location to redirect: " + location.getValue());


                String locationStr = location.getValue();
                result.addLocation(locationStr);

                // Release the connection to avoid reach the max number of connections per host
                // Release the connection to avoid reach the max number of connections per host
                // due to it will be set a different url
                // due to it will be set a different url
                exhaustResponse(method.getResponseBodyAsStream());
                exhaustResponse(method.getResponseBodyAsStream());
                method.releaseConnection();
                method.releaseConnection();


                method.setURI(new URI(location.getValue(), true));
                method.setURI(new URI(locationStr, true));
                Header destination = method.getRequestHeader("Destination");
                Header destination = method.getRequestHeader("Destination");
                if (destination == null) {
                if (destination == null) {
                	destination = method.getRequestHeader("destination");
                	destination = method.getRequestHeader("destination");
                }
                }
                if (destination != null) {
                if (destination != null) {
                	String locationStr = location.getValue();
                	int suffixIndex = locationStr.lastIndexOf(
                	int suffixIndex = locationStr.lastIndexOf(
                	    	(mCredentials instanceof OwnCloudBearerCredentials) ? 
                	    	(mCredentials instanceof OwnCloudBearerCredentials) ? 
                	    			AccountUtils.ODAV_PATH :
                	    			AccountUtils.ODAV_PATH :
@@ -281,6 +282,7 @@ public class OwnCloudClient extends HttpClient {
                    method.setRequestHeader(destination);
                    method.setRequestHeader(destination);
                }
                }
                status = super.executeMethod(method);
                status = super.executeMethod(method);
                result.addStatus(status);
                redirectionsCount++;
                redirectionsCount++;
                
                
            } else {
            } else {
@@ -288,7 +290,7 @@ public class OwnCloudClient extends HttpClient {
                status = HttpStatus.SC_NOT_FOUND;
                status = HttpStatus.SC_NOT_FOUND;
            }
            }
        }
        }
        return status;
        return result;
	}
	}


	/**
	/**
@@ -356,6 +358,9 @@ public class OwnCloudClient extends HttpClient {
        mFollowRedirects = followRedirects;
        mFollowRedirects = followRedirects;
    }
    }


    public boolean getFollowRedirects() {
        return mFollowRedirects;
    }


	private void logCookiesAtRequest(Header[] headers, String when) {
	private void logCookiesAtRequest(Header[] headers, String when) {
        int counter = 0;
        int counter = 0;
+127 −0
Original line number Original line Diff line number Diff line
/* ownCloud Android Library is available under MIT license
 *
 *   @author David A. Velasco
 *
 *   Copyright (C) 2015 ownCloud Inc.
 *
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 *   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 *   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 *   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 *
 */

package com.owncloud.android.lib.common.network;

import org.apache.http.HttpStatus;

import java.util.Arrays;


/**
 * Aggregate saving the list of URLs followed in a sequence of redirections during the exceution of a
 * {@link com.owncloud.android.lib.common.operations.RemoteOperation}, and the status codes corresponding to all
 * of them.
 *
 * The last status code saved corresponds to the first response not being a redirection, unless the sequence exceeds
 * the maximum length of redirections allowed by the {@link com.owncloud.android.lib.common.OwnCloudClient} instance
 * that ran the operation.
 *
 * If no redirection was followed, the last (and first) status code contained corresponds to the original URL in the
 * request.
 */
public class RedirectionPath {

    private int[] mStatuses = null;

    private int mLastStatus = -1;

    private String[] mLocations = null;

    private int mLastLocation = -1;
    private int maxRedirections;

    /**
     * Public constructor.
     *
     * @param status            Status code resulting of executing a request on the original URL.
     * @param maxRedirections   Maximum number of redirections that will be contained.
     * @throws IllegalArgumentException     If 'maxRedirections' is < 0
     */
    public RedirectionPath(int status, int maxRedirections) {
        if (maxRedirections < 0) {
            throw new IllegalArgumentException("maxRedirections MUST BE zero or greater");
        }
        mStatuses = new int[maxRedirections + 1];
        Arrays.fill(mStatuses, -1);
        mStatuses[++mLastStatus] = status;
    }

    /**
     * Adds a new location URL to the list of followed redirections.
     *
     * @param location      URL extracted from a 'Location' header in a redirection.
     */
    public void addLocation(String location) {
        if (mLocations == null) {
            mLocations = new String[mStatuses.length - 1];
        }
        if (mLastLocation < mLocations.length - 1) {
            mLocations[++mLastLocation] = location;
        }
    }


    /**
     * Adds a new status code to the list of status corresponding to followed redirections.
     *
     * @param status     Status code from the response of another followed redirection.
     */
    public void addStatus(int status) {
        if (mLastStatus < mStatuses.length - 1) {
            mStatuses[++mLastStatus] = status;
        }
    }

    /**
     * @return      Last status code saved.
     */
    public int getLastStatus() {
        return mStatuses[mLastStatus];
    }

    /**
     * @return      Last location followed corresponding to a permanent redirection (status code 301).
     */
    public String getLastPermanentLocation() {
        for (int i = mLastStatus; i >= 0; i--) {
            if (mStatuses[i] == HttpStatus.SC_MOVED_PERMANENTLY && i <= mLastLocation) {
                return mLocations[i];
            }
        }
        return null;
    }

    /**
     * @return      Count of locations.
     */
    public int getRedirectionsCount() {
        return mLastLocation + 1;
    }


}
+14 −5
Original line number Original line Diff line number Diff line
@@ -60,9 +60,9 @@ import com.owncloud.android.lib.common.utils.Log_OC;
public class RemoteOperationResult implements Serializable {
public class RemoteOperationResult implements Serializable {
	
	
	/** Generated - should be refreshed every time the class changes!! */;
	/** Generated - should be refreshed every time the class changes!! */;
	private static final long serialVersionUID = -9003837206000993465L;
    private static final long serialVersionUID = 25745846447996048L;


	private static final String TAG = "RemoteOperationResult";
    private static final String TAG = RemoteOperationResult.class.getSimpleName();


    public enum ResultCode {
    public enum ResultCode {
        OK,
        OK,
@@ -112,6 +112,7 @@ public class RemoteOperationResult implements Serializable {
    private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
    private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
    private String mRedirectedLocation;
    private String mRedirectedLocation;
    private String mAuthenticate;
    private String mAuthenticate;
    private String mLastPermanentLocation = null;


    private ArrayList<Object> mData;
    private ArrayList<Object> mData;


@@ -391,4 +392,12 @@ public class RemoteOperationResult implements Serializable {
    	return mAuthenticate;
    	return mAuthenticate;
    }
    }


    public String getLastPermanentLocation() {
        return mLastPermanentLocation;
    }

    public void setLastPermanentLocation(String lastPermanentLocation) {
        mLastPermanentLocation = lastPermanentLocation;
    }

}
}
+26 −2
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager;


import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
@@ -52,6 +53,9 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
    private Context mContext;
    private Context mContext;
    private boolean mSuccessIfAbsent;
    private boolean mSuccessIfAbsent;


    /** Sequence of redirections followed. Available only after executing the operation */
    private RedirectionPath mRedirectionPath = null;
        // TODO move to {@link RemoteOperation}, that needs a nice refactoring


    /**
    /**
     * Full constructor. Success of the operation will depend upon the value of successIfAbsent.
     * Full constructor. Success of the operation will depend upon the value of successIfAbsent.
@@ -75,9 +79,13 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
        }
        }
        RemoteOperationResult result = null;
        RemoteOperationResult result = null;
        HeadMethod head = null;
        HeadMethod head = null;
        boolean previousFollowRedirects = client.getFollowRedirects();
        try {
        try {
            head = new HeadMethod(client.getWebdavUri() + WebdavUtils.encodePath(mPath));
            head = new HeadMethod(client.getWebdavUri() + WebdavUtils.encodePath(mPath));
            int status = client.executeMethod(head, TIMEOUT, TIMEOUT);
            client.setFollowRedirects(false);
            client.executeMethod(head, TIMEOUT, TIMEOUT);
            mRedirectionPath = client.followRedirection(head);
            int status = mRedirectionPath.getLastStatus();
            client.exhaustResponse(head.getResponseBodyAsStream());
            client.exhaustResponse(head.getResponseBodyAsStream());
            boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) ||
            boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) ||
                    (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
                    (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
@@ -97,6 +105,7 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
        } finally {
        } finally {
            if (head != null)
            if (head != null)
                head.releaseConnection();
                head.releaseConnection();
            client.setFollowRedirects(previousFollowRedirects);
        }
        }
        return result;
        return result;
	}
	}
@@ -109,4 +118,19 @@ public class ExistenceCheckRemoteOperation extends RemoteOperation {
    }
    }




    /**
     * Gets the sequence of redirections followed during the execution of the operation.
     *
     * @return      Sequence of redirections followed, if any, or NULL if the operation was not executed.
     */
    public RedirectionPath getRedirectionPath() {
        return mRedirectionPath;
    }

    /**
     * @return      'True' if the operation was executed and at least one redirection was followed.
     */
    public boolean wasRedirected() {
        return (mRedirectionPath != null && mRedirectionPath.getRedirectionsCount() > 0);
    }
}
}
+1 −3
Original line number Original line Diff line number Diff line
@@ -103,9 +103,7 @@ public class GetRemoteStatusOperation extends RemoteOperation {
				);
				);
        		get.releaseConnection();
        		get.releaseConnection();
        		get = new GetMethod(redirectedLocation);
        		get = new GetMethod(redirectedLocation);
        		status = client.executeMethod(
        		status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
        				get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT
				);
        		mLatestResult = new RemoteOperationResult(
        		mLatestResult = new RemoteOperationResult(
        				(status == HttpStatus.SC_OK), 
        				(status == HttpStatus.SC_OK), 
        				status, 
        				status, 
+2 −2

File changed.

Contains only whitespace changes.

+1 −1

File changed.

Contains only whitespace changes.

Loading