Skip to content

Commit

Permalink
Introduce caching of ResteasyUriInfo.InitData
Browse files Browse the repository at this point in the history
This is done because the computation of the data is expensive

Relates to: #4345
  • Loading branch information
geoand committed Oct 15, 2019
1 parent 235ed78 commit 653e617
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public void staticInit(ResteasyStandaloneRecorder recorder,
rootPath = httpBuildTimeConfig.rootPath + rootPath;
}
Set<String> knownPaths = getClasspathResources(applicationArchivesBuildItem);
recorder.staticInit(deployment.getDeployment(), rootPath, knownPaths);
recorder.staticInit(deployment.getDeployment(), rootPath, knownPaths, 100); // TODO we should set this via config
standalone.produce(new ResteasyStandaloneBuildItem());

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,14 @@ public static void setHotDeploymentResources(List<Path> resources) {
private static ResteasyDeployment deployment;
private static Set<String> knownPaths;
private static String contextPath;
private static int resteasyUriInfoCacheMaxSize;

public void staticInit(ResteasyDeployment dep, String path, Set<String> known) {
public void staticInit(ResteasyDeployment dep, String path, Set<String> known, int uriInfoCacheMaxSize) {
deployment = dep;
deployment.start();
knownPaths = known;
contextPath = path;
resteasyUriInfoCacheMaxSize = uriInfoCacheMaxSize;
}

public Consumer<Route> start(RuntimeValue<Vertx> vertxValue,
Expand Down Expand Up @@ -130,7 +132,8 @@ public void run() {
});
}

VertxRequestHandler requestHandler = new VertxRequestHandler(vertx, beanContainer, deployment, contextPath, ALLOCATOR);
VertxRequestHandler requestHandler = new VertxRequestHandler(vertx, beanContainer, deployment, contextPath,
resteasyUriInfoCacheMaxSize, ALLOCATOR);

handlers.add(requestHandler);
return new Consumer<Route>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -35,20 +37,25 @@ public class VertxRequestHandler implements Handler<RoutingContext> {
protected final Vertx vertx;
protected final RequestDispatcher dispatcher;
protected final String servletMappingPrefix;
protected final int resteasyUriInfoCacheMaxSize;
protected final BufferAllocator allocator;
protected final BeanContainer beanContainer;
protected final CurrentIdentityAssociation association;

private final Map<String, ResteasyUriInfo.InitData> resteasyUriInfoInitDataMap = new ConcurrentHashMap<>();;

public VertxRequestHandler(Vertx vertx,
BeanContainer beanContainer,
ResteasyDeployment deployment,
String servletMappingPrefix,
int resteasyUriInfoCacheMaxSize,
BufferAllocator allocator) {
this.vertx = vertx;
this.beanContainer = beanContainer;
this.dispatcher = new RequestDispatcher((SynchronousDispatcher) deployment.getDispatcher(),
deployment.getProviderFactory(), null);
this.servletMappingPrefix = servletMappingPrefix;
this.resteasyUriInfoCacheMaxSize = resteasyUriInfoCacheMaxSize;
this.allocator = allocator;
Instance<CurrentIdentityAssociation> association = CDI.current().select(CurrentIdentityAssociation.class);
this.association = association.isResolvable() ? association.get() : null;
Expand Down Expand Up @@ -90,7 +97,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) && resteasyUriInfoCacheMaxSize > 0) {
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(),
Expand All @@ -114,6 +136,19 @@ 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) {
// we don't want the cache to grow unbounded since values path params could potentially be infinite
// and if left unchecked would take up all memory if the application is up for long enough
if (resteasyUriInfoInitDataMap.size() > resteasyUriInfoCacheMaxSize) {
resteasyUriInfoInitDataMap.clear(); // this is super lame and should probably be revisited
}
// 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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<String, ResteasyUriInfo.InitData> 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) {
Expand Down

0 comments on commit 653e617

Please sign in to comment.