use of io.quarkus.vertx.http.runtime.filters.GracefulShutdownFilter in project quarkus by quarkusio.
the class VertxHttpProcessor method finalizeRouter.
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
ServiceStartBuildItem finalizeRouter(VertxHttpRecorder recorder, BeanContainerBuildItem beanContainer, CoreVertxBuildItem vertx, LaunchModeBuildItem launchMode, List<DefaultRouteBuildItem> defaultRoutes, List<FilterBuildItem> filters, VertxWebRouterBuildItem httpRouteRouter, HttpRootPathBuildItem httpRootPathBuildItem, NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem, HttpBuildTimeConfig httpBuildTimeConfig, List<RequireBodyHandlerBuildItem> requireBodyHandlerBuildItems, BodyHandlerBuildItem bodyHandlerBuildItem, BuildProducer<ShutdownListenerBuildItem> shutdownListenerBuildItemBuildProducer, ShutdownConfig shutdownConfig, LiveReloadConfig lrc, // Injected to be sure that Vert.x has been produced before calling this method.
CoreVertxBuildItem core, ExecutorBuildItem executorBuildItem) throws BuildException, IOException {
Optional<DefaultRouteBuildItem> defaultRoute;
if (defaultRoutes == null || defaultRoutes.isEmpty()) {
defaultRoute = Optional.empty();
} else {
if (defaultRoutes.size() > 1) {
// this should never happen
throw new BuildException("Too many default routes.", Collections.emptyList());
} else {
defaultRoute = Optional.of(defaultRoutes.get(0));
}
}
HttpRemoteDevClientProvider.liveReloadConfig = lrc;
GracefulShutdownFilter gracefulShutdownFilter = recorder.createGracefulShutdownHandler();
shutdownListenerBuildItemBuildProducer.produce(new ShutdownListenerBuildItem(gracefulShutdownFilter));
List<Filter> listOfFilters = filters.stream().filter(f -> f.getHandler() != null).map(FilterBuildItem::toFilter).collect(Collectors.toList());
// if the body handler is required then we know it is installed for all routes, so we don't need to register it here
Handler<RoutingContext> bodyHandler = !requireBodyHandlerBuildItems.isEmpty() ? bodyHandlerBuildItem.getHandler() : null;
Optional<RuntimeValue<Router>> mainRouter = httpRouteRouter.getMainRouter() != null ? Optional.of(httpRouteRouter.getMainRouter()) : Optional.empty();
if (httpRouteRouter.getFrameworkRouter() != null) {
if (nonApplicationRootPathBuildItem.isAttachedToMainRouter()) {
// Mount nested framework router
recorder.mountFrameworkRouter(httpRouteRouter.getHttpRouter(), httpRouteRouter.getFrameworkRouter(), nonApplicationRootPathBuildItem.getVertxRouterPath());
} else {
// Create main router, not mounted under application router
if (!mainRouter.isPresent()) {
mainRouter = Optional.of(recorder.initializeRouter(vertx.getVertx()));
}
// Mount independent framework router under new main router
recorder.mountFrameworkRouter(mainRouter.get(), httpRouteRouter.getFrameworkRouter(), nonApplicationRootPathBuildItem.getVertxRouterPath());
}
}
recorder.finalizeRouter(beanContainer.getValue(), defaultRoute.map(DefaultRouteBuildItem::getRoute).orElse(null), listOfFilters, vertx.getVertx(), lrc, mainRouter, httpRouteRouter.getHttpRouter(), httpRouteRouter.getMutinyRouter(), httpRootPathBuildItem.getRootPath(), launchMode.getLaunchMode(), !requireBodyHandlerBuildItems.isEmpty(), bodyHandler, gracefulShutdownFilter, shutdownConfig, executorBuildItem.getExecutorProxy());
return new ServiceStartBuildItem("vertx-http");
}
use of io.quarkus.vertx.http.runtime.filters.GracefulShutdownFilter in project quarkus by quarkusio.
the class VertxHttpRecorder method finalizeRouter.
public void finalizeRouter(BeanContainer container, Consumer<Route> defaultRouteHandler, List<Filter> filterList, Supplier<Vertx> vertx, LiveReloadConfig liveReloadConfig, Optional<RuntimeValue<Router>> mainRouterRuntimeValue, RuntimeValue<Router> httpRouterRuntimeValue, RuntimeValue<io.vertx.mutiny.ext.web.Router> mutinyRouter, String rootPath, LaunchMode launchMode, boolean requireBodyHandler, Handler<RoutingContext> bodyHandler, GracefulShutdownFilter gracefulShutdownFilter, ShutdownConfig shutdownConfig, Executor executor) {
HttpConfiguration httpConfiguration = this.httpConfiguration.getValue();
// install the default route at the end
Router httpRouteRouter = httpRouterRuntimeValue.getValue();
// allow the router to be modified programmatically
Event<Object> event = Arc.container().beanManager().getEvent();
// First, fire an event with the filter collector
Filters filters = new Filters();
event.select(Filters.class).fire(filters);
filterList.addAll(filters.getFilters());
// Then, fire the resuming router
event.select(Router.class).fire(httpRouteRouter);
// Also fires the Mutiny one
event.select(io.vertx.mutiny.ext.web.Router.class).fire(mutinyRouter.getValue());
for (Filter filter : filterList) {
if (filter.getHandler() != null) {
// Filters with high priority gets called first.
httpRouteRouter.route().order(-1 * filter.getPriority()).handler(filter.getHandler());
}
}
if (defaultRouteHandler != null) {
defaultRouteHandler.accept(httpRouteRouter.route().order(DEFAULT_ROUTE_ORDER));
}
if (httpBuildTimeConfig.enableCompression) {
httpRouteRouter.route().order(0).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext ctx) {
// Add "Content-Encoding: identity" header that disables the compression
// This header can be removed to enable the compression
ctx.response().putHeader(HttpHeaders.CONTENT_ENCODING, HttpHeaders.IDENTITY);
ctx.next();
}
});
}
httpRouteRouter.route().last().failureHandler(new QuarkusErrorHandler(launchMode.isDevOrTest(), httpConfiguration.unhandledErrorContentTypeDefault));
if (requireBodyHandler) {
// if this is set then everything needs the body handler installed
// TODO: config etc
httpRouteRouter.route().order(Integer.MIN_VALUE + 1).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext routingContext) {
routingContext.request().resume();
bodyHandler.handle(routingContext);
}
});
}
if (httpConfiguration.limits.maxBodySize.isPresent()) {
long limit = httpConfiguration.limits.maxBodySize.get().asLongValue();
Long limitObj = limit;
httpRouteRouter.route().order(-2).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
String lengthString = event.request().headers().get(HttpHeaderNames.CONTENT_LENGTH);
if (lengthString != null) {
long length = Long.parseLong(lengthString);
if (length > limit) {
event.response().headers().add(HttpHeaderNames.CONNECTION, "close");
event.response().setStatusCode(HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE.code());
event.response().endHandler(new Handler<Void>() {
@Override
public void handle(Void e) {
event.request().connection().close();
}
});
event.response().end();
return;
}
} else {
event.put(MAX_REQUEST_SIZE_KEY, limitObj);
}
event.next();
}
});
}
// Filter Configuration per path
var filtersInConfig = httpConfiguration.filter;
if (!filtersInConfig.isEmpty()) {
for (var entry : filtersInConfig.entrySet()) {
var filterConfig = entry.getValue();
var matches = filterConfig.matches;
var order = filterConfig.order.orElse(Integer.MIN_VALUE);
var methods = filterConfig.methods;
var headers = filterConfig.header;
if (methods.isEmpty()) {
httpRouteRouter.routeWithRegex(matches).order(order).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
event.response().headers().setAll(headers);
event.next();
}
});
} else {
for (var method : methods.get()) {
httpRouteRouter.routeWithRegex(HttpMethod.valueOf(method.toUpperCase(Locale.ROOT)), matches).order(order).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
event.response().headers().setAll(headers);
event.next();
}
});
}
}
}
}
// Headers sent on any request, regardless of the response
Map<String, HeaderConfig> headers = httpConfiguration.header;
if (!headers.isEmpty()) {
// Creates a handler for each header entry
for (Map.Entry<String, HeaderConfig> entry : headers.entrySet()) {
var name = entry.getKey();
var config = entry.getValue();
if (config.methods.isEmpty()) {
httpRouteRouter.route(config.path).order(Integer.MIN_VALUE).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
event.response().headers().set(name, config.value);
event.next();
}
});
} else {
for (String method : config.methods.get()) {
httpRouteRouter.route(HttpMethod.valueOf(method.toUpperCase(Locale.ROOT)), config.path).order(Integer.MIN_VALUE).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
event.response().headers().add(name, config.value);
event.next();
}
});
}
}
}
}
Handler<HttpServerRequest> root;
if (rootPath.equals("/")) {
if (hotReplacementHandler != null) {
// recorders are always executed in the current CL
ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
httpRouteRouter.route().order(Integer.MIN_VALUE).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
Thread.currentThread().setContextClassLoader(currentCl);
hotReplacementHandler.handle(event);
}
});
}
root = httpRouteRouter;
} else {
Router mainRouter = mainRouterRuntimeValue.isPresent() ? mainRouterRuntimeValue.get().getValue() : Router.router(vertx.get());
mainRouter.mountSubRouter(rootPath, httpRouteRouter);
if (hotReplacementHandler != null) {
ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
mainRouter.route().order(Integer.MIN_VALUE).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
Thread.currentThread().setContextClassLoader(currentCl);
hotReplacementHandler.handle(event);
}
});
}
root = mainRouter;
}
warnIfDeprecatedHttpConfigPropertiesPresent(httpConfiguration);
warnIfProxyAddressForwardingAllowedWithMultipleHeaders(httpConfiguration);
ForwardingProxyOptions forwardingProxyOptions = ForwardingProxyOptions.from(httpConfiguration);
if (forwardingProxyOptions.proxyAddressForwarding) {
Handler<HttpServerRequest> delegate = root;
root = new Handler<HttpServerRequest>() {
@Override
public void handle(HttpServerRequest event) {
delegate.handle(new ForwardedServerRequestWrapper(event, forwardingProxyOptions));
}
};
}
boolean quarkusWrapperNeeded = false;
if (shutdownConfig.isShutdownTimeoutSet()) {
gracefulShutdownFilter.next(root);
root = gracefulShutdownFilter;
quarkusWrapperNeeded = true;
}
AccessLogConfig accessLog = httpConfiguration.accessLog;
if (accessLog.enabled) {
AccessLogReceiver receiver;
if (accessLog.logToFile) {
File outputDir = accessLog.logDirectory.isPresent() ? new File(accessLog.logDirectory.get()) : new File("");
receiver = new DefaultAccessLogReceiver(executor, outputDir, accessLog.baseFileName, accessLog.logSuffix, accessLog.rotate);
} else {
receiver = new JBossLoggingAccessLogReceiver(accessLog.category);
}
AccessLogHandler handler = new AccessLogHandler(receiver, accessLog.pattern, getClass().getClassLoader(), accessLog.excludePattern);
httpRouteRouter.route().order(Integer.MIN_VALUE).handler(handler);
quarkusWrapperNeeded = true;
}
BiConsumer<Cookie, HttpServerRequest> cookieFunction = null;
if (!httpConfiguration.sameSiteCookie.isEmpty()) {
cookieFunction = processSameSiteConfig(httpConfiguration.sameSiteCookie);
quarkusWrapperNeeded = true;
}
BiConsumer<Cookie, HttpServerRequest> cookieConsumer = cookieFunction;
if (quarkusWrapperNeeded) {
Handler<HttpServerRequest> old = root;
root = new Handler<HttpServerRequest>() {
@Override
public void handle(HttpServerRequest event) {
old.handle(new QuarkusRequestWrapper(event, cookieConsumer));
}
};
}
Handler<HttpServerRequest> delegate = root;
root = new Handler<HttpServerRequest>() {
@Override
public void handle(HttpServerRequest event) {
if (!VertxContext.isOnDuplicatedContext()) {
// Vert.x should call us on a duplicated context.
// But in the case of pipelined requests, it does not.
// See https://github.com/quarkusio/quarkus/issues/24626.
Context context = VertxContext.createNewDuplicatedContext();
context.runOnContext(new Handler<Void>() {
@Override
public void handle(Void x) {
setCurrentContextSafe(true);
delegate.handle(new ResumingRequestWrapper(event));
}
});
} else {
setCurrentContextSafe(true);
delegate.handle(new ResumingRequestWrapper(event));
}
}
};
if (httpConfiguration.recordRequestStartTime) {
httpRouteRouter.route().order(Integer.MIN_VALUE).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
event.put(REQUEST_START_TIME, System.nanoTime());
event.next();
}
});
}
if (launchMode == LaunchMode.DEVELOPMENT && liveReloadConfig.password.isPresent() && hotReplacementContext.getDevModeType() == DevModeType.REMOTE_SERVER_SIDE) {
root = remoteSyncHandler = new RemoteSyncHandler(liveReloadConfig.password.get(), root, hotReplacementContext);
}
rootHandler = root;
}
Aggregations