Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit c56461ea authored by Ricki Hirner's avatar Ricki Hirner Committed by GitHub
Browse files

WebDAV: allow other MIME types for (Ranged) GET, use coroutines for streaming (#503)

* StreamingFileDescriptor: use coroutines instead of threading

* WebDAV GET: accept any MIME type, but prefer known one
parent 769147b1
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -13,9 +13,16 @@ import at.bitfire.davdroid.network.Android10Resolver
import okhttp3.HttpUrl
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import org.xbill.DNS.*
import org.xbill.DNS.ExtendedResolver
import org.xbill.DNS.Lookup
import org.xbill.DNS.Record
import org.xbill.DNS.SRVRecord
import org.xbill.DNS.SimpleResolver
import org.xbill.DNS.TXTRecord
import java.net.InetAddress
import java.util.*
import java.util.LinkedList
import java.util.Locale
import java.util.TreeMap

/**
 * Some WebDAV and HTTP network utility methods.
@@ -30,6 +37,19 @@ object DavUtils {
    val MEDIA_TYPE_OCTET_STREAM = "application/octet-stream".toMediaType()
    val MEDIA_TYPE_VCARD = "text/vcard".toMediaType()

    /**
     * Builds an HTTP `Accept` header that accepts anything (*/*), but optionally
     * specifies a preference.
     *
     * @param preferred  preferred MIME type (optional)
     *
     * @return `media-range` for `Accept` header that accepts anything, but prefers [preferred] (if it was specified)
     */
    fun acceptAnything(preferred: MediaType?): String =
        if (preferred != null)
            "$preferred, $MIME_TYPE_ACCEPT_ALL;q=0.8"
        else
            MIME_TYPE_ACCEPT_ALL

    @Suppress("FunctionName")
    fun ARGBtoCalDAVColor(colorWithAlpha: Int): String {
+1 −1
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ class RandomAccessCallback private constructor(

        var result: ByteArray? = null
        dav.getRange(
            mimeType?.toString() ?: DavUtils.MIME_TYPE_ACCEPT_ALL,
            DavUtils.acceptAnything(preferred = mimeType),
            key.segment * PAGE_SIZE.toLong(),
            PAGE_SIZE,
            ifMatch
+10 −7
Original line number Diff line number Diff line
@@ -12,12 +12,16 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import at.bitfire.dav4jvm.DavResource
import at.bitfire.dav4jvm.exception.HttpException
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.ui.NotificationUtils
import at.bitfire.davdroid.ui.NotificationUtils.notifyIfPossible
import at.bitfire.davdroid.util.DavUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runInterruptible
import okhttp3.HttpUrl
import okhttp3.MediaType
import okhttp3.RequestBody
@@ -26,7 +30,6 @@ import okio.BufferedSink
import org.apache.commons.io.FileUtils
import java.io.IOException
import java.util.logging.Level
import kotlin.concurrent.thread

/**
 * @param client    HTTP client– [StreamingFileDescriptor] is responsible to close it
@@ -64,7 +67,7 @@ class StreamingFileDescriptor(
    private fun doStreaming(upload: Boolean): ParcelFileDescriptor {
        val (readFd, writeFd) = ParcelFileDescriptor.createReliablePipe()

        val worker = thread {
        val result = CoroutineScope(Dispatchers.IO).async {
            try {
                if (upload)
                    uploadNow(readFd)
@@ -92,7 +95,7 @@ class StreamingFileDescriptor(

        cancellationSignal?.setOnCancelListener {
            Logger.log.fine("Cancelling transfer of $url")
            worker.interrupt()
            result.cancel()
        }

        return if (upload)
@@ -102,8 +105,8 @@ class StreamingFileDescriptor(
    }

    @WorkerThread
    private fun downloadNow(writeFd: ParcelFileDescriptor) {
        dav.get(mimeType?.toString() ?: DavUtils.MIME_TYPE_ACCEPT_ALL, null) { response ->
    private suspend fun downloadNow(writeFd: ParcelFileDescriptor) = runInterruptible {
        dav.get(DavUtils.acceptAnything(preferred = mimeType), null) { response ->
            response.body?.use { body ->
                if (response.isSuccessful) {
                    val length = response.headersContentLength()
@@ -156,7 +159,7 @@ class StreamingFileDescriptor(
    }

    @WorkerThread
    private fun uploadNow(readFd: ParcelFileDescriptor) {
    private suspend fun uploadNow(readFd: ParcelFileDescriptor) = runInterruptible {
        val body = object: RequestBody() {
            override fun contentType(): MediaType? = mimeType
            override fun isOneShot() = true
+8 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ package at.bitfire.davdroid
import at.bitfire.davdroid.util.DavUtils
import at.bitfire.davdroid.util.DavUtils.parent
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaType
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
@@ -19,6 +20,13 @@ class DavUtilsTest {

    val exampleURL = "http://example.com/"


    @Test
    fun testAcceptAnything() {
        assertEquals("*/*", DavUtils.acceptAnything(null))
        assertEquals("some/thing;v=2.1, */*;q=0.8", DavUtils.acceptAnything("some/thing;v=2.1".toMediaType()))
    }

    @Test
    fun testARGBtoCalDAVColor() {
        assertEquals("#00000000", DavUtils.ARGBtoCalDAVColor(0))