From e6eb4b6e539ef3443acb077e93a4b898f0b3c085 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Tue, 23 Feb 2016 16:58:56 +0100 Subject: [PATCH 1/5] Added DELAYED_FOR_WIFI to RemoteOperationResult --- .../android/lib/common/operations/RemoteOperationResult.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 28709905..828ef9f16 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -108,7 +108,9 @@ public class RemoteOperationResult implements Serializable { PARTIAL_MOVE_DONE, PARTIAL_COPY_DONE, SHARE_WRONG_PARAMETER, - WRONG_SERVER_RESPONSE, INVALID_CHARACTER_DETECT_IN_SERVER + WRONG_SERVER_RESPONSE, + INVALID_CHARACTER_DETECT_IN_SERVER, + DELAYED_FOR_WIFI } private boolean mSuccess = false; From 023d8107caa0f54d6d6b780a6668f5af0176958d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Carlos=20Gonz=C3=A1lez=20Cabrero?= Date: Wed, 24 Feb 2016 10:26:51 +0100 Subject: [PATCH 2/5] New Result code added to RemoteOperationResult --- .../android/lib/common/operations/RemoteOperationResult.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 828ef9f16..85673c85 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -110,7 +110,8 @@ public class RemoteOperationResult implements Serializable { SHARE_WRONG_PARAMETER, WRONG_SERVER_RESPONSE, INVALID_CHARACTER_DETECT_IN_SERVER, - DELAYED_FOR_WIFI + DELAYED_FOR_WIFI, + LOCAL_FILE_NOT_FOUND } private boolean mSuccess = false; From d36fa0b38b50c5851a8429992d4bf6d26d374c55 Mon Sep 17 00:00:00 2001 From: masensio Date: Fri, 26 Feb 2016 14:14:44 +0100 Subject: [PATCH 3/5] Clean code --- .../lib/resources/status/OwnCloudVersion.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/com/owncloud/android/lib/resources/status/OwnCloudVersion.java b/src/com/owncloud/android/lib/resources/status/OwnCloudVersion.java index 9607cdc9..1b9f8546 100644 --- a/src/com/owncloud/android/lib/resources/status/OwnCloudVersion.java +++ b/src/com/owncloud/android/lib/resources/status/OwnCloudVersion.java @@ -36,7 +36,9 @@ public class OwnCloudVersion implements Comparable { 0x04000000); public static final OwnCloudVersion owncloud_v4_5 = new OwnCloudVersion( 0x04050000); - + + public static final int MINIMUN_VERSION_FOR_CHUNKED_UPLOADS = 0x04050000; // 4.5 + public static final int MINIMUM_VERSION_FOR_SHARING_API = 0x05001B00; // 5.0.27 public static final int MINIMUM_VERSION_WITH_FORBIDDEN_CHARS = 0x08010000; // 8.1 @@ -125,8 +127,12 @@ public class OwnCloudVersion implements Comparable { return versionValue; } - - + + + public boolean isChunkedUploadSupported() { + return (mVersion >= MINIMUN_VERSION_FOR_CHUNKED_UPLOADS); + } + public boolean isSharedSupported() { return (mVersion >= MINIMUM_VERSION_FOR_SHARING_API); } @@ -150,6 +156,4 @@ public class OwnCloudVersion implements Comparable { public boolean isVersionWithCapabilitiesAPI(){ return (mVersion>= MINIMUM_VERSION_CAPABILITIES_API); } - - } From 78b9aa6247f619780b6d9d93469c33d31c713e21 Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Mon, 14 Mar 2016 09:25:47 +0100 Subject: [PATCH 4/5] Redirections to the Identity Provider (IdP) are translated into ResultCode.UNAUTHORIZED --- .../android/lib/common/operations/RemoteOperation.java | 3 ++- .../android/lib/common/operations/RemoteOperationResult.java | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java index cb0d6db4..242f614a 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperation.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperation.java @@ -307,7 +307,8 @@ public abstract class RemoteOperation implements Runnable { * to trigger authentication update */ if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() && - (result.getCode() == ResultCode.UNAUTHORIZED || result.isIdPRedirection())) { + ResultCode.UNAUTHORIZED.equals(result.getCode()) + ) { /// possible fail due to lack of authorization // in an operation performed in foreground OwnCloudCredentials cred = mClient.getCredentials(); diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 85673c85..411c4f52 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -183,6 +183,9 @@ public class RemoteOperationResult implements Serializable { } } } + if (isIdPRedirection()) { + mCode = ResultCode.UNAUTHORIZED; // overrides default ResultCode.UNKNOWN + } } public RemoteOperationResult(boolean success, String bodyResponse, int httpCode) { From 0bfc3857072e8ac5e85a4fcb6746b8ea02fd46ec Mon Sep 17 00:00:00 2001 From: "David A. Velasco" Date: Mon, 21 Mar 2016 14:45:23 +0100 Subject: [PATCH 5/5] Improved detection of exceptions in uplaods due to local errors --- .../ChunkFromFileChannelRequestEntity.java | 33 +++++++++---- .../lib/common/network/FileRequestEntity.java | 48 +++++++++++++++---- .../operations/RemoteOperationResult.java | 4 ++ .../files/UploadRemoteFileOperation.java | 16 +++++++ 4 files changed, 83 insertions(+), 18 deletions(-) diff --git a/src/com/owncloud/android/lib/common/network/ChunkFromFileChannelRequestEntity.java b/src/com/owncloud/android/lib/common/network/ChunkFromFileChannelRequestEntity.java index 02c2fd59..39c3f000 100644 --- a/src/com/owncloud/android/lib/common/network/ChunkFromFileChannelRequestEntity.java +++ b/src/com/owncloud/android/lib/common/network/ChunkFromFileChannelRequestEntity.java @@ -25,6 +25,7 @@ package com.owncloud.android.lib.common.network; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -58,7 +59,9 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres Set mDataTransferListeners = new HashSet(); private ByteBuffer mBuffer = ByteBuffer.allocate(4096); - public ChunkFromFileChannelRequestEntity(final FileChannel channel, final String contentType, long chunkSize, final File file) { + public ChunkFromFileChannelRequestEntity( + final FileChannel channel, final String contentType, long chunkSize, final File file + ) { super(); if (channel == null) { throw new IllegalArgumentException("File may not be null"); @@ -119,15 +122,20 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres public void writeRequest(final OutputStream out) throws IOException { int readCount = 0; Iterator it = null; - - try { + + try { mChannel.position(mOffset); long size = mFile.length(); if (size == 0) size = -1; long maxCount = Math.min(mOffset + mChunkSize, mChannel.size()); while (mChannel.position() < maxCount) { readCount = mChannel.read(mBuffer); - out.write(mBuffer.array(), 0, readCount); + try { + out.write(mBuffer.array(), 0, readCount); + } catch (IOException io) { + // work-around try catch to filter exception in writing + throw new FileRequestEntity.WriteException(io); + } mBuffer.clear(); if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks mTransferred += readCount; @@ -139,12 +147,21 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres } } } - + } catch (IOException io) { - Log_OC.e(TAG, io.getMessage()); - throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io); - + // any read problem will be handled as if the file is not there + if (io instanceof FileNotFoundException) { + throw io; + } else { + FileNotFoundException fnf = new FileNotFoundException("Exception reading source file"); + fnf.initCause(io); + throw fnf; + } + + } catch (FileRequestEntity.WriteException we) { + throw we.getWrapped(); } + } } \ No newline at end of file diff --git a/src/com/owncloud/android/lib/common/network/FileRequestEntity.java b/src/com/owncloud/android/lib/common/network/FileRequestEntity.java index d2e1db9f..a79e5043 100644 --- a/src/com/owncloud/android/lib/common/network/FileRequestEntity.java +++ b/src/com/owncloud/android/lib/common/network/FileRequestEntity.java @@ -26,6 +26,7 @@ package com.owncloud.android.lib.common.network; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; @@ -100,12 +101,9 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer @Override public void writeRequest(final OutputStream out) throws IOException { - //byte[] tmp = new byte[4096]; ByteBuffer tmp = ByteBuffer.allocate(4096); int readResult = 0; - // TODO(bprzybylski): each mem allocation can throw OutOfMemoryError we need to handle it - // globally in some fashionable manner RandomAccessFile raf = new RandomAccessFile(mFile, "r"); FileChannel channel = raf.getChannel(); Iterator it = null; @@ -114,7 +112,12 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer if (size == 0) size = -1; try { while ((readResult = channel.read(tmp)) >= 0) { - out.write(tmp.array(), 0, readResult); + try { + out.write(tmp.array(), 0, readResult); + } catch (IOException io) { + // work-around try catch to filter exception in writing + throw new WriteException(io); + } tmp.clear(); transferred += readResult; synchronized (mDataTransferListeners) { @@ -124,14 +127,39 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer } } } - + } catch (IOException io) { - Log_OC.e("FileRequestException", io.getMessage()); - throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io); - + // any read problem will be handled as if the file is not there + if (io instanceof FileNotFoundException) { + throw io; + } else { + FileNotFoundException fnf = new FileNotFoundException("Exception reading source file"); + fnf.initCause(io); + throw fnf; + } + + } catch (WriteException we) { + throw we.getWrapped(); + } finally { - channel.close(); - raf.close(); + try { + channel.close(); + raf.close(); + } catch (IOException io) { + // ignore failures closing source file + } + } + } + + protected static class WriteException extends Exception { + IOException mWrapped; + + WriteException(IOException wrapped) { + mWrapped = wrapped; + } + + public IOException getWrapped() { + return mWrapped; } } diff --git a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 411c4f52..ce2cbd1c 100644 --- a/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -25,6 +25,7 @@ package com.owncloud.android.lib.common.operations; import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; @@ -260,6 +261,9 @@ public class RemoteOperationResult implements Serializable { mCode = ResultCode.SSL_ERROR; } + } else if (e instanceof FileNotFoundException) { + mCode = ResultCode.LOCAL_FILE_NOT_FOUND; + } else { mCode = ResultCode.UNKNOWN_ERROR; } diff --git a/src/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java b/src/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java index aca54f05..2080c4a2 100644 --- a/src/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java +++ b/src/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java @@ -32,9 +32,11 @@ 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; @@ -87,8 +89,16 @@ public class UploadRemoteFileOperation extends RemoteOperation { @Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; + DefaultHttpMethodRetryHandler oldRetryHandler = + (DefaultHttpMethodRetryHandler) client.getParams().getParameter(HttpMethodParams.RETRY_HANDLER); try { + // prevent that uploads are retried automatically by network library + client.getParams().setParameter( + HttpMethodParams.RETRY_HANDLER, + new DefaultHttpMethodRetryHandler(0, false) + ); + mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath)); if (mCancellationRequested.get()) { @@ -114,6 +124,12 @@ public class UploadRemoteFileOperation extends RemoteOperation { } else { result = new RemoteOperationResult(e); } + } finally { + // reset previous retry handler + client.getParams().setParameter( + HttpMethodParams.RETRY_HANDLER, + oldRetryHandler + ); } return result; }