Java tutorial
/** * Copyright 2016-2019 Nitor Creations Oy, Jonas Berlin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.nitor.api.backend.proxy; import io.nitor.api.backend.proxy.Proxy.DefaultPumpStarter; import io.nitor.api.backend.proxy.Proxy.ProxyException; import io.nitor.api.backend.proxy.Proxy.RejectReason; import io.nitor.api.backend.routing.ServiceRouterBuilder; import io.vertx.core.Vertx; import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.Router; import java.util.HashMap; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import static io.netty.handler.codec.http.HttpResponseStatus.BAD_GATEWAY; import static io.vertx.core.http.HttpVersion.HTTP_1_1; import static java.util.concurrent.TimeUnit.SECONDS; public class SetupProxy { private static final Logger logger = LogManager.getLogger(SetupProxy.class); public static void setupProxy(Vertx vertx, ServiceRouterBuilder routerBuilder, JsonObject proxyConf, HttpServerOptions serverOptions, boolean isOrigReqHttps) { boolean ssl = proxyConf.getBoolean("ssl", false); HttpClient client = vertx.createHttpClient(new HttpClientOptions() .setConnectTimeout((int) SECONDS.toMillis(proxyConf.getInteger("connectTimeout", 10))) .setIdleTimeout((int) SECONDS.toSeconds(proxyConf.getInteger("idleTimeout", 15))) .setMaxPoolSize(proxyConf.getInteger("maxPoolSize", 30)) .setPipelining(proxyConf.getInteger("pipelineDepth", 0) > 1) .setPipeliningLimit(proxyConf.getInteger("pipelineDepth", 1)).setMaxWaitQueueSize(100) .setUsePooledBuffers(true).setProtocolVersion(HTTP_1_1).setTryUseCompression(false).setSsl(ssl)); String prefix = proxyConf.getString("path", ""); if (prefix.endsWith("/")) { prefix = prefix.substring(0, prefix.length() - 1); } String route = proxyConf.getString("route", ""); if (route.endsWith("*")) { route = route.substring(0, route.length() - 1); } if (route.endsWith("/")) { route = route.substring(0, route.length() - 1); } final String proxyRoute = route; final Proxy.Target proxyTarget = new Proxy.Target(proxyConf.getString("host"), proxyConf.getInteger("port"), prefix, proxyConf.getString("hostHeader")); logger.info("Proxying {} to {}://{}:{}/{}", route, ssl ? "https" : "http", proxyTarget.socketHost, proxyTarget.socketPort, proxyTarget.uri); Proxy proxy = new Proxy(client, (routingContext, targetHandler) -> { String suffix = routingContext.request().uri().substring(proxyRoute.length()); targetHandler.handle(proxyTarget.withSuffix(suffix)); }, serverOptions.getIdleTimeout(), proxyConf.getInteger("clientReceiveTimeout", 300), isOrigReqHttps, SimpleLogProxyTracer::new, new DefaultPumpStarter()); if (proxyConf.getJsonObject("addHeaders") != null) { final Map<String, String> addHeaders = new HashMap<>(); for (Map.Entry<String, Object> entry : proxyConf.getJsonObject("addHeaders")) { addHeaders.put(entry.getKey(), entry.getValue().toString()); } proxy.addHeaders(addHeaders); } routerBuilder.route(proxyConf.getString("route"), proxy::handle, routingContext -> { if (routingContext.failed()) { Throwable error = routingContext.failure(); logger.warn("General failure handler", error); String statusMsg = ""; int statusCode = BAD_GATEWAY.code(); if (error instanceof ProxyException) { ProxyException ex = (ProxyException) error; statusCode = ex.statusCode; if (ex.getCause() != null) { statusMsg = ex.getCause().getMessage(); } else if (ex.reason == RejectReason.noHostHeader) { statusMsg = "Exhausted resources while trying to extract Host header from the request"; } } if (!routingContext.response().headWritten() && !routingContext.response().ended()) { routingContext.response().setStatusCode(statusCode); routingContext.response().headers().set("content-type", "text/plain;charset=UTF-8"); routingContext.response().end(statusMsg); } } else { routingContext.next(); } }); } }