Use the right base URL for the ESS config/well known endpoints (#7469)

* Rename `UrlContentFetcher` to `ClientUrlContentFetcher` and add missing base URL data (server name, homeserver URL)

* Avoid passing the `homeserverUrl/serverName` around.

Calculate the URL in `DefaultRemoteEnterpriseConfigRetriever` using the newly added `homserver` and `server` values as the possible base URLs, depending on the remote config source

* Make sure we don't perform blocking requests to fetch the remote config when restoring a session

Add a `needsRefresh` parameter to `RemoteEnterpriseConfigResult.NotFound` to handle this, and store a `no-config` value in the store to indicate an endpoint has been checked and no config was found

* Bump enterprise module
This commit is contained in:
Jorge Martin Espinosa
2026-08-19 09:24:22 +02:00
committed by GitHub
parent c31d7e6cce
commit a1e86ad499
23 changed files with 79 additions and 57 deletions
@@ -8,9 +8,19 @@
package io.element.android.libraries.matrix.api
/**
* An interface to fetch content from a URL using a simple GET request.
* An interface to fetch content from a URL using a simple GET request launched from a Matrix client.
*/
fun interface UrlContentFetcher {
interface ClientUrlContentFetcher {
/**
* The domain of the public server for this homeserver.
*/
val server: String?
/**
* The URL of the actual Matrix homeserver.
*/
val homeserverUrl: String
/**
* Execute generic GET requests through the SDKs internal HTTP client.
*/
@@ -60,16 +60,13 @@ import java.util.Optional
* One instance exists per session, created on login or session restore and torn down by [logout], [clearCache] or account deactivation.
* Suspending members here report failures through a [Result] instead of throwing, and run their work off the main thread.
*/
interface MatrixClient : UrlContentFetcher {
interface MatrixClient : ClientUrlContentFetcher {
/** Identifier of the logged in user; a [SessionId] and a [UserId] are the same value. */
val sessionId: SessionId
/** Identifier of this device, as assigned by the homeserver when the session was created. */
val deviceId: DeviceId
/** Base URL of the homeserver this client is connected to. */
val homeserverUrl: String
/** Directories holding this session's databases, caches and downloaded media. */
val sessionPaths: SessionPaths
@@ -15,4 +15,4 @@ import java.lang.AutoCloseable
* Note: this client implements an [AutoCloseable] interface, so using [AutoCloseable.close] or [AutoCloseable.use] will clean up any resources associated
* with it, such as temporary files.
*/
interface TemporaryMatrixClient : UrlContentFetcher, AutoCloseable
interface TemporaryMatrixClient : ClientUrlContentFetcher, AutoCloseable
@@ -12,10 +12,10 @@ package io.element.android.libraries.matrix.api
*/
interface TemporaryMatrixClientFactory {
/**
* Builds an unauthenticated client pointing at [homeServerUrl], backed by a fresh set of temporary session directories.
* Builds an unauthenticated client pointing at [serverName], backed by a fresh set of temporary session directories.
* The caller owns the returned client and must close it to delete those directories.
*
* @param homeServerUrl the URL of the homeserver the client will talk to.
* @param serverName the domain of the public-facing server for the actual homeserver
*/
suspend fun create(homeServerUrl: String): Result<TemporaryMatrixClient>
suspend fun create(serverName: String): Result<TemporaryMatrixClient>
}
@@ -7,7 +7,7 @@
package io.element.android.libraries.matrix.api.scanner
import io.element.android.libraries.matrix.api.UrlContentFetcher
import io.element.android.libraries.matrix.api.ClientUrlContentFetcher
import io.element.android.libraries.matrix.api.core.SessionId
/**
@@ -26,6 +26,6 @@ fun interface ContentScannerUrlProvider {
/**
* @param urlContentFetcher used to read the configuration advertised by the homeserver; a client that is not authenticated yet also works.
*/
fun create(urlContentFetcher: UrlContentFetcher): ContentScannerUrlProvider
fun create(urlContentFetcher: ClientUrlContentFetcher): ContentScannerUrlProvider
}
}
@@ -163,6 +163,7 @@ class RustMatrixClient(
) : MatrixClient {
override val sessionId: UserId = UserId(innerClient.userId())
override val deviceId: DeviceId = DeviceId(innerClient.deviceId())
override val server: String? = innerClient.server()
override val homeserverUrl: String = innerClient.homeserver()
override val sessionCoroutineScope = appCoroutineScope.childScope(dispatchers.main, "Session-$sessionId")
private val sessionDispatcher = dispatchers.io.limitedParallelism(64)
@@ -22,6 +22,9 @@ class RustTemporaryMatrixClient(
client.getUrl(url)
}.mapFailure { it.mapClientException() }
override val server: String? = client.server()
override val homeserverUrl: String = client.homeserver()
override fun close() {
client.close()
paths?.let {
@@ -19,7 +19,7 @@ class RustTemporaryMatrixClientFactory(
private val sessionPathsFactory: SessionPathsFactory,
private val rustMatrixClientFactory: RustMatrixClientFactory,
) : TemporaryMatrixClientFactory {
override suspend fun create(homeServerUrl: String): Result<TemporaryMatrixClient> {
override suspend fun create(serverName: String): Result<TemporaryMatrixClient> {
return runCatchingExceptions {
val sessionPaths = sessionPathsFactory.create()
val client = rustMatrixClientFactory.getBaseClientBuilder(
@@ -28,7 +28,7 @@ class RustTemporaryMatrixClientFactory(
slidingSyncType = ClientBuilderSlidingSync.Native,
isMessageSearchAvailable = false,
)
.homeserverUrl(homeServerUrl)
.serverName(serverName)
.build()
RustTemporaryMatrixClient(client, sessionPaths)
}
@@ -278,7 +278,6 @@ class RustMatrixAuthenticationService(
.let {
enterpriseService.tweakMasUrl(
url = it,
homeserver = client.server() ?: client.homeserver(),
urlContentFetcher = getUrlResolver,
)
}
@@ -13,9 +13,9 @@ import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.ClientUrlContentFetcher
import io.element.android.libraries.matrix.api.HomeserverCapabilitiesProvider
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.UrlContentFetcher
import io.element.android.libraries.matrix.api.core.DeviceId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.encryption.EncryptionService
@@ -111,7 +111,7 @@ object SessionMatrixModule {
}
@Provides
fun providesGetUrlResolverClient(matrixClient: MatrixClient): UrlContentFetcher {
fun providesGetUrlResolverClient(matrixClient: MatrixClient): ClientUrlContentFetcher {
return matrixClient
}
}
@@ -16,7 +16,6 @@ import io.element.android.tests.testutils.lambda.value
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.NoHandle
import java.io.File
import kotlin.io.path.createTempDirectory
import org.matrix.rustcomponents.sdk.ClientException as RustClientException
@@ -84,7 +83,7 @@ class RustTemporaryMatrixClientTest {
}
private fun createRustTemporaryMatrixClient(
client: Client = Client(NoHandle),
client: Client = FakeFfiClient(),
paths: SessionPaths,
): RustTemporaryMatrixClient {
return RustTemporaryMatrixClient(client, paths)
@@ -12,6 +12,7 @@ import io.element.android.libraries.matrix.impl.fixtures.factories.aRustSession
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustUserProfile
import io.element.android.libraries.matrix.test.A_DEVICE_ID
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
import io.element.android.libraries.matrix.test.A_SERVER_NAME
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.simulateLongTask
@@ -45,6 +46,7 @@ class FakeFfiClient(
private val userId: String = A_USER_ID.value,
private val deviceId: String = A_DEVICE_ID.value,
private val homeserver: String = A_HOMESERVER_URL,
private val server: String? = A_SERVER_NAME,
private val notificationClient: NotificationClient = FakeFfiNotificationClient(),
private val notificationSettings: NotificationSettings = FakeFfiNotificationSettings(),
private val encryption: Encryption = FakeFfiEncryption(),
@@ -66,6 +68,7 @@ class FakeFfiClient(
override fun userId(): String = userId
override fun deviceId(): String = deviceId
override fun homeserver(): String = homeserver
override fun server(): String? = server
override suspend fun notificationClient(processSetup: NotificationProcessSetup) = notificationClient
override suspend fun getNotificationSettings(): NotificationSettings = notificationSettings
override fun encryption(): Encryption = encryption
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.test
import io.element.android.libraries.matrix.api.ClientUrlContentFetcher
import io.element.android.tests.testutils.lambda.lambdaError
class FakeClientUrlContentFetcher(
override val server: String = A_SERVER_NAME,
override val homeserverUrl: String = A_HOMESERVER_URL,
private val getUrlResult: (String) -> Result<ByteArray> = { lambdaError() },
) : ClientUrlContentFetcher {
override suspend fun getUrl(url: String): Result<ByteArray> {
return getUrlResult(url)
}
}
@@ -79,6 +79,7 @@ class FakeMatrixClient(
override val sessionId: SessionId = A_SESSION_ID,
override val sessionPaths: SessionPaths = SessionPaths(fileDirectory = File("files"), cacheDirectory = File("cache")),
override val deviceId: DeviceId = A_DEVICE_ID,
override val server: String = A_SERVER_NAME,
override val homeserverUrl: String = A_HOMESERVER_URL,
override val sessionCoroutineScope: CoroutineScope = TestScope(),
private val userDisplayName: String? = A_USER_NAME,
@@ -11,10 +11,11 @@ import io.element.android.libraries.matrix.api.TemporaryMatrixClient
import io.element.android.tests.testutils.lambda.lambdaError
class FakeTemporaryMatrixClient(
override val server: String = A_SERVER_NAME,
override val homeserverUrl: String = A_HOMESERVER_URL,
private val getUrlResult: (String) -> Result<ByteArray> = { lambdaError() },
private val closeLambda: () -> Unit = {},
) : TemporaryMatrixClient {
override suspend fun getUrl(url: String): Result<ByteArray> = getUrlResult(url)
override fun close() = closeLambda()
}
@@ -13,5 +13,5 @@ import io.element.android.libraries.matrix.api.TemporaryMatrixClientFactory
class FakeTemporaryMatrixClientFactory(
private val createResult: (String) -> Result<TemporaryMatrixClient> = { Result.success(FakeTemporaryMatrixClient()) },
) : TemporaryMatrixClientFactory {
override suspend fun create(homeServerUrl: String): Result<TemporaryMatrixClient> = createResult(homeServerUrl)
override suspend fun create(serverName: String): Result<TemporaryMatrixClient> = createResult(serverName)
}
@@ -72,6 +72,7 @@ const val A_SPACE_NAME = "A space name"
const val A_REDACTION_REASON = "A redaction reason"
const val A_SERVER_NAME = "matrix.org"
const val A_HOMESERVER_URL = "matrix.org"
const val A_HOMESERVER_URL_2 = "matrix-client.org"