Skip to content

Commit a3fad6a

Browse files
authored
fix: correctly parse URLs with '@' symbol (#1032)
1 parent 2e099f9 commit a3fad6a

File tree

4 files changed

+36
-8
lines changed

4 files changed

+36
-8
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "ed8a74dd-01a4-46c3-96eb-8ac9356bead6",
3+
"type": "bugfix",
4+
"description": "Correctly parse URLs which contain the `@` symbol in the path and/or fragment (but not in the userinfo)",
5+
"issues": [
6+
"awslabs/smithy-kotlin#1031"
7+
]
8+
}

runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/net/url/Url.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,18 @@ public class Url private constructor(
5050
val scanner = Scanner(value)
5151
scanner.requireAndSkip("://") { scheme = Scheme.parse(it) }
5252

53-
scanner.optionalAndSkip("@") {
54-
userInfo.parseEncoded(it)
55-
}
56-
5753
scanner.upToOrEnd("/", "?", "#") { authority ->
58-
val (h, p) = authority.parseHostPort()
59-
host = h
60-
p?.let { port = it }
54+
val innerScanner = Scanner(authority)
55+
56+
innerScanner.optionalAndSkip("@") {
57+
userInfo.parseEncoded(it)
58+
}
59+
60+
innerScanner.upToOrEnd { hostport ->
61+
val (h, p) = hostport.parseHostPort()
62+
host = h
63+
p?.let { port = it }
64+
}
6165
}
6266

6367
scanner.ifStartsWith("/") {

runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/text/Scanner.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public class Scanner(public val text: String) {
169169
* ```
170170
*
171171
* @param literals One or more strings to search for at/after the current position
172-
* @param handler The handler to invoke on the substring *up to but not including nearest found element of
172+
* @param handler The handler to invoke on the substring *up to but not including* nearest found element of
173173
* [literals] or, if none of [literals] are found,
174174
*/
175175
public fun upToOrEnd(vararg literals: String, handler: (String) -> Unit) {

runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/net/url/UrlParsingTest.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,22 @@ class UrlParsingTest {
276276
assertEquals(expected, Url.parse("https://user%3A:pass%40@host").userInfo)
277277
}
278278

279+
@Test
280+
fun testAtSymbolsOutsideOfUserInfo() {
281+
data class Test(val url: String, val userInfo: String, val path: String, val fragment: String?)
282+
listOf(
283+
Test("https://host/foo/bar@baz/blah", "", "/foo/bar@baz/blah", null),
284+
Test("https://host/foo/bar/baz/blah#qux@quux", "", "/foo/bar/baz/blah", "qux@quux"),
285+
Test("https://user:pass@host/foo/bar@baz/blah", "user:pass", "/foo/bar@baz/blah", null),
286+
Test("https://user:pass@host/foo/bar@baz/blah#qux@quux", "user:pass", "/foo/bar@baz/blah", "qux@quux"),
287+
).forEach { (urlString, expectedUserInfo, expectedPath, expectedFragment) ->
288+
val url = Url.parse(urlString)
289+
assertEquals(expectedUserInfo, url.userInfo.toString(), "Error parsing $urlString")
290+
assertEquals(expectedPath, url.path.encoded, "Error parsing $urlString")
291+
assertEquals(expectedFragment, url.fragment?.encoded, "Error parsing $urlString")
292+
}
293+
}
294+
279295
@Test
280296
fun testComplete() {
281297
val expected = Url {

0 commit comments

Comments
 (0)