From dfd05be9295497dae153dd7c1f602b439c004ae8 Mon Sep 17 00:00:00 2001 From: Erin Schnabel Date: Thu, 8 Apr 2021 20:24:32 -0400 Subject: [PATCH] micrometer: cors preflight requests --- .../deployment/binder/UriTagCorsTest.java | 104 ++++++++++++++++++ .../runtime/binder/RequestMetricInfo.java | 2 +- .../binder/vertx/HttpRequestMetric.java | 11 ++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/UriTagCorsTest.java diff --git a/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/UriTagCorsTest.java b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/UriTagCorsTest.java new file mode 100644 index 0000000000000..e99d89a1ab1a6 --- /dev/null +++ b/extensions/micrometer/deployment/src/test/java/io/quarkus/micrometer/deployment/binder/UriTagCorsTest.java @@ -0,0 +1,104 @@ +package io.quarkus.micrometer.deployment.binder; + +import static io.restassured.RestAssured.given; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.quarkus.micrometer.test.HelloResource; +import io.quarkus.micrometer.test.Util; +import io.quarkus.micrometer.test.VertxWebEndpoint; +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class UriTagCorsTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withConfigurationResource("test-logging.properties") + .overrideConfigKey("quarkus.micrometer.binder-enabled-default", "false") + .overrideConfigKey("quarkus.micrometer.binder.http-server.enabled", "true") + .overrideConfigKey("quarkus.micrometer.binder.vertx.enabled", "true") + .overrideConfigKey("quarkus.http.cors", "true") + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(Util.class, + VertxWebEndpoint.class, + HelloResource.class)); + + static SimpleMeterRegistry registry = new SimpleMeterRegistry(); + + @BeforeAll + static void setRegistry() { + registry = new SimpleMeterRegistry(); + Metrics.addRegistry(registry); + } + + @AfterAll() + static void removeRegistry() { + Metrics.removeRegistry(registry); + } + + @Test + public void testCORSPreflightRequest() { + String origin = "http://custom.origin.quarkus"; + String methods = "GET,POST"; + String headers = "X-Custom"; + RestAssured.given() + .header("Origin", origin) + .header("Access-Control-Request-Method", methods) + .header("Access-Control-Request-Headers", headers) + .when().options("/hello/world").then() + .header("Access-Control-Allow-Origin", origin) + .header("Access-Control-Allow-Methods", methods) + .header("Access-Control-Allow-Headers", headers) + .statusCode(200); + + RestAssured.given() + .header("Origin", origin) + .header("Access-Control-Request-Method", methods) + .header("Access-Control-Request-Headers", headers) + .when().options("/vertx/echo/anything").then() + .header("Access-Control-Allow-Origin", origin) + .header("Access-Control-Allow-Methods", methods) + .header("Access-Control-Allow-Headers", headers) + .statusCode(200); + + RestAssured.given() + .header("Origin", origin) + .header("Access-Control-Request-Method", methods) + .header("Access-Control-Request-Headers", headers) + .when().options("/vertx/item/123").then() + .header("Access-Control-Allow-Origin", origin) + .header("Access-Control-Allow-Methods", methods) + .header("Access-Control-Allow-Headers", headers) + .statusCode(200); + + RestAssured.given() + .when().options("/vertx/echo/anything").then() + .statusCode(200); + + RestAssured.given() + .when().options("/hello/world").then() + .statusCode(200); + + // CORS pre-flight + Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/cors-preflight").timers().size(), + Util.foundServerRequests(registry, "/cors-preflight should be used for preflight requests")); + Timer t = registry.find("http.server.requests").tag("uri", "/cors-preflight").timer(); + Assertions.assertEquals(3, t.count(), "/cors-preflight checked twice"); + + // Normal OPTIONS requests + Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/vertx/echo/{msg}").timers().size(), + Util.foundServerRequests(registry, "/vertx/echo/{msg} for options request")); + Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/hello/{message}").timers().size(), + Util.foundServerRequests(registry, "/hello/{message} for options request")); + } +} diff --git a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/RequestMetricInfo.java b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/RequestMetricInfo.java index cb1f35eb4b0cc..2bede135ed28c 100644 --- a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/RequestMetricInfo.java +++ b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/RequestMetricInfo.java @@ -69,7 +69,7 @@ static String applyMatchPatterns(String path, Map matchPatterns } /** Return path or null if it should be ignored */ - static String filterIgnored(String path, List ignorePatterns) { + protected static String filterIgnored(String path, List ignorePatterns) { if (!ignorePatterns.isEmpty()) { for (Pattern p : ignorePatterns) { if (p.matcher(path).matches()) { diff --git a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/vertx/HttpRequestMetric.java b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/vertx/HttpRequestMetric.java index 6007d64068554..ee702023033aa 100644 --- a/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/vertx/HttpRequestMetric.java +++ b/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/vertx/HttpRequestMetric.java @@ -6,6 +6,7 @@ import java.util.regex.Pattern; import io.quarkus.micrometer.runtime.binder.RequestMetricInfo; +import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpServerRequest; import io.vertx.ext.web.RoutingContext; @@ -31,6 +32,9 @@ public HttpRequestMetric(HttpServerRequest request) { } public String getNormalizedUriPath(Map matchPatterns, List ignorePatterns) { + if (isCORSPreflightRequest()) { + return filterIgnored("/cors-preflight", ignorePatterns); + } return super.getNormalizedUriPath(matchPatterns, ignorePatterns, initialPath); } @@ -85,4 +89,11 @@ public String toString() { return "HttpRequestMetric [initialPath=" + initialPath + ", currentRoutePath=" + getCurrentRoute() + ", templatePath=" + templatePath + ", request=" + request + "]"; } + + private boolean isCORSPreflightRequest() { + return request.method() == HttpMethod.OPTIONS + && request.getHeader("Origin") != null + && request.getHeader("Access-Control-Request-Method") != null + && request.getHeader("Access-Control-Request-Headers") != null; + } }