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

Unverified Commit b86c5d5d authored by AndyScherzinger's avatar AndyScherzinger
Browse files

manually patch remaining classes for improved error info handling

parent ed3125f4
Loading
Loading
Loading
Loading
+148 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.owncloud.android.lib.resources.notifications.models.PushResponse;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
import org.json.JSONException;
@@ -57,7 +58,7 @@ import javax.net.ssl.SSLException;

/**
 * The result of a remote operation required to an ownCloud server.
 * <p/>
 *
 * Provides a common classification of remote operation results for all the
 * application.
 *
@@ -124,6 +125,7 @@ public class RemoteOperationResult implements Serializable {

    private boolean mSuccess = false;
    private int mHttpCode = -1;
    private String mHttpPhrase = null;
    private Exception mException = null;
    private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
    private String mRedirectedLocation;
@@ -134,6 +136,13 @@ public class RemoteOperationResult implements Serializable {
    private List<Notification> mNotificationData;
    private PushResponse mPushResponse;

    /**
     * Public constructor from result code.
     * <p>
     * To be used when the caller takes the responsibility of interpreting the result of a {@link RemoteOperation}
     *
     * @param code {@link ResultCode} decided by the caller.
     */
    public RemoteOperationResult(ResultCode code) {
        mCode = code;
		mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL ||
@@ -228,9 +237,17 @@ public class RemoteOperationResult implements Serializable {
                            httpCode);
            }
        }

    }

    /**
     * Public constructor from exception.
     *
     * To be used when an exception prevented the end of the {@link RemoteOperation}.
     *
     * Determines a {@link ResultCode} depending on the type of the exception.
     *
     * @param e Exception that interrupted the {@link RemoteOperation}
     */
    public RemoteOperationResult(Exception e) {
        mException = e;

@@ -278,9 +295,134 @@ public class RemoteOperationResult implements Serializable {
        } else {
            mCode = ResultCode.UNKNOWN_ERROR;
        }
    }

    /**
     * Public constructor from separate elements of an HTTP or DAV response.
     *
     * To be used when the result needs to be interpreted from the response of an HTTP/DAV method.
     *
     * Determines a {@link ResultCode} from the already executed method received as a parameter. Generally,
     * will depend on the HTTP code and HTTP response headers received. In some cases will inspect also the
     * response body.
     *
     * @param success    The operation was considered successful or not.
     * @param httpMethod HTTP/DAV method already executed which response will be examined to interpret the
     *                   result.
     */
    public RemoteOperationResult(boolean success, HttpMethod httpMethod) throws IOException {
        this(
                success,
                httpMethod.getStatusCode(),
                httpMethod.getStatusText(),
                httpMethod.getResponseHeaders()
        );

        if (mHttpCode == HttpStatus.SC_BAD_REQUEST) {   // 400
            String bodyResponse = httpMethod.getResponseBodyAsString();
            // do not get for other HTTP codes!; could not be available

            if (bodyResponse != null && bodyResponse.length() > 0) {
                InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
                InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
                try {
                    if (xmlParser.parseXMLResponse(is)) {
                        mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER;
                    }

                } catch (Exception e) {
                    Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
                    // mCode stays as set in this(success, httpCode, headers)
                }
            }
        }
    }

    /**
     * Public constructor from separate elements of an HTTP or DAV response.
     *
     * To be used when the result needs to be interpreted from HTTP response elements that could come from
     * different requests (WARNING: black magic, try to avoid).
     *
     * If all the fields come from the same HTTP/DAV response, {@link #RemoteOperationResult(boolean, HttpMethod)}
     * should be used instead.
     *
     * Determines a {@link ResultCode} depending on the HTTP code and HTTP response headers received.
     *
     * @param success     The operation was considered successful or not.
     * @param httpCode    HTTP status code returned by an HTTP/DAV method.
     * @param httpPhrase  HTTP status line phrase returned by an HTTP/DAV method
     * @param httpHeaders HTTP response header returned by an HTTP/DAV method
     */
    public RemoteOperationResult(boolean success, int httpCode, String httpPhrase, Header[] httpHeaders) {
        this(success, httpCode, httpPhrase);
        if (httpHeaders != null) {
            Header current;
            for (Header httpHeader : httpHeaders) {
                current = httpHeader;
                if ("location".equals(current.getName().toLowerCase())) {
                    mRedirectedLocation = current.getValue();
                    continue;
                }
                if ("www-authenticate".equals(current.getName().toLowerCase())) {
                    mAuthenticate = current.getValue();
                    break;
                }
            }
        }
        if (isIdPRedirection()) {
            mCode = ResultCode.UNAUTHORIZED;    // overrides default ResultCode.UNKNOWN
        }
    }

    /**
     * Private constructor for results built interpreting a HTTP or DAV response.
     *
     * Determines a {@link ResultCode} depending of the type of the exception.
     *
     * @param success    Operation was successful or not.
     * @param httpCode   HTTP status code returned by the HTTP/DAV method.
     * @param httpPhrase HTTP status line phrase returned by the HTTP/DAV method
     */
    private RemoteOperationResult(boolean success, int httpCode, String httpPhrase) {
        mSuccess = success;
        mHttpCode = httpCode;
        mHttpPhrase = httpPhrase;

        if (success) {
            mCode = ResultCode.OK;

        } else if (httpCode > 0) {
            switch (httpCode) {
                case HttpStatus.SC_UNAUTHORIZED:                    // 401
                    mCode = ResultCode.UNAUTHORIZED;
                    break;
                case HttpStatus.SC_FORBIDDEN:                       // 403
                    mCode = ResultCode.FORBIDDEN;
                    break;
                case HttpStatus.SC_NOT_FOUND:                       // 404
                    mCode = ResultCode.FILE_NOT_FOUND;
                    break;
                case HttpStatus.SC_CONFLICT:                        // 409
                    mCode = ResultCode.CONFLICT;
                    break;
                case HttpStatus.SC_INTERNAL_SERVER_ERROR:           // 500
                    mCode = ResultCode.INSTANCE_NOT_CONFIGURED;     // assuming too much...
                    break;
                case HttpStatus.SC_SERVICE_UNAVAILABLE:             // 503
                    mCode = ResultCode.MAINTENANCE_MODE;
                    break;
                case HttpStatus.SC_INSUFFICIENT_STORAGE:            // 507
                    mCode = ResultCode.QUOTA_EXCEEDED;
                    break;
                default:
                    mCode = ResultCode.UNHANDLED_HTTP_CODE;         // UNKNOWN ERROR
                    Log_OC.d(TAG,
                            "RemoteOperationResult has processed UNHANDLED_HTTP_CODE: "
                                    + mHttpCode + " " + mHttpPhrase);
            }
        }
    }

    public void setData(ArrayList<Object> files) {
        mData = files;
@@ -318,6 +460,10 @@ public class RemoteOperationResult implements Serializable {
        return mHttpCode;
    }

    public String getHttpPhrase() {
        return mHttpPhrase;
    }

    public ResultCode getCode() {
        return mCode;
    }
+17 −21
Original line number Diff line number Diff line
@@ -31,15 +31,13 @@ import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.ChunkFromFileChannelRequestEntity;
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.InvalidCharacterExceptionParser;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;

import org.apache.commons.httpclient.methods.PutMethod;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Calendar;
@@ -70,8 +68,9 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
    }
    
    @Override
    protected int uploadFile(OwnCloudClient client) throws IOException {
    protected RemoteOperationResult uploadFile(OwnCloudClient client) throws IOException {
        int status = -1;
        RemoteOperationResult result = null;

        FileChannel channel = null;
        RandomAccessFile raf = null;
@@ -136,19 +135,7 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation

                status = client.executeMethod(mPutMethod);

                if (status == 400) {
                    InvalidCharacterExceptionParser xmlParser =
                            new InvalidCharacterExceptionParser();
                    InputStream is = new ByteArrayInputStream(
                            mPutMethod.getResponseBodyAsString().getBytes());
                    try {
                        mForbiddenCharsInServer = xmlParser.parseXMLResponse(is);

                    } catch (Exception e) {
                        mForbiddenCharsInServer = false;
                        Log_OC.e(TAG, "Exception reading exception from server", e);
                    }
                }
                result = new RemoteOperationResult(isSuccess(status), mPutMethod);

                client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
                Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath +
@@ -173,13 +160,22 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation
            }

            if (channel != null)
                try {
                    channel.close();
            if (raf != null)
                } catch (IOException e) {
                    Log_OC.e(TAG, "Error closing file channel!", e);
                }
            if (raf != null) {
                try {
                    raf.close();
                } catch (IOException e) {
                    Log_OC.e(TAG, "Error closing file access!", e);
                }
            }
            if (mPutMethod != null)
                mPutMethod.releaseConnection();    // let the connection available for other methods
        }
        return status;
        return result;
    }

    private String getDateAsString() {
+8 −12
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ import java.io.IOException;
/**
 * Remote operation moving a remote file or folder in the ownCloud server to a different folder
 * in the same account.
 * <p/>
 *
 * Allows renaming the moving file/folder at the same time.
 *
 * @author David A. Velasco
@@ -65,7 +65,7 @@ public class CopyRemoteFileOperation extends RemoteOperation {

    /**
     * Constructor.
     * <p/>
     *
     * TODO Paths should finish in "/" in the case of folders. ?
     *
     * @param srcRemotePath    Remote path of the file/folder to move.
@@ -134,18 +134,17 @@ public class CopyRemoteFileOperation extends RemoteOperation {
                client.exhaustResponse(copyMethod.getResponseBodyAsStream());
            }

            Log.i(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
                    result.getLogMessage());
            Log.i(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage());

        } catch (Exception e) {
            result = new RemoteOperationResult(e);
            Log.e(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " +
                    result.getLogMessage(), e);
            Log.e(TAG, "Copy " + mSrcRemotePath + " to " + mTargetRemotePath + ": " + result.getLogMessage(), e);

        } finally {
            if (copyMethod != null)
            if (copyMethod != null) {
                copyMethod.releaseConnection();
            }
        }

        return result;
    }
@@ -153,10 +152,10 @@ public class CopyRemoteFileOperation extends RemoteOperation {

    /**
     * Analyzes a multistatus response from the OC server to generate an appropriate result.
     * <p/>
     *
     * In WebDAV, a COPY request on collections (folders) can be PARTIALLY successful: some
     * children are copied, some other aren't.
     * <p/>
     *
     * According to the WebDAV specification, a multistatus response SHOULD NOT include partial
     * successes (201, 204) nor for descendants of already failed children (424) in the response
     * entity. But SHOULD NOT != MUST NOT, so take carefully.
@@ -193,12 +192,9 @@ public class CopyRemoteFileOperation extends RemoteOperation {
        }

        return result;

    }


    protected boolean isSuccess(int status) {
        return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT;
    }

}
+18 −39
Original line number Diff line number Diff line
@@ -24,30 +24,26 @@

package com.owncloud.android.lib.resources.files;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;

import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.FileRequestEntity;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.InvalidCharacterExceptionParser;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Remote operation performing the upload of a remote file to the ownCloud server.
@@ -69,7 +65,6 @@ public class UploadRemoteFileOperation extends RemoteOperation {
	protected String mMimeType;
	protected String mFileLastModifTimestamp;
	protected PutMethod mPutMethod = null;
	protected boolean mForbiddenCharsInServer = false;
	protected String mRequiredEtag = null;

	protected final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
@@ -112,14 +107,7 @@ public class UploadRemoteFileOperation extends RemoteOperation {

			} else {
				// perform the upload
				int status = uploadFile(client);
				if (mForbiddenCharsInServer){
					result = new RemoteOperationResult(
							RemoteOperationResult.ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER);
				} else {
					result = new RemoteOperationResult(isSuccess(status), status,
							(mPutMethod != null ? mPutMethod.getResponseHeaders() : null));
				}
				result = uploadFile(client);
			}

		} catch (Exception e) {
@@ -144,8 +132,10 @@ public class UploadRemoteFileOperation extends RemoteOperation {
                status == HttpStatus.SC_NO_CONTENT));
	}

	protected int uploadFile(OwnCloudClient client) throws IOException {
	protected RemoteOperationResult uploadFile(OwnCloudClient client) throws IOException {
		int status = -1;
		RemoteOperationResult result;

		try {
			File f = new File(mLocalPath);
			mEntity  = new FileRequestEntity(f, mMimeType);
@@ -161,25 +151,14 @@ public class UploadRemoteFileOperation extends RemoteOperation {
			mPutMethod.setRequestEntity(mEntity);
			status = client.executeMethod(mPutMethod);

			if (status == 400) {
				InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
				InputStream is = new ByteArrayInputStream(
						mPutMethod.getResponseBodyAsString().getBytes());
				try {
					mForbiddenCharsInServer = xmlParser.parseXMLResponse(is);

				} catch (Exception e) {
					mForbiddenCharsInServer = false;
					Log_OC.e(TAG, "Exception reading exception from server", e);
				}
			}
			result = new RemoteOperationResult(isSuccess(status), mPutMethod);

			client.exhaustResponse(mPutMethod.getResponseBodyAsStream());

		} finally {
			mPutMethod.releaseConnection(); // let the connection available for other methods
		}
		return status;
		return result;
	}

    public Set<OnDatatransferProgressListener> getDataTransferListeners() {
+7 −15
Original line number Diff line number Diff line
@@ -85,11 +85,7 @@ public class GetRemoteStatusOperation extends RemoteOperation {
            client.setFollowRedirects(false);
            boolean isRedirectToNonSecureConnection = false;
            int status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
            mLatestResult = new RemoteOperationResult(
            		(status == HttpStatus.SC_OK),
            		status,
            		get.getResponseHeaders()
    		);
            mLatestResult = new RemoteOperationResult((status == HttpStatus.SC_OK), get);

        	String redirectedLocation = mLatestResult.getRedirectedLocation();
        	while (redirectedLocation != null && redirectedLocation.length() > 0
@@ -102,11 +98,7 @@ public class GetRemoteStatusOperation extends RemoteOperation {
                get.releaseConnection();
                get = new GetMethod(redirectedLocation);
                status = client.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
        		mLatestResult = new RemoteOperationResult(
        				(status == HttpStatus.SC_OK), 
        				status, 
        				get.getResponseHeaders()
				); 
                mLatestResult = new RemoteOperationResult((status == HttpStatus.SC_OK), get);
                redirectedLocation = mLatestResult.getRedirectedLocation();
            }