Skip to content

Commit 97a9dcd

Browse files
committed
Use WebdavScoped for in-memory cookie store "singleton" that is cleared when DavDocumentsProvider is shut down
1 parent 7d88a22 commit 97a9dcd

18 files changed

+217
-109
lines changed

.idea/codeStyles/Project.xml

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
3+
*/
4+
5+
package at.bitfire.davdroid.di
6+
7+
import javax.inject.Qualifier
8+
9+
@Qualifier
10+
@Retention(AnnotationRetention.RUNTIME)
11+
annotation class Bridged
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
3+
*/
4+
5+
package at.bitfire.davdroid.webdav
6+
7+
import android.util.Log
8+
import at.bitfire.davdroid.network.MemoryCookieStore
9+
import okhttp3.CookieJar
10+
11+
class CookieStoreManager {
12+
13+
init {
14+
Log.i("CookieStoreManager", "CookieStoreManager.init()")
15+
}
16+
17+
private val cookieStores = mutableMapOf<Long, CookieJar>()
18+
19+
fun forMount(mountId: Long) =
20+
cookieStores.getOrPut(mountId) {
21+
MemoryCookieStore()
22+
}
23+
24+
}

app/src/main/kotlin/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,11 @@
44

55
package at.bitfire.davdroid.webdav
66

7-
import android.content.Context
87
import android.graphics.Point
98
import android.os.CancellationSignal
10-
import android.provider.DocumentsContract.buildRootsUri
119
import android.provider.DocumentsProvider
12-
import at.bitfire.dav4jvm.property.webdav.CurrentUserPrivilegeSet
13-
import at.bitfire.dav4jvm.property.webdav.DisplayName
14-
import at.bitfire.dav4jvm.property.webdav.GetContentLength
15-
import at.bitfire.dav4jvm.property.webdav.GetContentType
16-
import at.bitfire.dav4jvm.property.webdav.GetETag
17-
import at.bitfire.dav4jvm.property.webdav.GetLastModified
18-
import at.bitfire.dav4jvm.property.webdav.QuotaAvailableBytes
19-
import at.bitfire.dav4jvm.property.webdav.QuotaUsedBytes
20-
import at.bitfire.dav4jvm.property.webdav.ResourceType
21-
import at.bitfire.davdroid.R
10+
import android.util.Log
11+
import at.bitfire.davdroid.webdav.di.WebdavComponentManager
2212
import at.bitfire.davdroid.webdav.operation.CopyDocumentOperation
2313
import at.bitfire.davdroid.webdav.operation.CreateDocumentOperation
2414
import at.bitfire.davdroid.webdav.operation.DeleteDocumentOperation
@@ -60,6 +50,7 @@ class DavDocumentsProvider: DocumentsProvider() {
6050
fun queryDocumentOperation(): QueryDocumentOperation
6151
fun queryRootsOperation(): QueryRootsOperation
6252
fun renameDocumentOperation(): RenameDocumentOperation
53+
fun webdavComponentManager(): WebdavComponentManager
6354
}
6455

6556
/**
@@ -72,10 +63,15 @@ class DavDocumentsProvider: DocumentsProvider() {
7263
}
7364

7465

75-
override fun onCreate() = true
66+
override fun onCreate(): Boolean {
67+
Log.v("DavDocumentsProvider", "onCreate()")
68+
return true
69+
}
7670

7771
override fun shutdown() {
72+
Log.v("DavDocumentsProvider", "onDestroy()")
7873
providerScope.cancel()
74+
entryPoint.webdavComponentManager().resetComponent()
7975
}
8076

8177

@@ -120,26 +116,4 @@ class DavDocumentsProvider: DocumentsProvider() {
120116
override fun openDocumentThumbnail(documentId: String, sizeHint: Point, signal: CancellationSignal?) =
121117
entryPoint.openDocumentThumbnailOperation().invoke(documentId, sizeHint, signal)
122118

123-
124-
companion object {
125-
126-
val DAV_FILE_FIELDS = arrayOf(
127-
ResourceType.NAME,
128-
CurrentUserPrivilegeSet.NAME,
129-
DisplayName.NAME,
130-
GetETag.NAME,
131-
GetContentType.NAME,
132-
GetContentLength.NAME,
133-
GetLastModified.NAME,
134-
QuotaAvailableBytes.NAME,
135-
QuotaUsedBytes.NAME,
136-
)
137-
138-
const val MAX_NAME_ATTEMPTS = 5
139-
140-
fun notifyMountsChanged(context: Context) {
141-
context.contentResolver.notifyChange(buildRootsUri(context.getString(R.string.webdav_authority)), null)
142-
}
143-
144-
}
145119
}

app/src/main/kotlin/at/bitfire/davdroid/webdav/DavHttpClientBuilder.kt

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
package at.bitfire.davdroid.webdav
66

77
import at.bitfire.davdroid.network.HttpClient
8-
import at.bitfire.davdroid.network.MemoryCookieStore
9-
import okhttp3.CookieJar
108
import okhttp3.logging.HttpLoggingInterceptor
119
import javax.inject.Inject
1210
import javax.inject.Provider
1311

1412
class DavHttpClientBuilder @Inject constructor(
13+
private val cookieStoreManager: CookieStoreManager,
1514
private val credentialsStore: CredentialsStore,
16-
private val httpClientBuilder: Provider<HttpClient.Builder>
15+
private val httpClientBuilder: Provider<HttpClient.Builder>,
1716
) {
1817

1918
/**
@@ -25,9 +24,7 @@ class DavHttpClientBuilder @Inject constructor(
2524
fun build(mountId: Long, logBody: Boolean = true): HttpClient {
2625
val builder = httpClientBuilder.get()
2726
.loggerInterceptorLevel(if (logBody) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.HEADERS)
28-
.setCookieStore(
29-
cookieStores.getOrPut(mountId) { MemoryCookieStore() }
30-
)
27+
.setCookieStore(cookieStoreManager.forMount(mountId))
3128

3229
credentialsStore.getCredentials(mountId)?.let { credentials ->
3330
builder.authenticate(host = null, getCredentials = { credentials })
@@ -36,12 +33,4 @@ class DavHttpClientBuilder @Inject constructor(
3633
return builder.build()
3734
}
3835

39-
40-
companion object {
41-
42-
// TODO global leak
43-
private val cookieStores = mutableMapOf<Long, CookieJar>()
44-
45-
}
46-
4736
}

app/src/main/kotlin/at/bitfire/davdroid/webdav/DocumentProviderUtils.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import android.content.Context
1010
import android.content.Intent
1111
import android.os.Build
1212
import android.provider.DocumentsContract.buildChildDocumentsUri
13+
import android.provider.DocumentsContract.buildRootsUri
1314
import android.webkit.MimeTypeMap
1415
import androidx.core.app.TaskStackBuilder
1516
import at.bitfire.dav4jvm.exception.HttpException
@@ -20,6 +21,8 @@ import java.net.HttpURLConnection
2021

2122
object DocumentProviderUtils {
2223

24+
const val MAX_DISPLAYNAME_TO_MEMBERNAME_ATTEMPTS = 5
25+
2326
internal fun displayNameToMemberName(displayName: String, appendNumber: Int = 0): String {
2427
val safeName = displayName.filterNot { it.isISOControl() }
2528

@@ -55,13 +58,18 @@ object DocumentProviderUtils {
5558
)
5659
}
5760

61+
internal fun notifyMountsChanged(context: Context) {
62+
context.contentResolver.notifyChange(
63+
buildRootsUri(context.getString(R.string.webdav_authority)),
64+
null)
65+
}
66+
5867
}
5968

6069
internal fun HttpException.throwForDocumentProvider(context: Context, ignorePreconditionFailed: Boolean = false) {
6170
when (code) {
6271
HttpURLConnection.HTTP_UNAUTHORIZED -> {
6372
if (Build.VERSION.SDK_INT >= 26) {
64-
// TODO edit mount
6573
val intent = Intent(context, WebdavMountsActivity::class.java)
6674
throw AuthenticationRequiredException(
6775
this,

app/src/main/kotlin/at/bitfire/davdroid/webdav/RandomAccessCallbackWrapper.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
package at.bitfire.davdroid.webdav
66

7-
import android.os.Build
87
import android.os.Handler
98
import android.os.HandlerThread
109
import android.os.ProxyFileDescriptorCallback
@@ -49,7 +48,7 @@ import kotlin.concurrent.schedule
4948
*
5049
* @param httpClient HTTP client – [RandomAccessCallbackWrapper] is responsible to close it
5150
*/
52-
@RequiresApi(Build.VERSION_CODES.O)
51+
@RequiresApi(26)
5352
class RandomAccessCallbackWrapper @AssistedInject constructor(
5453
@Assisted private val httpClient: HttpClient,
5554
@Assisted private val url: HttpUrl,

app/src/main/kotlin/at/bitfire/davdroid/webdav/WebDavMountRepository.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class WebDavMountRepository @Inject constructor(
6666
credentialsStore.setCredentials(id, credentials)
6767

6868
// notify content URI listeners
69-
DavDocumentsProvider.notifyMountsChanged(context)
69+
DocumentProviderUtils.notifyMountsChanged(context)
7070

7171
return true
7272
}
@@ -79,7 +79,7 @@ class WebDavMountRepository @Inject constructor(
7979
CredentialsStore(context).setCredentials(mount.id, null)
8080

8181
// notify content URI listeners
82-
DavDocumentsProvider.notifyMountsChanged(context)
82+
DocumentProviderUtils.notifyMountsChanged(context)
8383
}
8484

8585
fun getAllFlow() = mountDao.getAllFlow()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
3+
*/
4+
5+
package at.bitfire.davdroid.webdav.di
6+
7+
import at.bitfire.davdroid.di.Bridged
8+
import at.bitfire.davdroid.webdav.CookieStoreManager
9+
import dagger.hilt.EntryPoint
10+
import dagger.hilt.InstallIn
11+
12+
@EntryPoint
13+
@InstallIn(WebdavComponent::class)
14+
internal interface WebDavEntryPoint {
15+
16+
@Bridged // without this qualifier, the CookieStoreManager from CookieStoreManagerBridgedModule would be used
17+
fun cookieStoreManager(): CookieStoreManager
18+
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
3+
*/
4+
5+
package at.bitfire.davdroid.webdav.di
6+
7+
import dagger.hilt.DefineComponent
8+
import dagger.hilt.components.SingletonComponent
9+
10+
@WebdavScoped
11+
@DefineComponent(parent = SingletonComponent::class)
12+
interface WebdavComponent {
13+
14+
@DefineComponent.Builder
15+
interface Builder {
16+
fun build(): WebdavComponent
17+
}
18+
19+
}

0 commit comments

Comments
 (0)