Search in sources :

Example 1 with ProxyContext

use of org.folio.okapi.util.ProxyContext in project okapi by folio-org.

the class ProxyService method redirectProxy.

/**
 * Extract tenantId from the request, rewrite the getPath, and proxy it.
 * Expects a request to something like /_/proxy/tenant/{tid}/mod-something.
 * Rewrites that to /mod-something, with the tenantId passed in the proper
 * header. As there is no authtoken, this will not work for many things, but
 * is needed for callbacks in the SSO systems, and who knows what else.
 *
 * @param ctx
 */
public void redirectProxy(RoutingContext ctx) {
    ProxyContext pc = new ProxyContext(ctx);
    final String origPath = ctx.request().path();
    String qry = ctx.request().query();
    String tid = origPath.replaceFirst("^/_/invoke/tenant/([^/ ]+)/.*$", "$1");
    String newPath = origPath.replaceFirst("^/_/invoke/tenant/[^/ ]+(/.*$)", "$1");
    if (qry != null && !qry.isEmpty()) {
        // vert.x 3.5 clears the parameters on reroute, so we pass them in ctx
        ctx.data().put(REDIRECTQUERY, qry);
        logger.debug("Hiding parameters into ctx " + qry);
    }
    ctx.request().headers().add(XOkapiHeaders.TENANT, tid);
    pc.debug("redirectProxy: '" + tid + "' '" + newPath + "'");
    ctx.reroute(newPath);
    logger.debug("redirectProxy: After rerouting: " + ctx.request().path() + " " + qry);
}
Also used : ProxyContext(org.folio.okapi.util.ProxyContext)

Example 2 with ProxyContext

use of org.folio.okapi.util.ProxyContext in project okapi by folio-org.

the class ProxyService method proxyHeaders.

private void proxyHeaders(Iterator<ModuleInstance> it, ProxyContext pc, ReadStream<Buffer> stream, Buffer bcontent, ModuleInstance mi) {
    RoutingContext ctx = pc.getCtx();
    HttpClientRequest cReq = httpClient.requestAbs(ctx.request().method(), makeUrl(mi, ctx), res -> {
        if (res.statusCode() < 200 || res.statusCode() >= 300) {
            proxyResponseImmediate(pc, res, mi);
            if (bcontent == null) {
                stream.resume();
            }
        } else if (it.hasNext()) {
            relayToRequest(res, pc, mi);
            makeTraceHeader(mi, res.statusCode(), pc);
            res.endHandler(x -> proxyR(it, pc, stream, bcontent));
        } else {
            relayToResponse(ctx.response(), res);
            makeTraceHeader(mi, res.statusCode(), pc);
            if (bcontent == null) {
                stream.handler(data -> {
                    ctx.response().write(data);
                    pc.trace("ProxyHeaders request chunk '" + data.toString() + "'");
                });
                stream.endHandler(v -> {
                    ctx.response().end();
                    pc.trace("ProxyHeaders request end");
                });
                stream.exceptionHandler(e -> pc.warn("proxyHeaders: content exception ", e));
                stream.resume();
            } else {
                pc.trace("ProxyHeaders request buf '" + bcontent + "'");
                ctx.response().end(bcontent);
            }
        }
    });
    cReq.exceptionHandler(e -> {
        pc.warn("proxyHeaders failure: " + mi.getUrl() + ": ", e);
        pc.responseText(500, "proxyHeaders failure: " + mi.getModuleDescriptor().getId() + " " + mi.getUrl() + ": " + e + " " + e.getMessage());
    });
    cReq.headers().setAll(ctx.request().headers());
    cReq.headers().remove("Content-Length");
    cReq.end();
    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)

Example 3 with ProxyContext

use of org.folio.okapi.util.ProxyContext in project okapi by folio-org.

the class ProxyService method proxy.

public void proxy(RoutingContext ctx) {
    ctx.request().pause();
    ReadStream<Buffer> stream = ctx.request();
    // Pause the request data stream before doing any slow ops, otherwise
    // it will get read into a buffer somewhere.
    ProxyContext pc = new ProxyContext(ctx);
    // It would be nice to pass the request-id to the client, so it knows what
    // to look for in Okapi logs. But that breaks the schemas, and RMB-based
    // modules will not accept the response. Maybe later...
    String tenantId = tenantHeader(pc);
    if (tenantId == null) {
        stream.resume();
        // Error code already set in ctx
        return;
    }
    sanitizeAuthHeaders(ctx.request().headers());
    tenantManager.get(tenantId, gres -> {
        if (gres.failed()) {
            stream.resume();
            pc.responseText(400, "No such Tenant " + tenantId);
            return;
        }
        Tenant tenant = gres.result();
        moduleManager.getEnabledModules(tenant, mres -> {
            if (mres.failed()) {
                stream.resume();
                pc.responseError(mres.getType(), mres.cause());
                return;
            }
            List<ModuleDescriptor> enabledModules = mres.result();
            String metricKey = "proxy." + tenantId + "." + ctx.request().method() + "." + ctx.normalisedPath();
            DropwizardHelper.markEvent(metricKey);
            List<ModuleInstance> l = getModulesForRequest(pc, enabledModules);
            if (l == null) {
                stream.resume();
                // ctx already set up
                return;
            }
            pc.setModList(l);
            pc.logRequest(ctx, tenantId);
            ctx.request().headers().add(XOkapiHeaders.URL, okapiUrl);
            ctx.request().headers().remove(XOkapiHeaders.MODULE_ID);
            resolveUrls(l.iterator(), res -> {
                if (res.failed()) {
                    stream.resume();
                    pc.responseError(res.getType(), res.cause());
                } else {
                    proxyR(l.iterator(), pc, stream, null);
                }
            });
        });
    });
}
Also used : Buffer(io.vertx.core.buffer.Buffer) ModuleDescriptor(org.folio.okapi.bean.ModuleDescriptor) Tenant(org.folio.okapi.bean.Tenant) ProxyContext(org.folio.okapi.util.ProxyContext) ModuleInstance(org.folio.okapi.bean.ModuleInstance)

Example 4 with ProxyContext

use of org.folio.okapi.util.ProxyContext 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)

Aggregations

Buffer (io.vertx.core.buffer.Buffer)3 ModuleDescriptor (org.folio.okapi.bean.ModuleDescriptor)3 ModuleInstance (org.folio.okapi.bean.ModuleInstance)3 Tenant (org.folio.okapi.bean.Tenant)3 ProxyContext (org.folio.okapi.util.ProxyContext)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 HttpClientResponse (io.vertx.core.http.HttpClientResponse)2 HttpMethod (io.vertx.core.http.HttpMethod)2 HttpServerRequest (io.vertx.core.http.HttpServerRequest)2 HttpServerResponse (io.vertx.core.http.HttpServerResponse)2 Json (io.vertx.core.json.Json)2 JsonObject (io.vertx.core.json.JsonObject)2 Logger (io.vertx.core.logging.Logger)2 ReadStream (io.vertx.core.streams.ReadStream)2 RoutingContext (io.vertx.ext.web.RoutingContext)2