-
-
Notifications
You must be signed in to change notification settings - Fork 244
/
Uri.kt
54 lines (45 loc) · 2.36 KB
/
Uri.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package org.http4k.core
import org.http4k.appendIfNotBlank
import org.http4k.appendIfPresent
data class Uri(val scheme: String, val userInfo: String, val host: String, val port: Int?, val path: String, val query: String, val fragment: String) {
companion object {
private val AUTHORITY = Regex("(?:([^@]+)@)?([^:]+)(?::([\\d]+))?")
private val RFC3986 = Regex("^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?")
@JvmStatic
fun of(value: String): Uri {
val result = RFC3986.matchEntire(value) ?: throw RuntimeException("Invalid Uri: $value")
val (scheme, authority, path, query, fragment) = result.destructured
val (userInfo, host, port) = parseAuthority(authority)
return Uri(scheme, userInfo, host, port, path, query, fragment)
}
private fun parseAuthority(authority: String): Triple<String, String, Int?> {
if(authority.isBlank()) return Triple("", "", null)
val (userInfo, host, portString) = AUTHORITY.matchEntire(authority)?.destructured ?: throw RuntimeException("Invalid authority: $authority")
val port = portString.toIntOrNull()
return Triple(userInfo, host, port)
}
}
val authority = StringBuilder()
.appendIfNotBlank(userInfo, userInfo, "@")
.appendIfNotBlank(host, host)
.appendIfPresent(port, ":", port.toString())
.toString()
fun scheme(scheme: String) = copy(scheme = scheme)
fun userInfo(userInfo: String) = copy(userInfo = userInfo)
fun host(host: String) = copy(host = host)
fun port(port: Int?) = copy(port = port)
fun path(path: String) = copy(path = path)
fun query(query: String) = copy(query = query)
fun fragment(fragment: String) = copy(fragment = fragment)
fun authority(authority: String): Uri {
val (userInfo, host, port) = parseAuthority(authority)
return copy(userInfo = userInfo, host = host, port = port)
}
override fun toString(): String = StringBuilder()
.appendIfNotBlank(scheme, scheme, ":")
.appendIfNotBlank(authority, "//", authority)
.append(path)
.appendIfNotBlank(query, "?", query)
.appendIfNotBlank(fragment, "#", fragment).toString()
}
fun Uri.query(name: String, value: String?): Uri = copy(query = query.toParameters().plus(name to value).toUrlEncoded())