From edb37b383fca554b9629a643e8a9c5f77fb763b6 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Fri, 10 Apr 2020 01:29:22 +0100 Subject: [PATCH] Add head request for gradle download (#165) --- .editorconfig | 8 +- .github/workflows/build.yml | 4 +- .../api/v3/routes/BinaryResource.kt | 80 +++++++++++++++++-- .../net/adoptopenjdk/api/BinaryPathTest.kt | 38 +++++++++ 4 files changed, 118 insertions(+), 12 deletions(-) diff --git a/.editorconfig b/.editorconfig index e9c04d2a..3039179b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,9 +4,9 @@ end_of_line = lf indent_size = 4 indent_style = space insert_final_newline = true -max_line_length = false +max_line_length = 9999 tab_width = 4 -ij_continuation_indent_size = 8 +ij_continuation_indent_size = 4 ij_formatter_off_tag = @formatter:off ij_formatter_on_tag = @formatter:on ij_formatter_tags_enabled = false @@ -871,7 +871,7 @@ ij_kotlin_align_multiline_binary_operation = false ij_kotlin_align_multiline_extends_list = false ij_kotlin_align_multiline_method_parentheses = false ij_kotlin_align_multiline_parameters = true -ij_kotlin_align_multiline_parameters_in_calls = true +ij_kotlin_align_multiline_parameters_in_calls = false ij_kotlin_assignment_wrap = off ij_kotlin_blank_lines_after_class_header = 0 ij_kotlin_blank_lines_around_block_when_branches = 0 @@ -941,7 +941,7 @@ ij_kotlin_wrap_elvis_expressions = 1 ij_kotlin_wrap_expression_body_functions = 0 ij_kotlin_wrap_first_method_in_call_chain = false -disabled_rules=no-wildcard-imports,import-ordering +disabled_rules=no-wildcard-imports,import-ordering,final-newline [{*.gson,*.gradle,*.groovy,*.gdsl,*.gy,*.gant}] ij_groovy_align_group_field_declarations = false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 14f28887..38b4213c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,13 +14,13 @@ jobs: java-package: jdk architecture: x64 - uses: actions/checkout@v1 + - name: ktlint + run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.35.0/ktlint && chmod a+x ktlint && ./ktlint - name: Build app run: ./mvnw clean install jacoco:report jacoco:report-aggregate - uses: codecov/codecov-action@v1 with: token: ${{ secrets.CODECOV_TOKEN }} - - name: ktlint - run: curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.35.0/ktlint && chmod a+x ktlint && ./ktlint - name: Extract openapi doc run: cd adoptopenjdk-api-v3-frontend && unzip target/adoptopenjdk-api-v3-frontend-*-runner.jar META-INF/quarkus-generated-openapi-doc.YAML - name: diff --git a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/BinaryResource.kt b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/BinaryResource.kt index 588fdc0f..5fc85602 100644 --- a/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/BinaryResource.kt +++ b/adoptopenjdk-api-v3-frontend/src/main/kotlin/net/adoptopenjdk/api/v3/routes/BinaryResource.kt @@ -27,9 +27,13 @@ import org.jboss.resteasy.annotations.jaxrs.PathParam import org.jboss.resteasy.annotations.jaxrs.QueryParam import java.net.URI import javax.ws.rs.GET +import javax.ws.rs.HEAD +import javax.ws.rs.HeaderParam import javax.ws.rs.Path import javax.ws.rs.Produces +import javax.ws.rs.core.Context import javax.ws.rs.core.MediaType +import javax.ws.rs.core.Request import javax.ws.rs.core.Response @Tag(name = "Binary") @@ -38,6 +42,7 @@ import javax.ws.rs.core.Response class BinaryResource { @GET + @HEAD @Path("/version/{release_name}/{os}/{arch}/{image_type}/{jvm_impl}/{heap_size}/{vendor}") @Produces("application/octet-stream") @Operation(summary = "Redirects to the binary that matches your current query", description = "Redirects to the binary that matches your current query") @@ -57,7 +62,7 @@ class BinaryResource { arch: Architecture?, @Parameter(name = "release_name", description = OpenApiDocs.RELASE_NAME, required = true, - schema = Schema(defaultValue = "jdk-11.0.6+10", type = SchemaType.STRING) + schema = Schema(defaultValue = "jdk-11.0.6+10", type = SchemaType.STRING) ) @PathParam("release_name") release_name: String?, @@ -80,13 +85,74 @@ class BinaryResource { @Parameter(name = "project", description = "Project", schema = Schema(defaultValue = "jdk", enumeration = ["jdk", "valhalla", "metropolis", "jfr"], required = false), required = false) @QueryParam("project") + project: Project?, + + @Context + request: Request, + + @HeaderParam("User-Agent") + userAgent: String + ): Response { + return when (request.method) { + "HEAD" -> versionHead(userAgent, release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project) + else -> versionGet(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project) + } + } + + private fun versionGet( + release_name: String?, + vendor: Vendor?, + os: OperatingSystem?, + arch: Architecture?, + image_type: ImageType?, + jvm_impl: JvmImpl?, + heap_size: HeapSize?, project: Project? + ): Response { + return getBinary(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project) { `package` -> + Response.temporaryRedirect(URI.create(`package`.link)).build() + } + } + + private fun versionHead( + userAgent: String, + release_name: String?, + vendor: Vendor?, + os: OperatingSystem?, + arch: Architecture?, + image_type: ImageType?, + jvm_impl: JvmImpl?, + heap_size: HeapSize?, + project: Project? + ): Response { + return if (userAgent.contains("Gradle")) { + getBinary(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project) { `package` -> + Response.status(200) + .header("size", `package`.size) + .header("content-disposition", """attachment; filename="${`package`.name}"; filename*=UTF-8''${`package`.name}""") + .build() + } + } else { + versionGet(release_name, vendor, os, arch, image_type, jvm_impl, heap_size, project) + } + } + + private fun getBinary( + release_name: String?, + vendor: Vendor?, + os: OperatingSystem?, + arch: Architecture?, + image_type: ImageType?, + jvm_impl: JvmImpl?, + heap_size: HeapSize?, + project: Project?, + createResponse: (net.adoptopenjdk.api.v3.models.Package) -> Response ): Response { val releaseFilter = ReleaseFilter(releaseName = release_name, vendor = vendor) val binaryFilter = BinaryFilter(os, arch, image_type, jvm_impl, heap_size, project) val releases = APIDataStore.getAdoptRepos().getFilteredReleases(releaseFilter, binaryFilter, SortOrder.DESC).toList() - return formResponse(releases) + return formResponse(releases, createResponse) } @GET @@ -101,7 +167,7 @@ class BinaryResource { ) fun returnBinary( @Parameter(name = "feature_version", description = OpenApiDocs.FEATURE_RELEASE, required = true, - schema = Schema(defaultValue = "8", type = SchemaType.INTEGER) + schema = Schema(defaultValue = "8", type = SchemaType.INTEGER) ) @PathParam("feature_version") version: Int?, @@ -152,10 +218,12 @@ class BinaryResource { val release = releases.sortedWith(comparator).lastOrNull() - return formResponse(if (release == null) emptyList() else listOf(release)) + return formResponse(if (release == null) emptyList() else listOf(release)) { `package` -> + Response.temporaryRedirect(URI.create(`package`.link)).build() + } } - private fun formResponse(releases: List): Response { + private fun formResponse(releases: List, createResponse: (net.adoptopenjdk.api.v3.models.Package) -> Response): Response { if (releases.size == 0) { return formErrorResponse(Response.Status.NOT_FOUND, "No releases match the request") } else if (releases.size > 1) { @@ -174,7 +242,7 @@ class BinaryResource { val names = packages.map { it.name } return formErrorResponse(Response.Status.BAD_REQUEST, "Multiple binaries match request: $names") } else { - return Response.temporaryRedirect(URI.create(packages.first().link)).build() + return createResponse(packages.first()) } } } diff --git a/adoptopenjdk-api-v3-frontend/src/test/kotlin/net/adoptopenjdk/api/BinaryPathTest.kt b/adoptopenjdk-api-v3-frontend/src/test/kotlin/net/adoptopenjdk/api/BinaryPathTest.kt index 3189f58a..328286af 100644 --- a/adoptopenjdk-api-v3-frontend/src/test/kotlin/net/adoptopenjdk/api/BinaryPathTest.kt +++ b/adoptopenjdk-api-v3-frontend/src/test/kotlin/net/adoptopenjdk/api/BinaryPathTest.kt @@ -99,6 +99,44 @@ class BinaryPathTest : BaseTest() { .statusCode(404) } + @Test + fun gradleHeadRequestToVersionGives200() { + val path = getVersionPath("jdk8u212-b04", OperatingSystem.linux, Architecture.x64, ImageType.jdk, JvmImpl.hotspot, HeapSize.normal, Vendor.adoptopenjdk, Project.jdk) + + RestAssured.given() + .`when`() + .header("user-agent", "Gradle") + .head(path) + .then() + .statusCode(200) + .header("size", Matchers.equalTo("104366847")) + .header("content-disposition", Matchers.equalTo("""attachment; filename="OpenJDK8U-jdk_x64_linux_hotspot_8u212b04.tar.gz"; filename*=UTF-8''OpenJDK8U-jdk_x64_linux_hotspot_8u212b04.tar.gz""")) + } + + @Test + fun nonGradleHeadRequestToVersionGives307() { + val path = getVersionPath("jdk8u212-b04", OperatingSystem.linux, Architecture.x64, ImageType.jdk, JvmImpl.hotspot, HeapSize.normal, Vendor.adoptopenjdk, Project.jdk) + + RestAssured.given() + .`when`() + .redirects().follow(false) + .head(path) + .then() + .statusCode(307) + } + + @Test + fun nonExistantHeadVersionRequestGives404() { + val path = getVersionPath("fooBar", OperatingSystem.linux, Architecture.x64, ImageType.jdk, JvmImpl.hotspot, HeapSize.normal, Vendor.adoptopenjdk, Project.jdk) + + RestAssured.given() + .`when`() + .header("user-agent", "Gradle") + .head(path) + .then() + .statusCode(404) + } + private fun performRequest(path: String): Response { return RestAssured.given() .`when`()