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

Commit 8a93572e authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Ignore fragments when comparing URLs

parent d6ae2af4
Loading
Loading
Loading
Loading

CHANGELOG.md

0 → 100644
+7 −0
Original line number Diff line number Diff line

# Version 1.x

## Version 1.0.1

- `UrlUtils.equals()`: ignore #fragment URL parts
- updated dependencies
+2 −2
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ object Libs {
    // We'll use 3.12 for now, but this branch won't receive feature updates anymore. Security
    // updates are limited to Dec 2020, so we'll have to update to 3.13 until then. On Android,
    // using 3.13 will raise the required SDK level to Android 5.
    const val okhttpVersion = "3.12.6"
    const val okhttpVersion = "3.12.8"

    // XmlPullParser library
    const val xpp3Version = "1.1.6"
@@ -18,7 +18,7 @@ repositories {
}

plugins {
    kotlin("jvm") version "1.3.50"
    kotlin("jvm") version "1.3.61"

    id("com.github.kukuhyoniatmoko.buildconfigkotlin") version "1.0.5"
    id("org.jetbrains.dokka") version "0.10.0"
+48 −7
Original line number Diff line number Diff line
@@ -12,14 +12,33 @@ import java.net.URISyntaxException

object UrlUtils {

    /**
     * Compares two URLs in WebDAV context. If two URLs are considered *equal*, both
     * represent the same WebDAV resource (e.g. `http://host:80/folder1` and `http://HOST/folder1#somefragment`).
     *
     * It decodes %xx entities in the path, so `/my@dav` and `/my%40dav` are considered the same.
     * This is important to process multi-status responses: some servers serve a multi-status
     * response with href `/my@dav` when you request `/my%40dav` and vice versa.
     *
     * This method does not deal with trailing slashes, so if you want to compare collection URLs,
     * make sure they both (don't) have a trailing slash before calling this method, for instance
     * with [omitTrailingSlash] or [withTrailingSlash].
     *
     * @param url1 the first URL to be compared
     * @param url2 the second URL to be compared
     *
     * @return whether [url1] and [url2] (usually) represent the same WebDAV resource
     */
    fun equals(url1: HttpUrl, url2: HttpUrl): Boolean {
        // if okhttp thinks the two URLs are equal, they're in any case
        // (and it's a simple String comparison)
        if (url1 == url2)
            return true

        val uri1 = url1.uri()
        val uri2 = url2.uri()
        // drop #fragment parts and convert to URI
        val uri1 = url1.newBuilder().fragment(null).build().uri()
        val uri2 = url2.newBuilder().fragment(null).build().uri()

        return try {
            val decoded1 = URI(uri1.scheme, uri1.schemeSpecificPart, uri1.fragment)
            val decoded2 = URI(uri2.scheme, uri2.schemeSpecificPart, uri2.fragment)
@@ -29,22 +48,37 @@ object UrlUtils {
        }
    }

    /**
     * Gets the first-level domain name (without subdomains) from a host name.
     * Also removes trailing dots.
     *
     * @param host name (e.g. `www.example.com.`)
     *
     * @return domain name (e.g. `example.com`)
     */
    fun hostToDomain(host: String?): String? {
        if (host == null)
            return null

        // remove optional dot at end
        @Suppress("NAME_SHADOWING")
        val host = host.removeSuffix(".")
        val withoutTrailingDot = host.removeSuffix(".")

        // split into labels
        val labels = host.split('.')
        val labels = withoutTrailingDot.split('.')
        return if (labels.size >= 2) {
            labels[labels.size - 2] + "." + labels[labels.size - 1]
        } else
            host
            withoutTrailingDot
    }

    /**
     * Ensures that a given URL doesn't have a trailing slash after member names.
     * If the path is the root path (`/`), the slash is preserved.
     *
     * @param url URL to process (e.g. 'http://host/test1/')
     *
     * @return URL without trailing slash (except when the path is the root path), e.g. `http://host/test1`
     */
    fun omitTrailingSlash(url: HttpUrl): HttpUrl {
        val idxLast = url.pathSize () - 1
        val hasTrailingSlash = url.pathSegments()[idxLast] == ""
@@ -55,6 +89,13 @@ object UrlUtils {
            url
    }

    /**
     * Ensures that a given URL has a trailing slash after member names.
     *
     * @param url URL to process (e.g. 'http://host/test1')
     *
     * @return URL with trailing slash, e.g. `http://host/test1/`
     */
    fun withTrailingSlash(url: HttpUrl): HttpUrl {
        val idxLast = url.pathSize() - 1
        val hasTrailingSlash = url.pathSegments()[idxLast] == ""
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ class UrlUtilsTest {
        assertTrue(UrlUtils.equals(HttpUrl.parse("http://host:80/resource")!!, HttpUrl.parse("http://host/resource")!!))
        assertTrue(UrlUtils.equals(HttpUrl.parse("https://HOST:443/resource")!!, HttpUrl.parse("https://host/resource")!!))
        assertTrue(UrlUtils.equals(HttpUrl.parse("https://host:443/my@dav/")!!, HttpUrl.parse("https://host/my%40dav/")!!))
        assertTrue(UrlUtils.equals(HttpUrl.parse("http://host/resource")!!, HttpUrl.parse("http://host/resource#frag1")!!))

        assertFalse(UrlUtils.equals(HttpUrl.parse("http://host/resource")!!, HttpUrl.parse("http://host/resource/")!!))
        assertFalse(UrlUtils.equals(HttpUrl.parse("http://host/resource")!!, HttpUrl.parse("http://host:81/resource")!!))