Search in sources :

Example 1 with RemoteSyncHandler

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);
}
Also used : QuarkusBindException(io.quarkus.runtime.QuarkusBindException) HttpServerOptions(io.vertx.core.http.HttpServerOptions) CompletableFuture(java.util.concurrent.CompletableFuture) ExecutionException(java.util.concurrent.ExecutionException) QuarkusBindException(io.quarkus.runtime.QuarkusBindException) BindException(java.net.BindException) AccessLogHandler(io.quarkus.vertx.http.runtime.filters.accesslog.AccessLogHandler) BodyHandler(io.vertx.ext.web.handler.BodyHandler) VertxHandler(io.vertx.core.net.impl.VertxHandler) RemoteSyncHandler(io.quarkus.vertx.http.runtime.devmode.RemoteSyncHandler) Handler(io.vertx.core.Handler) CountDownLatch(java.util.concurrent.CountDownLatch) ConfigurationException(io.quarkus.runtime.configuration.ConfigurationException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) URISyntaxException(java.net.URISyntaxException) QuarkusBindException(io.quarkus.runtime.QuarkusBindException) BindException(java.net.BindException) AbstractVerticle(io.vertx.core.AbstractVerticle) Verticle(io.vertx.core.Verticle) DeploymentOptions(io.vertx.core.DeploymentOptions) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AsyncResult(io.vertx.core.AsyncResult)

Example 2 with RemoteSyncHandler

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;
}
Also used : QuarkusRequestWrapper(io.quarkus.vertx.http.runtime.filters.QuarkusRequestWrapper) DefaultAccessLogReceiver(io.quarkus.vertx.http.runtime.filters.accesslog.DefaultAccessLogReceiver) Filters(io.quarkus.vertx.http.runtime.filters.Filters) RoutingContext(io.vertx.ext.web.RoutingContext) DefaultAccessLogReceiver(io.quarkus.vertx.http.runtime.filters.accesslog.DefaultAccessLogReceiver) AccessLogReceiver(io.quarkus.vertx.http.runtime.filters.accesslog.AccessLogReceiver) JBossLoggingAccessLogReceiver(io.quarkus.vertx.http.runtime.filters.accesslog.JBossLoggingAccessLogReceiver) ShutdownContext(io.quarkus.runtime.ShutdownContext) EventLoopContext(io.vertx.core.impl.EventLoopContext) RoutingContext(io.vertx.ext.web.RoutingContext) Context(io.vertx.core.Context) VertxContext(io.smallrye.common.vertx.VertxContext) HotReplacementContext(io.quarkus.dev.spi.HotReplacementContext) Cookie(io.vertx.core.http.Cookie) ShutdownContext(io.quarkus.runtime.ShutdownContext) EventLoopContext(io.vertx.core.impl.EventLoopContext) RoutingContext(io.vertx.ext.web.RoutingContext) Context(io.vertx.core.Context) VertxContext(io.smallrye.common.vertx.VertxContext) HotReplacementContext(io.quarkus.dev.spi.HotReplacementContext) HttpServerRequest(io.vertx.core.http.HttpServerRequest) Router(io.vertx.ext.web.Router) AccessLogHandler(io.quarkus.vertx.http.runtime.filters.accesslog.AccessLogHandler) BodyHandler(io.vertx.ext.web.handler.BodyHandler) VertxHandler(io.vertx.core.net.impl.VertxHandler) RemoteSyncHandler(io.quarkus.vertx.http.runtime.devmode.RemoteSyncHandler) Handler(io.vertx.core.Handler) JBossLoggingAccessLogReceiver(io.quarkus.vertx.http.runtime.filters.accesslog.JBossLoggingAccessLogReceiver) AccessLogHandler(io.quarkus.vertx.http.runtime.filters.accesslog.AccessLogHandler) RemoteSyncHandler(io.quarkus.vertx.http.runtime.devmode.RemoteSyncHandler) GracefulShutdownFilter(io.quarkus.vertx.http.runtime.filters.GracefulShutdownFilter) Filter(io.quarkus.vertx.http.runtime.filters.Filter) Map(java.util.Map) TreeMap(java.util.TreeMap) HashMap(java.util.HashMap) File(java.io.File)

Example 3 with RemoteSyncHandler

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);
    }
}
Also used : LiveReloadConfig(io.quarkus.runtime.LiveReloadConfig) HttpServerRequest(io.vertx.core.http.HttpServerRequest) Router(io.vertx.ext.web.Router) Vertx(io.vertx.core.Vertx) ConfigurationException(io.quarkus.runtime.configuration.ConfigurationException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) URISyntaxException(java.net.URISyntaxException) QuarkusBindException(io.quarkus.runtime.QuarkusBindException) BindException(java.net.BindException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RoutingContext(io.vertx.ext.web.RoutingContext) RemoteSyncHandler(io.quarkus.vertx.http.runtime.devmode.RemoteSyncHandler) VertxConfiguration(io.quarkus.vertx.core.runtime.config.VertxConfiguration)

Aggregations

RemoteSyncHandler (io.quarkus.vertx.http.runtime.devmode.RemoteSyncHandler)3 QuarkusBindException (io.quarkus.runtime.QuarkusBindException)2 ConfigurationException (io.quarkus.runtime.configuration.ConfigurationException)2 AccessLogHandler (io.quarkus.vertx.http.runtime.filters.accesslog.AccessLogHandler)2 Handler (io.vertx.core.Handler)2 HttpServerRequest (io.vertx.core.http.HttpServerRequest)2 VertxHandler (io.vertx.core.net.impl.VertxHandler)2 Router (io.vertx.ext.web.Router)2 RoutingContext (io.vertx.ext.web.RoutingContext)2 BodyHandler (io.vertx.ext.web.handler.BodyHandler)2 IOException (java.io.IOException)2 BindException (java.net.BindException)2 URISyntaxException (java.net.URISyntaxException)2 ExecutionException (java.util.concurrent.ExecutionException)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 HotReplacementContext (io.quarkus.dev.spi.HotReplacementContext)1 LiveReloadConfig (io.quarkus.runtime.LiveReloadConfig)1 ShutdownContext (io.quarkus.runtime.ShutdownContext)1 VertxConfiguration (io.quarkus.vertx.core.runtime.config.VertxConfiguration)1 Filter (io.quarkus.vertx.http.runtime.filters.Filter)1