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

Commit 108024cf authored by Ricki Hirner's avatar Ricki Hirner
Browse files

DavResource: support HEAD and GET with byte range

parent 5c067a2f
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -29,7 +29,9 @@ class BasicDigestAuthHandler(
        val domain: String?,

        val username: String,
        val password: String
        val password: String,

        val insecurePreemptive: Boolean = false
): Authenticator, Interceptor {

    companion object {
@@ -68,7 +70,7 @@ class BasicDigestAuthHandler(
        if (response == null) {
            // we're not processing a 401 response

            if (basicAuth == null && digestAuth == null && request.isHttps) {
            if (basicAuth == null && digestAuth == null && (request.isHttps || insecurePreemptive)) {
                Dav4jvm.log.fine("Trying Basic auth preemptively")
                basicAuth = Challenge("Basic", "")
            }
+70 −7
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ open class DavResource @JvmOverloads constructor(
    companion object {
        const val MAX_REDIRECTS = 5

        const val HTTP_MULTISTATUS = 207
        val MIME_XML = "application/xml; charset=utf-8".toMediaType()

        val PROPFIND = Property.Name(XmlUtils.NS_WEBDAV, "propfind")
@@ -123,7 +124,7 @@ open class DavResource @JvmOverloads constructor(
                    .execute()
        }.use { response ->
            checkStatus(response)
            if (response.code == 207)
            if (response.code == HTTP_MULTISTATUS)
                /* Multiple resources were to be affected by the MOVE, but errors on some
                of them prevented the operation from taking place.
                [_] (RFC 4918 9.9.4. Status Codes for MOVE Method) */
@@ -165,7 +166,7 @@ open class DavResource @JvmOverloads constructor(
        }.use{ response ->
            checkStatus(response)

            if (response.code == 207)
            if (response.code == HTTP_MULTISTATUS)
                /* Multiple resources were to be affected by the COPY, but errors on some
                of them prevented the operation from taking place.
                [_] (RFC 4918 9.8.5. Status Codes for COPY Method) */
@@ -197,6 +198,31 @@ open class DavResource @JvmOverloads constructor(
        }
    }

    /**
     * Sends a HEAD request to the resource.
     *
     * Follows up to [MAX_REDIRECTS] redirects.
     *
     * @param callback called with server response unless an exception is thrown
     *
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
    fun head(callback: (response: Response) -> Unit) {
        followRedirects {
            httpClient.newCall(
                Request.Builder()
                    .head()
                    .url(location)
                    .build()
            ).execute()
        }.use { response ->
            checkStatus(response)
            callback(response)
        }
    }

    /**
     * Sends a GET request to the resource. Sends `Accept-Encoding: identity` to disable
     * compression, because compression might change the ETag.
@@ -225,6 +251,43 @@ open class DavResource @JvmOverloads constructor(
        }
    }

    /**
     * Sends a GET request to the resource for a specific byte range.
     *
     * Follows up to [MAX_REDIRECTS] redirects.
     *
     * @param offset   zero-based index of first byte to request
     * @param size     number of bytes to request
     * @param callback called with server response unless an exception is thrown
     *
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws DavException on high-level errors
     */
    @Throws(IOException::class, HttpException::class)
    fun getRange(offset: Long, size: Int, headers: Headers? = null, callback: (response: Response) -> Unit) {
        followRedirects {
            val request = Request.Builder()
                .get()
                .url(location)

            if (headers != null)
                request.headers(headers)
            
            val lastIndex = offset + size - 1
            request.header("Range", "bytes=$offset-$lastIndex")

            httpClient.newCall(request.build()).execute()
        }.use { response ->
            checkStatus(response)

            if (response.code != HttpURLConnection.HTTP_PARTIAL)
                throw DavException("Expected 206 Partial Content, got ${response.code} ${response.message}")

            callback(response)
        }
    }

    /**
     * Sends a PUT request to the resource. Follows up to [MAX_REDIRECTS] redirects.
     *
@@ -294,7 +357,7 @@ open class DavResource @JvmOverloads constructor(
        }.use { response ->
            checkStatus(response)

            if (response.code == 207)
            if (response.code == HTTP_MULTISTATUS)
                /* If an error occurs deleting a member resource (a resource other than
                   the resource identified in the Request-URI), then the response can be
                   a 207 (Multi-Status). […] (RFC 4918 9.6.1. DELETE for Collections) */
@@ -426,7 +489,7 @@ open class DavResource @JvmOverloads constructor(
     * @throws DavException if the response is not a Multi-Status response
     */
    private fun assertMultiStatus(response: Response) {
        if (response.code != 207)
        if (response.code != HTTP_MULTISTATUS)
            throw DavException("Expected 207 Multi-Status, got ${response.code} ${response.message}", httpResponse = response)

        if (response.body == null)
+15 −0
Original line number Diff line number Diff line
@@ -262,6 +262,21 @@ class DavResourceTest {
        assertTrue(called)
    }

    @Test
    fun testGetRange_Ok() {
        val url = sampleUrl()
        val dav = DavResource(httpClient, url)

        mockServer.enqueue(MockResponse()
            .setResponseCode(HttpURLConnection.HTTP_PARTIAL))
        var called = false
        dav.getRange(100, 342) { response ->
            assertEquals("bytes=100-441", response.request.header("Range"))
            called = true
        }
        assertTrue(called)
    }

    @Test
    fun testPut() {
        val url = sampleUrl()