use of io.quarkus.vertx.http.runtime.devmode.RemoteSyncHandler in project quarkus by quarkusio.
the class VertxHttpRecorder method doServerStart.
private static void doServerStart(Vertx vertx, HttpBuildTimeConfig httpBuildTimeConfig, HttpConfiguration httpConfiguration, LaunchMode launchMode, Supplier<Integer> eventLoops, List<String> websocketSubProtocols, boolean auxiliaryApplication) throws IOException {
// Http server configuration
HttpServerOptions httpServerOptions = createHttpServerOptions(httpBuildTimeConfig, httpConfiguration, launchMode, websocketSubProtocols);
HttpServerOptions domainSocketOptions = createDomainSocketOptions(httpBuildTimeConfig, httpConfiguration, websocketSubProtocols);
HttpServerOptions sslConfig = createSslOptions(httpBuildTimeConfig, httpConfiguration, launchMode, websocketSubProtocols);
if (httpConfiguration.insecureRequests != HttpConfiguration.InsecureRequests.ENABLED && sslConfig == null) {
throw new IllegalStateException("Cannot set quarkus.http.redirect-insecure-requests without enabling SSL.");
}
int eventLoopCount = eventLoops.get();
final int ioThreads;
if (httpConfiguration.ioThreads.isPresent()) {
ioThreads = Math.min(httpConfiguration.ioThreads.getAsInt(), eventLoopCount);
} else if (launchMode.isDevOrTest()) {
// Don't start ~100 threads to run a couple unit tests
ioThreads = Math.min(2, eventLoopCount);
} else {
ioThreads = eventLoopCount;
}
CompletableFuture<String> futureResult = new CompletableFuture<>();
AtomicInteger connectionCount = new AtomicInteger();
vertx.deployVerticle(new Supplier<Verticle>() {
@Override
public Verticle get() {
return new WebDeploymentVerticle(httpServerOptions, sslConfig, domainSocketOptions, launchMode, httpConfiguration.insecureRequests, httpConfiguration, connectionCount);
}
}, new DeploymentOptions().setInstances(ioThreads), new Handler<AsyncResult<String>>() {
@Override
public void handle(AsyncResult<String> event) {
if (event.failed()) {
Throwable effectiveCause = event.cause();
if (effectiveCause instanceof BindException) {
if ((sslConfig == null) && (httpServerOptions != null)) {
effectiveCause = new QuarkusBindException(httpServerOptions.getPort());
} else if ((httpConfiguration.insecureRequests == InsecureRequests.DISABLED) && (sslConfig != null)) {
effectiveCause = new QuarkusBindException(sslConfig.getPort());
} else if ((sslConfig != null) && (httpConfiguration.insecureRequests == InsecureRequests.ENABLED) && (httpServerOptions != null)) {
effectiveCause = new QuarkusBindException(List.of(httpServerOptions.getPort(), sslConfig.getPort()));
}
}
futureResult.completeExceptionally(effectiveCause);
} else {
futureResult.complete(event.result());
}
}
});
try {
String deploymentId = futureResult.get();
VertxCoreRecorder.setWebDeploymentId(deploymentId);
closeTask = new Runnable() {
@Override
public synchronized void run() {
// guard against this being run twice
if (closeTask == this) {
if (vertx.deploymentIDs().contains(deploymentId)) {
CountDownLatch latch = new CountDownLatch(1);
try {
vertx.undeploy(deploymentId, new Handler<AsyncResult<Void>>() {
@Override
public void handle(AsyncResult<Void> event) {
latch.countDown();
}
});
} catch (Exception e) {
e.printStackTrace();
}
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
closeTask = null;
if (remoteSyncHandler != null) {
remoteSyncHandler.close();
remoteSyncHandler = null;
}
}
}
};
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Unable to start HTTP server", e);
}
setHttpServerTiming(httpConfiguration.insecureRequests, httpServerOptions, sslConfig, domainSocketOptions, auxiliaryApplication);
}
use of io.quarkus.vertx.http.runtime.devmode.RemoteSyncHandler 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;
}
use of io.quarkus.vertx.http.runtime.devmode.RemoteSyncHandler in project quarkus by quarkusio.
the class VertxHttpRecorder method startServerAfterFailedStart.
public static void startServerAfterFailedStart() {
if (closeTask != null) {
// it is possible start failed after the server was started
// we shut it down in this case, as we have no idea what state it is in
final Handler<RoutingContext> prevHotReplacementHandler = hotReplacementHandler;
shutDownDevMode();
// reset back to the older live reload handler, so that it can be used
// to watch any artifacts that need hot deployment to fix the reason which caused
// the server start to fail
hotReplacementHandler = prevHotReplacementHandler;
}
Supplier<Vertx> supplier = VertxCoreRecorder.getVertx();
Vertx vertx;
if (supplier == null) {
VertxConfiguration vertxConfiguration = new VertxConfiguration();
ConfigInstantiator.handleObject(vertxConfiguration);
vertx = VertxCoreRecorder.recoverFailedStart(vertxConfiguration).get();
} else {
vertx = supplier.get();
}
try {
HttpBuildTimeConfig buildConfig = new HttpBuildTimeConfig();
ConfigInstantiator.handleObject(buildConfig);
HttpConfiguration config = new HttpConfiguration();
ConfigInstantiator.handleObject(config);
if (config.host == null) {
// HttpHostConfigSource does not come into play here
config.host = "localhost";
}
Router router = Router.router(vertx);
if (hotReplacementHandler != null) {
router.route().order(Integer.MIN_VALUE).blockingHandler(hotReplacementHandler);
}
Handler<HttpServerRequest> root = router;
LiveReloadConfig liveReloadConfig = new LiveReloadConfig();
ConfigInstantiator.handleObject(liveReloadConfig);
if (liveReloadConfig.password.isPresent() && hotReplacementContext.getDevModeType() == DevModeType.REMOTE_SERVER_SIDE) {
root = remoteSyncHandler = new RemoteSyncHandler(liveReloadConfig.password.get(), root, hotReplacementContext);
}
rootHandler = root;
// we can't really do
doServerStart(vertx, buildConfig, config, LaunchMode.DEVELOPMENT, new Supplier<Integer>() {
@Override
public Integer get() {
return ProcessorInfo.availableProcessors() * // this is dev mode, so the number of IO threads not always being 100% correct does not really matter in this case
2;
}
}, null, false);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Aggregations