diff --git a/README.md b/README.md index 7a29cb82..b86531b1 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,11 @@ ownCloud Android Library is available under MIT license. See the file LICENSE.md #### Third party libraries -ownCloud Android Library uses OkHttp version 3.10, licensed under Apache License and version 2.0. Besides, it uses Dav4Android, licensed under Mozilla Public License, v. 2.0 +ownCloud Android Library uses OkHttp version 4.6.0, licensed under Apache License and version 2.0. Besides, it uses Dav4Android, licensed under Mozilla Public License, v. 2.0 ### Compatibility -ownCloud Android Library is valid for Android systems from version Android 2.2 (android:minSdkVersion="8" android:targetSdkVersion="19"). +ownCloud Android Library is valid for Android systems from version Android 5 (android:minSdkVersion="21" android:targetSdkVersion="29"). ownCloud Android library supports ownCloud server from version 4.5. diff --git a/build.gradle b/build.gradle index 6ce35582..f51df2b2 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' + classpath 'com.android.tools.build:gradle:4.0.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2f02f8a6..391434d7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip diff --git a/owncloudComLibrary/build.gradle b/owncloudComLibrary/build.gradle index 97a1bbae..ef04982b 100644 --- a/owncloudComLibrary/build.gradle +++ b/owncloudComLibrary/build.gradle @@ -4,9 +4,9 @@ apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-allopen' dependencies { - api 'com.squareup.okhttp3:okhttp:3.12.0' + api 'com.squareup.okhttp3:okhttp:4.6.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" - api 'com.gitlab.ownclouders:dav4android:oc_support_1.0.1' + api 'com.gitlab.ownclouders:dav4android:oc_support_2.1.5' api 'com.github.hannesa2:Logcat:1.6.0' api 'net.openid:appauth:0.7.1' @@ -23,14 +23,14 @@ allOpen { } android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 29 - versionCode = 10000500 - versionName = "1.0.5" + versionCode = 10000600 + versionName = "1.0.6" // This is pretty ugly but manifest placeholders don't seem to work very well when using different modules // See https://github.com/openid/AppAuth-Android/issues/325 diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java index 3ab812d4..7491e0ae 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/OwnCloudClient.java @@ -29,7 +29,7 @@ import android.accounts.AccountManager; import android.accounts.AccountsException; import android.net.Uri; -import at.bitfire.dav4android.exception.HttpException; +import at.bitfire.dav4jvm.exception.HttpException; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.authentication.OwnCloudCredentials; import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory; @@ -89,11 +89,6 @@ public class OwnCloudClient extends HttpClient { if (!(mCredentials instanceof OwnCloudAnonymousCredentials)) { mCredentials = OwnCloudCredentialsFactory.getAnonymousCredentials(); } - mCredentials.applyTo(this); - } - - void applyCredentials() { - mCredentials.applyTo(this); } public int executeHttpMethod(HttpBaseMethod method) throws Exception { @@ -102,8 +97,17 @@ public class OwnCloudClient extends HttpClient { int status; do { - setRequestId(method); + String requestId = RandomUtils.generateRandomUUID(); + // Header to allow tracing requests in apache and ownCloud logs + Timber.d("Executing in request with id %s", requestId); + method.setRequestHeader(HttpConstants.OC_X_REQUEST_ID, requestId); + method.setRequestHeader(HttpConstants.USER_AGENT_HEADER, SingleSessionManager.getUserAgent()); + method.setRequestHeader(HttpConstants.PARAM_SINGLE_COOKIE_HEADER, "true"); + method.setRequestHeader(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY); + if (mCredentials.getHeaderAuth() != null) { + method.setRequestHeader(HttpConstants.AUTHORIZATION_HEADER, mCredentials.getHeaderAuth()); + } status = method.execute(); if (mFollowRedirects) { @@ -125,8 +129,17 @@ public class OwnCloudClient extends HttpClient { int status; do { - setRequestId(method); + String requestId = RandomUtils.generateRandomUUID(); + // Header to allow tracing requests in apache and ownCloud logs + Timber.d("Executing in request with id %s", requestId); + method.setRequestHeader(OC_X_REQUEST_ID, requestId); + method.setRequestHeader(HttpConstants.USER_AGENT_HEADER, SingleSessionManager.getUserAgent()); + method.setRequestHeader(HttpConstants.PARAM_SINGLE_COOKIE_HEADER, "true"); + method.setRequestHeader(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY); + if (mCredentials.getHeaderAuth() != null) { + method.setRequestHeader(HttpConstants.AUTHORIZATION_HEADER, mCredentials.getHeaderAuth()); + } status = method.execute(); repeatWithFreshCredentials = checkUnauthorizedAccess(status, repeatCounter); @@ -138,19 +151,6 @@ public class OwnCloudClient extends HttpClient { return status; } - private void setRequestId(HttpBaseMethod method) { - // Clean previous request id. This is a bit hacky but is the only way to add request headers in WebDAV - // methods by using Dav4Android - deleteHeaderForAllRequests(OC_X_REQUEST_ID); - - String requestId = RandomUtils.generateRandomUUID(); - - // Header to allow tracing requests in apache and ownCloud logs - addHeaderForAllRequests(OC_X_REQUEST_ID, requestId); - - Timber.d("Executing in request with id %s", requestId); - } - public RedirectionPath followRedirection(HttpBaseMethod method) throws Exception { int redirectionsCount = 0; int status = method.getStatusCode(); @@ -215,9 +215,6 @@ public class OwnCloudClient extends HttpClient { public void exhaustResponse(InputStream responseBodyAsStream) { if (responseBodyAsStream != null) { try { - while (responseBodyAsStream.read(sExhaustBuffer) >= 0) { - ; - } responseBodyAsStream.close(); } catch (IOException io) { @@ -273,7 +270,6 @@ public class OwnCloudClient extends HttpClient { public void setCredentials(OwnCloudCredentials credentials) { if (credentials != null) { mCredentials = credentials; - mCredentials.applyTo(this); } else { clearCredentials(); } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/SingleSessionManager.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/SingleSessionManager.java index f448e45b..e011a7fa 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/SingleSessionManager.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/SingleSessionManager.java @@ -32,6 +32,7 @@ import android.content.Context; import android.net.Uri; import com.owncloud.android.lib.common.accounts.AccountUtils; +import com.owncloud.android.lib.common.authentication.OwnCloudCredentials; import com.owncloud.android.lib.common.http.HttpClient; import timber.log.Timber; @@ -129,7 +130,6 @@ public class SingleSessionManager { Timber.v("reusing client for session %s", sessionName); } - keepCredentialsUpdated(client); keepCookiesUpdated(context, account, client); keepUriUpdated(account, client); } @@ -176,10 +176,6 @@ public class SingleSessionManager { Timber.d("All sessions saved"); } - private void keepCredentialsUpdated(OwnCloudClient reusedClient) { - reusedClient.applyCredentials(); - } - private void keepCookiesUpdated(Context context, OwnCloudAccount account, OwnCloudClient reusedClient) { AccountManager am = AccountManager.get(context.getApplicationContext()); if (am != null && account.getSavedAccount() != null) { @@ -191,6 +187,15 @@ public class SingleSessionManager { } } + public void refreshCredentialsForAccount(String accountName, OwnCloudCredentials credentials) { + OwnCloudClient ownCloudClient = mClientsWithKnownUsername.get(accountName); + if (ownCloudClient == null) { + return; + } + ownCloudClient.setCredentials(credentials); + mClientsWithKnownUsername.replace(accountName, ownCloudClient); + } + // this method is just a patch; we need to distinguish accounts in the same host but // different paths; but that requires updating the accountNames for apps upgrading private void keepUriUpdated(OwnCloudAccount account, OwnCloudClient reusedClient) { diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/accounts/AccountUtils.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/accounts/AccountUtils.java index 40d1013a..d8983ed9 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/accounts/AccountUtils.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/accounts/AccountUtils.java @@ -41,6 +41,7 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion; import okhttp3.Cookie; import timber.log.Timber; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -249,7 +250,7 @@ public class AccountUtils { .domain(serverUri.getHost()) .path( serverUri.getPath().equals("") - ? FileUtils.PATH_SEPARATOR + ? File.separator : serverUri.getPath() ) .build()); diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudBasicCredentials.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudBasicCredentials.java index af3e9d75..3f1eeb4c 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudBasicCredentials.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudBasicCredentials.java @@ -23,11 +23,9 @@ */ package com.owncloud.android.lib.common.authentication; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.http.HttpClient; -import com.owncloud.android.lib.common.http.HttpConstants; import okhttp3.Credentials; -import okhttp3.internal.Util; + +import static java.nio.charset.StandardCharsets.UTF_8; public class OwnCloudBasicCredentials implements OwnCloudCredentials { @@ -39,21 +37,6 @@ public class OwnCloudBasicCredentials implements OwnCloudCredentials { mPassword = password != null ? password : ""; } - public OwnCloudBasicCredentials(String username, String password, boolean preemptiveMode) { - mUsername = username != null ? username : ""; - mPassword = password != null ? password : ""; - } - - @Override - public void applyTo(OwnCloudClient client) { - // Clear previous basic credentials - HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER); - HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER); - - HttpClient.addHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER, - Credentials.basic(mUsername, mPassword, Util.UTF_8)); - } - @Override public String getUsername() { return mUsername; @@ -64,6 +47,11 @@ public class OwnCloudBasicCredentials implements OwnCloudCredentials { return mPassword; } + @Override + public String getHeaderAuth() { + return Credentials.basic(mUsername, mPassword, UTF_8); + } + @Override public boolean authTokenExpires() { return false; diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudBearerCredentials.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudBearerCredentials.java index e455cb39..0dbf326a 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudBearerCredentials.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudBearerCredentials.java @@ -23,8 +23,6 @@ */ package com.owncloud.android.lib.common.authentication; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.http.HttpClient; import com.owncloud.android.lib.common.http.HttpConstants; public class OwnCloudBearerCredentials implements OwnCloudCredentials { @@ -37,16 +35,6 @@ public class OwnCloudBearerCredentials implements OwnCloudCredentials { mAccessToken = accessToken != null ? accessToken : ""; } - @Override - public void applyTo(OwnCloudClient client) { - // Clear previous credentials - HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER); - HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER); - - HttpClient.addHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER, - HttpConstants.BEARER_AUTHORIZATION_KEY + mAccessToken); - } - @Override public String getUsername() { // not relevant for authentication, but relevant for informational purposes @@ -58,6 +46,11 @@ public class OwnCloudBearerCredentials implements OwnCloudCredentials { return mAccessToken; } + @Override + public String getHeaderAuth() { + return HttpConstants.BEARER_AUTHORIZATION_KEY + mAccessToken; + } + @Override public boolean authTokenExpires() { return true; diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentials.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentials.java index 978dde8b..6ee06b58 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentials.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentials.java @@ -24,16 +24,14 @@ package com.owncloud.android.lib.common.authentication; -import com.owncloud.android.lib.common.OwnCloudClient; - public interface OwnCloudCredentials { - void applyTo(OwnCloudClient ownCloudClient); - String getUsername(); String getAuthToken(); + String getHeaderAuth(); + boolean authTokenExpires(); boolean authTokenCanBeRefreshed(); diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentialsFactory.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentialsFactory.java index 75b523cc..3d5dae91 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentialsFactory.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/authentication/OwnCloudCredentialsFactory.java @@ -55,14 +55,12 @@ public class OwnCloudCredentialsFactory { } @Override - public void applyTo(OwnCloudClient client) { - // Clear previous basic credentials - HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER); - HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER); + public String getAuthToken() { + return ""; } @Override - public String getAuthToken() { + public String getHeaderAuth() { return ""; } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpClient.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpClient.java index 27e83e62..12571a88 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpClient.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpClient.java @@ -26,9 +26,6 @@ package com.owncloud.android.lib.common.http; import android.content.Context; -import com.owncloud.android.lib.common.SingleSessionManager; -import com.owncloud.android.lib.common.http.interceptors.HttpInterceptor; -import com.owncloud.android.lib.common.http.interceptors.RequestHeaderInterceptor; import com.owncloud.android.lib.common.network.AdvancedX509TrustManager; import com.owncloud.android.lib.common.network.NetworkUtils; import okhttp3.Cookie; @@ -58,7 +55,6 @@ import java.util.concurrent.TimeUnit; */ public class HttpClient { private static OkHttpClient sOkHttpClient; - private static HttpInterceptor sOkHttpInterceptor; private static Context sContext; private static HashMap> sCookieStore = new HashMap<>(); @@ -71,16 +67,21 @@ public class HttpClient { SSLContext sslContext; try { - sslContext = SSLContext.getInstance("TLSv1.2"); - } catch (NoSuchAlgorithmException tlsv12Exception) { + sslContext = SSLContext.getInstance("TLSv1.3"); + } catch (NoSuchAlgorithmException tlsv13Exception) { try { - Timber.w("TLSv1.2 is not supported in this device; falling through TLSv1.1"); - sslContext = SSLContext.getInstance("TLSv1.1"); - } catch (NoSuchAlgorithmException tlsv11Exception) { - Timber.w("TLSv1.1 is not supported in this device; falling through TLSv1.0"); - sslContext = SSLContext.getInstance("TLSv1"); - // should be available in any device; see reference of supported protocols in - // http://developer.android.com/reference/javax/net/ssl/SSLSocket.html + Timber.w("TLSv1.3 is not supported in this device; falling through TLSv1.2"); + sslContext = SSLContext.getInstance("TLSv1.2"); + } catch (NoSuchAlgorithmException tlsv12Exception) { + try { + Timber.w("TLSv1.2 is not supported in this device; falling through TLSv1.1"); + sslContext = SSLContext.getInstance("TLSv1.1"); + } catch (NoSuchAlgorithmException tlsv11Exception) { + Timber.w("TLSv1.1 is not supported in this device; falling through TLSv1.0"); + sslContext = SSLContext.getInstance("TLSv1"); + // should be available in any device; see reference of supported protocols in + // http://developer.android.com/reference/javax/net/ssl/SSLSocket.html + } } } @@ -109,7 +110,6 @@ public class HttpClient { }; OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() - .addInterceptor(getOkHttpInterceptor()) .protocols(Arrays.asList(Protocol.HTTP_1_1)) .readTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS) .writeTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS) @@ -129,36 +129,6 @@ public class HttpClient { return sOkHttpClient; } - private static HttpInterceptor getOkHttpInterceptor() { - if (sOkHttpInterceptor == null) { - sOkHttpInterceptor = new HttpInterceptor(); - addHeaderForAllRequests(HttpConstants.USER_AGENT_HEADER, SingleSessionManager.getUserAgent()); - addHeaderForAllRequests(HttpConstants.PARAM_SINGLE_COOKIE_HEADER, "true"); - addHeaderForAllRequests(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY); - } - return sOkHttpInterceptor; - } - - /** - * Add header that will be included for all the requests from now on - * - * @param headerName - * @param headerValue - */ - public static void addHeaderForAllRequests(String headerName, String headerValue) { - HttpInterceptor httpInterceptor = getOkHttpInterceptor(); - - if (getOkHttpInterceptor() != null) { - httpInterceptor.addRequestInterceptor( - new RequestHeaderInterceptor(headerName, headerValue) - ); - } - } - - public static void deleteHeaderForAllRequests(String headerName) { - getOkHttpInterceptor().deleteRequestHeaderInterceptor(headerName); - } - public Context getContext() { return sContext; } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/TLSSocketFactory.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/TLSSocketFactory.java index 5cff6b43..25ce9ad9 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/TLSSocketFactory.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/TLSSocketFactory.java @@ -74,8 +74,8 @@ public class TLSSocketFactory extends SSLSocketFactory { } private Socket enableTLSOnSocket(Socket socket) { - if(socket != null && (socket instanceof SSLSocket)) { - ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"}); + if((socket instanceof SSLSocket)) { + ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2", "TLSv1.3"}); } return socket; } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/interceptors/HttpInterceptor.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/interceptors/HttpInterceptor.java deleted file mode 100644 index b9965548..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/interceptors/HttpInterceptor.java +++ /dev/null @@ -1,116 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.http.interceptors; - -import okhttp3.Interceptor; -import okhttp3.Request; -import okhttp3.Response; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.ListIterator; - -/** - * Http interceptor to use multiple interceptors in the same {@link okhttp3.OkHttpClient} instance - * - * @author David González Verdugo - */ -public class HttpInterceptor implements Interceptor { - - private final ArrayList mRequestInterceptors = new ArrayList<>(); - private final ArrayList mResponseInterceptors = new ArrayList<>(); - - @Override - public Response intercept(Chain chain) throws IOException { - Request request = chain.request(); - - ListIterator requestInterceptorIterator = mRequestInterceptors.listIterator(); - - while (requestInterceptorIterator.hasNext()) { - RequestInterceptor currentRequestInterceptor = requestInterceptorIterator.next(); - request = currentRequestInterceptor.intercept(request); - } - - Response response = chain.proceed(request); - - ListIterator responseInterceptorIterator = mResponseInterceptors.listIterator(); - - while (responseInterceptorIterator.hasNext()) { - ResponseInterceptor currentResponseInterceptor = responseInterceptorIterator.next(); - response = currentResponseInterceptor.intercept(response); - } - - return response; - } - - public HttpInterceptor addRequestInterceptor(RequestInterceptor requestInterceptor) { - mRequestInterceptors.listIterator().add(requestInterceptor); - return this; - } - - public HttpInterceptor addResponseInterceptor(ResponseInterceptor responseInterceptor) { - mResponseInterceptors.listIterator().add(responseInterceptor); - return this; - } - - public ArrayList getRequestInterceptors() { - return mRequestInterceptors; - } - - private ArrayList getRequestHeaderInterceptors() { - ArrayList requestHeaderInterceptors = new ArrayList<>(); - - for (RequestInterceptor requestInterceptor : mRequestInterceptors) { - if (requestInterceptor instanceof RequestHeaderInterceptor) { - requestHeaderInterceptors.add((RequestHeaderInterceptor) requestInterceptor); - } - } - - return requestHeaderInterceptors; - } - - public void deleteRequestHeaderInterceptor(String headerName) { - ListIterator requestInterceptorIterator = mRequestInterceptors.listIterator(); - while (requestInterceptorIterator.hasNext()) { - RequestInterceptor currentRequestInterceptor = requestInterceptorIterator.next(); - if (currentRequestInterceptor instanceof RequestHeaderInterceptor && - ((RequestHeaderInterceptor) currentRequestInterceptor).getHeaderName().equals(headerName)) { - requestInterceptorIterator.remove(); - } - } - } - - public ArrayList getResponseInterceptors() { - return mResponseInterceptors; - } - - public interface RequestInterceptor { - Request intercept(Request request) throws IOException; - } - - public interface ResponseInterceptor { - Response intercept(Response response) throws IOException; - } -} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/interceptors/RequestHeaderInterceptor.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/interceptors/RequestHeaderInterceptor.java deleted file mode 100644 index d7cb6dc4..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/interceptors/RequestHeaderInterceptor.java +++ /dev/null @@ -1,54 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.http.interceptors; - -import okhttp3.Request; - -/** - * Intercept requests to update their headers - */ -public class RequestHeaderInterceptor implements HttpInterceptor.RequestInterceptor { - - private String mHeaderName; - private String mHeaderValue; - - public RequestHeaderInterceptor(String headerName, String headerValue) { - this.mHeaderName = headerName; - this.mHeaderValue = headerValue; - } - - @Override - public Request intercept(Request request) { - return request.newBuilder().addHeader(mHeaderName, mHeaderValue).build(); - } - - public String getHeaderName() { - return mHeaderName; - } - - public String getHeaderValue() { - return mHeaderValue; - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/HttpBaseMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/HttpBaseMethod.java deleted file mode 100644 index 9dc8de97..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/HttpBaseMethod.java +++ /dev/null @@ -1,191 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.http.methods; - -import com.owncloud.android.lib.common.http.HttpClient; -import okhttp3.Call; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.concurrent.TimeUnit; - -/** - * Wrapper to perform http calls transparently by using: - * - OkHttp for non webdav methods - * - Dav4Android for webdav methods - * - * @author David González Verdugo - */ -public abstract class HttpBaseMethod { - protected OkHttpClient mOkHttpClient; - protected Request mRequest; - protected RequestBody mRequestBody; - protected Response mResponse; - protected String mResponseBodyString; - protected Call mCall; - - protected HttpBaseMethod(URL url) { - mOkHttpClient = HttpClient.getOkHttpClient(); - mRequest = new Request.Builder() - .url(HttpUrl.parse(url.toString())) - .build(); - } - - public int execute() throws Exception { - return onExecute(); - } - - public void abort() { - mCall.cancel(); - } - - public boolean isAborted() { - return mCall.isCanceled(); - } - - ////////////////////////////// - // For override - ////////////////////////////// - - protected abstract int onExecute() throws Exception; - - ////////////////////////////// - // Getter - ////////////////////////////// - - // Request - - public Headers getRequestHeaders() { - return mRequest.headers(); - } - - public String getRequestHeader(String name) { - return mRequest.header(name); - } - - // Response - - public int getStatusCode() { - return mResponse.code(); - } - - public String getStatusMessage() { - return mResponse.message(); - } - - public String getResponseBodyAsString() throws IOException { - if (mResponseBodyString == null && mResponse.body() != null) { - mResponseBodyString = mResponse.body().string(); - } - - return mResponseBodyString; - } - - public InputStream getResponseBodyAsStream() { - if (mResponse.body() != null) { - return mResponse.body().byteStream(); - } - return null; - } - - public Headers getResponseHeaders() { - return mResponse.headers(); - } - - public String getResponseHeader(String headerName) { - return mResponse.header(headerName); - } - - public boolean getRetryOnConnectionFailure() { - return mOkHttpClient.retryOnConnectionFailure(); - } - - ////////////////////////////// - // Setter - ////////////////////////////// - - // Connection parameters - - public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) { - mOkHttpClient = mOkHttpClient.newBuilder() - .retryOnConnectionFailure(retryOnConnectionFailure) - .build(); - } - - public void setReadTimeout(long readTimeout, TimeUnit timeUnit) { - mOkHttpClient = mOkHttpClient.newBuilder() - .readTimeout(readTimeout, timeUnit) - .build(); - } - - public void setConnectionTimeout(long connectionTimeout, TimeUnit timeUnit) { - mOkHttpClient = mOkHttpClient.newBuilder() - .readTimeout(connectionTimeout, timeUnit) - .build(); - } - - public void setFollowRedirects(boolean followRedirects) { - mOkHttpClient = mOkHttpClient.newBuilder() - .followRedirects(followRedirects) - .build(); - } - - // Request - - public void addRequestHeader(String name, String value) { - mRequest = mRequest.newBuilder() - .addHeader(name, value) - .build(); - } - - /** - * Sets a header and replace it if already exists with that name - * - * @param name header name - * @param value header value - */ - public void setRequestHeader(String name, String value) { - mRequest = mRequest.newBuilder() - .header(name, value) - .build(); - } - - public void setRequestBody(RequestBody requestBody) { - mRequestBody = requestBody; - } - - public void setUrl(HttpUrl url) { - mRequest = mRequest.newBuilder() - .url(url) - .build(); - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/HttpBaseMethod.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/HttpBaseMethod.kt new file mode 100644 index 00000000..0c4c7ada --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/HttpBaseMethod.kt @@ -0,0 +1,152 @@ +package com.owncloud.android.lib.common.http.methods + +import com.owncloud.android.lib.common.http.HttpClient +import okhttp3.Call +import okhttp3.Headers +import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import java.io.InputStream +import java.net.MalformedURLException +import java.net.URL +import java.util.concurrent.TimeUnit + +abstract class HttpBaseMethod constructor(url: URL) { + var okHttpClient: OkHttpClient + var httpUrl: HttpUrl = url.toHttpUrlOrNull() ?: throw MalformedURLException() + var request: Request + abstract var response: Response + + var call: Call? = null + + init { + okHttpClient = HttpClient.getOkHttpClient() + request = Request.Builder() + .url(httpUrl) + .build() + } + + @Throws(Exception::class) + open fun execute(): Int { + return onExecute() + } + + open fun setUrl(url: HttpUrl) { + request = request.newBuilder() + .url(url) + .build() + } + + /**************** + *** Requests *** + ****************/ + + fun getRequestHeader(name: String): String? { + return request.header(name) + } + + fun getRequestHeadersAsHashMap(): HashMap { + val headers: HashMap = HashMap() + val superHeaders: Set = request.headers.names() + superHeaders.forEach { + headers[it] = getRequestHeader(it) + } + return headers + } + + open fun addRequestHeader(name: String, value: String) { + request = request.newBuilder() + .addHeader(name, value) + .build() + } + + /** + * Sets a header and replace it if already exists with that name + * + * @param name header name + * @param value header value + */ + open fun setRequestHeader(name: String, value: String) { + request = request.newBuilder() + .header(name, value) + .build() + } + + /**************** + *** Response *** + ****************/ + val statusCode: Int + get() = response.code + + val statusMessage: String + get() = response.message + + // Headers + open fun getResponseHeaders(): Headers? { + return response.headers + } + + open fun getResponseHeader(headerName: String): String? { + return response.header(headerName) + } + + // Body + fun getResponseBodyAsString(): String? = response.body?.string() + + open fun getResponseBodyAsStream(): InputStream? { + return response.body?.byteStream() + } + + /************************* + *** Connection Params *** + *************************/ + + ////////////////////////////// + // Setter + ////////////////////////////// + // Connection parameters + open fun setRetryOnConnectionFailure(retryOnConnectionFailure: Boolean) { + okHttpClient = okHttpClient.newBuilder() + .retryOnConnectionFailure(retryOnConnectionFailure) + .build() + } + + open fun setReadTimeout(readTimeout: Long, timeUnit: TimeUnit) { + okHttpClient = okHttpClient.newBuilder() + .readTimeout(readTimeout, timeUnit) + .build() + } + + open fun setConnectionTimeout( + connectionTimeout: Long, + timeUnit: TimeUnit + ) { + okHttpClient = okHttpClient.newBuilder() + .readTimeout(connectionTimeout, timeUnit) + .build() + } + + open fun setFollowRedirects(followRedirects: Boolean) { + okHttpClient = okHttpClient.newBuilder() + .followRedirects(followRedirects) + .build() + } + + /************ + *** Call *** + ************/ + open fun abort() { + call?.cancel() + } + + open val isAborted: Boolean + get() = call?.isCanceled() ?: false + + ////////////////////////////// + // For override + ////////////////////////////// + @Throws(Exception::class) + protected abstract fun onExecute(): Int +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/DeleteMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/DeleteMethod.kt similarity index 75% rename from owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/DeleteMethod.java rename to owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/DeleteMethod.kt index 42039dde..51069bc2 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/DeleteMethod.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/DeleteMethod.kt @@ -21,29 +21,22 @@ * THE SOFTWARE. * */ +package com.owncloud.android.lib.common.http.methods.nonwebdav -package com.owncloud.android.lib.common.http.methods.nonwebdav; - -import java.io.IOException; -import java.net.URL; +import java.io.IOException +import java.net.URL /** * OkHttp delete calls wrapper * * @author David González Verdugo */ -public class DeleteMethod extends HttpMethod { - - public DeleteMethod(URL url) { - super(url); +class DeleteMethod(url: URL) : HttpMethod(url) { + @Throws(IOException::class) + override fun onExecute(): Int { + request = request.newBuilder() + .delete() + .build() + return super.onExecute() } - - @Override - public int onExecute() throws IOException { - mRequest = mRequest.newBuilder() - .delete() - .build(); - - return super.onExecute(); - } -} \ No newline at end of file +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/GetMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/GetMethod.kt similarity index 76% rename from owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/GetMethod.java rename to owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/GetMethod.kt index 55022bbe..65bf40fc 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/GetMethod.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/GetMethod.kt @@ -21,29 +21,22 @@ * THE SOFTWARE. * */ +package com.owncloud.android.lib.common.http.methods.nonwebdav -package com.owncloud.android.lib.common.http.methods.nonwebdav; - -import java.io.IOException; -import java.net.URL; +import java.io.IOException +import java.net.URL /** * OkHttp get calls wrapper * * @author David González Verdugo */ -public class GetMethod extends HttpMethod { - - public GetMethod(URL url) { - super(url); +class GetMethod(url: URL) : HttpMethod(url) { + @Throws(IOException::class) + override fun onExecute(): Int { + request = request.newBuilder() + .get() + .build() + return super.onExecute() } - - @Override - public int onExecute() throws IOException { - mRequest = mRequest.newBuilder() - .get() - .build(); - - return super.onExecute(); - } -} \ No newline at end of file +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/HttpMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/HttpMethod.kt similarity index 76% rename from owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/HttpMethod.java rename to owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/HttpMethod.kt index 971923b7..da759ada 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/HttpMethod.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/HttpMethod.kt @@ -21,29 +21,26 @@ * THE SOFTWARE. * */ +package com.owncloud.android.lib.common.http.methods.nonwebdav -package com.owncloud.android.lib.common.http.methods.nonwebdav; - -import com.owncloud.android.lib.common.http.methods.HttpBaseMethod; - -import java.io.IOException; -import java.net.URL; +import com.owncloud.android.lib.common.http.methods.HttpBaseMethod +import okhttp3.Response +import java.net.URL /** * Wrapper to perform OkHttp calls * * @author David González Verdugo */ -public abstract class HttpMethod extends HttpBaseMethod { +abstract class HttpMethod( + url: URL +) : HttpBaseMethod(url) { - public HttpMethod(URL url) { - super(url); - } + override lateinit var response: Response - @Override - public int onExecute() throws IOException { - mCall = mOkHttpClient.newCall(mRequest); - mResponse = mCall.execute(); - return super.getStatusCode(); + public override fun onExecute(): Int { + call = okHttpClient.newCall(request) + call?.let { response = it.execute() } + return super.statusCode } -} \ No newline at end of file +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PostMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PostMethod.kt similarity index 74% rename from owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PostMethod.java rename to owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PostMethod.kt index 1efb26d0..ba4f6d4d 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PostMethod.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PostMethod.kt @@ -21,29 +21,26 @@ * THE SOFTWARE. * */ +package com.owncloud.android.lib.common.http.methods.nonwebdav -package com.owncloud.android.lib.common.http.methods.nonwebdav; - -import java.io.IOException; -import java.net.URL; +import okhttp3.RequestBody +import java.io.IOException +import java.net.URL /** * OkHttp post calls wrapper * * @author David González Verdugo */ -public class PostMethod extends HttpMethod { - - public PostMethod(URL url) { - super(url); +class PostMethod( + url: URL, + private val postRequestBody: RequestBody +) : HttpMethod(url) { + @Throws(IOException::class) + override fun onExecute(): Int { + request = request.newBuilder() + .post(postRequestBody) + .build() + return super.onExecute() } - - @Override - public int onExecute() throws IOException { - mRequest = mRequest.newBuilder() - .post(mRequestBody) - .build(); - - return super.onExecute(); - } -} \ No newline at end of file +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PutMethod.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PutMethod.kt new file mode 100644 index 00000000..98be1503 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PutMethod.kt @@ -0,0 +1,46 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2020 ownCloud GmbH. + * + * 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.http.methods.nonwebdav + +import okhttp3.RequestBody +import java.io.IOException +import java.net.URL + +/** + * OkHttp put calls wrapper + * + * @author David González Verdugo + */ +class PutMethod( + url: URL, + private val putRequestBody: RequestBody +) : HttpMethod(url) { + @Throws(IOException::class) + override fun onExecute(): Int { + request = request.newBuilder() + .put(putRequestBody) + .build() + return super.onExecute() + } +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/CopyMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/CopyMethod.java deleted file mode 100644 index 718f948c..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/CopyMethod.java +++ /dev/null @@ -1,57 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.http.methods.webdav; - -import kotlin.Unit; - -import java.net.URL; - -/** - * Copy calls wrapper - * - * @author Christian Schabesberger - * @author David González Verdugo - */ -public class CopyMethod extends DavMethod { - - final String destinationUrl; - final boolean forceOverride; - - public CopyMethod(URL url, String destinationUrl, boolean forceOverride) { - super(url); - this.destinationUrl = destinationUrl; - this.forceOverride = forceOverride; - } - - @Override - public int onExecute() throws Exception { - mDavResource.copy(destinationUrl, forceOverride, response -> { - mResponse = response; - return Unit.INSTANCE; - }); - - return super.getStatusCode(); - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/CopyMethod.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/CopyMethod.kt new file mode 100644 index 00000000..2c816d75 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/CopyMethod.kt @@ -0,0 +1,51 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2020 ownCloud GmbH. + * + * 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.http.methods.webdav + +import okhttp3.Response +import java.net.URL + +/** + * Copy calls wrapper + * + * @author Christian Schabesberger + * @author David González Verdugo + */ +class CopyMethod( + val url: URL, + private val destinationUrl: String, + private val forceOverride: Boolean +) : DavMethod(url) { + @Throws(Exception::class) + public override fun onExecute(): Int { + davResource.copy( + destinationUrl, + forceOverride, + super.getRequestHeadersAsHashMap() + ) { callBackResponse: Response -> + response = callBackResponse + } + return super.statusCode + } +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavConstants.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavConstants.kt similarity index 87% rename from owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavConstants.java rename to owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavConstants.kt index 67fd90ba..03e36bdb 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavConstants.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavConstants.kt @@ -21,13 +21,12 @@ * THE SOFTWARE. * */ - -package com.owncloud.android.lib.common.http.methods.webdav; +package com.owncloud.android.lib.common.http.methods.webdav /** * @author David González Verdugo */ -public class DavConstants { - public static final int DEPTH_0 = 0; - public static final int DEPTH_1 = 1; +object DavConstants { + const val DEPTH_0 = 0 + const val DEPTH_1 = 1 } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavMethod.java deleted file mode 100644 index 4255e1a6..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavMethod.java +++ /dev/null @@ -1,162 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.http.methods.webdav; - -import at.bitfire.dav4android.Constants; -import at.bitfire.dav4android.DavOCResource; -import at.bitfire.dav4android.exception.HttpException; -import at.bitfire.dav4android.exception.RedirectException; -import com.owncloud.android.lib.common.http.HttpConstants; -import com.owncloud.android.lib.common.http.methods.HttpBaseMethod; -import okhttp3.HttpUrl; -import okhttp3.Protocol; -import okhttp3.Response; -import okhttp3.ResponseBody; - -import java.net.URL; -import java.util.concurrent.TimeUnit; - -/** - * Wrapper to perform WebDAV (dav4android) calls - * - * @author David González Verdugo - */ -public abstract class DavMethod extends HttpBaseMethod { - - protected DavOCResource mDavResource; - - protected DavMethod(URL url) { - super(url); - mDavResource = new DavOCResource( - mOkHttpClient, - HttpUrl.parse(url.toString()), - Constants.INSTANCE.getLog()); - } - - @Override - public void abort() { - mDavResource.cancelCall(); - } - - @Override - public int execute() throws Exception { - try { - return onExecute(); - } catch (HttpException httpException) { - // Modify responses with information gathered from exceptions - if (httpException instanceof RedirectException) { - mResponse = new Response.Builder() - .header( - HttpConstants.LOCATION_HEADER, ((RedirectException) httpException).getRedirectLocation() - ) - .code(httpException.getCode()) - .request(mRequest) - .message(httpException.getMessage()) - .protocol(Protocol.HTTP_1_1) - .build(); - - } else if (mResponse != null) { - // The check below should be included in okhttp library, method ResponseBody.create( - // TODO check most recent versions of okhttp to see if this is already fixed and try to update if so - if (mResponse.body().contentType() != null) { - ResponseBody responseBody = ResponseBody.create( - mResponse.body().contentType(), - httpException.getResponseBody() - ); - - mResponse = mResponse.newBuilder() - .body(responseBody) - .build(); - } - } - - return httpException.getCode(); - } - } - - ////////////////////////////// - // Setter - ////////////////////////////// - - // Connection parameters - @Override - public void setReadTimeout(long readTimeout, TimeUnit timeUnit) { - super.setReadTimeout(readTimeout, timeUnit); - mDavResource = new DavOCResource( - mOkHttpClient, - HttpUrl.parse(mRequest.url().toString()), - Constants.INSTANCE.getLog()); - } - - @Override - public void setConnectionTimeout(long connectionTimeout, TimeUnit timeUnit) { - super.setConnectionTimeout(connectionTimeout, timeUnit); - mDavResource = new DavOCResource( - mOkHttpClient, - HttpUrl.parse(mRequest.url().toString()), - Constants.INSTANCE.getLog()); - } - - @Override - public void setFollowRedirects(boolean followRedirects) { - super.setFollowRedirects(followRedirects); - mDavResource = new DavOCResource( - mOkHttpClient, - HttpUrl.parse(mRequest.url().toString()), - Constants.INSTANCE.getLog()); - } - - @Override - public void setUrl(HttpUrl url) { - super.setUrl(url); - mDavResource = new DavOCResource( - mOkHttpClient, - HttpUrl.parse(mRequest.url().toString()), - Constants.INSTANCE.getLog()); - } - - @Override - public boolean getRetryOnConnectionFailure() { - return false; //TODO: implement me - } - - ////////////////////////////// - // Getter - ////////////////////////////// - - @Override - public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) { - super.setRetryOnConnectionFailure(retryOnConnectionFailure); - mDavResource = new DavOCResource( - mOkHttpClient, - HttpUrl.parse(mRequest.url().toString()), - Constants.INSTANCE.getLog()); - } - - @Override - public boolean isAborted() { - return mDavResource.isCallAborted(); - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavMethod.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavMethod.kt new file mode 100644 index 00000000..b9bc14cd --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavMethod.kt @@ -0,0 +1,161 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2020 ownCloud GmbH. + * + * 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.http.methods.webdav + +import at.bitfire.dav4jvm.Dav4jvm.log +import at.bitfire.dav4jvm.DavOCResource +import at.bitfire.dav4jvm.exception.HttpException +import at.bitfire.dav4jvm.exception.RedirectException +import com.owncloud.android.lib.common.http.HttpConstants +import com.owncloud.android.lib.common.http.methods.HttpBaseMethod +import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.Protocol +import okhttp3.Response +import okhttp3.ResponseBody.Companion.toResponseBody +import java.net.MalformedURLException +import java.net.URL +import java.util.concurrent.TimeUnit + +/** + * Wrapper to perform WebDAV (dav4android) calls + * + * @author David González Verdugo + */ +abstract class DavMethod protected constructor(url: URL) : HttpBaseMethod(url) { + protected var davResource: DavOCResource + + override lateinit var response: Response + + init { + val httpUrl = url.toHttpUrlOrNull() ?: throw MalformedURLException() + davResource = DavOCResource( + okHttpClient, + httpUrl, + log + ) + } + + override fun abort() { + davResource.cancelCall() + } + + @Throws(Exception::class) + override fun execute(): Int { + return try { + onExecute() + } catch (httpException: HttpException) { + // Modify responses with information gathered from exceptions + if (httpException is RedirectException) { + response = Response.Builder() + .header( + HttpConstants.LOCATION_HEADER, httpException.redirectLocation + ) + .code(httpException.code) + .request(request) + .message(httpException.message ?: "") + .protocol(Protocol.HTTP_1_1) + .build() + } else { + // The check below should be included in okhttp library, method ResponseBody.create( + // TODO check most recent versions of okhttp to see if this is already fixed and try to update if so + if (response.body?.contentType() != null) { + val responseBody = (httpException.responseBody ?: "").toResponseBody(response.body?.contentType()) + response = response.newBuilder() + .body(responseBody) + .build() + } + } + httpException.code + } + } + + ////////////////////////////// + // Setter + ////////////////////////////// + // Connection parameters + override fun setReadTimeout(readTimeout: Long, timeUnit: TimeUnit) { + super.setReadTimeout(readTimeout, timeUnit) + davResource = DavOCResource( + okHttpClient, + request.url, + log + ) + } + + override fun setConnectionTimeout( + connectionTimeout: Long, + timeUnit: TimeUnit + ) { + super.setConnectionTimeout(connectionTimeout, timeUnit) + davResource = DavOCResource( + okHttpClient, + request.url, + log + ) + } + + override fun setFollowRedirects(followRedirects: Boolean) { + super.setFollowRedirects(followRedirects) + davResource = DavOCResource( + okHttpClient, + request.url, + log + ) + } + + override fun setUrl(url: HttpUrl) { + super.setUrl(url) + davResource = DavOCResource( + okHttpClient, + request.url, + log + ) + } + + override fun setRequestHeader(name: String, value: String) { + super.setRequestHeader(name, value) + davResource = DavOCResource( + okHttpClient, + request.url, + log + ) + } + + ////////////////////////////// + // Getter + ////////////////////////////// + override fun setRetryOnConnectionFailure(retryOnConnectionFailure: Boolean) { + super.setRetryOnConnectionFailure(retryOnConnectionFailure) + davResource = DavOCResource( + okHttpClient, + request.url, + log + ) + } + + override val isAborted: Boolean + get() = davResource.isCallAborted() + +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.java deleted file mode 100644 index 484c4ec1..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.owncloud.android.lib.common.http.methods.webdav; - -import at.bitfire.dav4android.Property; -import at.bitfire.dav4android.PropertyUtils; - -public class DavUtils { - - public static final Property.Name[] getAllPropset() { - return PropertyUtils.INSTANCE.getAllPropSet(); - } - - public static final Property.Name[] getQuotaPropSet() { - return PropertyUtils.INSTANCE.getQuotaPropset(); - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PutMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.kt similarity index 74% rename from owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PutMethod.java rename to owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.kt index c51a1958..22e1981f 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/nonwebdav/PutMethod.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/DavUtils.kt @@ -21,24 +21,16 @@ * THE SOFTWARE. * */ +package com.owncloud.android.lib.common.http.methods.webdav -package com.owncloud.android.lib.common.http.methods.nonwebdav; +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.PropertyUtils.getAllPropSet +import at.bitfire.dav4jvm.PropertyUtils.getQuotaPropset -import java.io.IOException; -import java.net.URL; +object DavUtils { + @JvmStatic val allPropset: Array + get() = getAllPropSet() -public class PutMethod extends HttpMethod { - - public PutMethod(URL url) { - super(url); - } - - @Override - public int onExecute() throws IOException { - mRequest = mRequest.newBuilder() - .put(mRequestBody) - .build(); - - return super.onExecute(); - } -} \ No newline at end of file + val quotaPropSet: Array + get() = getQuotaPropset() +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MkColMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MkColMethod.kt similarity index 73% rename from owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MkColMethod.java rename to owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MkColMethod.kt index 9c4a3e34..03c8aff0 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MkColMethod.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MkColMethod.kt @@ -21,12 +21,10 @@ * THE SOFTWARE. * */ +package com.owncloud.android.lib.common.http.methods.webdav -package com.owncloud.android.lib.common.http.methods.webdav; - -import kotlin.Unit; - -import java.net.URL; +import okhttp3.Response +import java.net.URL /** * MkCol calls wrapper @@ -34,18 +32,15 @@ import java.net.URL; * @author Christian Schabesberger * @author David González Verdugo */ -public class MkColMethod extends DavMethod { - public MkColMethod(URL url) { - super(url); +class MkColMethod(url: URL) : DavMethod(url) { + @Throws(Exception::class) + public override fun onExecute(): Int { + davResource.mkCol( + xmlBody = null, + listOfHeaders = super.getRequestHeadersAsHashMap() + ) { callBackResponse: Response -> + response = callBackResponse + } + return super.statusCode } - - @Override - public int onExecute() throws Exception { - mDavResource.mkCol(null, response -> { - mResponse = response; - return Unit.INSTANCE; - }); - - return super.getStatusCode(); - } -} \ No newline at end of file +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MoveMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MoveMethod.java deleted file mode 100644 index a57a86b1..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MoveMethod.java +++ /dev/null @@ -1,61 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.http.methods.webdav; - -import com.owncloud.android.lib.common.http.HttpConstants; -import kotlin.Unit; - -import java.net.URL; - -/** - * Move calls wrapper - * - * @author Christian Schabesberger - * @author David González Verdugo - */ -public class MoveMethod extends DavMethod { - final String destinationUrl; - final boolean forceOverride; - - public MoveMethod(URL url, String destinationUrl, boolean forceOverride) { - super(url); - this.destinationUrl = destinationUrl; - this.forceOverride = forceOverride; - } - - @Override - public int onExecute() throws Exception { - mDavResource.move( - destinationUrl, - forceOverride, - super.getRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER), - super.getRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER), response -> { - mResponse = response; - return Unit.INSTANCE; - }); - - return super.getStatusCode(); - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MoveMethod.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MoveMethod.kt new file mode 100644 index 00000000..4c65cb98 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/MoveMethod.kt @@ -0,0 +1,52 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2020 ownCloud GmbH. + * + * 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.http.methods.webdav + +import okhttp3.Response +import java.net.URL + +/** + * Move calls wrapper + * + * @author Christian Schabesberger + * @author David González Verdugo + */ +class MoveMethod( + url: URL, + private val destinationUrl: String, + private val forceOverride: Boolean +) : DavMethod(url) { + @Throws(Exception::class) + public override fun onExecute(): Int { + davResource.move( + destinationUrl, + forceOverride, + super.getRequestHeadersAsHashMap() + ) { callBackResponse: Response -> + response = callBackResponse + } + return super.statusCode + } + +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PropfindMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PropfindMethod.java deleted file mode 100644 index 6a48fc80..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PropfindMethod.java +++ /dev/null @@ -1,94 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.http.methods.webdav; - -import at.bitfire.dav4android.Property; -import at.bitfire.dav4android.Response; -import at.bitfire.dav4android.exception.DavException; -import kotlin.Unit; - -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -/** - * Propfind calls wrapper - * - * @author David González Verdugo - */ -public class PropfindMethod extends DavMethod { - - // request - private final int mDepth; - private final Property.Name[] mPropertiesToRequest; - - // response - private final List mMembers; - private Response mRoot; - - public PropfindMethod(URL url, int depth, Property.Name[] propertiesToRequest) { - super(url); - mDepth = depth; - mPropertiesToRequest = propertiesToRequest; - mMembers = new ArrayList<>(); - mRoot = null; - } - - @Override - public int onExecute() throws IOException, DavException { - mDavResource.propfind(mDepth, mPropertiesToRequest, - (Response response, Response.HrefRelation hrefRelation) -> { - switch (hrefRelation) { - case MEMBER: - mMembers.add(response); - break; - case SELF: - mRoot = response; - break; - case OTHER: - default: - } - return Unit.INSTANCE; - }, response -> { - mResponse = response; - return Unit.INSTANCE; - }); - - return getStatusCode(); - } - - public int getDepth() { - return mDepth; - } - - public List getMembers() { - return mMembers; - } - - public Response getRoot() { - return mRoot; - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PropfindMethod.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PropfindMethod.kt new file mode 100644 index 00000000..66cc313b --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PropfindMethod.kt @@ -0,0 +1,72 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2020 ownCloud GmbH. + * + * 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.http.methods.webdav + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.Response +import at.bitfire.dav4jvm.Response.HrefRelation +import at.bitfire.dav4jvm.exception.DavException +import java.io.IOException +import java.net.URL + +/** + * Propfind calls wrapper + * + * @author David González Verdugo + */ +class PropfindMethod( + url: URL, + private val depth: Int, + private val propertiesToRequest: Array +) : DavMethod(url) { + + // response + val members: MutableList + var root: Response? + private set + + @Throws(IOException::class, DavException::class) + public override fun onExecute(): Int { + davResource.propfind( + depth = depth, + reqProp = *propertiesToRequest, + listOfHeaders = super.getRequestHeadersAsHashMap(), + callback = { response: Response, hrefRelation: HrefRelation? -> + when (hrefRelation) { + HrefRelation.MEMBER -> members.add(response) + HrefRelation.SELF -> this.root = response + HrefRelation.OTHER -> { + } + } + }, rawCallback = { callBackResponse: okhttp3.Response -> + response = callBackResponse + }) + return statusCode + } + + init { + members = arrayListOf() + this.root = null + } +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PutMethod.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PutMethod.java deleted file mode 100644 index 243a4d5a..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PutMethod.java +++ /dev/null @@ -1,61 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.http.methods.webdav; - -import at.bitfire.dav4android.exception.HttpException; -import com.owncloud.android.lib.common.http.HttpConstants; -import kotlin.Unit; - -import java.io.IOException; -import java.net.URL; - -/** - * Put calls wrapper - * - * @author David González Verdugo - */ -public class PutMethod extends DavMethod { - - public PutMethod(URL url) { - super(url); - } - - ; - - @Override - public int onExecute() throws IOException, HttpException { - mDavResource.put( - mRequestBody, - super.getRequestHeader(HttpConstants.IF_MATCH_HEADER), - super.getRequestHeader(HttpConstants.CONTENT_TYPE_HEADER), - super.getRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER), - super.getRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER), response -> { - mResponse = response; - return Unit.INSTANCE; - }); - - return super.getStatusCode(); - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PutMethod.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PutMethod.kt new file mode 100644 index 00000000..70dea1de --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/methods/webdav/PutMethod.kt @@ -0,0 +1,52 @@ +/* ownCloud Android Library is available under MIT license + * Copyright (C) 2020 ownCloud GmbH. + * + * 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.http.methods.webdav + +import at.bitfire.dav4jvm.exception.HttpException +import com.owncloud.android.lib.common.http.HttpConstants +import okhttp3.RequestBody +import java.io.IOException +import java.net.URL + +/** + * Put calls wrapper + * + * @author David González Verdugo + */ +class PutMethod( + url: URL, + private val putRequestBody: RequestBody +) : DavMethod(url) { + @Throws(IOException::class, HttpException::class) + public override fun onExecute(): Int { + davResource.put( + putRequestBody, + super.getRequestHeader(HttpConstants.IF_MATCH_HEADER), + getRequestHeadersAsHashMap() + ) { callBackResponse -> + response = callBackResponse + } + return super.statusCode + } +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/AdvancedX509TrustManager.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/AdvancedX509TrustManager.java index d76ecbca..b84c03de 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/AdvancedX509TrustManager.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/AdvancedX509TrustManager.java @@ -45,6 +45,7 @@ public class AdvancedX509TrustManager implements X509TrustManager { private X509TrustManager mStandardTrustManager; private KeyStore mKnownServersKeyStore; + /** * Constructor for AdvancedX509TrustManager * @@ -66,7 +67,7 @@ public class AdvancedX509TrustManager implements X509TrustManager { * @return The first X509TrustManager found in factory. */ private X509TrustManager findX509TrustManager(TrustManagerFactory factory) { - TrustManager tms[] = factory.getTrustManagers(); + TrustManager[] tms = factory.getTrustManagers(); for (TrustManager tm : tms) { if (tm instanceof X509TrustManager) { return (X509TrustManager) tm; diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/FileRequestBody.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/FileRequestBody.java index 63d07bec..2df9884d 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/FileRequestBody.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/FileRequestBody.java @@ -44,9 +44,9 @@ import java.util.Set; */ public class FileRequestBody extends RequestBody implements ProgressiveDataTransferer { + final Set mDataTransferListeners = new HashSet<>(); protected File mFile; private MediaType mContentType; - final Set mDataTransferListeners = new HashSet<>(); public FileRequestBody(File file, MediaType contentType) { mFile = file; diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java index 5647dec4..e86f89d7 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java @@ -34,9 +34,6 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import static com.owncloud.android.lib.common.OwnCloudClient.WEBDAV_FILES_PATH_4_0; -import static com.owncloud.android.lib.common.OwnCloudClient.WEBDAV_PATH_4_0_AND_LATER; - public class WebdavUtils { private static final SimpleDateFormat[] DATETIME_FORMATS = { diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 715ed32c..64386964 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -27,8 +27,8 @@ package com.owncloud.android.lib.common.operations; import android.accounts.Account; import android.accounts.AccountsException; -import at.bitfire.dav4android.exception.DavException; -import at.bitfire.dav4android.exception.HttpException; +import at.bitfire.dav4jvm.exception.DavException; +import at.bitfire.dav4jvm.exception.HttpException; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.http.HttpConstants; import com.owncloud.android.lib.common.http.methods.HttpBaseMethod; diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/CheckPathExistenceRemoteOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/CheckPathExistenceRemoteOperation.kt index aafa5fc7..f3da9a72 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/CheckPathExistenceRemoteOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/CheckPathExistenceRemoteOperation.kt @@ -25,7 +25,7 @@ package com.owncloud.android.lib.resources.files import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.http.HttpConstants -import com.owncloud.android.lib.common.http.methods.webdav.DavUtils +import com.owncloud.android.lib.common.http.methods.webdav.DavUtils.allPropset import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod import com.owncloud.android.lib.common.network.RedirectionPath import com.owncloud.android.lib.common.network.WebdavUtils @@ -66,7 +66,7 @@ class CheckPathExistenceRemoteOperation( if (isUserLogged) client.baseFilesWebDavUri.toString() else client.userFilesWebDavUri.toString() + WebdavUtils.encodePath(remotePath) - val propFindMethod = PropfindMethod(URL(stringUrl), 0, DavUtils.getAllPropset()).apply { + val propFindMethod = PropfindMethod(URL(stringUrl), 0, allPropset).apply { setReadTimeout(TIMEOUT.toLong(), TimeUnit.SECONDS) setConnectionTimeout(TIMEOUT.toLong(), TimeUnit.SECONDS) } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java index 0843783f..481ca168 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java @@ -29,12 +29,11 @@ import timber.log.Timber; import java.io.File; public class FileUtils { - public static final String PATH_SEPARATOR = "/"; public static final String FINAL_CHUNKS_FILE = ".file"; static String getParentPath(String remotePath) { String parentPath = new File(remotePath).getParent(); - parentPath = parentPath.endsWith(PATH_SEPARATOR) ? parentPath : parentPath + PATH_SEPARATOR; + parentPath = parentPath.endsWith(File.separator) ? parentPath : parentPath + File.separator; return parentPath; } @@ -42,14 +41,12 @@ public class FileUtils { * Validate the fileName to detect if contains any forbidden character: / , \ , < , > , * : , " , | , ? , * * - * @param fileName - * @return */ public static boolean isValidName(String fileName) { boolean result = true; Timber.d("fileName =======%s", fileName); - if (fileName.contains(PATH_SEPARATOR)) { + if (fileName.contains(File.separator)) { result = false; } return result; diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java index 730bd86b..03cb3aa7 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/ReadRemoteFolderOperation.java @@ -24,7 +24,7 @@ package com.owncloud.android.lib.resources.files; -import at.bitfire.dav4android.Response; +import at.bitfire.dav4jvm.Response; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.http.HttpConstants; @@ -122,7 +122,6 @@ public class ReadRemoteFolderOperation extends RemoteOperation - * The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'. + * The path received must be URL-decoded. Path separator must be File.separator, and it must be the first character in 'path'. * * @param path The remote path of the file. */ public RemoteFile(String path) { resetData(); - if (path == null || path.length() <= 0 || !path.startsWith(FileUtils.PATH_SEPARATOR)) { + if (path == null || path.length() <= 0 || !path.startsWith(File.separator)) { throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path); } mRemotePath = path; diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFileUtil.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFileUtil.kt index ace0675b..30550e70 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFileUtil.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RemoteFileUtil.kt @@ -41,7 +41,7 @@ class RemoteFileUtil { */ fun getRemotePathFromUrl(url: HttpUrl, userId: String): String? { val davFilesPath = OwnCloudClient.WEBDAV_FILES_PATH_4_0 + userId - val absoluteDavPath = Uri.decode(url.encodedPath()) + val absoluteDavPath = Uri.decode(url.encodedPath) val pathToOc = absoluteDavPath.split(davFilesPath)[0] return absoluteDavPath.replace(pathToOc + davFilesPath, "") } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java index 90a9c469..f27fdb53 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/RenameRemoteFileOperation.java @@ -68,11 +68,10 @@ public class RenameRemoteFileOperation extends RemoteOperation { mNewName = newName; String parent = (new File(mOldRemotePath)).getParent(); - parent = (parent.endsWith(FileUtils.PATH_SEPARATOR)) ? parent : parent + - FileUtils.PATH_SEPARATOR; + parent = (parent.endsWith(File.separator)) ? parent : parent + File.separator; mNewRemotePath = parent + mNewName; if (isFolder) { - mNewRemotePath += FileUtils.PATH_SEPARATOR; + mNewRemotePath += File.separator; } } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java index 939eafee..43181b28 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/UploadRemoteFileOperation.java @@ -84,10 +84,6 @@ public class UploadRemoteFileOperation extends RemoteOperation { RemoteOperationResult result; try { - mPutMethod = new PutMethod( - new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath))); - - mPutMethod.setRetryOnConnectionFailure(false); if (mCancellationRequested.get()) { // the operation was cancelled before getting it's turn to be executed in the queue of uploads @@ -125,6 +121,11 @@ public class UploadRemoteFileOperation extends RemoteOperation { mFileRequestBody.addDatatransferProgressListeners(mDataTransferListeners); } + mPutMethod = new PutMethod( + new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)), mFileRequestBody); + + mPutMethod.setRetryOnConnectionFailure(false); + if (mRequiredEtag != null && mRequiredEtag.length() > 0) { mPutMethod.addRequestHeader(HttpConstants.IF_MATCH_HEADER, mRequiredEtag); } @@ -132,8 +133,6 @@ public class UploadRemoteFileOperation extends RemoteOperation { mPutMethod.addRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER, String.valueOf(fileToUpload.length())); mPutMethod.addRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER, mFileLastModifTimestamp); - mPutMethod.setRequestBody(mFileRequestBody); - int status = client.executeHttpMethod(mPutMethod); if (isSuccess(status)) { diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/chunks/ChunkedUploadRemoteFileOperation.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/chunks/ChunkedUploadRemoteFileOperation.java index bbc297c8..14d0fbf5 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/chunks/ChunkedUploadRemoteFileOperation.java +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/files/chunks/ChunkedUploadRemoteFileOperation.java @@ -29,7 +29,6 @@ import com.owncloud.android.lib.common.http.methods.webdav.PutMethod; import com.owncloud.android.lib.common.network.ChunkFromFileRequestBody; import com.owncloud.android.lib.common.operations.OperationCancelledException; import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import com.owncloud.android.lib.resources.files.FileUtils; import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation; import okhttp3.MediaType; import timber.log.Timber; @@ -82,18 +81,11 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation } long offset = 0; - String uriPrefix = client.getUploadsWebDavUri() + FileUtils.PATH_SEPARATOR + String.valueOf(mTransferId); + String uriPrefix = client.getUploadsWebDavUri() + File.separator + mTransferId; long totalLength = fileToUpload.length(); long chunkCount = (long) Math.ceil((double) totalLength / CHUNK_SIZE); for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++, offset += CHUNK_SIZE) { - mPutMethod = new PutMethod( - new URL(uriPrefix + FileUtils.PATH_SEPARATOR + chunkIndex) - ); - - if (mRequiredEtag != null && mRequiredEtag.length() > 0) { - mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\""); - } ((ChunkFromFileRequestBody) mFileRequestBody).setOffset(offset); @@ -101,6 +93,12 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation result = new RemoteOperationResult<>(new OperationCancelledException()); break; } else { + mPutMethod = new PutMethod(new URL(uriPrefix + File.separator + chunkIndex), mFileRequestBody); + + if (mRequiredEtag != null && mRequiredEtag.length() > 0) { + mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\""); + } + if (chunkIndex == chunkCount - 1) { // Added a high timeout to the last chunk due to when the last chunk // arrives to the server with the last PUT, all chunks get assembled @@ -108,8 +106,6 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation mPutMethod.setReadTimeout(LAST_CHUNK_TIMEOUT, TimeUnit.MILLISECONDS); } - mPutMethod.setRequestBody(mFileRequestBody); - status = client.executeHttpMethod(mPutMethod); Timber.d("Upload of " + mLocalPath + " to " + mRemotePath + diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.kt index 5d5eeb39..896f570a 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/CreateRemoteShareOperation.kt @@ -116,9 +116,7 @@ class CreateRemoteShareOperation( val uriBuilder = requestUri.buildUpon() uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH) - val postMethod = PostMethod(URL(uriBuilder.build().toString())) - - postMethod.setRequestBody(formBodyBuilder.build()) + val postMethod = PostMethod(URL(uriBuilder.build().toString()), formBodyBuilder.build()) postMethod.setRequestHeader(HttpConstants.CONTENT_TYPE_HEADER, HttpConstants.CONTENT_TYPE_URLENCODED_UTF8) postMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) @@ -133,7 +131,7 @@ class CreateRemoteShareOperation( parser.oneOrMoreSharesRequired = true parser.ownCloudVersion = client.ownCloudVersion parser.serverBaseUri = client.baseUri - result = parser.parse(postMethod.responseBodyAsString) + result = parser.parse(postMethod.getResponseBodyAsString()) if (result.isSuccess && retrieveShareDetails) { // retrieve more info - POST only returns the index of the new share @@ -145,7 +143,7 @@ class CreateRemoteShareOperation( } } else { - result = parser.parse(postMethod.responseBodyAsString) + result = parser.parse(postMethod.getResponseBodyAsString()) } } catch (e: Exception) { diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/GetRemoteShareesOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/GetRemoteShareesOperation.kt index 11449fb0..e3432b5b 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/GetRemoteShareesOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/GetRemoteShareesOperation.kt @@ -98,7 +98,7 @@ class GetRemoteShareesOperation getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) val status = client.executeHttpMethod(getMethod) - val response = getMethod.responseBodyAsString + val response = getMethod.getResponseBodyAsString() if (isSuccess(status)) { Timber.d("Successful response: $response") diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.kt index ae09166b..ea1d7e2a 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/GetRemoteSharesForFileOperation.kt @@ -86,10 +86,10 @@ class GetRemoteSharesForFileOperation( ) parser.ownCloudVersion = client.ownCloudVersion parser.serverBaseUri = client.baseUri - result = parser.parse(getMethod.responseBodyAsString) + result = parser.parse(getMethod.getResponseBodyAsString()) if (result.isSuccess) { - Timber.d("Got " + result.data.shares.size + " shares") + Timber.d("Got ${result.data.shares.size} shares") } } else { result = RemoteOperationResult(getMethod) diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/RemoteShare.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/RemoteShare.kt index 12032316..20bb1ae9 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/RemoteShare.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/RemoteShare.kt @@ -25,6 +25,7 @@ package com.owncloud.android.lib.resources.shares import com.owncloud.android.lib.resources.files.FileUtils +import java.io.File /** * Contains the data of a Share from the Share API @@ -48,7 +49,7 @@ data class RemoteShare( var permissions: Int = DEFAULT_PERMISSION, var sharedDate: Long = INIT_SHARED_DATE, var expirationDate: Long = INIT_EXPIRATION_DATE_IN_MILLIS, - var isFolder: Boolean = path.endsWith(FileUtils.PATH_SEPARATOR), + var isFolder: Boolean = path.endsWith(File.separator), var userId: Long = 0, val isValid: Boolean = id > -1 ) { diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.kt index 034be286..5fa18169 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/RemoveRemoteShareOperation.kt @@ -73,9 +73,9 @@ class RemoveRemoteShareOperation(private val remoteShareId: Long) : RemoteOperat val parser = ShareToRemoteOperationResultParser( ShareXMLParser() ) - result = parser.parse(deleteMethod.responseBodyAsString) + result = parser.parse(deleteMethod.getResponseBodyAsString()) - Timber.d("Unshare " + remoteShareId + ": " + result.logMessage) + Timber.d("Unshare $remoteShareId: ${result.logMessage}") } else { result = RemoteOperationResult(deleteMethod) @@ -83,7 +83,7 @@ class RemoveRemoteShareOperation(private val remoteShareId: Long) : RemoteOperat } catch (e: Exception) { result = RemoteOperationResult(e) - Timber.e(e, "Unshare Link Exception " + result.logMessage) + Timber.e(e, "Unshare Link Exception ${result.logMessage}") } return result diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.kt index 0fa93482..a63c35a7 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/ShareXMLParser.kt @@ -25,14 +25,11 @@ package com.owncloud.android.lib.resources.shares import android.util.Xml - import com.owncloud.android.lib.common.network.WebdavUtils -import com.owncloud.android.lib.resources.files.FileUtils - import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParserException import org.xmlpull.v1.XmlPullParserFactory - +import java.io.File import java.io.IOException import java.io.InputStream import java.util.ArrayList @@ -330,9 +327,9 @@ class ShareXMLParser { private fun fixPathForFolder(share: RemoteShare) { if (share.isFolder && share.path.isNotEmpty() && - !share.path.endsWith(FileUtils.PATH_SEPARATOR) + !share.path.endsWith(File.separator) ) { - share.path = share.path + FileUtils.PATH_SEPARATOR + share.path = share.path + File.separator } } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/UpdateRemoteShareOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/UpdateRemoteShareOperation.kt index 0b4a08e5..e2af8959 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/UpdateRemoteShareOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/shares/UpdateRemoteShareOperation.kt @@ -143,9 +143,7 @@ class UpdateRemoteShareOperation uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH) uriBuilder.appendEncodedPath(remoteId.toString()) - val putMethod = PutMethod(URL(uriBuilder.build().toString())) - - putMethod.setRequestBody(formBodyBuilder.build()) + val putMethod = PutMethod(URL(uriBuilder.build().toString()), formBodyBuilder.build()) putMethod.setRequestHeader(HttpConstants.CONTENT_TYPE_HEADER, HttpConstants.CONTENT_TYPE_URLENCODED_UTF8) putMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE) @@ -158,12 +156,12 @@ class UpdateRemoteShareOperation ) if (!isSuccess(status)) { - return parser.parse(putMethod.responseBodyAsString) + return parser.parse(putMethod.getResponseBodyAsString()) } parser.ownCloudVersion = client.ownCloudVersion parser.serverBaseUri = client.baseUri - result = parser.parse(putMethod.responseBodyAsString) + result = parser.parse(putMethod.getResponseBodyAsString()) if (result.isSuccess && retrieveShareDetails) { // retrieve more info - PUT only returns the index of the new share diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteCapabilitiesOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteCapabilitiesOperation.kt index 256e03b6..f9f164eb 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteCapabilitiesOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteCapabilitiesOperation.kt @@ -65,7 +65,7 @@ class GetRemoteCapabilitiesOperation : RemoteOperation() { } val status = client.executeHttpMethod(getMethod) - val response = getMethod.responseBodyAsString + val response = getMethod.getResponseBodyAsString() if (status == HttpConstants.HTTP_OK) { Timber.d("Successful response $response") diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.kt index b6fd1b39..f47544b1 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.kt @@ -108,7 +108,7 @@ class GetRemoteStatusOperation : RemoteOperation() { } if (isSuccess(status)) { - val respJSON = JSONObject(getMethod.responseBodyAsString) + val respJSON = JSONObject(getMethod.getResponseBodyAsString()) if (!respJSON.getBoolean(NODE_INSTALLED)) { latestResult = RemoteOperationResult(ResultCode.INSTANCE_NOT_CONFIGURED) } else { diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/OwnCloudVersion.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/OwnCloudVersion.kt index c8c75653..c73805b8 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/OwnCloudVersion.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/OwnCloudVersion.kt @@ -38,6 +38,8 @@ class OwnCloudVersion(version: String) : Comparable, Parcelable var isVersionValid: Boolean = false set + var isVersionHidden: Boolean = false + val version: String get() = if (isVersionValid) { toString() @@ -55,6 +57,7 @@ class OwnCloudVersion(version: String) : Comparable, Parcelable var versionToParse = version mVersion = 0 isVersionValid = false + isVersionHidden = version.isBlank() val countDots = versionToParse.length - versionToParse.replace(".", "").length // Complete the version. Version must have 3 dots diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/services/implementation/OCServerInfoService.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/services/implementation/OCServerInfoService.kt index 8efd9def..76f82a46 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/services/implementation/OCServerInfoService.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/services/implementation/OCServerInfoService.kt @@ -21,6 +21,7 @@ package com.owncloud.android.lib.resources.status.services.implementation import android.net.Uri import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory.getAnonymousCredentials import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.status.services.ServerInfoService import com.owncloud.android.lib.resources.files.CheckPathExistenceRemoteOperation @@ -38,6 +39,6 @@ class OCServerInfoService : ServerInfoService { GetRemoteStatusOperation().execute(createClientFromPath(path)) private fun createClientFromPath(path: String): OwnCloudClient { - return OwnCloudClient(Uri.parse(path)) + return OwnCloudClient(Uri.parse(path)).apply { credentials = getAnonymousCredentials() } } } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserAvatarOperation.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserAvatarOperation.java deleted file mode 100644 index e9e78df6..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserAvatarOperation.java +++ /dev/null @@ -1,185 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * - * Copyright (C) 2020 ownCloud GmbH. - * - * 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.resources.users; - -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.http.HttpConstants; -import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod; -import com.owncloud.android.lib.common.network.WebdavUtils; -import com.owncloud.android.lib.common.operations.RemoteOperation; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import timber.log.Timber; - -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK; - -/** - * Gets avatar about the user logged in, if available - * - * @author David A. Velasco - * @author David González Verdugo - */ -public class GetRemoteUserAvatarOperation extends RemoteOperation { - - private static final String NON_OFFICIAL_AVATAR_PATH = "/index.php/avatar/"; - - /** - * Desired size in pixels of the squared image - */ - private int mDimension; - - public GetRemoteUserAvatarOperation(int dimension) { - mDimension = dimension; - } - - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - GetMethod getMethod = null; - RemoteOperationResult result; - InputStream inputStream = null; - BufferedInputStream bis = null; - ByteArrayOutputStream bos = null; - - try { - final String url = client.getBaseUri() + NON_OFFICIAL_AVATAR_PATH + client.getCredentials().getUsername() + "/" + mDimension; - Timber.d("avatar URI: %s", url); - - getMethod = new GetMethod(new URL(url)); - - int status = client.executeHttpMethod(getMethod); - - if (isSuccess(status)) { - // find out size of file to read - int totalToTransfer = 0; - String contentLength = getMethod.getResponseHeader(HttpConstants.CONTENT_LENGTH_HEADER); - - if (contentLength != null && contentLength.length() > 0) { - totalToTransfer = Integer.parseInt(contentLength); - } - - // find out MIME-type! - String mimeType; - String contentType = getMethod.getResponseHeader(HttpConstants.CONTENT_TYPE_HEADER); - - if (contentType == null || !contentType.startsWith("image")) { - Timber.w("Not an image, failing with no avatar"); - result = new RemoteOperationResult<>(RemoteOperationResult.ResultCode.FILE_NOT_FOUND); - return result; - } - - mimeType = contentType; - - /// download will be performed to a buffer - inputStream = getMethod.getResponseBodyAsStream(); - bis = new BufferedInputStream(inputStream); - bos = new ByteArrayOutputStream(totalToTransfer); - - byte[] bytes = new byte[4096]; - int readResult; - while ((readResult = bis.read(bytes)) != -1) { - bos.write(bytes, 0, readResult); - } - // TODO check total bytes transferred? - - // find out etag - String etag = WebdavUtils.getEtagFromResponse(getMethod); - if (etag.length() == 0) { - Timber.w("Could not read Etag from avatar"); - } - - // Result - result = new RemoteOperationResult<>(OK); - result.setData(new ResultData(bos.toByteArray(), mimeType, etag)); - - } else { - result = new RemoteOperationResult<>(getMethod); - client.exhaustResponse(getMethod.getResponseBodyAsStream()); - } - - } catch (Exception e) { - result = new RemoteOperationResult<>(e); - Timber.e(e, "Exception while getting OC user avatar"); - - } finally { - if (getMethod != null) { - try { - if (inputStream != null) { - client.exhaustResponse(inputStream); - if (bis != null) { - bis.close(); - } else { - inputStream.close(); - } - } - } catch (IOException i) { - Timber.e(i, "Unexpected exception closing input stream"); - } - try { - if (bos != null) { - bos.close(); - } - } catch (IOException o) { - Timber.e(o, "Unexpected exception closing output stream"); - } - } - } - - return result; - } - - private boolean isSuccess(int status) { - return (status == HttpConstants.HTTP_OK); - } - - public static class ResultData { - private String mEtag; - private String mMimeType; - private byte[] mAvatarData; - - ResultData(byte[] avatarData, String mimeType, String etag) { - mAvatarData = avatarData; - mMimeType = (mimeType == null) ? "" : mimeType; - mEtag = (etag == null) ? "" : etag; - } - - public String getEtag() { - return mEtag; - } - - public String getMimeType() { - return mMimeType; - } - - public byte[] getAvatarData() { - return mAvatarData; - } - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserAvatarOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserAvatarOperation.kt new file mode 100644 index 00000000..2efbacb6 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserAvatarOperation.kt @@ -0,0 +1,114 @@ +/* ownCloud Android Library is available under MIT license + * + * Copyright (C) 2020 ownCloud GmbH. + * + * 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.resources.users + +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.http.HttpConstants +import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod +import com.owncloud.android.lib.common.network.WebdavUtils +import com.owncloud.android.lib.common.operations.RemoteOperation +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import timber.log.Timber +import java.io.File +import java.io.IOException +import java.io.InputStream +import java.net.URL + +/** + * Gets avatar about the user logged in, if available + * + * @author David A. Velasco + * @author David González Verdugo + */ +class GetRemoteUserAvatarOperation(private val avatarDimension: Int) : RemoteOperation() { + override fun run(client: OwnCloudClient): RemoteOperationResult { + var inputStream: InputStream? = null + var result: RemoteOperationResult + + try { + val endPoint = + client.baseUri.toString() + NON_OFFICIAL_AVATAR_PATH + client.credentials.username + File.separator + avatarDimension + Timber.d("avatar URI: %s", endPoint) + + val getMethod = GetMethod(URL(endPoint)) + + val status = client.executeHttpMethod(getMethod) + + if (isSuccess(status)) { + // find out size of file to read + val contentLength = getMethod.getResponseHeader(HttpConstants.CONTENT_LENGTH_HEADER)?.toInt() + + // find out MIME-type! + val mimeType = getMethod.getResponseHeader(HttpConstants.CONTENT_TYPE_HEADER) + + if (mimeType == null || !mimeType.startsWith("image")) { + Timber.w("Not an image, failing with no avatar") + return RemoteOperationResult(RemoteOperationResult.ResultCode.FILE_NOT_FOUND) + } + + /// download will be performed to a buffer + inputStream = getMethod.getResponseBodyAsStream() + val bytesArray = inputStream?.readBytes()?: byteArrayOf() + + // TODO check total bytes transferred? + Timber.d("Avatar size: Bytes received ${bytesArray.size} of $contentLength") + + // find out etag + val etag = WebdavUtils.getEtagFromResponse(getMethod) + if (etag.isEmpty()) { + Timber.w("Could not read Etag from avatar") + } + + // Result + result = RemoteOperationResult(RemoteOperationResult.ResultCode.OK) + result.setData(RemoteAvatarData(bytesArray, mimeType, etag)) + + } else { + result = RemoteOperationResult(getMethod) + client.exhaustResponse(getMethod.getResponseBodyAsStream()) + } + + } catch (e: Exception) { + result = RemoteOperationResult(e) + Timber.e(e, "Exception while getting OC user avatar") + + } finally { + try { + client.exhaustResponse(inputStream) + inputStream?.close() + } catch (i: IOException) { + Timber.e(i, "Unexpected exception closing input stream") + } + } + + return result + } + + private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK + + companion object { + private const val NON_OFFICIAL_AVATAR_PATH = "/index.php/avatar/" + } +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserInfoOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserInfoOperation.kt index 7ea63c69..53600d29 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserInfoOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserInfoOperation.kt @@ -53,7 +53,7 @@ class GetRemoteUserInfoOperation : RemoteOperation() { try { val getMethod = GetMethod(URL(client.baseUri.toString() + OCS_ROUTE)) val status = client.executeHttpMethod(getMethod) - val response = getMethod.responseBodyAsString + val response = getMethod.getResponseBodyAsString() ?: "" if (status == HttpConstants.HTTP_OK) { Timber.d("Successful response $response") diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java deleted file mode 100644 index e4d834d8..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.java +++ /dev/null @@ -1,185 +0,0 @@ -/* ownCloud Android Library is available under MIT license - * - * Copyright (C) 2020 ownCloud Inc. - * Copyright (C) 2015 Bartosz Przybylski - * Copyright (C) 2014 Marcello Steiner - * - * 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.resources.users; - -import at.bitfire.dav4android.Property; -import at.bitfire.dav4android.property.QuotaAvailableBytes; -import at.bitfire.dav4android.property.QuotaUsedBytes; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.http.HttpConstants; -import com.owncloud.android.lib.common.http.methods.webdav.DavUtils; -import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod; -import com.owncloud.android.lib.common.network.WebdavUtils; -import com.owncloud.android.lib.common.operations.RemoteOperation; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import timber.log.Timber; - -import java.net.URL; -import java.util.List; - -import static com.owncloud.android.lib.common.http.methods.webdav.DavConstants.DEPTH_0; -import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK; - -/** - * @author marcello - * @author David González Verdugo - */ -public class GetRemoteUserQuotaOperation extends RemoteOperation { - - private String mRemotePath; - - /** - * Constructor - * - * @param remotePath Remote path of the file. - */ - public GetRemoteUserQuotaOperation(String remotePath) { - mRemotePath = remotePath; - } - - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - RemoteOperationResult result = null; - - try { - PropfindMethod propfindMethod = new PropfindMethod( - new URL(client.getUserFilesWebDavUri() + WebdavUtils.encodePath(mRemotePath)), - DEPTH_0, - DavUtils.getQuotaPropSet()); - - int status = client.executeHttpMethod(propfindMethod); - - if (isSuccess(status)) { - RemoteQuota remoteQuota = readData(propfindMethod.getRoot().getProperties()); - - result = new RemoteOperationResult<>(OK); - - // Add data to the result - if (result.isSuccess()) { - result.setData(remoteQuota); - } - - } else { // synchronization failed - result = new RemoteOperationResult<>(propfindMethod); - } - - } catch (Exception e) { - result = new RemoteOperationResult<>(e); - - } finally { - if (result.isSuccess()) { - Timber.i("Get quota from " + mRemotePath + ": " + result.getLogMessage()); - } else { - if (result.isException()) { - Timber.e(result.getException(), "Get quota from " + mRemotePath + ": " + result.getLogMessage()); - } else { - Timber.e("Get quota from " + mRemotePath + ": " + result.getLogMessage()); - } - } - } - - return result; - } - - private boolean isSuccess(int status) { - return status == HttpConstants.HTTP_MULTI_STATUS || status == HttpConstants.HTTP_OK; - } - - /** - * Read the data retrieved from the server about the quota - * - * @param properties WebDAV properties containing quota data - * @return new {@link RemoteQuota} instance representing the data read from the server - */ - private RemoteQuota readData(List properties) { - long quotaAvailable = 0; - long quotaUsed = 0; - - for (Property property : properties) { - if (property instanceof QuotaAvailableBytes) { - quotaAvailable = ((QuotaAvailableBytes) property).getQuotaAvailableBytes(); - } - if (property instanceof QuotaUsedBytes) { - quotaUsed = ((QuotaUsedBytes) property).getQuotaUsedBytes(); - } - } - - // If there's a special case, quota available will contain a negative code - // -1, PENDING: Not computed yet, e.g. external storage mounted but folder sizes need scanning - // -2, UNKNOWN: Storage not accessible, e.g. external storage with no API to ask for the free space - // -3, UNLIMITED: Quota using all the storage - if (quotaAvailable < 0) { - return new RemoteQuota( - quotaAvailable, - quotaUsed, - 0, - 0 - ); - } else { - long totalQuota = quotaAvailable + quotaUsed; - double relativeQuota = (double) (quotaUsed * 100) / totalQuota; - double roundedRelativeQuota = Math.round(relativeQuota * 100) / 100.0d; - - return new RemoteQuota( - quotaAvailable, - quotaUsed, - totalQuota, - roundedRelativeQuota - ); - } - } - - static public class RemoteQuota { - - long mFree, mUsed, mTotal; - double mRelative; - - public RemoteQuota(long free, long used, long total, double relative) { - mFree = free; - mUsed = used; - mTotal = total; - mRelative = relative; - } - - public long getFree() { - return mFree; - } - - public long getUsed() { - return mUsed; - } - - public long getTotal() { - return mTotal; - } - - public double getRelative() { - return mRelative; - } - } -} \ No newline at end of file diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.kt new file mode 100644 index 00000000..2607bd92 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/GetRemoteUserQuotaOperation.kt @@ -0,0 +1,126 @@ +/* ownCloud Android Library is available under MIT license +* +* Copyright (C) 2020 ownCloud Inc. +* Copyright (C) 2015 Bartosz Przybylski +* Copyright (C) 2014 Marcello Steiner +* +* 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.resources.users + +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.property.QuotaAvailableBytes +import at.bitfire.dav4jvm.property.QuotaUsedBytes +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.http.HttpConstants +import com.owncloud.android.lib.common.http.methods.webdav.DavConstants +import com.owncloud.android.lib.common.http.methods.webdav.DavUtils +import com.owncloud.android.lib.common.http.methods.webdav.PropfindMethod +import com.owncloud.android.lib.common.operations.RemoteOperation +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode +import com.owncloud.android.lib.resources.users.GetRemoteUserQuotaOperation.RemoteQuota +import timber.log.Timber +import java.net.URL +import kotlin.math.roundToLong + +/** + * @author marcello + * @author David González Verdugo + */ +class GetRemoteUserQuotaOperation : RemoteOperation() { + override fun run(client: OwnCloudClient): RemoteOperationResult = + try { + val propfindMethod = PropfindMethod( + URL(client.userFilesWebDavUri.toString()), + DavConstants.DEPTH_0, + DavUtils.quotaPropSet + ) + with(client.executeHttpMethod(propfindMethod)) { + if (isSuccess(this)) { + RemoteOperationResult(ResultCode.OK).apply { + data = readData(propfindMethod.root?.properties) + }.also { + Timber.i("Get quota completed: ${it.data} and message: ${it.logMessage}") + } + } else { // synchronization failed + RemoteOperationResult(propfindMethod).also { + Timber.e("Get quota without success: ${it.logMessage}") + } + } + } + } catch (e: Exception) { + RemoteOperationResult(e).also { + Timber.e(it.exception, "Get quota: ${it.logMessage}") + } + } + + private fun isSuccess(status: Int) = status == HttpConstants.HTTP_MULTI_STATUS || status == HttpConstants.HTTP_OK + + /** + * Read the data retrieved from the server about the quota + * + * @param properties WebDAV properties containing quota data + * @return new [RemoteQuota] instance representing the data read from the server + */ + private fun readData(properties: List?): RemoteQuota { + var quotaAvailable: Long = 0 + var quotaUsed: Long = 0 + + if (properties == null) { + // Should not happen + Timber.d("Unable to get quota") + return RemoteQuota(0, 0, 0, 0.0) + } + + for (property in properties) { + if (property is QuotaAvailableBytes) { + quotaAvailable = property.quotaAvailableBytes + } + if (property is QuotaUsedBytes) { + quotaUsed = property.quotaUsedBytes + } + } + Timber.d("Quota used: $quotaUsed, QuotaAvailable: $quotaAvailable") + // If there's a special case, quota available will contain a negative code + // -1, PENDING: Not computed yet, e.g. external storage mounted but folder sizes need scanning + // -2, UNKNOWN: Storage not accessible, e.g. external storage with no API to ask for the free space + // -3, UNLIMITED: Quota using all the storage + return if (quotaAvailable < 0) { + RemoteQuota( + free = quotaAvailable, + used = quotaUsed, + total = 0, + relative = 0.0 + ) + } else { + val totalQuota = quotaAvailable + quotaUsed + val roundedRelativeQuota = if (totalQuota > 0) { + val relativeQuota = (quotaUsed * 100).toDouble() / totalQuota + (relativeQuota * 100).roundToLong() / 100.0 + } else 0.0 + + RemoteQuota(quotaAvailable, quotaUsed, totalQuota, roundedRelativeQuota) + } + } + + data class RemoteQuota(var free: Long, var used: Long, var total: Long, var relative: Double) +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/RemoteAvatarData.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/RemoteAvatarData.kt new file mode 100644 index 00000000..1f68b7b0 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/RemoteAvatarData.kt @@ -0,0 +1,30 @@ +/* ownCloud Android Library is available under MIT license + * + * Copyright (C) 2020 ownCloud GmbH. + * + * 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.resources.users + +data class RemoteAvatarData( + val avatarData: ByteArray = byteArrayOf(), + val mimeType: String = "", + val eTag: String = "" +) diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/services/UserService.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/services/UserService.kt index 4ef2e1a7..15a201bb 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/services/UserService.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/services/UserService.kt @@ -26,8 +26,12 @@ package com.owncloud.android.lib.resources.users.services import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.Service +import com.owncloud.android.lib.resources.users.GetRemoteUserQuotaOperation +import com.owncloud.android.lib.resources.users.RemoteAvatarData import com.owncloud.android.lib.resources.users.RemoteUserInfo -interface UserService: Service { - fun getUserInfo() : RemoteOperationResult +interface UserService : Service { + fun getUserInfo(): RemoteOperationResult + fun getUserQuota(): RemoteOperationResult + fun getUserAvatar(avatarDimension: Int): RemoteOperationResult } diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/services/implementation/OCUserService.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/services/implementation/OCUserService.kt index 6b07b25e..d21d2909 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/services/implementation/OCUserService.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/users/services/implementation/OCUserService.kt @@ -21,12 +21,21 @@ package com.owncloud.android.lib.resources.users.services.implementation import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.users.GetRemoteUserAvatarOperation import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation +import com.owncloud.android.lib.resources.users.GetRemoteUserQuotaOperation +import com.owncloud.android.lib.resources.users.RemoteAvatarData import com.owncloud.android.lib.resources.users.RemoteUserInfo import com.owncloud.android.lib.resources.users.services.UserService -class OCUserService(override val client: OwnCloudClient) : - UserService { +class OCUserService(override val client: OwnCloudClient) : UserService { override fun getUserInfo(): RemoteOperationResult = GetRemoteUserInfoOperation().execute(client) + + override fun getUserQuota(): RemoteOperationResult = + GetRemoteUserQuotaOperation().execute(client) + + override fun getUserAvatar(avatarDimension: Int): RemoteOperationResult = + GetRemoteUserAvatarOperation(avatarDimension).execute(client) + } diff --git a/sample_client/build.gradle b/sample_client/build.gradle index 4d0c1d4b..d3112b7a 100644 --- a/sample_client/build.gradle +++ b/sample_client/build.gradle @@ -5,11 +5,11 @@ dependencies { } android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 29 // This is pretty ugly but manifest placeholders don't seem to work very well when using different modules // See https://github.com/openid/AppAuth-Android/issues/325 diff --git a/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java b/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java index bff10fed..6492b944 100644 --- a/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java +++ b/sample_client/src/main/java/com/owncloud/android/lib/sampleclient/MainActivity.java @@ -47,7 +47,6 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation; -import com.owncloud.android.lib.resources.files.FileUtils; import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation; import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation; @@ -151,14 +150,14 @@ public class MainActivity extends Activity implements OnRemoteOperationListener, } private void startRefresh() { - ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation(FileUtils.PATH_SEPARATOR); + ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation(File.separator); refreshOperation.execute(mClient, this, mHandler); } private void startUpload() { File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path)); File fileToUpload = upFolder.listFiles()[0]; - String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName(); + String remotePath = File.separator + fileToUpload.getName(); String mimeType = getString(R.string.sample_file_mimetype); // Get the last modification date of the file from the file system @@ -174,7 +173,7 @@ public class MainActivity extends Activity implements OnRemoteOperationListener, private void startRemoteDeletion() { File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path)); File fileToUpload = upFolder.listFiles()[0]; - String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName(); + String remotePath = File.separator + fileToUpload.getName(); RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath); removeOperation.execute(mClient, this, mHandler); @@ -185,7 +184,7 @@ public class MainActivity extends Activity implements OnRemoteOperationListener, downFolder.mkdir(); File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path)); File fileToUpload = upFolder.listFiles()[0]; - String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName(); + String remotePath = File.separator + fileToUpload.getName(); DownloadRemoteFileOperation downloadOperation = new DownloadRemoteFileOperation(remotePath, downFolder.getAbsolutePath());