...
 
Commits (5)
This diff is collapsed.
......@@ -5,33 +5,24 @@
# dav4android
dav4android is an Android WebDAV/CalDAV/CardDAV library which has
primarily been developed for [DAVdroid](https://www.davdroid.com).
initially been developed for [DAVdroid](https://www.davdroid.com).
It's not intended as a general WebDAV framework for all kinds of
applications, but you may find it useful to fork and adapt it
to your needs.
Original repository: https://gitlab.com/bitfireAT/dav4android/
Generated KDoc: https://bitfireAT.gitlab.io/dav4android/dokka/dav4android/
## Contact
## Contact / License
```
bitfire web engineering – Stockmann, Hirner GesnbR
Florastraße 27
2540 Bad Vöslau, AUSTRIA
```
Email: [play@bitfire.at](mailto:play@bitfire.at) (do not use this)
dav4android is licensed under [Mozilla Public License, v. 2.0](LICENSE).
For questions, suggestions etc. please use the DAVdroid forum:
https://www.davdroid.com/forums/
Email: [play@bitfire.at](mailto:play@bitfire.at)
## License
Copyright (C) bitfire web engineering (Ricki Hirner, Bernhard Stockmann).
## Contributors
This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome
to redistribute it under the conditions of the [GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.html).
* Ricki Hirner (initial contributor)
buildscript {
ext.kotlin_version = '1.2.40'
ext.kotlin_version = '1.2.41'
ext.dokka_version = '0.9.16'
repositories {
......@@ -33,7 +33,8 @@ android {
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 14
//noinspection MinSdkTooLow
minSdkVersion 9 // Android 2.3
targetSdkVersion 27
buildConfigField "String", "version_okhttp", "\"$okhttp_version\""
......@@ -55,14 +56,15 @@ android {
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
compile "com.squareup.okhttp3:okhttp:$okhttp_version"
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
androidTestCompile "com.squareup.okhttp3:mockwebserver:$okhttp_version"
androidTestCompile 'com.android.support.test:runner:1.0.2'
androidTestImplementation "com.squareup.okhttp3:mockwebserver:$okhttp_version"
androidTestImplementation 'com.android.support.test:runner:1.0.2'
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
testCompile 'junit:junit:4.12'
testCompile "com.squareup.okhttp3:mockwebserver:$okhttp_version"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
testImplementation 'junit:junit:4.12'
testImplementation "com.squareup.okhttp3:mockwebserver:$okhttp_version"
testImplementation 'org.ogce:xpp3:1.1.6' // XmlPullParser
}
<!--
~ Copyright © Ricki Hirner (bitfire web engineering).
~ All rights reserved. This program and the accompanying materials
~ are made available under the terms of the GNU Public License v3.0
~ which accompanies this distribution, and is available at
~ http://www.gnu.org/licenses/gpl.html
~ 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 http://mozilla.org/MPL/2.0/.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
......@@ -11,6 +9,4 @@
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="@string/app_name"/>
</manifest>
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......@@ -25,7 +23,7 @@ import java.util.concurrent.atomic.AtomicInteger
* Authentication methods/credentials found to be working will be cached for further requests
* (this is why the interceptor is needed).
*
* Usage: Set as authenticator <b>and</b> as network interceptor.
* Usage: Set as authenticator **and** as network interceptor.
*/
class BasicDigestAuthHandler(
/** Authenticate only against hosts ending with this domain (may be null, which means no restriction) */
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......@@ -33,7 +31,7 @@ class DavAddressBook @JvmOverloads constructor(
* @throws HttpException on HTTP error
* @throws DavException on DAV error
*/
fun addressbookQuery() {
fun addressbookQuery(): DavResponse {
/* <!ELEMENT addressbook-query ((DAV:allprop |
DAV:propname |
DAV:prop)?, filter, limit?)>
......@@ -61,11 +59,10 @@ class DavAddressBook @JvmOverloads constructor(
.header("Depth", "1")
.build()).execute()
checkStatus(response, false)
checkStatus(response)
assertMultiStatus(response)
resetMembers()
response.body()?.charStream()?.use { processMultiStatus(it) }
return processMultiStatus(response.body()?.charStream()!!)
}
/**
......@@ -74,7 +71,7 @@ class DavAddressBook @JvmOverloads constructor(
* @throws HttpException on HTTP error
* @throws DavException on DAV error
*/
fun multiget(urls: List<HttpUrl>, vCard4: Boolean) {
fun multiget(urls: List<HttpUrl>, vCard4: Boolean): DavResponse {
/* <!ELEMENT addressbook-multiget ((DAV:allprop |
DAV:propname |
DAV:prop)?,
......@@ -113,11 +110,10 @@ class DavAddressBook @JvmOverloads constructor(
.header("Depth", "0") // "The request MUST include a Depth: 0 header [...]"
.build()).execute()
checkStatus(response, false)
checkStatus(response)
assertMultiStatus(response)
resetMembers()
response.body()?.charStream()?.use { processMultiStatus(it) }
return processMultiStatus(response.body()?.charStream()!!)
}
}
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......@@ -40,7 +38,7 @@ class DavCalendar @JvmOverloads constructor(
* @throws HttpException on HTTP error
* @throws DavException on DAV error
*/
fun calendarQuery(component: String, start: Date?, end: Date?) {
fun calendarQuery(component: String, start: Date?, end: Date?): DavResponse {
/* <!ELEMENT calendar-query ((DAV:allprop |
DAV:propname |
DAV:prop)?, filter, timezone?)>
......@@ -88,11 +86,10 @@ class DavCalendar @JvmOverloads constructor(
.header("Depth", "1")
.build()).execute()
checkStatus(response, false)
checkStatus(response)
assertMultiStatus(response)
resetMembers()
response.body()?.charStream()?.use { processMultiStatus(it) }
return processMultiStatus(response.body()?.charStream()!!)
}
/**
......@@ -101,7 +98,7 @@ class DavCalendar @JvmOverloads constructor(
* @throws HttpException on HTTP error
* @throws DavException on DAV error
*/
fun multiget(urls: List<HttpUrl>) {
fun multiget(urls: List<HttpUrl>): DavResponse {
/* <!ELEMENT calendar-multiget ((DAV:allprop |
DAV:propname |
DAV:prop)?, DAV:href+)>
......@@ -134,11 +131,10 @@ class DavCalendar @JvmOverloads constructor(
.method("REPORT", RequestBody.create(MIME_XML, writer.toString()))
.build()).execute()
checkStatus(response, false)
checkStatus(response)
assertMultiStatus(response)
resetMembers()
response.body()?.charStream()?.use { processMultiStatus(it) }
return processMultiStatus(response.body()?.charStream()!!)
}
}
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......@@ -37,7 +35,7 @@ open class DavCollection @JvmOverloads constructor(
* @throws DavException on DAV error
*/
fun reportChanges(syncToken: String?, infiniteDepth: Boolean, limit: Int?, vararg properties: Property.Name) {
fun reportChanges(syncToken: String?, infiniteDepth: Boolean, limit: Int?, vararg properties: Property.Name): DavResponse {
/* <!ELEMENT sync-collection (sync-token, sync-level, limit?, prop)>
<!ELEMENT sync-token CDATA> <!-- Text MUST be a URI -->
......@@ -82,11 +80,10 @@ open class DavCollection @JvmOverloads constructor(
.header("Depth", "0")
.build()).execute()
checkStatus(response, false)
checkStatus(response)
assertMultiStatus(response)
resetMembers()
response.body()?.charStream()?.use { processMultiStatus(it) }
return processMultiStatus(response.body()?.charStream()!!)
}
}
\ No newline at end of file
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
import at.bitfire.dav4android.property.SyncToken
import okhttp3.HttpUrl
import okhttp3.Response
import okhttp3.ResponseBody
import java.io.Closeable
/**
* Immutable container for a WebDAV multistatus response. Note that property elements
* are not immutable automatically.
*/
class DavResponse private constructor(
/** resource this response is about */
val url: HttpUrl,
/** corresponding HTTP response object */
val body: ResponseBody?,
/** HTTP capabilities reported by an OPTIONS response */
val capabilities: Set<String>,
/** WebDAV properties of this resource */
val properties: List<Property>,
/** members of the requested collection */
val members: List<DavResponse>,
/** removed members of the requested collection (HTTP status 404) */
val removedMembers: List<DavResponse>,
/** information about resources which are not members of the requested collection */
val related: List<DavResponse>,
/** sync-token as returned by REPORT sync-collection */
val syncToken: SyncToken?,
/** whether further results are available (requested collection had HTTP status 507) */
val furtherResults: Boolean
): Closeable {
/**
* After closing this response, the [body] will not be usable anymore, but other properties
* can be used normally.
*/
override fun close() {
body?.close()
}
/**
* Convenience method to get a certain property from the current response. Does't take
* members or related resources into consideration.
*/
operator fun<T: Property> get(clazz: Class<T>): T? {
return properties.filterIsInstance(clazz).firstOrNull()
}
/**
* Recursively searches for a property, i.e. in this object and in
* [members] and [related] and returns the first occurrence with its source.
*/
fun<T: Property> searchProperty(clazz: Class<T>): Pair<DavResponse, T>? {
get(clazz)?.let { return Pair(this, it) }
members.forEach { response ->
response[clazz]?.let { return Pair(response, it) }
}
related.forEach { response ->
response[clazz]?.let { return Pair(response, it) }
}
return null
}
/**
* Recursively (i.e. in this object, and in [members] and [related]) searches for a
* property, and returns all occurrences together with their sources.
*/
fun<T: Property> searchProperties(clazz: Class<T>): Map<DavResponse, T> {
val map = mutableMapOf<DavResponse, T>()
get(clazz)?.let { map[this] = it }
members.forEach { response ->
response[clazz]?.let { map[response] = it }
}
related.forEach { response ->
response[clazz]?.let { map[response] = it }
}
return map
}
class Builder(
val url: HttpUrl
) {
private var responseBody: ResponseBody? = null
fun responseBody(newValue: ResponseBody?): Builder {
responseBody = newValue
return this
}
private var capabilities: Set<String> = setOf()
fun capabilities(newValue: Set<String>): Builder {
capabilities = newValue
return this
}
private var properties: List<Property> = listOf()
fun properties(newValue: List<Property>): Builder {
properties = newValue
return this
}
private val members: MutableList<DavResponse.Builder> = mutableListOf()
fun addMember(member: DavResponse.Builder): Builder {
members += member
return this
}
private val removedMembers: MutableList<DavResponse.Builder> = mutableListOf()
fun addRemovedMember(member: DavResponse.Builder): Builder {
removedMembers += member
return this
}
private val related: MutableList<DavResponse.Builder> = mutableListOf()
fun addRelated(related: DavResponse.Builder): Builder {
this.related += related
return this
}
private var syncToken: SyncToken? = null
fun syncToken(newValue: SyncToken?): Builder {
syncToken = newValue
return this
}
private var furtherResults = false
fun furtherResults(newValue: Boolean): Builder {
furtherResults = newValue
return this
}
fun build(): DavResponse = DavResponse(
url,
responseBody,
capabilities,
properties,
members.map { it.build() },
removedMembers.map { it.build() },
related.map { it.build() },
syncToken,
furtherResults
)
}
}
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.dav4android
import java.util.*
import java.util.Collections.unmodifiableMap
class PropertyCollection {
val properties = lazy { mutableMapOf<Property.Name, Property?>() }
/**
* Returns a WebDAV property, or null if this property is not known.
* In most cases, using the alternative [get] with [Class] parameter is better because it provides type safety.
*/
operator fun get(name: Property.Name): Property? =
if (!properties.isInitialized())
null
else
properties.value[name]
/**
* Returns a WebDAV property, or null if this property is not known.
*/
operator fun<T: Property> get(clazz: Class<T>): T? {
if (!properties.isInitialized())
return null
return try {
val name = clazz.getDeclaredField("NAME").get(null) as Property.Name
properties.value[name] as? T
} catch (e: NoSuchFieldException) {
Constants.log.severe("$clazz does not have a static NAME field")
null
}
}
private fun getMap(): Map<Property.Name, Property?> =
if (!properties.isInitialized())
mapOf()
else
unmodifiableMap(properties.value)
operator fun set(name: Property.Name, property: Property?) {
properties.value[name] = property
}
operator fun minusAssign(name: Property.Name) {
if (!properties.isInitialized())
return
properties.value.remove(name)
}
fun size() =
if (!properties.isInitialized())
0
else
properties.value.size
/**
* Merges another [PropertyCollection] into [properties].
* Existing properties will be overwritten.
*
* @param another property collection to take the properties from
* @param removeNullValues Indicates how "another" properties with null values should be treated.
* - true: If the "another" property value is null, the property will be removed in [properties].
* - false: If the "another" property value is null, the property in [properties] will be set to null, too,
* but only if it doesn't exist yet. This means values in [properties] will never be overwritten by null.
*/
fun merge(another: PropertyCollection, removeNullValues: Boolean) {
val properties = another.getMap()
for ((name, prop) in properties) {
if (prop != null)
set(name, prop)
else {
// prop == null
if (removeNullValues)
this -= name
else if (get(name) == null) // never overwrite non-null values
set(name, null)
}
}
}
fun nullAllValues() {
if (!properties.isInitialized())
return
val props = properties.value
for (name in props.keys)
props[name] = null
}
override fun toString(): String {
val s = LinkedList<String>()
for ((name, value) in getMap())
s.add("$name = $value")
return "[${s.joinToString(", ")}]"
}
}
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.exception
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.exception
import at.bitfire.dav4android.Constants
import at.bitfire.dav4android.Property
import at.bitfire.dav4android.XmlUtils
import okhttp3.MediaType
import okhttp3.Request
import okhttp3.Response
import okio.Buffer
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.Serializable
import java.util.logging.Level
/**
* Signals that an error occurred during a WebDAV-related operation.
*
* This could be a logical error like when a required ETag has not been
* received, but also an explicit HTTP error.
*/
open class DavException @JvmOverloads constructor(
message: String,
ex: Throwable? = null
): Exception(message, ex)
\ No newline at end of file
ex: Throwable? = null,
/**
* An associated HTTP [Response]. Will be closed after evaluation.
*/
httpResponse: Response? = null
): Exception(message, ex), Serializable {
companion object {
const val MAX_EXCERPT_SIZE = 10*1024 // don't dump more than 20 kB
fun isPlainText(type: MediaType) =
type.type() == "text" ||
(type.type() == "application" && type.subtype() in arrayOf("html", "xml"))
}
var request: Request? = null
private set
var requestBody: String? = null
private set
/**
* Associated HTTP [Response]. Do not access [Response.body] because it will be closed.
* Use [responseBody] instead.
*/
val response: Response?
/**
* Body excerpt of [response] (up to [MAX_EXCERPT_SIZE] characters). Only available
* if the HTTP response body was textual content.
*/
var responseBody: String? = null
private set
/**
* Precondition/postcondition XML elements which have been found in the XML response.
*/
var errors: Set<Property.Name> = setOf()
private set
init {
if (httpResponse != null) {
response = httpResponse
try {
request = httpResponse.request()
request?.body()?.let { body ->
body.contentType()?.let {
if (isPlainText(it)) {
val buffer = Buffer()
body.writeTo(buffer)
val baos = ByteArrayOutputStream()
buffer.writeTo(baos)
requestBody = baos.toString(it.charset(Charsets.UTF_8)!!.name())
}
}
}
} catch (e: Exception) {
Constants.log.log(Level.WARNING, "Couldn't read HTTP request", e)
requestBody = "Couldn't read HTTP request: ${e.message}"
}
try {
// save response body excerpt
if (httpResponse.body()?.source() != null) {
// response body has a source
httpResponse.peekBody(MAX_EXCERPT_SIZE.toLong())?.use { body ->
body.contentType()?.let {
if (isPlainText(it))
responseBody = body.string()
}
}
httpResponse.body()?.use { body ->
body.contentType()?.let {
if (it.type() in arrayOf("application", "text") && it.subtype() == "xml") {
// look for precondition/postcondition XML elements
try {
val parser = XmlUtils.newPullParser()
parser.setInput(body.charStream())
var eventType = parser.eventType
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG && parser.depth == 1)
if (parser.namespace == XmlUtils.NS_WEBDAV && parser.name == "error")
errors = parseXmlErrors(parser)
eventType = parser.next()
}
} catch (e: XmlPullParserException) {
Constants.log.log(Level.WARNING, "Couldn't parse XML response", e)
}
}
}
}
}
} catch (e: IOException) {
Constants.log.log(Level.WARNING, "Couldn't read HTTP response", e)
responseBody = "Couldn't read HTTP response: ${e.message}"
} finally {
httpResponse.body()?.close()
}
} else
response = null
}
private fun parseXmlErrors(parser: XmlPullParser): Set<Property.Name> {
val names = mutableSetOf<Property.Name>()
val depth = parser.depth
var eventType = parser.eventType
while (!(eventType == XmlPullParser.END_TAG && parser.depth == depth)) {
if (eventType == XmlPullParser.START_TAG && parser.depth == depth + 1)
names += Property.Name(parser.namespace, parser.name)
eventType = parser.next()
}
return names
}
}
\ No newline at end of file
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.exception
import at.bitfire.dav4android.Constants
import okhttp3.Response
import okio.Buffer
import java.io.*
open class HttpException: Exception, Serializable {
companion object {
// don't dump more than 20 kB
private const val MAX_DUMP_SIZE = 20*1024
}
val status: Int
val request: String?
val response: String?
constructor(message: String?): super(message) {
status = -1
request = null
response = null
}
constructor(status: Int, message: String?): super("$status $message") {
this.status = status
request = null
response = null
}
/**
* Brings [response] into an readable format. Reads and closes the [response] body.
*/
constructor(response: Response): super("${response.code()} ${response.message()}") {
status = response.code()
/* As we don't know the media type and character set of request and response body,
only printable ASCII characters will be shown in clear text. Other octets will
be shown as "[xx]" where xx is the hex value of the octet.
*/
// format request
val request = response.request()
var formatted = StringBuilder()
formatted.append(request.method()).append(" ").append(request.url().encodedPath()).append("\n")
for ((name,values) in request.headers().toMultimap())
for (value in values)
formatted.append(name).append(": ").append(value).append("\n")
request.body()?.let {
formatted.append("Content-Type: ").append(it.contentType()).append("\n")
formatted.append("Content-Length: ").append(it.contentLength()).append("\n")
try {
val buffer = Buffer()
it.writeTo(buffer)
val baos = ByteArrayOutputStream()
formatByteStream(buffer.inputStream(), baos)
formatted.append("\n").append(baos.toString())
} catch (e: IOException) {
Constants.log.warning("Couldn't read request body")
}
}
this.request = formatted.toString()
/**
* Signals that a HTTP error was sent by the server.
*/
open class HttpException: DavException {
// format response
formatted = StringBuilder()
formatted.append(response.protocol()).append(" ").append(response.code()).append(" ").append(response.message()).append("\n")
for ((name,values) in response.headers().toMultimap())
for (value in values)
formatted.append(name).append(": ").append(value).append("\n")
var code: Int
response.body()?.use {
formatted.append("[body length: ").append(it.contentLength()).append(" bytes]").append("\n")
try {
val baos = ByteArrayOutputStream()
formatByteStream(it.byteStream(), baos)
formatted.append("\n").append(baos.toString())
} catch(e: IOException) {
Constants.log.warning("Couldn't read response body")
}
}
this.response = formatted.toString()
constructor(response: Response): super(
"HTTP ${response.code()} ${response.message()}",
httpResponse = response
) {
code = response.code()
}
private fun formatByteStream(input: InputStream, output: ByteArrayOutputStream) {
OutputStreamWriter(output).use { writer ->
var b = input.read()
var written = 0
while (b != -1) {
if (written++ >= MAX_DUMP_SIZE) {
writer.append("[…]")
break
}
when (b) {
'\t'.toInt() -> writer.append('↦')
'\r'.toInt() -> writer.append('↵')
'\n'.toInt() -> writer.append('\n')
in 0x20..0x7E -> writer.write(b) // printable ASCII
else -> writer.append("[${String.format("%02x", b)}]")
}
b = input.read()
}
}
constructor(code: Int, message: String?): super("HTTP $code $message") {
this.code = code
}
}
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.dav4android.exception
class InvalidDavResponseException @JvmOverloads constructor(
message: String,
ex: Throwable? = null
): DavException(message, ex)
\ No newline at end of file
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.exception
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.exception
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.exception
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.exception
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.dav4android.exception
class UnsupportedDavException(message: String): DavException(message)
\ No newline at end of file
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android.property
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">DAV4Android</string>
</resources>
\ No newline at end of file
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
......
/*
* Copyright © Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
* 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 http://mozilla.org/MPL/2.0/.
*/
package at.bitfire.dav4android
import at.bitfire.dav4android.exception.HttpException
import at.bitfire.dav4android.property.GetETag
import at.bitfire.dav4android.property.SyncToken
import okhttp3.OkHttpClient
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
......@@ -27,13 +24,13 @@ class DavCollectionTest {
private val mockServer = MockWebServer()
private fun sampleUrl() = mockServer.url("/dav/")
@Before
fun startServer() = mockServer.start()
@After
fun stopServer() = mockServer.shutdown()
/**
* Test sample response for an initial sync-collection report from RFC 6578 3.8.
*/
......@@ -95,25 +92,25 @@ class DavCollectionTest {
" <D:sync-token>http://example.com/ns/sync/1234</D:sync-token>\n" +
" </D:multistatus>")
)
collection.reportChanges(null, false, null, GetETag.NAME)
assertEquals(3, collection.members.size)
val members = collection.members.iterator()
val member1 = members.next()
assertEquals(sampleUrl().newBuilder().addPathSegment("test.doc").build(), member1.location)
assertEquals(