From 6c832bde60c1d7c819be0dc7cf4149e7b7c8beb6 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 15 Oct 2019 10:49:06 +0300 Subject: [PATCH] Introduce caching of ResteasyUriInfo.InitData This is done because the computation of the data is expensive Relates to: #4345 --- .../standalone/VertxRequestHandler.java | 29 ++++++++++++++++++- .../runtime/standalone/VertxUtil.java | 13 +++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/extensions/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxRequestHandler.java b/extensions/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxRequestHandler.java index a8e67a580b994c..d12bb06bfd2cf9 100644 --- a/extensions/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxRequestHandler.java +++ b/extensions/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxRequestHandler.java @@ -2,6 +2,8 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import javax.enterprise.inject.Instance; import javax.enterprise.inject.spi.CDI; @@ -39,6 +41,8 @@ public class VertxRequestHandler implements Handler { protected final BeanContainer beanContainer; protected final CurrentIdentityAssociation association; + private final Map resteasyUriInfoInitDataMap = new ConcurrentHashMap<>(); + public VertxRequestHandler(Vertx vertx, BeanContainer beanContainer, ResteasyDeployment deployment, @@ -90,7 +94,22 @@ private void dispatch(RoutingContext routingContext, InputStream is, VertxOutput try { Context ctx = vertx.getOrCreateContext(); HttpServerRequest request = routingContext.request(); - ResteasyUriInfo uriInfo = VertxUtil.extractUriInfo(request, servletMappingPrefix); + + String uriString = VertxUtil.getUriString(request); + ResteasyUriInfo.InitData resteasyUriInfoCachedInitData = null; + boolean setInitDataUponSuccess = false; + if (ResteasyUriInfo.InitData.canBeCached(uriString)) { + String cacheKey = ResteasyUriInfo.InitData.getCacheKey(uriString, servletMappingPrefix); + resteasyUriInfoCachedInitData = resteasyUriInfoInitDataMap.get(cacheKey); + if (resteasyUriInfoCachedInitData == null) { + setInitDataUponSuccess = true; + } + } + if (resteasyUriInfoCachedInitData == null) { + resteasyUriInfoCachedInitData = new ResteasyUriInfo.InitData(uriString, servletMappingPrefix); + } + + ResteasyUriInfo uriInfo = new ResteasyUriInfo(uriString, servletMappingPrefix, resteasyUriInfoCachedInitData); ResteasyHttpHeaders headers = VertxUtil.extractHttpHeaders(request); HttpServerResponse response = request.response(); VertxHttpResponse vertxResponse = new VertxHttpResponse(request, dispatcher.getProviderFactory(), @@ -114,6 +133,14 @@ private void dispatch(RoutingContext routingContext, InputStream is, VertxOutput if (!vertxRequest.getAsyncContext().isSuspended()) { try { vertxResponse.finish(); + // the reason we only cache successful responses is to ensure that a torrent of erroneous URLs + // doesn't fill up the cache and cause a DoS + if (setInitDataUponSuccess && vertxResponse.getStatus() >= 200 && vertxResponse.getStatus() <= 300) { + // this could potentially be written multiple times for initial requests but it doesn't matter + // since the data is always the same + resteasyUriInfoInitDataMap.put(ResteasyUriInfo.InitData.getCacheKey(uriString, servletMappingPrefix), + resteasyUriInfoCachedInitData); + } } catch (IOException e) { log.error("Unexpected failure", e); } diff --git a/extensions/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxUtil.java b/extensions/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxUtil.java index 83ae68924659ad..28ddc772b14512 100644 --- a/extensions/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxUtil.java +++ b/extensions/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxUtil.java @@ -27,7 +27,7 @@ public class VertxUtil { private static final Pattern COMMA_PATTERN = Pattern.compile(","); - public static ResteasyUriInfo extractUriInfo(HttpServerRequest req, String contextPath) { + public static String getUriString(HttpServerRequest req) { String uri = req.absoluteURI(); String protocol = req.scheme(); @@ -44,7 +44,16 @@ public static ResteasyUriInfo extractUriInfo(HttpServerRequest req, String conte uriString = protocol + "://" + host + uri; } - return new ResteasyUriInfo(uriString, contextPath); + return uriString; + } + + public static ResteasyUriInfo.InitData extractUriInfoInitData(String uriString, String contextPath, + Map resteasyUriInfoInitDataMap) { + if (ResteasyUriInfo.InitData.canBeCached(uriString)) { + String cacheKey = ResteasyUriInfo.InitData.getCacheKey(uriString, contextPath); + return resteasyUriInfoInitDataMap.get(cacheKey); + } + return null; } public static ResteasyHttpHeaders extractHttpHeaders(HttpServerRequest request) {