From b375f9fac06214eab3cbb3b4b739d2063a3f7260 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Oct 2021 12:22:29 +0100 Subject: [PATCH] Ignore parameters when checking if */* is accepted Previously the parameters were not ignored so */*;q=0.8 was not identified as accepting */*. As a result, the most recent producible content type was returned rather than the default. This commit updates the argument resolver to ignore parameters. The default content type is now produced in response to a request that accepts */*, irrespective of its parameters. Fixes gh-28446 --- .../ProducibleOperationArgumentResolver.java | 10 +++------- .../PrometheusScrapeEndpointIntegrationTests.java | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ProducibleOperationArgumentResolver.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ProducibleOperationArgumentResolver.java index 6e9b639a2f88..75a76f787aff 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ProducibleOperationArgumentResolver.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ProducibleOperationArgumentResolver.java @@ -65,7 +65,7 @@ private Enum> resolveProducible(Class> result = null; for (String accept : accepts) { for (String mimeType : MimeTypeUtils.tokenize(accept)) { - result = mostRecent(result, forMimeType(values, mimeType)); + result = mostRecent(result, forMimeType(values, MimeTypeUtils.parseMimeType(mimeType))); } } return result; @@ -78,14 +78,10 @@ private Enum> mostRecent(Enum> e return (candidateOrdinal > existingOrdinal) ? candidate : existing; } - private Enum> forMimeType(List>> values, String mimeType) { - if ("*/*".equals(mimeType)) { + private Enum> forMimeType(List>> values, MimeType mimeType) { + if (mimeType.isWildcardType() && mimeType.isWildcardSubtype()) { return getDefaultValue(values); } - return forMimeType(values, MimeTypeUtils.parseMimeType(mimeType)); - } - - private Enum> forMimeType(List>> values, MimeType mimeType) { for (Enum> candidate : values) { if (mimeType.isCompatibleWith(((Producible) candidate).getProducedMimeType())) { return candidate; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpointIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpointIntegrationTests.java index dbce312303bb..1265d82106ff 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpointIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpointIntegrationTests.java @@ -41,12 +41,25 @@ class PrometheusScrapeEndpointIntegrationTests { @WebEndpointTest void scrapeHasContentTypeText004ByDefault(WebTestClient client) { + String expectedContentType = TextFormat.CONTENT_TYPE_004; + assertThat(TextFormat.chooseContentType(null)).isEqualTo(expectedContentType); client.get().uri("/actuator/prometheus").exchange().expectStatus().isOk().expectHeader() - .contentType(MediaType.parseMediaType(TextFormat.CONTENT_TYPE_004)).expectBody(String.class) + .contentType(MediaType.parseMediaType(expectedContentType)).expectBody(String.class) .value((body) -> assertThat(body).contains("counter1_total").contains("counter2_total") .contains("counter3_total")); } + @WebEndpointTest + void scrapeHasContentTypeText004ByDefaultWhenClientAcceptsWildcardWithParameter(WebTestClient client) { + String expectedContentType = TextFormat.CONTENT_TYPE_004; + String accept = "*/*;q=0.8"; + assertThat(TextFormat.chooseContentType(accept)).isEqualTo(expectedContentType); + client.get().uri("/actuator/prometheus").accept(MediaType.parseMediaType(accept)).exchange().expectStatus() + .isOk().expectHeader().contentType(MediaType.parseMediaType(expectedContentType)) + .expectBody(String.class).value((body) -> assertThat(body).contains("counter1_total") + .contains("counter2_total").contains("counter3_total")); + } + @WebEndpointTest void scrapeCanProduceOpenMetrics100(WebTestClient client) { MediaType openMetrics = MediaType.parseMediaType(TextFormat.CONTENT_TYPE_OPENMETRICS_100);