Skip to content

Commit 08c61aa

Browse files
author
Oleksandr Dzhychko
authored
Merge pull request #234 from modelix/fix/escape-slashes-in-url-for-branches-and-repositories
Fix/escape slashes in url for branches and repositories
2 parents 37b9f75 + 932e4fc commit 08c61aa

File tree

4 files changed

+66
-8
lines changed

4 files changed

+66
-8
lines changed

model-client/src/commonMain/kotlin/org/modelix/model/client2/ModelClientV2.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import io.ktor.client.request.post
2424
import io.ktor.client.request.setBody
2525
import io.ktor.client.statement.bodyAsText
2626
import io.ktor.http.ContentType
27+
import io.ktor.http.URLBuilder
2728
import io.ktor.http.appendPathSegments
2829
import io.ktor.http.contentType
2930
import io.ktor.http.takeFrom
@@ -90,7 +91,7 @@ class ModelClientV2(
9091
val response = httpClient.post {
9192
url {
9293
takeFrom(baseUrl)
93-
appendPathSegments("repositories", repository.id, "init")
94+
appendPathSegmentsEncodingSlash("repositories", repository.id, "init")
9495
}
9596
}
9697
val delta = response.body<VersionDelta>()
@@ -110,7 +111,7 @@ class ModelClientV2(
110111
return httpClient.get {
111112
url {
112113
takeFrom(baseUrl)
113-
appendPathSegments("repositories", repository.id, "branches")
114+
appendPathSegmentsEncodingSlash("repositories", repository.id, "branches")
114115
}
115116
}.bodyAsText().lines().map { repository.getBranchReference(it) }
116117
}
@@ -138,7 +139,7 @@ class ModelClientV2(
138139
val response = httpClient.post {
139140
url {
140141
takeFrom(baseUrl)
141-
appendPathSegments("repositories", branch.repositoryId.id, "branches", branch.branchName)
142+
appendPathSegmentsEncodingSlash("repositories", branch.repositoryId.id, "branches", branch.branchName)
142143
}
143144
contentType(ContentType.Application.Json)
144145
val body = VersionDelta(version.getContentHash(), null, objectsMap = objects)
@@ -154,7 +155,7 @@ class ModelClientV2(
154155
val response = httpClient.get {
155156
url {
156157
takeFrom(baseUrl)
157-
appendPathSegments("repositories", branch.repositoryId.id, "branches", branch.branchName)
158+
appendPathSegmentsEncodingSlash("repositories", branch.repositoryId.id, "branches", branch.branchName)
158159
if (lastKnownVersion != null) {
159160
parameters["lastKnown"] = lastKnownVersion.hash
160161
}
@@ -170,7 +171,7 @@ class ModelClientV2(
170171
val response = httpClient.get {
171172
url {
172173
takeFrom(baseUrl)
173-
appendPathSegments("repositories", branch.repositoryId.id, "branches", branch.branchName, "poll")
174+
appendPathSegmentsEncodingSlash("repositories", branch.repositoryId.id, "branches", branch.branchName, "poll")
174175
if (lastKnownVersion != null) {
175176
parameters["lastKnown"] = lastKnownVersion.hash
176177
}
@@ -280,5 +281,8 @@ expect class ModelClientV2PlatformSpecificBuilder() : ModelClientV2Builder
280281
fun VersionDelta.checkObjectHashes() {
281282
HashUtil.checkObjectHashes(objectsMap)
282283
}
284+
private fun URLBuilder.appendPathSegmentsEncodingSlash(vararg components: String): URLBuilder {
285+
return appendPathSegments(components.toList(), true)
286+
}
283287

284288
fun VersionDelta.getAllObjects(): Map<String, String> = objectsMap + objects.associateBy { HashUtil.sha256(it) }

model-server/src/main/kotlin/org/modelix/model/server/handlers/RepositoryOverview.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package org.modelix.model.server.handlers
22

3+
import io.ktor.http.encodeURLPathPart
34
import io.ktor.server.application.Application
45
import io.ktor.server.application.call
56
import io.ktor.server.html.respondHtmlTemplate
67
import io.ktor.server.routing.get
78
import io.ktor.server.routing.routing
89
import kotlinx.html.FlowContent
10+
import kotlinx.html.FlowOrInteractiveOrPhrasingContent
911
import kotlinx.html.a
1012
import kotlinx.html.h1
1113
import kotlinx.html.i
@@ -74,9 +76,7 @@ class RepositoryOverview(private val repoManager: RepositoriesManager) {
7476
}
7577
}
7678
td {
77-
a("../history/${branch.repositoryId.id}/${branch.branchName}/") {
78-
+"Show History"
79-
}
79+
buildHistoryLink(branch.repositoryId.id, branch.branchName)
8080
}
8181
td {
8282
val latestVersion = repoManager.getVersion(branch)
@@ -94,3 +94,9 @@ class RepositoryOverview(private val repoManager: RepositoriesManager) {
9494
}
9595
}
9696
}
97+
98+
fun FlowOrInteractiveOrPhrasingContent.buildHistoryLink(repositoryId: String, branchName: String) {
99+
a("../history/${repositoryId.encodeURLPathPart()}/${branchName.encodeURLPathPart()}/") {
100+
+"Show History"
101+
}
102+
}

model-server/src/test/kotlin/org/modelix/model/server/ModelClientV2Test.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,19 @@ class ModelClientV2Test {
8686
setOf(repositoryId.getBranchReference(), branchId),
8787
)
8888
}
89+
90+
@Test
91+
fun testSlashesInPathSegmentsFromRepositoryIdAndBranchId() = runTest {
92+
val url = "http://localhost/v2"
93+
val client = ModelClientV2.builder().url(url).client(client).build()
94+
client.init()
95+
val repositoryId = RepositoryId("repo/v1")
96+
val initialVersion = client.initRepository(repositoryId)
97+
val branchId = repositoryId.getBranchReference("my-branch/v1")
98+
client.push(branchId, initialVersion, null)
99+
assertEquals(
100+
client.listBranches(repositoryId).toSet(),
101+
setOf(repositoryId.getBranchReference(), branchId),
102+
)
103+
}
89104
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2023.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.server.handlers
18+
19+
import kotlinx.html.span
20+
import kotlinx.html.stream.createHTML
21+
import kotlin.test.Test
22+
import kotlin.test.assertEquals
23+
24+
class RepositoryOverviewTest {
25+
26+
@Test
27+
fun testSlashesInPathSegmentsFromRepositoryIdAndBranchId() {
28+
val html = createHTML().span {
29+
buildHistoryLink("repository/v1", "branch/v2")
30+
}
31+
assertEquals("<span><a href=\"../history/repository%2Fv1/branch%2Fv2/\">Show History</a></span>", html)
32+
}
33+
}

0 commit comments

Comments
 (0)