Search in sources :

Example 11 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class ProxyService method resolveRedirects.

private boolean resolveRedirects(ProxyContext pc, List<ModuleInstance> mods, RoutingEntry re, List<ModuleDescriptor> enabledModules, final String loop, final String uri, final String origMod) {
    RoutingContext ctx = pc.getCtx();
    if (re.getProxyType() == ProxyType.REDIRECT) {
        // resolve redirects
        boolean found = false;
        final String redirectPath = re.getRedirectPath();
        for (ModuleDescriptor trymod : enabledModules) {
            List<RoutingEntry> rr = trymod.getProxyRoutingEntries();
            for (RoutingEntry tryre : rr) {
                if (tryre.match(redirectPath, ctx.request().method().name())) {
                    final String newUri = re.getRedirectUri(uri);
                    found = true;
                    pc.debug("resolveRedirects: " + ctx.request().method() + " " + uri + " => " + trymod + " " + newUri);
                    if (loop.contains(redirectPath + " ")) {
                        pc.responseError(500, "Redirect loop: " + loop + " -> " + redirectPath);
                        return false;
                    }
                    ModuleInstance mi = new ModuleInstance(trymod, tryre, newUri);
                    mods.add(mi);
                    if (!resolveRedirects(pc, mods, tryre, enabledModules, loop + " -> " + redirectPath, newUri, origMod)) {
                        return false;
                    }
                }
            }
        }
        if (!found) {
            String msg = "Redirecting " + uri + " to " + redirectPath + " FAILED. No suitable module found";
            pc.responseError(500, msg);
        }
        return found;
    }
    return true;
}
Also used : ModuleDescriptor(org.folio.okapi.bean.ModuleDescriptor) RoutingContext(io.vertx.ext.web.RoutingContext) RoutingEntry(org.folio.okapi.bean.RoutingEntry) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Example 12 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class ProxyService method proxyRequestHttpClient.

private void proxyRequestHttpClient(Iterator<ModuleInstance> it, ProxyContext pc, Buffer bcontent, ModuleInstance mi) {
    RoutingContext ctx = pc.getCtx();
    String url = makeUrl(mi, ctx);
    HttpMethod meth = ctx.request().method();
    HttpClientRequest cReq = httpClient.requestAbs(meth, url, res -> {
        if (res.statusCode() < 200 || res.statusCode() >= 300) {
            proxyResponseImmediate(pc, res, mi);
        } else if (it.hasNext()) {
            makeTraceHeader(mi, res.statusCode(), pc);
            pc.closeTimer();
            relayToRequest(res, pc, mi);
            proxyR(it, pc, null, bcontent);
        } else {
            relayToResponse(ctx.response(), res);
            makeTraceHeader(mi, res.statusCode(), pc);
            res.endHandler(x -> {
                pc.closeTimer();
                pc.trace("ProxyRequestHttpClient final response buf '" + bcontent + "'");
                ctx.response().end(bcontent);
            });
            res.exceptionHandler(e -> pc.warn("proxyRequestHttpClient: res exception (b)", e));
        }
    });
    cReq.exceptionHandler(e -> {
        pc.warn("proxyRequestHttpClient failure: " + url, e);
        pc.responseText(500, "proxyRequestHttpClient failure: " + mi.getModuleDescriptor().getId() + " " + mi.getUrl() + ": " + e + " " + e.getMessage());
    });
    cReq.headers().setAll(ctx.request().headers());
    cReq.headers().remove("Content-Length");
    pc.trace("ProxyRequestHttpClient request buf '" + bcontent + "'");
    cReq.end(bcontent);
    log(pc, cReq);
}
Also used : HttpServerRequest(io.vertx.core.http.HttpServerRequest) Json(io.vertx.core.json.Json) Arrays(java.util.Arrays) ModuleDescriptor(org.folio.okapi.bean.ModuleDescriptor) XOkapiHeaders(org.folio.okapi.common.XOkapiHeaders) NOT_FOUND(org.folio.okapi.common.ErrorType.NOT_FOUND) MultiMap(io.vertx.core.MultiMap) OkapiToken(org.folio.okapi.common.OkapiToken) HashMap(java.util.HashMap) Random(java.util.Random) RoutingContext(io.vertx.ext.web.RoutingContext) Tenant(org.folio.okapi.bean.Tenant) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) OkapiClient(org.folio.okapi.common.OkapiClient) OkapiLogger(org.folio.okapi.common.OkapiLogger) HttpClientRequest(io.vertx.core.http.HttpClientRequest) HttpClientResponse(io.vertx.core.http.HttpClientResponse) Matcher(java.util.regex.Matcher) DeploymentDescriptor(org.folio.okapi.bean.DeploymentDescriptor) ProxyType(org.folio.okapi.bean.RoutingEntry.ProxyType) Map(java.util.Map) RoutingEntry(org.folio.okapi.bean.RoutingEntry) ProxyContext(org.folio.okapi.util.ProxyContext) ReadStream(io.vertx.core.streams.ReadStream) DiscoveryManager(org.folio.okapi.discovery.DiscoveryManager) ExtendedAsyncResult(org.folio.okapi.common.ExtendedAsyncResult) JsonObject(io.vertx.core.json.JsonObject) Failure(org.folio.okapi.common.Failure) InternalModule(org.folio.okapi.web.InternalModule) HttpClientOptions(io.vertx.core.http.HttpClientOptions) Logger(io.vertx.core.logging.Logger) USER(org.folio.okapi.common.ErrorType.USER) Iterator(java.util.Iterator) Vertx(io.vertx.core.Vertx) Set(java.util.Set) Success(org.folio.okapi.common.Success) ModuleInstance(org.folio.okapi.bean.ModuleInstance) List(java.util.List) INTERNAL(org.folio.okapi.common.ErrorType.INTERNAL) Buffer(io.vertx.core.buffer.Buffer) HttpMethod(io.vertx.core.http.HttpMethod) HttpServerResponse(io.vertx.core.http.HttpServerResponse) DropwizardHelper(org.folio.okapi.util.DropwizardHelper) Pattern(java.util.regex.Pattern) Handler(io.vertx.core.Handler) Comparator(java.util.Comparator) HttpClient(io.vertx.core.http.HttpClient) RoutingContext(io.vertx.ext.web.RoutingContext) HttpClientRequest(io.vertx.core.http.HttpClientRequest) HttpMethod(io.vertx.core.http.HttpMethod)

Example 13 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class ProxyService method authResponse.

/**
 * Process the auth module response. Set tokens for those modules that
 * received one.
 */
private void authResponse(HttpClientResponse res, ProxyContext pc) {
    String modTok = res.headers().get(XOkapiHeaders.MODULE_TOKENS);
    if (modTok != null && !modTok.isEmpty()) {
        JsonObject jo = new JsonObject(modTok);
        for (ModuleInstance mi : pc.getModList()) {
            String id = mi.getModuleDescriptor().getId();
            if (jo.containsKey(id)) {
                String tok = jo.getString(id);
                mi.setAuthToken(tok);
                pc.debug("authResponse: token for " + id + ": " + tok);
            } else if (jo.containsKey("_")) {
                String tok = jo.getString("_");
                mi.setAuthToken(tok);
                pc.debug("authResponse: Default (_) token for " + id + ": " + tok);
            }
        }
    }
}
Also used : JsonObject(io.vertx.core.json.JsonObject) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Example 14 with ModuleInstance

use of org.folio.okapi.bean.ModuleInstance in project okapi by folio-org.

the class ProxyService method proxyR.

private void proxyR(Iterator<ModuleInstance> it, ProxyContext pc, ReadStream<Buffer> stream, Buffer bcontent) {
    RoutingContext ctx = pc.getCtx();
    if (!it.hasNext()) {
        stream.resume();
        pc.debug("proxyR: Not found");
        // Should have been caught earlier
        pc.responseText(404, "");
    } else {
        ModuleInstance mi = it.next();
        String tenantId = ctx.request().getHeader(XOkapiHeaders.TENANT);
        if (tenantId == null || tenantId.isEmpty()) {
            // Should not happen, we have validated earlier
            tenantId = "???";
        }
        String metricKey = "proxy." + tenantId + ".module." + mi.getModuleDescriptor().getId();
        pc.startTimer(metricKey);
        // Pass the right token
        ctx.request().headers().remove(XOkapiHeaders.TOKEN);
        String token = mi.getAuthToken();
        if (token != null && !token.isEmpty()) {
            ctx.request().headers().add(XOkapiHeaders.TOKEN, token);
        }
        // Pass the X-Okapi-Filter header for filters (only)
        // And all kind of things for the auth filter
        ctx.request().headers().remove(XOkapiHeaders.FILTER);
        if (mi.getRoutingEntry().getPhase() != null) {
            String pth = mi.getRoutingEntry().getPathPattern();
            if (pth == null) {
                pth = mi.getRoutingEntry().getPath();
            }
            String filt = mi.getRoutingEntry().getPhase() + " " + pth;
            pc.debug("Adding " + XOkapiHeaders.FILTER + ": " + filt);
            ctx.request().headers().add(XOkapiHeaders.FILTER, filt);
            // The auth filter needs all kinds of special headers
            if ("auth".equals(mi.getRoutingEntry().getPhase())) {
                authHeaders(pc.getModList(), ctx.request().headers(), pc);
            }
        }
        ProxyType pType = mi.getRoutingEntry().getProxyType();
        if (pType != ProxyType.REDIRECT) {
            pc.debug("Invoking module " + mi.getModuleDescriptor().getId() + " type " + pType + " level " + mi.getRoutingEntry().getPhaseLevel() + " path " + mi.getPath() + " url " + mi.getUrl());
        }
        switch(pType) {
            case REQUEST_ONLY:
                proxyRequestOnly(it, pc, stream, bcontent, mi);
                break;
            case REQUEST_RESPONSE:
                proxyRequestResponse(it, pc, stream, bcontent, mi);
                break;
            case HEADERS:
                proxyHeaders(it, pc, stream, bcontent, mi);
                break;
            case REDIRECT:
                proxyRedirect(it, pc, stream, bcontent, mi);
                break;
            case INTERNAL:
                proxyInternal(it, pc, stream, bcontent, mi);
                break;
            case REQUEST_RESPONSE_1_0:
                proxyRequestResponse10(it, pc, stream, bcontent, mi);
                break;
            default:
                // Should not happen
                pc.responseText(500, "Bad proxy type '" + pType + "' in module " + mi.getModuleDescriptor().getId());
                break;
        }
    }
}
Also used : RoutingContext(io.vertx.ext.web.RoutingContext) ProxyType(org.folio.okapi.bean.RoutingEntry.ProxyType) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Aggregations

ModuleInstance (org.folio.okapi.bean.ModuleInstance)14 RoutingEntry (org.folio.okapi.bean.RoutingEntry)8 JsonObject (io.vertx.core.json.JsonObject)5 ModuleDescriptor (org.folio.okapi.bean.ModuleDescriptor)5 RoutingContext (io.vertx.ext.web.RoutingContext)4 HashMap (java.util.HashMap)4 Buffer (io.vertx.core.buffer.Buffer)3 HttpServerRequest (io.vertx.core.http.HttpServerRequest)3 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 DeploymentDescriptor (org.folio.okapi.bean.DeploymentDescriptor)3 ProxyType (org.folio.okapi.bean.RoutingEntry.ProxyType)3 Tenant (org.folio.okapi.bean.Tenant)3 OkapiClient (org.folio.okapi.common.OkapiClient)3 Handler (io.vertx.core.Handler)2 MultiMap (io.vertx.core.MultiMap)2 Vertx (io.vertx.core.Vertx)2 HttpClient (io.vertx.core.http.HttpClient)2 HttpClientOptions (io.vertx.core.http.HttpClientOptions)2 HttpClientRequest (io.vertx.core.http.HttpClientRequest)2