Loading src/main/kotlin/at/bitfire/dav4jvm/BasicDigestAuthHandler.kt +4 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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", "") } Loading src/main/kotlin/at/bitfire/dav4jvm/DavResource.kt +70 −7 Original line number Diff line number Diff line Loading @@ -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") Loading Loading @@ -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) */ Loading Loading @@ -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) */ Loading Loading @@ -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. Loading Loading @@ -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. * Loading Loading @@ -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) */ Loading Loading @@ -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) Loading src/test/kotlin/at/bitfire/dav4jvm/DavResourceTest.kt +15 −0 Original line number Diff line number Diff line Loading @@ -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() Loading Loading
src/main/kotlin/at/bitfire/dav4jvm/BasicDigestAuthHandler.kt +4 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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", "") } Loading
src/main/kotlin/at/bitfire/dav4jvm/DavResource.kt +70 −7 Original line number Diff line number Diff line Loading @@ -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") Loading Loading @@ -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) */ Loading Loading @@ -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) */ Loading Loading @@ -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. Loading Loading @@ -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. * Loading Loading @@ -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) */ Loading Loading @@ -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) Loading
src/test/kotlin/at/bitfire/dav4jvm/DavResourceTest.kt +15 −0 Original line number Diff line number Diff line Loading @@ -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() Loading