mirror of
				https://github.com/owncloud/android-library.git
				synced 2025-10-31 02:17:41 +00:00 
			
		
		
		
	detach request logic from operation
This commit is contained in:
		
							parent
							
								
									884820e6c6
								
							
						
					
					
						commit
						94f69af7d3
					
				| @ -25,16 +25,12 @@ package com.owncloud.android.lib.resources.status | ||||
| 
 | ||||
| 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 org.json.JSONException | ||||
| import org.json.JSONObject | ||||
| import timber.log.Timber | ||||
| import java.net.URL | ||||
| import java.util.concurrent.TimeUnit | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Checks if the server is valid | ||||
| @ -45,6 +41,11 @@ import java.util.concurrent.TimeUnit | ||||
|  * @author Abel García de Prada | ||||
|  */ | ||||
| class GetRemoteStatusOperation : RemoteOperation<OwnCloudVersion>() { | ||||
|     companion object { | ||||
|         const val HTTPS_SCHEME = "https" | ||||
|         const val HTTP_SCHEME = "http" | ||||
|     } | ||||
| 
 | ||||
|     override fun run(client: OwnCloudClient): RemoteOperationResult<OwnCloudVersion> { | ||||
|         if (client.baseUri.scheme.isNullOrEmpty()) | ||||
|             client.baseUri = Uri.parse(HTTPS_SCHEME + "://" + client.baseUri.toString()) | ||||
| @ -59,114 +60,17 @@ class GetRemoteStatusOperation : RemoteOperation<OwnCloudVersion>() { | ||||
|         return result | ||||
|     } | ||||
| 
 | ||||
|     fun updateLocationWithRedirectPath(oldLocation: String, redirectedLocation: String): String { | ||||
|         if (!redirectedLocation.startsWith("/")) | ||||
|             return redirectedLocation | ||||
|         val oldLocation = URL(oldLocation) | ||||
|         return URL(oldLocation.protocol, oldLocation.host, oldLocation.port, redirectedLocation).toString() | ||||
|     } | ||||
| 
 | ||||
|     private fun checkIfConnectionIsRedirectedToNoneSecure( | ||||
|         isConnectionSecure: Boolean, | ||||
|         baseUrl: String, | ||||
|         redirectedUrl: String | ||||
|     ): Boolean { | ||||
|         return isConnectionSecure || | ||||
|                 (baseUrl.startsWith(HTTPS_SCHEME) && redirectedUrl.startsWith(HTTP_SCHEME)) | ||||
|     } | ||||
| 
 | ||||
|     private fun getGetMethod(url: String): GetMethod { | ||||
|         return GetMethod(URL(url + OwnCloudClient.STATUS_PATH)).apply { | ||||
|             setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS) | ||||
|             setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     data class RequestResult( | ||||
|         val getMethod: GetMethod, | ||||
|         val status: Int, | ||||
|         val result: RemoteOperationResult<OwnCloudVersion>, | ||||
|         val redirectedToUnsecureLocation: Boolean | ||||
|     ) | ||||
| 
 | ||||
|     fun requestAndFollowRedirects(baseLocation: String): RequestResult { | ||||
|         var currentLocation = baseLocation | ||||
|         var redirectedToUnsecureLocation = false | ||||
|         var status: Int | ||||
| 
 | ||||
|         while (true) { | ||||
|             val getMethod = getGetMethod(currentLocation) | ||||
| 
 | ||||
|             status = client.executeHttpMethod(getMethod) | ||||
|             val result = | ||||
|                 if (isSuccess(status)) RemoteOperationResult<OwnCloudVersion>(ResultCode.OK) | ||||
|                 else RemoteOperationResult(getMethod) | ||||
| 
 | ||||
|             if (result.redirectedLocation.isNullOrEmpty() || result.isSuccess) { | ||||
|                 return RequestResult(getMethod, status, result, redirectedToUnsecureLocation) | ||||
|             } else { | ||||
|                 val nextLocation = updateLocationWithRedirectPath(currentLocation, result.redirectedLocation) | ||||
|                 redirectedToUnsecureLocation = | ||||
|                     checkIfConnectionIsRedirectedToNoneSecure( | ||||
|                         redirectedToUnsecureLocation, | ||||
|                         currentLocation, | ||||
|                         nextLocation | ||||
|                     ) | ||||
|                 currentLocation = nextLocation | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun handleRequestResult( | ||||
|         requestResult: RequestResult, | ||||
|         baseUrl: String | ||||
|     ): RemoteOperationResult<OwnCloudVersion> { | ||||
|         if (!isSuccess(requestResult.status)) | ||||
|             return RemoteOperationResult(requestResult.getMethod) | ||||
| 
 | ||||
|         val respJSON = JSONObject(requestResult.getMethod.getResponseBodyAsString()) | ||||
|         if (!respJSON.getBoolean(NODE_INSTALLED)) | ||||
|             return RemoteOperationResult(ResultCode.INSTANCE_NOT_CONFIGURED) | ||||
| 
 | ||||
|         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) | ||||
|         val result = | ||||
|             if (requestResult.redirectedToUnsecureLocation) { | ||||
|                 RemoteOperationResult<OwnCloudVersion>(ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION) | ||||
|             } else { | ||||
|                 if (baseUrl.startsWith(HTTPS_SCHEME)) RemoteOperationResult(ResultCode.OK_SSL) | ||||
|                 else RemoteOperationResult(ResultCode.OK_NO_SSL) | ||||
|             } | ||||
|         result.data = ocVersion | ||||
|         return result | ||||
|     } | ||||
| 
 | ||||
|     private fun tryToConnect(client: OwnCloudClient): RemoteOperationResult<OwnCloudVersion> { | ||||
|         val baseUrl = client.baseUri.toString() | ||||
|         client.setFollowRedirects(false) | ||||
|         return try { | ||||
|             val requestResult = requestAndFollowRedirects(baseUrl) | ||||
|             handleRequestResult(requestResult, baseUrl) | ||||
|             val requestor = StatusRequestor() | ||||
|             val requestResult = requestor.requestAndFollowRedirects(baseUrl, client) | ||||
|             requestor.handleRequestResult(requestResult, baseUrl) | ||||
|         } catch (e: JSONException) { | ||||
|             RemoteOperationResult(ResultCode.INSTANCE_NOT_CONFIGURED) | ||||
|         } catch (e: Exception) { | ||||
|             RemoteOperationResult(e) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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. | ||||
|          */ | ||||
|         private const val TRY_CONNECTION_TIMEOUT: Long = 5000 | ||||
|         private const val NODE_INSTALLED = "installed" | ||||
|         private const val NODE_VERSION = "version" | ||||
|         private const val HTTPS_SCHEME = "https" | ||||
|         private const val HTTP_SCHEME = "http" | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,113 @@ | ||||
| package com.owncloud.android.lib.resources.status | ||||
| 
 | ||||
| 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.RemoteOperationResult | ||||
| import org.json.JSONObject | ||||
| import java.net.URL | ||||
| import java.util.concurrent.TimeUnit | ||||
| 
 | ||||
| internal class StatusRequestor { | ||||
| 
 | ||||
|     companion object { | ||||
|         /** | ||||
|          * Maximum time to wait for a response from the server when the connection is being tested, | ||||
|          * in MILLISECONDs. | ||||
|          */ | ||||
|         private const val TRY_CONNECTION_TIMEOUT: Long = 5000 | ||||
|         private const val NODE_INSTALLED = "installed" | ||||
|         private const val HTTPS_SCHEME = "https" | ||||
|         private const val HTTP_SCHEME = "http" | ||||
|         private const val NODE_VERSION = "version" | ||||
|     } | ||||
| 
 | ||||
|     private fun checkIfConnectionIsRedirectedToNoneSecure( | ||||
|         isConnectionSecure: Boolean, | ||||
|         baseUrl: String, | ||||
|         redirectedUrl: String | ||||
|     ): Boolean { | ||||
|         return isConnectionSecure || | ||||
|                 (baseUrl.startsWith(HTTPS_SCHEME) && redirectedUrl.startsWith( | ||||
|                     HTTP_SCHEME | ||||
|                 )) | ||||
|     } | ||||
| 
 | ||||
|     fun updateLocationWithRedirectPath(oldLocation: String, redirectedLocation: String): String { | ||||
|         if (!redirectedLocation.startsWith("/")) | ||||
|             return redirectedLocation | ||||
|         val oldLocation = URL(oldLocation) | ||||
|         return URL(oldLocation.protocol, oldLocation.host, oldLocation.port, redirectedLocation).toString() | ||||
|     } | ||||
| 
 | ||||
|     private fun getGetMethod(url: String): GetMethod { | ||||
|         return GetMethod(URL(url + OwnCloudClient.STATUS_PATH)).apply { | ||||
|             setReadTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS) | ||||
|             setConnectionTimeout(TRY_CONNECTION_TIMEOUT, TimeUnit.SECONDS) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     data class RequestResult( | ||||
|         val getMethod: GetMethod, | ||||
|         val status: Int, | ||||
|         val result: RemoteOperationResult<OwnCloudVersion>, | ||||
|         val redirectedToUnsecureLocation: Boolean | ||||
|     ) | ||||
| 
 | ||||
|     fun requestAndFollowRedirects(baseLocation: String, client: OwnCloudClient): RequestResult { | ||||
|         var currentLocation = baseLocation | ||||
|         var redirectedToUnsecureLocation = false | ||||
|         var status: Int | ||||
| 
 | ||||
|         while (true) { | ||||
|             val getMethod = getGetMethod(currentLocation) | ||||
| 
 | ||||
|             status = client.executeHttpMethod(getMethod) | ||||
|             val result = | ||||
|                 if (isSuccess(status)) RemoteOperationResult<OwnCloudVersion>(RemoteOperationResult.ResultCode.OK) | ||||
|                 else RemoteOperationResult(getMethod) | ||||
| 
 | ||||
|             if (result.redirectedLocation.isNullOrEmpty() || result.isSuccess) { | ||||
|                 return RequestResult(getMethod, status, result, redirectedToUnsecureLocation) | ||||
|             } else { | ||||
|                 val nextLocation = updateLocationWithRedirectPath(currentLocation, result.redirectedLocation) | ||||
|                 redirectedToUnsecureLocation = | ||||
|                     checkIfConnectionIsRedirectedToNoneSecure( | ||||
|                         redirectedToUnsecureLocation, | ||||
|                         currentLocation, | ||||
|                         nextLocation | ||||
|                     ) | ||||
|                 currentLocation = nextLocation | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK | ||||
| 
 | ||||
|     fun handleRequestResult( | ||||
|         requestResult: RequestResult, | ||||
|         baseUrl: String | ||||
|     ): RemoteOperationResult<OwnCloudVersion> { | ||||
|         if (!isSuccess(requestResult.status)) | ||||
|             return RemoteOperationResult(requestResult.getMethod) | ||||
| 
 | ||||
|         val respJSON = JSONObject(requestResult.getMethod.getResponseBodyAsString() ?: "") | ||||
|         if (!respJSON.getBoolean(NODE_INSTALLED)) | ||||
|             return RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED) | ||||
| 
 | ||||
|         val ocVersion = OwnCloudVersion(respJSON.getString(NODE_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) | ||||
|         val result = | ||||
|             if (requestResult.redirectedToUnsecureLocation) { | ||||
|                 RemoteOperationResult<OwnCloudVersion>(RemoteOperationResult.ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION) | ||||
|             } else { | ||||
|                 if (baseUrl.startsWith(HTTPS_SCHEME)) RemoteOperationResult( | ||||
|                     RemoteOperationResult.ResultCode.OK_SSL | ||||
|                 ) | ||||
|                 else RemoteOperationResult(RemoteOperationResult.ResultCode.OK_NO_SSL) | ||||
|             } | ||||
|         result.data = ocVersion | ||||
|         return result | ||||
|     } | ||||
| } | ||||
| @ -1,24 +1,24 @@ | ||||
| package com.owncloud.android.lib | ||||
| 
 | ||||
| import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation | ||||
| import com.owncloud.android.lib.resources.status.StatusRequestor | ||||
| import org.junit.Assert.assertEquals | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class GetRemoteStatusOperationTest { | ||||
|     private val remoteStatusOperation = GetRemoteStatusOperation() | ||||
| class StatusRequestorTest { | ||||
|     private val requestor = StatusRequestor() | ||||
| 
 | ||||
|     @Test | ||||
|     fun `update location with an absolute path`() { | ||||
|         val newLocation = remoteStatusOperation.updateLocationWithRedirectPath( | ||||
|         val newLocation = requestor.updateLocationWithRedirectPath( | ||||
|             "https://cloud.somewhere.com", "https://cloud.somewhere.com/subdir" | ||||
|         ) | ||||
|         assertEquals("https://cloud.somewhere.com/subdir", newLocation) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun `update location with a smaler aboslute path`() { | ||||
| 
 | ||||
|         val newLocation = remoteStatusOperation.updateLocationWithRedirectPath( | ||||
|     fun `update location with a smaler aboslute path`() { | ||||
|         val newLocation = requestor.updateLocationWithRedirectPath( | ||||
|             "https://cloud.somewhere.com/subdir", "https://cloud.somewhere.com/" | ||||
|         ) | ||||
|         assertEquals("https://cloud.somewhere.com/", newLocation) | ||||
| @ -26,7 +26,7 @@ class GetRemoteStatusOperationTest { | ||||
| 
 | ||||
|     @Test | ||||
|     fun `update location with a relative path`() { | ||||
|         val newLocation = remoteStatusOperation.updateLocationWithRedirectPath( | ||||
|         val newLocation = requestor.updateLocationWithRedirectPath( | ||||
|             "https://cloud.somewhere.com", "/subdir" | ||||
|         ) | ||||
|         assertEquals("https://cloud.somewhere.com/subdir", newLocation) | ||||
| @ -34,7 +34,7 @@ class GetRemoteStatusOperationTest { | ||||
| 
 | ||||
|     @Test | ||||
|     fun `update location by replacing the relative path`() { | ||||
|         val newLocation = remoteStatusOperation.updateLocationWithRedirectPath( | ||||
|         val newLocation = requestor.updateLocationWithRedirectPath( | ||||
|             "https://cloud.somewhere.com/some/other/subdir", "/subdir" | ||||
|         ) | ||||
|         assertEquals("https://cloud.somewhere.com/subdir", newLocation) | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user