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

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

Require <getetag> eTag values (#10)

- introduce XmlUtils.requireReadText()
- Property.parse(): ignore invalid properties
- GetETag: require input text so that the value fields don't have to be nullable
parent f434c9d1
Loading
Loading
Loading
Loading
+17 −10
Original line number Diff line number Diff line
@@ -7,9 +7,11 @@
package at.bitfire.dav4jvm

import at.bitfire.dav4jvm.Dav4jvm.log
import at.bitfire.dav4jvm.exception.InvalidPropertyException
import org.xmlpull.v1.XmlPullParser
import java.io.Serializable
import java.util.*
import java.util.logging.Level

/**
 * Represents a WebDAV property.
@@ -39,7 +41,9 @@ interface Property {
            while (!(eventType == XmlPullParser.END_TAG && parser.depth == depth)) {
                if (eventType == XmlPullParser.START_TAG && parser.depth == depth + 1) {
                    val depthBeforeParsing = parser.depth
                    val name = Property.Name(parser.namespace, parser.name)
                    val name = Name(parser.namespace, parser.name)

                    try {
                        val property = PropertyRegistry.create(name, parser)
                        assert(parser.depth == depthBeforeParsing)

@@ -47,6 +51,9 @@ interface Property {
                            properties.add(property)
                        } else
                            log.fine("Ignoring unknown property $name")
                    } catch (e: InvalidPropertyException) {
                        log.log(Level.WARNING, "Ignoring invalid property", e)
                    }
                }
                eventType = parser.next()
            }
+11 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

package at.bitfire.dav4jvm

import at.bitfire.dav4jvm.exception.InvalidPropertyException
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import org.xmlpull.v1.XmlPullParserFactory
@@ -60,6 +61,16 @@ object XmlUtils {
        return text
    }

    /**
     * Same as [readText], but requires a [XmlPullParser.TEXT] value.
     *
     * @throws InvalidPropertyException when no text could be read
     */
    @Throws(InvalidPropertyException::class, IOException::class, XmlPullParserException::class)
    fun requireReadText(parser: XmlPullParser): String =
        readText(parser) ?:
        throw InvalidPropertyException("XML text for ${parser.namespace}:${parser.name} must not be empty")

    @Throws(IOException::class, XmlPullParserException::class)
    fun readTextProperty(parser: XmlPullParser, name: Property.Name): String? {
        val depth = parser.depth
+8 −0
Original line number Diff line number Diff line
package at.bitfire.dav4jvm.exception

/**
 * Represents an invalid XML (WebDAV) property. This is for instance thrown
 * when parsing something like `<multistatus>...<getetag><novalue/></getetag>`
 * because a text value would be expected.
 */
class InvalidPropertyException(message: String): Exception(message)
+30 −22
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ import org.xmlpull.v1.XmlPullParser
 * header value to the constructor and then use [eTag] and [weak].
 */
class GetETag(
    rawETag: String?
    rawETag: String
): Property {

    companion object {
@@ -32,38 +32,46 @@ class GetETag(
    }

    /**
     * The parsed eTag value. May be null if the tag is weak.
     * The parsed ETag value, excluding the weakness indicator and the quotes.
     */
    val eTag: String?
    val eTag: String

    /**
     * If the tag is weak. May be null if the tag passed is null.
     * Whether the ETag is weak.
     */
    val weak: Boolean?
    var weak: Boolean

    init {
        /* entity-tag = [ weak ] opaque-tag
           weak       = "W/"
           opaque-tag = quoted-string
        */
        var tag: String? = rawETag
        if (tag != null) {
        val tag: String

        // remove trailing "W/"
            if (tag.startsWith("W/") && tag.length >= 3) {
        if (rawETag.startsWith("W/") && rawETag.length >= 2) {
            // entity tag is weak
                tag = tag.substring(2)
            tag = rawETag.substring(2)
            weak = true
            } else
        } else {
            tag = rawETag
            weak = false
        }

            tag = QuotedStringUtils.decodeQuotedString(tag)
        } else
            weak = null
        eTag = QuotedStringUtils.decodeQuotedString(tag)
    }

        eTag = tag
    override fun toString() = "ETag(weak=${weak}, tag=$eTag)"

    override fun equals(other: Any?): Boolean {
        if (other !is GetETag)
            return false
        return eTag == other.eTag && weak == other.weak
    }

    override fun toString() = eTag ?: "(null)"
    override fun hashCode(): Int {
        return eTag.hashCode() xor weak.hashCode()
    }


    object Factory: PropertyFactory {
@@ -71,7 +79,7 @@ class GetETag(
        override fun getName() = NAME

        override fun create(parser: XmlPullParser) =
            GetETag(XmlUtils.readText(parser))
            GetETag(XmlUtils.requireReadText(parser))

    }

+6 −6
Original line number Diff line number Diff line
@@ -105,24 +105,24 @@ class DavCollectionTest {
                    assertTrue(response.isSuccess())
                    assertEquals(Response.HrefRelation.MEMBER, relation)
                    val eTag = response[GetETag::class.java]
                    assertEquals("00001-abcd1", eTag?.eTag)
                    assertTrue(eTag?.weak == false)
                    assertEquals("00001-abcd1", eTag!!.eTag)
                    assertFalse(eTag.weak)
                    nrCalled++
                }
                url.resolve("/dav/vcard.vcf") -> {
                    assertTrue(response.isSuccess())
                    assertEquals(Response.HrefRelation.MEMBER, relation)
                    val eTag = response[GetETag::class.java]
                    assertEquals("00002-abcd1", eTag?.eTag)
                    assertTrue(eTag?.weak == false)
                    assertEquals("00002-abcd1", eTag!!.eTag)
                    assertFalse(eTag.weak)
                    nrCalled++
                }
                url.resolve("/dav/calendar.ics") -> {
                    assertTrue(response.isSuccess())
                    assertEquals(Response.HrefRelation.MEMBER, relation)
                    val eTag = response[GetETag::class.java]
                    assertEquals("00003-abcd1", eTag?.eTag)
                    assertTrue(eTag?.weak == false)
                    assertEquals("00003-abcd1", eTag!!.eTag)
                    assertFalse(eTag.weak)
                    nrCalled++
                }
            }
Loading