Skip to content

Commit

Permalink
New rest api path schema in OciRepositoryHandler
Browse files Browse the repository at this point in the history
- replace base64 encoding of registryUrl, imageName and imageReference with escaping only slashes

previous schema:
/v0.11/<base64(registryUrl)> / <group>/<name>/<version> / <...>.module
/v0.11/<base64(registryUrl)> / <group>/<name>/<version> / <base64(imageReference)>/<digest>/<size>/<base64(capabilities)>/<...>oci-component.json
/v0.11/<base64(registryUrl)> / <group>/<name>/<version> / <base64(imageName)>/<digest>/<size>/<...>oci-layer

new schema:
/v0.11/<base64(registryUrl)> / <group>/<name>/<version> / <...>.module
/v0.11/<escapeSlash(registryUrl)> / <group>/<name>/<version> / <escapeSlash(imageReference)>/<digest>/<size>/<base64(capabilities)>/<...>oci-component.json
/v0.11/<escapeSlash(registryUrl)> / <group>/<name>/<version> / <escapeSlash(imageName)>/<digest>/<size>/<...>oci-layer
  • Loading branch information
SgtSilvio committed Jun 17, 2024
1 parent d30593b commit 7e35514
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import io.github.sgtsilvio.gradle.oci.internal.gradle.optionalPasswordCredential
import io.github.sgtsilvio.gradle.oci.internal.gradle.passwordCredentials
import io.github.sgtsilvio.gradle.oci.internal.reactor.netty.OciLoopResources
import io.github.sgtsilvio.gradle.oci.internal.reactor.netty.OciRegistryHttpClient
import io.github.sgtsilvio.gradle.oci.internal.registry.Credentials
import io.github.sgtsilvio.gradle.oci.internal.registry.OciComponentRegistry
import io.github.sgtsilvio.gradle.oci.internal.registry.OciRegistryApi
import io.github.sgtsilvio.gradle.oci.internal.registry.OciRepositoryHandler
import io.github.sgtsilvio.gradle.oci.internal.registry.*
import io.github.sgtsilvio.gradle.oci.mapping.OciImageMappingData
import io.github.sgtsilvio.gradle.oci.mapping.OciImageMappingImpl
import io.netty.buffer.UnpooledByteBufAllocator
Expand All @@ -22,6 +19,7 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.ResolvableDependencies
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.artifacts.repositories.IvyArtifactRepository
import org.gradle.api.credentials.HttpHeaderCredentials
import org.gradle.api.credentials.PasswordCredentials
import org.gradle.api.model.ObjectFactory
Expand All @@ -41,7 +39,6 @@ import reactor.netty.http.server.HttpServerRequest
import reactor.netty.http.server.HttpServerResponse
import java.net.InetSocketAddress
import java.net.URI
import java.util.*
import java.util.function.BiFunction
import javax.inject.Inject

Expand Down Expand Up @@ -124,11 +121,11 @@ internal abstract class OciRegistryImpl @Inject constructor(
final override val finalUrl: Provider<URI> =
providerFactory.gradleProperty(url.map(URI::toString)).map(::URI).orElse(url)
final override val credentials = objectFactory.property<PasswordCredentials>()
final override val repository = repositoryHandler.ivy {
final override val repository: IvyArtifactRepository = repositoryHandler.ivy {
name = this@OciRegistryImpl.name + "OciRegistry"
setUrl(finalUrl.zip(registries.repositoryPort) { url, repositoryPort ->
val urlBase64 = Base64.getUrlEncoder().encodeToString(url.toString().toByteArray())
URI("http://localhost:$repositoryPort/v0.11/$urlBase64")
val escapedUrl = url.toString().escapePathSegment()
URI("http://localhost:$repositoryPort/v0.11/$escapedUrl")
})
isAllowInsecureProtocol = true
layout("gradle")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ import java.util.function.BiFunction
/v2/repository/<base64(registryUrl)> / <group>/<name>/<version> / <variantName>/<digest>/<size>/<...>oci-layer
/v0.11/<base64(registryUrl)> / <group>/<name>/<version> / <...>.module
/v0.11/<base64(registryUrl)> / <group>/<name>/<version> / <base64(imageReference)>/<digest>/<size>/<base64(capabilities)>/<...>oci-component.json
/v0.11/<base64(registryUrl)> / <group>/<name>/<version> / <base64(imageName)>/<digest>/<size>/<...>oci-layer
/v0.11/<escapeSlash(registryUrl)> / <group>/<name>/<version> / <escapeSlash(imageReference)>/<digest>/<size>/<base64(capabilities)>/<...>oci-component.json
/v0.11/<escapeSlash(registryUrl)> / <group>/<name>/<version> / <escapeSlash(imageName)>/<digest>/<size>/<...>oci-layer
*/

/**
Expand Down Expand Up @@ -87,7 +87,7 @@ internal class OciRepositoryHandler(
response.sendNotFound()
}
val registryUri = try {
URI(Base64.getUrlDecoder().decode(segments[0]).decodeToString())
URI(segments[0].unescapePathSegment())
} catch (e: IllegalArgumentException) {
return response.sendBadRequest()
} catch (e: URISyntaxException) {
Expand Down Expand Up @@ -116,7 +116,7 @@ internal class OciRepositoryHandler(
return response.sendNotFound()
}
val imageReference = try {
Base64.getUrlDecoder().decode(segments[4]).decodeToString().toOciImageReference()
segments[4].unescapePathSegment().toOciImageReference()
} catch (e: IllegalArgumentException) {
return response.sendBadRequest()
}
Expand Down Expand Up @@ -157,7 +157,7 @@ internal class OciRepositoryHandler(
return response.sendNotFound()
}
val imageName = try {
Base64.getUrlDecoder().decode(segments[4]).decodeToString()
segments[4].unescapePathSegment()
} catch (e: IllegalArgumentException) {
return response.sendBadRequest()
}
Expand Down Expand Up @@ -219,17 +219,17 @@ internal class OciRepositoryHandler(
addObject {
val componentJson = component.encodeToJsonString().toByteArray()
val componentName = "$fileNamePrefix-${createOciComponentClassifier(variantName)}.json"
val imageReferenceBase64 = Base64.getUrlEncoder().encodeToString(component.imageReference.toString().toByteArray())
val escapedImageReference = component.imageReference.toString().escapePathSegment()
val capabilitiesBase64 = Base64.getUrlEncoder().encodeToString(jsonArray { encodeCapabilities(component.capabilities) }.toByteArray())
addString("name", componentName)
addString("url", "$imageReferenceBase64/$componentDigest/$componentSize/$capabilitiesBase64/$componentName")
addString("url", "$escapedImageReference/$componentDigest/$componentSize/$capabilitiesBase64/$componentName")
addNumber("size", componentJson.size.toLong())
addString("sha512", DigestUtils.sha512Hex(componentJson))
addString("sha256", DigestUtils.sha256Hex(componentJson))
addString("sha1", DigestUtils.sha1Hex(componentJson))
addString("md5", DigestUtils.md5Hex(componentJson))
}
val imageNameBase64 = Base64.getUrlEncoder().encodeToString(component.imageReference.name.toByteArray())
val escapedImageName = component.imageReference.name.escapePathSegment()
for ((mediaType, digest, size) in component.allLayerDescriptors.distinctBy { it.digest }) {
addObject {
val algorithmId = digest.algorithm.id
Expand All @@ -240,7 +240,7 @@ internal class OciRepositoryHandler(
)
val layerName = "$fileNamePrefix-$classifier"
addString("name", layerName + mapLayerMediaTypeToExtension(mediaType))
addString("url", "$imageNameBase64/$digest/$size/$layerName")
addString("url", "$escapedImageName/$digest/$size/$layerName")
addNumber("size", size)
addString(algorithmId, encodedHash)
}
Expand Down Expand Up @@ -351,3 +351,7 @@ internal fun JsonArrayStringBuilder.encodeCapabilities(capabilities: SortedSet<V
}

internal fun JsonArray.decodeCapabilities() = toSet(TreeSet()) { asObject().decodeVersionedCoordinates() }

internal fun String.escapePathSegment() = replace("$", "$0").replace("/", "$1")

internal fun String.unescapePathSegment() = replace("$1", "/").replace("$0", "$")

0 comments on commit 7e35514

Please sign in to comment.