From 6cf97bb67fa63b0b3f47b884543d6d0dd47deb58 Mon Sep 17 00:00:00 2001 From: Anton Erofeev Date: Mon, 23 Dec 2024 21:37:46 +0300 Subject: [PATCH] KTOR-4816: UrlBuilder: support tel scheme (#4518) --- .../common/src/io/ktor/http/URLBuilder.kt | 10 ++++++++++ ktor-http/common/src/io/ktor/http/URLParser.kt | 6 ++++++ .../common/test/io/ktor/tests/http/UrlTest.kt | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/ktor-http/common/src/io/ktor/http/URLBuilder.kt b/ktor-http/common/src/io/ktor/http/URLBuilder.kt index 721c4c2671c..e86ee95bbfb 100644 --- a/ktor-http/common/src/io/ktor/http/URLBuilder.kt +++ b/ktor-http/common/src/io/ktor/http/URLBuilder.kt @@ -155,6 +155,11 @@ private fun URLBuilder.appendTo(out: A): A { out.appendAbout(host) return out } + + "tel" -> { + out.appendTel(host) + return out + } } out.append("://") @@ -190,6 +195,11 @@ private fun Appendable.appendAbout(host: String) { append(host) } +private fun Appendable.appendTel(host: String) { + append(":") + append(host) +} + /** * Hostname of current origin. * diff --git a/ktor-http/common/src/io/ktor/http/URLParser.kt b/ktor-http/common/src/io/ktor/http/URLParser.kt index bb4a2871e93..68d7c2085ba 100644 --- a/ktor-http/common/src/io/ktor/http/URLParser.kt +++ b/ktor-http/common/src/io/ktor/http/URLParser.kt @@ -63,6 +63,12 @@ internal fun URLBuilder.takeFromUnsafe(urlString: String): URLBuilder { return this } + if (protocol.name == "tel") { + require(slashCount == 0) + host = urlString.substring(startIndex, endIndex) + return this + } + if (slashCount >= 2) { loop@ while (true) { val delimiter = urlString.indexOfAny("@/\\?#".toCharArray(), startIndex).takeIf { it > 0 } ?: endIndex diff --git a/ktor-http/common/test/io/ktor/tests/http/UrlTest.kt b/ktor-http/common/test/io/ktor/tests/http/UrlTest.kt index d6f725cf1bc..bbd31fae2d1 100644 --- a/ktor-http/common/test/io/ktor/tests/http/UrlTest.kt +++ b/ktor-http/common/test/io/ktor/tests/http/UrlTest.kt @@ -365,4 +365,22 @@ class UrlTest { assertEquals(URLProtocol.HTTP, urlHttp.protocol) assertTrue(urlHttp.rawSegments.contains("about")) } + + @Test + fun testTelUrl() { + val globalTelUrl = Url("tel:+14085555555") + assertEquals("tel:+14085555555", globalTelUrl.toString()) + assertEquals("tel", globalTelUrl.protocol.name) + assertEquals("+14085555555", globalTelUrl.host) + + val localTelUrlWithContext = Url("tel:863-1234;phone-context=+1-914-555") + assertEquals("tel:863-1234;phone-context=+1-914-555", localTelUrlWithContext.toString()) + assertEquals("tel", localTelUrlWithContext.protocol.name) + assertEquals("863-1234;phone-context=+1-914-555", localTelUrlWithContext.host) + + val telUrlWithParams = Url("tel:+1-408-555-5555;extension=ext;phone-context=context") + assertEquals("tel:+1-408-555-5555;extension=ext;phone-context=context", telUrlWithParams.toString()) + assertEquals("tel", telUrlWithParams.protocol.name) + assertEquals("+1-408-555-5555;extension=ext;phone-context=context", telUrlWithParams.host) + } }