Skip to content

Commit acf8e4e

Browse files
authored
Fix URL parsing to handle URLDecodeException (#149)
* Fix URL parsing to handle URLDecodeException - Update `toUrlOrNull` method to catch all exceptions - Add test case for invalid HTTPS URL with decoding issues * Change catch block from `URLParserException` to `Exception` in `ResponseParser.kt` and `DavResource.kt`
1 parent 8f96097 commit acf8e4e

File tree

4 files changed

+19
-6
lines changed

4 files changed

+19
-6
lines changed

src/main/kotlin/at/bitfire/dav4jvm/ktor/DavResource.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import io.ktor.http.HttpHeaders
4141
import io.ktor.http.HttpMethod
4242
import io.ktor.http.HttpStatusCode
4343
import io.ktor.http.URLBuilder
44-
import io.ktor.http.URLParserException
4544
import io.ktor.http.Url
4645
import io.ktor.http.contentType
4746
import io.ktor.http.isSecure
@@ -643,7 +642,7 @@ open class DavResource(
643642
URLBuilder(location)
644643
.takeFrom(newLocation)
645644
.build()
646-
} catch (e: URLParserException) {
645+
} catch (e: Exception) {
647646
throw DavException("Redirected to invalid Location", cause = e)
648647
}
649648

src/main/kotlin/at/bitfire/dav4jvm/ktor/KtorHttpUtils.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import io.ktor.client.statement.HttpResponse
1414
import io.ktor.http.BadContentTypeFormatException
1515
import io.ktor.http.ContentType
1616
import io.ktor.http.HttpStatusCode
17-
import io.ktor.http.URLParserException
1817
import io.ktor.http.Url
1918

2019
object KtorHttpUtils {
@@ -118,13 +117,24 @@ fun String?.toContentTypeOrNull(): ContentType? {
118117
}
119118
}
120119

120+
/**
121+
* Converts the [String] into a Ktor [Url], if possible.
122+
*
123+
* Differs from [io.ktor.http.parseUrl]:
124+
*
125+
* - `"relative".toUrlOrNull() == Url("relative")` (without host) but
126+
* - `parseUrl("relative") == null` (requires host)
127+
*
128+
* @return the Ktor [Url], or `null` if the string couldn't be converted
129+
*/
121130
fun String?.toUrlOrNull(): Url? {
122131
if (this == null)
123132
return null
124133

125134
return try {
126135
Url(this)
127-
} catch (_: URLParserException) {
136+
} catch (_: Exception) {
137+
// parseUrl doesn't catch URLDecodeException, see https://github.com/ktorio/ktor/pull/5231
128138
null
129139
}
130140
}

src/main/kotlin/at/bitfire/dav4jvm/ktor/ResponseParser.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import at.bitfire.dav4jvm.property.webdav.ResourceType
1717
import at.bitfire.dav4jvm.property.webdav.WebDAV
1818
import io.ktor.http.HttpStatusCode
1919
import io.ktor.http.URLBuilder
20-
import io.ktor.http.URLParserException
2120
import io.ktor.http.Url
2221
import io.ktor.http.isSuccess
2322
import io.ktor.http.takeFrom
@@ -168,7 +167,7 @@ class ResponseParser(
168167

169168
val urlBuilder = try {
170169
URLBuilder(location).takeFrom(sHref)
171-
} catch (e: URLParserException) {
170+
} catch (e: Exception) {
172171
logger.log(Level.WARNING, "Unresolvable <href> in <response>: $hrefString", e)
173172
return null
174173
}

src/test/kotlin/at/bitfire/dav4jvm/ktor/KtorHttpUtilsTest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ class KtorHttpUtilsTest {
267267
assertNull("mailto:invalid".toUrlOrNull())
268268
}
269269

270+
@Test
271+
fun `toUrlOrNull with invalid HTTPS URL that can't be decoded`() {
272+
assertNull("https://example.com/%f".toUrlOrNull())
273+
}
274+
270275
@Test
271276
fun `toUrlOrNull with valid HTTPS URL`() {
272277
assertEquals(

0 commit comments

Comments
 (0)