Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ dependencies {
api(libs.spotbugs.annotations)
api(libs.xpp3)

implementation(libs.ktor.client.core)

testImplementation(libs.junit4)
testImplementation(libs.ktor.client.mock)
testImplementation(libs.okhttp.mockwebserver)
}
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ kotlin = "2.2.20"
okhttpVersion = "5.1.0"
spotbugs = "4.9.6"
xpp3Version = "1.1.6"
ktor = "3.2.1"

[libraries]
junit4 = { module = "junit:junit", version.ref = "junit4" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttpVersion" }
okhttp-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver3", version.ref = "okhttpVersion" }
spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version.ref = "spotbugs" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.okhttp
package at.bitfire.dav4jvm

import at.bitfire.dav4jvm.okhttp.property.webdav.NS_WEBDAV
import at.bitfire.dav4jvm.property.webdav.NS_WEBDAV
import org.xmlpull.v1.XmlPullParser
import java.io.Serializable

Expand Down Expand Up @@ -53,8 +53,8 @@ data class Error(
}

override fun equals(other: Any?) =
(other is Error) && other.name == name
(other is Error) && other.name == name

override fun hashCode() = name.hashCode()

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.okhttp
package at.bitfire.dav4jvm

import at.bitfire.dav4jvm.okhttp.HttpUtils.httpDateFormat
import okhttp3.HttpUrl
import okhttp3.Response
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
Expand All @@ -33,52 +30,6 @@ object HttpUtils {
private val logger
get() = Logger.getLogger(javaClass.name)


/**
* Gets the resource name (the last segment of the path) from an URL.
* Empty if the resource is the base directory.
*
* * `dir` for `https://example.com/dir/`
* * `file` for `https://example.com/file`
* * `` for `https://example.com` or `https://example.com/`
*
* @return resource name
*/
fun fileName(url: HttpUrl): String {
val pathSegments = url.pathSegments.dropLastWhile { it == "" }
return pathSegments.lastOrNull() ?: ""
}

/**
* Gets all values of a header that is defined as a list [RFC 9110 5.6.1],
* regardless of they're sent as one line or as multiple lines.
*
* For instance, regardless of whether a server sends:
*
* ```
* DAV: 1
* DAV: 2
* ```
*
* or
*
* ```
* DAV: 1, 2
* ```
*
* this method would return `arrayOf("1","2")` for the `DAV` header.
*
* @param response the HTTP response to evaluate
* @param name header name (for instance: `DAV`)
*
* @return all values for the given header name
*/
fun listHeader(response: Response, name: String): Array<String> {
val value = response.headers(name).joinToString(",")
return value.split(',').filter { it.isNotEmpty() }.toTypedArray()
}


/**
* Formats a date for use in HTTP headers using [httpDateFormat].
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.okhttp
package at.bitfire.dav4jvm

import at.bitfire.dav4jvm.okhttp.exception.InvalidPropertyException
import org.xmlpull.v1.XmlPullParser
import java.io.Serializable
import java.util.LinkedList
Expand Down Expand Up @@ -60,7 +59,7 @@ interface Property {
properties.add(property)
} else
logger.fine("Ignoring unknown property $name")
} catch (e: InvalidPropertyException) {
} catch (e: Exception) { // catching here generic exception in order to avoid dependency on specific okhttp or ktor Exception
logger.log(Level.WARNING, "Ignoring invalid property", e)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.okhttp
package at.bitfire.dav4jvm

import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,48 @@
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.okhttp
package at.bitfire.dav4jvm

import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarColor
import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarData
import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarDescription
import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarHomeSet
import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarProxyReadFor
import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarProxyWriteFor
import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarTimezone
import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarTimezoneId
import at.bitfire.dav4jvm.okhttp.property.caldav.CalendarUserAddressSet
import at.bitfire.dav4jvm.okhttp.property.caldav.GetCTag
import at.bitfire.dav4jvm.okhttp.property.caldav.ScheduleTag
import at.bitfire.dav4jvm.okhttp.property.caldav.Source
import at.bitfire.dav4jvm.okhttp.property.caldav.SupportedCalendarComponentSet
import at.bitfire.dav4jvm.okhttp.property.caldav.SupportedCalendarData
import at.bitfire.dav4jvm.okhttp.property.carddav.AddressData
import at.bitfire.dav4jvm.okhttp.property.carddav.AddressbookDescription
import at.bitfire.dav4jvm.okhttp.property.carddav.AddressbookHomeSet
import at.bitfire.dav4jvm.okhttp.property.carddav.SupportedAddressData
import at.bitfire.dav4jvm.okhttp.property.push.PushMessage
import at.bitfire.dav4jvm.okhttp.property.push.PushRegister
import at.bitfire.dav4jvm.okhttp.property.push.PushTransports
import at.bitfire.dav4jvm.okhttp.property.push.Subscription
import at.bitfire.dav4jvm.okhttp.property.push.Topic
import at.bitfire.dav4jvm.okhttp.property.push.WebPushSubscription
import at.bitfire.dav4jvm.okhttp.property.webdav.AddMember
import at.bitfire.dav4jvm.okhttp.property.webdav.CreationDate
import at.bitfire.dav4jvm.okhttp.property.webdav.CurrentUserPrincipal
import at.bitfire.dav4jvm.okhttp.property.webdav.CurrentUserPrivilegeSet
import at.bitfire.dav4jvm.okhttp.property.webdav.DisplayName
import at.bitfire.dav4jvm.okhttp.property.webdav.GetContentLength
import at.bitfire.dav4jvm.okhttp.property.webdav.GetContentType
import at.bitfire.dav4jvm.okhttp.property.webdav.GetETag
import at.bitfire.dav4jvm.okhttp.property.webdav.GetLastModified
import at.bitfire.dav4jvm.okhttp.property.webdav.GroupMembership
import at.bitfire.dav4jvm.okhttp.property.webdav.Owner
import at.bitfire.dav4jvm.okhttp.property.webdav.QuotaAvailableBytes
import at.bitfire.dav4jvm.okhttp.property.webdav.QuotaUsedBytes
import at.bitfire.dav4jvm.okhttp.property.webdav.ResourceType
import at.bitfire.dav4jvm.okhttp.property.webdav.SupportedReportSet
import at.bitfire.dav4jvm.okhttp.property.webdav.SyncToken
import at.bitfire.dav4jvm.property.caldav.CalendarColor
import at.bitfire.dav4jvm.property.caldav.CalendarData
import at.bitfire.dav4jvm.property.caldav.CalendarDescription
import at.bitfire.dav4jvm.property.caldav.CalendarHomeSet
import at.bitfire.dav4jvm.property.caldav.CalendarProxyReadFor
import at.bitfire.dav4jvm.property.caldav.CalendarProxyWriteFor
import at.bitfire.dav4jvm.property.caldav.CalendarTimezone
import at.bitfire.dav4jvm.property.caldav.CalendarTimezoneId
import at.bitfire.dav4jvm.property.caldav.CalendarUserAddressSet
import at.bitfire.dav4jvm.property.caldav.GetCTag
import at.bitfire.dav4jvm.property.caldav.ScheduleTag
import at.bitfire.dav4jvm.property.caldav.Source
import at.bitfire.dav4jvm.property.caldav.SupportedCalendarComponentSet
import at.bitfire.dav4jvm.property.caldav.SupportedCalendarData
import at.bitfire.dav4jvm.property.carddav.AddressData
import at.bitfire.dav4jvm.property.carddav.AddressbookDescription
import at.bitfire.dav4jvm.property.carddav.AddressbookHomeSet
import at.bitfire.dav4jvm.property.carddav.SupportedAddressData
import at.bitfire.dav4jvm.property.push.PushMessage
import at.bitfire.dav4jvm.property.push.PushRegister
import at.bitfire.dav4jvm.property.push.PushTransports
import at.bitfire.dav4jvm.property.push.Subscription
import at.bitfire.dav4jvm.property.push.Topic
import at.bitfire.dav4jvm.property.push.WebPushSubscription
import at.bitfire.dav4jvm.property.webdav.AddMember
import at.bitfire.dav4jvm.property.webdav.CreationDate
import at.bitfire.dav4jvm.property.webdav.CurrentUserPrincipal
import at.bitfire.dav4jvm.property.webdav.CurrentUserPrivilegeSet
import at.bitfire.dav4jvm.property.webdav.DisplayName
import at.bitfire.dav4jvm.property.webdav.GetContentLength
import at.bitfire.dav4jvm.property.webdav.GetContentType
import at.bitfire.dav4jvm.property.webdav.GetETag
import at.bitfire.dav4jvm.property.webdav.GetLastModified
import at.bitfire.dav4jvm.property.webdav.GroupMembership
import at.bitfire.dav4jvm.property.webdav.Owner
import at.bitfire.dav4jvm.property.webdav.QuotaAvailableBytes
import at.bitfire.dav4jvm.property.webdav.QuotaUsedBytes
import at.bitfire.dav4jvm.property.webdav.ResourceType
import at.bitfire.dav4jvm.property.webdav.SupportedReportSet
import at.bitfire.dav4jvm.property.webdav.SyncToken
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import java.util.logging.Level
Expand Down Expand Up @@ -92,8 +92,8 @@ object PropertyRegistry {
GetETag.Factory,
GetLastModified.Factory,
GroupMembership.Factory,
at.bitfire.dav4jvm.okhttp.property.caldav.MaxResourceSize.Factory,
at.bitfire.dav4jvm.okhttp.property.carddav.MaxResourceSize.Factory,
at.bitfire.dav4jvm.property.caldav.MaxResourceSize.Factory,
at.bitfire.dav4jvm.property.carddav.MaxResourceSize.Factory,
Owner.Factory,
PushMessage.Factory,
PushRegister.Factory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.okhttp
package at.bitfire.dav4jvm

object QuotedStringUtils {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.okhttp
package at.bitfire.dav4jvm

import at.bitfire.dav4jvm.okhttp.XmlUtils.propertyName
import at.bitfire.dav4jvm.okhttp.property.caldav.SupportedCalendarData.Companion.CONTENT_TYPE
import at.bitfire.dav4jvm.okhttp.property.caldav.SupportedCalendarData.Companion.VERSION
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import at.bitfire.dav4jvm.XmlUtils.propertyName
import at.bitfire.dav4jvm.property.caldav.SupportedCalendarData.Companion.CONTENT_TYPE
import at.bitfire.dav4jvm.property.caldav.SupportedCalendarData.Companion.VERSION
import io.ktor.http.ContentType
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import java.io.IOException
Expand Down Expand Up @@ -160,15 +159,17 @@ class XmlReader(
* attribute with [onNewType].
*
* @param tagName The name of the tag that contains the [CONTENT_TYPE] attribute value.
* @param onNewType Called every time a new [MediaType] is found.
* @param onNewType Called every time a new [ContentType] is found.
*/
fun readContentTypes(tagName: Property.Name, onNewType: (MediaType) -> Unit) {
fun readContentTypes(tagName: Property.Name, onNewType: (String) -> Unit) {
try {
processTag(tagName) {
parser.getAttributeValue(null, CONTENT_TYPE)?.let { contentType ->
var type = contentType
parser.getAttributeValue(null, VERSION)?.let { version -> type += "; version=$version" }
type.toMediaTypeOrNull()?.let(onNewType)
try {
onNewType(ContentType.parse(type).toString())
} catch (_: Exception) { }
}
}
} catch(e: XmlPullParserException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.okhttp
package at.bitfire.dav4jvm

import at.bitfire.dav4jvm.okhttp.XmlUtils.FEATURE_RELAXED
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import org.xmlpull.v1.XmlPullParserFactory
Expand Down
48 changes: 48 additions & 0 deletions src/main/kotlin/at/bitfire/dav4jvm/ktor/CallbackInterfaces.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/

package at.bitfire.dav4jvm.ktor

import io.ktor.client.statement.HttpResponse

/**
* Callback for the OPTIONS request.
*/
fun interface CapabilitiesCallback {
fun onCapabilities(davCapabilities: Set<String>, response: HttpResponse)
}

/**
* Callback for 207 Multi-Status responses.
*/
fun interface MultiResponseCallback {
/**
* Called for every `<response>` element in the `<multistatus>` body. For instance,
* in response to a `PROPFIND` request, this callback will be called once for every found
* member resource.
*
* Known collections have [response] `href` with trailing slash, see [Response.parse] for details.
*
* @param response the parsed response (including URL)
* @param relation relation of the response to the called resource
*/
fun onResponse(response: Response, relation: Response.HrefRelation)
}

/**
* Callback for HTTP responses.
*/
fun interface ResponseCallback {
/**
* Called for a HTTP response. Typically this is only called for successful/redirect
* responses because HTTP errors throw an exception before this callback is called.
*/
fun onResponse(response: HttpResponse)
}
Loading