All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkiverse.quinoa.QuinoaRecorder Maven / Gradle / Ivy

package io.quarkiverse.quinoa;

import static io.quarkus.vertx.http.runtime.RouteConstants.ROUTE_ORDER_DEFAULT;

import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;

import org.jboss.logging.Logger;

import io.quarkus.runtime.annotations.Recorder;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.impl.MimeMapping;
import io.vertx.ext.web.RoutingContext;

@Recorder
public class QuinoaRecorder {
    private static final Logger LOG = Logger.getLogger(QuinoaRecorder.class);
    public static final String META_INF_WEB_UI = "META-INF/webui";
    public static final int QUINOA_ROUTE_ORDER = 1100;
    public static final int QUINOA_SPA_ROUTE_ORDER = ROUTE_ORDER_DEFAULT + 30_000;
    public static final Set HANDLED_METHODS = Set.of(HttpMethod.HEAD, HttpMethod.OPTIONS, HttpMethod.GET);

    public Handler quinoaProxyDevHandler(final QuinoaDevProxyHandlerConfig handlerConfig, Supplier vertx,
            QuinoaNetworkConfiguration network) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Quinoa dev proxy-handler is ignoring paths starting with: "
                    + String.join(", ", handlerConfig.ignoredPathPrefixes));
        }
        return new QuinoaDevProxyHandler(handlerConfig, vertx.get(), network);
    }

    public Handler quinoaSPARoutingHandler(List ignoredPathPrefixes) throws IOException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Quinoa SPA routing handler is ignoring paths starting with: " + String.join(", ", ignoredPathPrefixes));
        }
        return new QuinoaSPARoutingHandler(ignoredPathPrefixes);
    }

    public void logUiRootPath(final String resolvedUiRootPath) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Quinoa is available at: " + resolvedUiRootPath);
        }
    }

    static String resolvePath(RoutingContext ctx) {
        // quarkus.http.root-path
        String path = (ctx.mountPoint() == null) ? ctx.normalizedPath()
                : ctx.normalizedPath().substring(
                        // let's be extra careful here in case Vert.x normalizes the mount points at
                        // some point
                        ctx.mountPoint().endsWith("/") ? ctx.mountPoint().length() - 1 : ctx.mountPoint().length());
        // quarkus.quinoa.ui-root-path
        String routePath = ctx.currentRoute().getPath();
        String resolvedPath = (routePath == null) ? path
                : path.substring(routePath.endsWith("/") ? routePath.length() - 1 : routePath.length());
        // use "/" when the path is empty
        // e.g. this happens when the request path is "/example" and the root path is "/example"
        return resolvedPath.isEmpty() ? "/" : resolvedPath;
    }

    static boolean matchesPathSeparatedPrefix(String path, String pathSeparatedPrefix) {
        if (path.startsWith(pathSeparatedPrefix)) {
            String restPath = path.substring(pathSeparatedPrefix.length());
            // the path matches the path separated prefix if the rest path is empty or starts with "/"
            // note that the pathSeparatedPrefix never ends in "/" except if it equals "/" exactly
            return restPath.isEmpty() || restPath.startsWith("/") || Objects.equals(pathSeparatedPrefix, "/");
        }
        return false;
    }

    static boolean isIgnored(final String path, final List ignoredPathPrefixes) {
        if (ignoredPathPrefixes.stream().anyMatch(prefix -> matchesPathSeparatedPrefix(path, prefix))) {
            LOG.debug("Quinoa is ignoring path (quarkus.quinoa.ignored-path-prefixes): " + path);
            return true;
        }
        return false;
    }

    static void compressIfNeeded(QuinoaDevProxyHandlerConfig config, RoutingContext ctx, String path) {
        if (config.enableCompression && isCompressed(config, path)) {
            // VertxHttpRecorder is adding "Content-Encoding: identity" to all requests if
            // compression is enabled.
            // Handlers can remove the "Content-Encoding: identity" header to enable
            // compression.
            ctx.response().headers().remove(HttpHeaders.CONTENT_ENCODING);
        }
    }

    private static boolean isCompressed(QuinoaDevProxyHandlerConfig config, String path) {
        if (config.compressMediaTypes.isEmpty()) {
            return false;
        }
        String contentType = MimeMapping.getMimeTypeForFilename(path);
        return contentType != null && config.compressMediaTypes.contains(contentType);
    }

    static boolean shouldHandleMethod(RoutingContext ctx) {
        return HANDLED_METHODS.contains(ctx.request().method());
    }

    static void next(ClassLoader cl, RoutingContext ctx) {
        // make sure we don't lose the correct TCCL to Vert.x...
        Thread.currentThread().setContextClassLoader(cl);
        ctx.next();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy