mirror of
				https://github.com/owncloud/android-library.git
				synced 2025-10-31 10:27:45 +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 android.net.Uri | ||||||
| import com.owncloud.android.lib.common.OwnCloudClient | 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.RemoteOperation | ||||||
| import com.owncloud.android.lib.common.operations.RemoteOperationResult | import com.owncloud.android.lib.common.operations.RemoteOperationResult | ||||||
| import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode | import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode | ||||||
| import org.json.JSONException | import org.json.JSONException | ||||||
| import org.json.JSONObject |  | ||||||
| import timber.log.Timber | import timber.log.Timber | ||||||
| import java.net.URL | 
 | ||||||
| import java.util.concurrent.TimeUnit |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Checks if the server is valid |  * Checks if the server is valid | ||||||
| @ -45,6 +41,11 @@ import java.util.concurrent.TimeUnit | |||||||
|  * @author Abel García de Prada |  * @author Abel García de Prada | ||||||
|  */ |  */ | ||||||
| class GetRemoteStatusOperation : RemoteOperation<OwnCloudVersion>() { | class GetRemoteStatusOperation : RemoteOperation<OwnCloudVersion>() { | ||||||
|  |     companion object { | ||||||
|  |         const val HTTPS_SCHEME = "https" | ||||||
|  |         const val HTTP_SCHEME = "http" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     override fun run(client: OwnCloudClient): RemoteOperationResult<OwnCloudVersion> { |     override fun run(client: OwnCloudClient): RemoteOperationResult<OwnCloudVersion> { | ||||||
|         if (client.baseUri.scheme.isNullOrEmpty()) |         if (client.baseUri.scheme.isNullOrEmpty()) | ||||||
|             client.baseUri = Uri.parse(HTTPS_SCHEME + "://" + client.baseUri.toString()) |             client.baseUri = Uri.parse(HTTPS_SCHEME + "://" + client.baseUri.toString()) | ||||||
| @ -59,114 +60,17 @@ class GetRemoteStatusOperation : RemoteOperation<OwnCloudVersion>() { | |||||||
|         return result |         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> { |     private fun tryToConnect(client: OwnCloudClient): RemoteOperationResult<OwnCloudVersion> { | ||||||
|         val baseUrl = client.baseUri.toString() |         val baseUrl = client.baseUri.toString() | ||||||
|         client.setFollowRedirects(false) |         client.setFollowRedirects(false) | ||||||
|         return try { |         return try { | ||||||
|             val requestResult = requestAndFollowRedirects(baseUrl) |             val requestor = StatusRequestor() | ||||||
|             handleRequestResult(requestResult, baseUrl) |             val requestResult = requestor.requestAndFollowRedirects(baseUrl, client) | ||||||
|  |             requestor.handleRequestResult(requestResult, baseUrl) | ||||||
|         } catch (e: JSONException) { |         } catch (e: JSONException) { | ||||||
|             RemoteOperationResult(ResultCode.INSTANCE_NOT_CONFIGURED) |             RemoteOperationResult(ResultCode.INSTANCE_NOT_CONFIGURED) | ||||||
|         } catch (e: Exception) { |         } catch (e: Exception) { | ||||||
|             RemoteOperationResult(e) |             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 | 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.Assert.assertEquals | ||||||
| import org.junit.Test | import org.junit.Test | ||||||
| 
 | 
 | ||||||
| class GetRemoteStatusOperationTest { | class StatusRequestorTest { | ||||||
|     private val remoteStatusOperation = GetRemoteStatusOperation() |     private val requestor = StatusRequestor() | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     fun `update location with an absolute path`() { |     fun `update location with an absolute path`() { | ||||||
|         val newLocation = remoteStatusOperation.updateLocationWithRedirectPath( |         val newLocation = requestor.updateLocationWithRedirectPath( | ||||||
|             "https://cloud.somewhere.com", "https://cloud.somewhere.com/subdir" |             "https://cloud.somewhere.com", "https://cloud.somewhere.com/subdir" | ||||||
|         ) |         ) | ||||||
|         assertEquals("https://cloud.somewhere.com/subdir", newLocation) |         assertEquals("https://cloud.somewhere.com/subdir", newLocation) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @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/" |             "https://cloud.somewhere.com/subdir", "https://cloud.somewhere.com/" | ||||||
|         ) |         ) | ||||||
|         assertEquals("https://cloud.somewhere.com/", newLocation) |         assertEquals("https://cloud.somewhere.com/", newLocation) | ||||||
| @ -26,7 +26,7 @@ class GetRemoteStatusOperationTest { | |||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     fun `update location with a relative path`() { |     fun `update location with a relative path`() { | ||||||
|         val newLocation = remoteStatusOperation.updateLocationWithRedirectPath( |         val newLocation = requestor.updateLocationWithRedirectPath( | ||||||
|             "https://cloud.somewhere.com", "/subdir" |             "https://cloud.somewhere.com", "/subdir" | ||||||
|         ) |         ) | ||||||
|         assertEquals("https://cloud.somewhere.com/subdir", newLocation) |         assertEquals("https://cloud.somewhere.com/subdir", newLocation) | ||||||
| @ -34,7 +34,7 @@ class GetRemoteStatusOperationTest { | |||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     fun `update location by replacing the relative path`() { |     fun `update location by replacing the relative path`() { | ||||||
|         val newLocation = remoteStatusOperation.updateLocationWithRedirectPath( |         val newLocation = requestor.updateLocationWithRedirectPath( | ||||||
|             "https://cloud.somewhere.com/some/other/subdir", "/subdir" |             "https://cloud.somewhere.com/some/other/subdir", "/subdir" | ||||||
|         ) |         ) | ||||||
|         assertEquals("https://cloud.somewhere.com/subdir", newLocation) |         assertEquals("https://cloud.somewhere.com/subdir", newLocation) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user