diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/server/CheckPathExistenceOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/server/CheckPathExistenceOperation.kt index e6f1e638..0e900dde 100644 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/server/CheckPathExistenceOperation.kt +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/server/CheckPathExistenceOperation.kt @@ -44,7 +44,7 @@ import java.util.concurrent.TimeUnit * @author Abel García de Prada * * @param remotePath Path to append to the URL owned by the client instance. - * @param isUserLogged When `true`, the username won't be added at the end of the PROPFIND url since is not + * @param isUserLogged When `true`, the username won't be added at the end of the PROPFIND url since is not * needed to check user credentials */ class CheckPathExistenceOperation( diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/server/GetRemoteStatusOperation.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/server/GetRemoteStatusOperation.kt new file mode 100644 index 00000000..6b903e33 --- /dev/null +++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/server/GetRemoteStatusOperation.kt @@ -0,0 +1,170 @@ +/* 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.server + +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkInfo +import android.net.Uri +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.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.status.OwnCloudVersion +import org.json.JSONException +import org.json.JSONObject +import timber.log.Timber +import java.net.URL +import java.util.concurrent.TimeUnit +import javax.net.ssl.SSLException + +/** + * Checks if the server is valid and if the server supports the Share API + * + * @author David A. Velasco + * @author masensio + * @author David González Verdugo + */ +class GetRemoteStatusOperation(private var context: Context) : RemoteOperation() { + private lateinit var latestResult: RemoteOperationResult + + override fun run(client: OwnCloudClient): RemoteOperationResult { + + if (!isOnline) { + return RemoteOperationResult(ResultCode.NO_NETWORK_CONNECTION) + } + + val baseUriStr = client.baseUri.toString() + if (baseUriStr.startsWith(HTTP_PREFIX) || baseUriStr.startsWith(HTTPS_PREFIX)) { + tryConnection(client) + } else { + client.baseUri = Uri.parse(HTTPS_PREFIX + baseUriStr) + val httpsSuccess = tryConnection(client) + if (!httpsSuccess && !latestResult.isSslRecoverableException) { + Timber.d("Establishing secure connection failed, trying non secure connection") + client.baseUri = Uri.parse(HTTP_PREFIX + baseUriStr) + tryConnection(client) + } + } + return latestResult + } + + private fun tryConnection(client: OwnCloudClient): Boolean { + var retval = false + val baseUrlSt = client.baseUri.toString() + try { + var getMethod = GetMethod(URL(baseUrlSt + OwnCloudClient.STATUS_PATH)).apply { + setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS) + setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS) + } + client.setFollowRedirects(false) + var isRedirectToNonSecureConnection = false + var status: Int + try { + status = client.executeHttpMethod(getMethod) + latestResult = + if (isSuccess(status)) RemoteOperationResult(ResultCode.OK) + else RemoteOperationResult(getMethod) + } catch (sslE: SSLException) { + latestResult = RemoteOperationResult(sslE) + return false + } + var redirectedLocation = latestResult.redirectedLocation + while (redirectedLocation != null && redirectedLocation.isNotEmpty() && !latestResult.isSuccess) { + isRedirectToNonSecureConnection = + isRedirectToNonSecureConnection or + (baseUrlSt.startsWith(HTTPS_PREFIX) && redirectedLocation.startsWith(HTTP_PREFIX)) + + getMethod = GetMethod(URL(redirectedLocation)).apply { + setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS) + setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS) + } + status = client.executeHttpMethod(getMethod) + latestResult = RemoteOperationResult(getMethod) + redirectedLocation = latestResult.redirectedLocation + } + + if (isSuccess(status)) { + Timber.d(getMethod.responseBodyAsString) + val respJSON = JSONObject(getMethod.responseBodyAsString) + if (!respJSON.getBoolean(NODE_INSTALLED)) { + latestResult = RemoteOperationResult(ResultCode.INSTANCE_NOT_CONFIGURED) + } else { + val version = respJSON.getString(NODE_VERSION) + val ocVersion = OwnCloudVersion(version) + // the version object will be returned even if the version is invalid, no error code; + // every app will decide how to act if (ocVersion.isVersionValid() == false) + latestResult = if (isRedirectToNonSecureConnection) { + RemoteOperationResult(ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION) + } else { + RemoteOperationResult(if (baseUrlSt.startsWith(HTTPS_PREFIX)) ResultCode.OK_SSL else ResultCode.OK_NO_SSL) + } + latestResult.data = ocVersion + retval = true + } + } else { + latestResult = RemoteOperationResult(getMethod) + } + } catch (e: JSONException) { + latestResult = RemoteOperationResult(ResultCode.INSTANCE_NOT_CONFIGURED) + } catch (e: Exception) { + latestResult = RemoteOperationResult(e) + } + when { + latestResult.isSuccess -> { + Timber.i("Connection check at $baseUrlSt: ${latestResult.logMessage}") + } + latestResult.exception != null -> { + Timber.e(latestResult.exception, "Connection check at $baseUrlSt: ${latestResult.logMessage}") + } + else -> { + Timber.e("Connection check at $baseUrlSt: ${latestResult.logMessage}") + } + } + return retval + } + + private val isOnline: Boolean + get() { + val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val activeNetwork: NetworkInfo? = cm.activeNetworkInfo + return activeNetwork?.isConnected == true + } + + private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK + + companion object { + /** + * Maximum time to wait for a response from the server when the connection is being tested, + * in MILLISECONDs. + */ + const val TRY_CONNECTION_TIMEOUT: Long = 5000 + private const val NODE_INSTALLED = "installed" + private const val NODE_VERSION = "version" + private const val HTTPS_PREFIX = "https://" + private const val HTTP_PREFIX = "http://" + } +} diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java deleted file mode 100644 index bab59562..00000000 --- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/GetRemoteStatusOperation.java +++ /dev/null @@ -1,196 +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.status; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.Uri; - -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.operations.RemoteOperation; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import org.json.JSONException; -import org.json.JSONObject; -import timber.log.Timber; - -import javax.net.ssl.SSLException; -import java.net.URL; -import java.util.concurrent.TimeUnit; - -import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK; - -/** - * Checks if the server is valid and if the server supports the Share API - * - * @author David A. Velasco - * @author masensio - * @author David González Verdugo - */ - -public class GetRemoteStatusOperation extends RemoteOperation { - - /** - * Maximum time to wait for a response from the server when the connection is being tested, - * in MILLISECONDs. - */ - public static final long TRY_CONNECTION_TIMEOUT = 5000; - - private static final String NODE_INSTALLED = "installed"; - private static final String NODE_VERSION = "version"; - private static final String HTTPS_PREFIX = "https://"; - private static final String HTTP_PREFIX = "http://"; - - private RemoteOperationResult mLatestResult; - private Context mContext; - - public GetRemoteStatusOperation(Context context) { - mContext = context; - } - - private boolean tryConnection(OwnCloudClient client) { - boolean retval = false; - String baseUrlSt = client.getBaseUri().toString(); - try { - GetMethod getMethod = new GetMethod(new URL(baseUrlSt + OwnCloudClient.STATUS_PATH)); - - getMethod.setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS); - getMethod.setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS); - - client.setFollowRedirects(false); - boolean isRedirectToNonSecureConnection = false; - int status; - try { - status = client.executeHttpMethod(getMethod); - mLatestResult = isSuccess(status) - ? new RemoteOperationResult<>(OK) - : new RemoteOperationResult<>(getMethod); - } catch (SSLException sslE) { - mLatestResult = new RemoteOperationResult(sslE); - return false; - } - - String redirectedLocation = mLatestResult.getRedirectedLocation(); - while (redirectedLocation != null && redirectedLocation.length() > 0 - && !mLatestResult.isSuccess()) { - - isRedirectToNonSecureConnection |= ( - baseUrlSt.startsWith(HTTPS_PREFIX) && - redirectedLocation.startsWith(HTTP_PREFIX) - ); - - getMethod = new GetMethod(new URL(redirectedLocation)); - getMethod.setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS); - getMethod.setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS); - - status = client.executeHttpMethod(getMethod); - mLatestResult = new RemoteOperationResult<>(getMethod); - redirectedLocation = mLatestResult.getRedirectedLocation(); - } - - if (isSuccess(status)) { - - JSONObject respJSON = new JSONObject(getMethod.getResponseBodyAsString()); - if (!respJSON.getBoolean(NODE_INSTALLED)) { - mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); - } else { - String version = respJSON.getString(NODE_VERSION); - OwnCloudVersion ocVersion = new OwnCloudVersion(version); - /// the version object will be returned even if the version is invalid, no error code; - /// every app will decide how to act if (ocVersion.isVersionValid() == false) - - if (isRedirectToNonSecureConnection) { - mLatestResult = new RemoteOperationResult<>( - RemoteOperationResult.ResultCode. - OK_REDIRECT_TO_NON_SECURE_CONNECTION); - } else { - mLatestResult = new RemoteOperationResult<>( - baseUrlSt.startsWith(HTTPS_PREFIX) ? - RemoteOperationResult.ResultCode.OK_SSL : - RemoteOperationResult.ResultCode.OK_NO_SSL); - } - - mLatestResult.setData(ocVersion); - retval = true; - } - - } else { - mLatestResult = new RemoteOperationResult<>(getMethod); - } - - } catch (JSONException e) { - mLatestResult = new RemoteOperationResult<>( - RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); - - } catch (Exception e) { - mLatestResult = new RemoteOperationResult<>(e); - } - - if (mLatestResult.isSuccess()) { - Timber.i("Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); - - } else if (mLatestResult.getException() != null) { - Timber.e(mLatestResult.getException(), "Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); - - } else { - Timber.e("Connection check at " + baseUrlSt + ": " + mLatestResult.getLogMessage()); - } - - return retval; - } - - private boolean isOnline() { - ConnectivityManager cm = (ConnectivityManager) mContext - .getSystemService(Context.CONNECTIVITY_SERVICE); - return cm != null && cm.getActiveNetworkInfo() != null - && cm.getActiveNetworkInfo().isConnectedOrConnecting(); - } - - @Override - protected RemoteOperationResult run(OwnCloudClient client) { - if (!isOnline()) { - return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION); - } - String baseUriStr = client.getBaseUri().toString(); - if (baseUriStr.startsWith(HTTP_PREFIX) || baseUriStr.startsWith(HTTPS_PREFIX)) { - tryConnection(client); - - } else { - client.setBaseUri(Uri.parse(HTTPS_PREFIX + baseUriStr)); - boolean httpsSuccess = tryConnection(client); - if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) { - Timber.d("Establishing secure connection failed, trying non secure connection"); - client.setBaseUri(Uri.parse(HTTP_PREFIX + baseUriStr)); - tryConnection(client); - } - } - return mLatestResult; - } - - private boolean isSuccess(int status) { - return (status == HttpConstants.HTTP_OK); - } -} \ No newline at end of file