use of org.swisspush.gateleen.logging.LoggingResourceManager in project gateleen by swisspush.
the class Forwarder method handleRequest.
private void handleRequest(final HttpServerRequest req, final Buffer bodyData, final String targetUri, final Logger log, final Map<String, String> profileHeaderMap) {
final LoggingHandler loggingHandler = new LoggingHandler(loggingResourceManager, req, vertx.eventBus());
final String uniqueId = req.headers().get("x-rp-unique_id");
final String timeout = req.headers().get("x-timeout");
final long startTime = monitoringHandler.startRequestMetricTracking(rule.getMetricName(), req.uri());
client.request(req.method(), port, rule.getHost(), targetUri, new Handler<>() {
@Override
public void handle(AsyncResult<HttpClientRequest> event) {
req.resume();
if (event.failed()) {
log.warn("Problem to request {}: {}", targetUri, event.cause());
final HttpServerResponse response = req.response();
response.setStatusCode(StatusCode.SERVICE_UNAVAILABLE.getStatusCode());
response.setStatusMessage(StatusCode.SERVICE_UNAVAILABLE.getStatusMessage());
response.end();
return;
}
HttpClientRequest cReq = event.result();
final Handler<AsyncResult<HttpClientResponse>> cResHandler = getAsyncHttpClientResponseHandler(req, targetUri, log, profileHeaderMap, loggingHandler, startTime);
if (timeout != null) {
cReq.setTimeout(Long.parseLong(timeout));
} else {
cReq.setTimeout(rule.getTimeout());
}
// per https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10
MultiMap headersToForward = req.headers();
headersToForward = HttpHeaderUtil.removeNonForwardHeaders(headersToForward);
cReq.headers().addAll(headersToForward);
if (!ResponseStatusCodeLogUtil.isRequestToExternalTarget(target)) {
cReq.headers().set(SELF_REQUEST_HEADER, "true");
}
if (uniqueId != null) {
cReq.headers().set("x-rp-unique-id", uniqueId);
}
setProfileHeaders(log, profileHeaderMap, cReq);
if (base64UsernamePassword != null) {
cReq.headers().set("Authorization", "Basic " + base64UsernamePassword);
}
final String errorMessage = applyHeaderFunctions(log, cReq.headers());
if (errorMessage != null) {
log.warn("Problem invoking Header functions: {}", errorMessage);
final HttpServerResponse response = req.response();
response.setStatusCode(StatusCode.BAD_REQUEST.getStatusCode());
response.setStatusMessage(StatusCode.BAD_REQUEST.getStatusMessage());
response.end(errorMessage);
return;
}
installExceptionHandler(req, targetUri, startTime, cReq);
/*
* If no bodyData is available
* this means, that the request body isn't
* consumed yet. So we can use the regular
* request for the data.
* If the body is already consumed, we use
* the buffer bodyData.
*/
if (bodyData == null) {
// Gateleen internal requests (e.g. from scedulers or delegates) often have neither "Content-Length" nor "Transfer-Encoding: chunked"
// header - so we must wait for a body buffer to know: Is there a body or not? Only looking on the headers and/or the http-method is not
// sustainable to know "has body or not"
// But: if there is a body, then we need to either setChunked or a Content-Length header (otherwise Vertx complains with an Exception)
//
// Setting 'chunked' always has the downside that we use it also for GET, HEAD, OPTIONS etc... Those request methods normally have no body at all
// But still it's allowed - so they 'could' have one. So using http-method to decide "chunked or not" is also not a sustainable solution.
//
// --> we need to wrap the client-Request to catch up the first (body)-buffer and "setChucked(true)" in advance and just-in-time.
WriteStream<Buffer> cReqWrapped = new WriteStream<>() {
private boolean firstBuffer = true;
@Override
public WriteStream<Buffer> exceptionHandler(Handler<Throwable> handler) {
cReq.exceptionHandler(handler);
return this;
}
@Override
public Future<Void> write(Buffer data) {
// only now we know for sure that there IS a body.
if (firstBuffer) {
// avoid multiple calls due to a 'syncronized' block in HttpClient's implementation
firstBuffer = false;
cReq.setChunked(true);
}
cReq.write(data);
return Future.succeededFuture();
}
@Override
public void write(Buffer data, Handler<AsyncResult<Void>> handler) {
write(data).onComplete(handler);
}
@Override
public Future<Void> end() {
return cReq.end();
}
@Override
public void end(Handler<AsyncResult<Void>> handler) {
this.end().onComplete(handler);
}
@Override
public WriteStream<Buffer> setWriteQueueMaxSize(int maxSize) {
cReq.setWriteQueueMaxSize(maxSize);
return this;
}
@Override
public boolean writeQueueFull() {
return cReq.writeQueueFull();
}
@Override
public WriteStream<Buffer> drainHandler(@Nullable Handler<Void> handler) {
cReq.drainHandler(handler);
return this;
}
};
req.exceptionHandler(t -> {
RequestLoggerFactory.getLogger(Forwarder.class, req).warn("Exception during forwarding - closing (forwarding) client connection", t);
HttpConnection connection = cReq.connection();
if (connection != null) {
connection.close();
}
});
final LoggingWriteStream loggingWriteStream = new LoggingWriteStream(cReqWrapped, loggingHandler, true);
final Pump pump = Pump.pump(req, loggingWriteStream);
if (req.isEnded()) {
// since Vert.x 3.6.0 it can happen that requests without body (e.g. a GET) are ended even while in paused-State
// Setting the endHandler would then lead to an Exception
// see also https://github.com/eclipse-vertx/vert.x/issues/2763
// so we now check if the request already is ended before installing an endHandler
cReq.send(cResHandler);
} else {
req.endHandler(v -> {
cReq.send(cResHandler);
});
pump.start();
}
} else {
loggingHandler.appendRequestPayload(bodyData);
// we already have the body complete in-memory - so we can use Content-Length header and avoid chunked transfer
cReq.putHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(bodyData.length()));
cReq.send(bodyData, cResHandler);
}
loggingHandler.request(cReq.headers());
}
});
}
use of org.swisspush.gateleen.logging.LoggingResourceManager in project gateleen by swisspush.
the class ForwarderTest method setUp.
@Before
public void setUp() {
vertx = Mockito.mock(Vertx.class);
loggingResourceManager = Mockito.mock(LoggingResourceManager.class);
monitoringHandler = Mockito.mock(MonitoringHandler.class);
httpClient = Mockito.mock(HttpClient.class);
storage = new MockResourceStorage(ImmutableMap.of(RULES_PATH, RULES));
logger = LoggerFactory.getLogger(ForwarderTest.class);
}
use of org.swisspush.gateleen.logging.LoggingResourceManager in project gateleen by swisspush.
the class AbstractTest method setupBeforeClass.
/**
* Starts redis before the test classes are instantiated.
*/
@BeforeClass
public static void setupBeforeClass(TestContext context) {
Async async = context.async();
vertx = Vertx.vertx();
jedis = new Jedis("localhost", REDIS_PORT, 10000);
jedis.flushAll();
final JsonObject info = new JsonObject();
final LocalHttpClient selfClient = new LocalHttpClient(vertx);
props.putAll(RunConfig.buildRedisProps("localhost", REDIS_PORT));
String redisHost = (String) props.get("redis.host");
Integer redisPort = (Integer) props.get("redis.port");
props.put(ExpansionHandler.MAX_EXPANSION_LEVEL_HARD_PROPERTY, "100");
props.put(ExpansionHandler.MAX_EXPANSION_LEVEL_SOFT_PROPERTY, "4");
RunConfig.deployModules(vertx, AbstractTest.class, props, success -> {
if (success) {
RedisClient redisClient = new RedisClient(vertx, new RedisOptions().setConnectionString("redis://" + redisHost + ":" + redisPort));
RedisAPI redisAPI = RedisAPI.api(redisClient);
ResourceStorage storage = new EventBusResourceStorage(vertx.eventBus(), Address.storageAddress() + "-main");
MonitoringHandler monitoringHandler = new MonitoringHandler(vertx, storage, PREFIX);
ConfigurationResourceManager configurationResourceManager = new ConfigurationResourceManager(vertx, storage);
String eventBusConfigurationResource = SERVER_ROOT + "/admin/v1/hookconfig";
EventBusHandler eventBusHandler = new EventBusHandler(vertx, SERVER_ROOT + "/event/v1/", SERVER_ROOT + "/event/v1/sock/", "event-", "channels/([^/]+).*", configurationResourceManager, eventBusConfigurationResource);
eventBusHandler.setEventbusBridgePingInterval(RunConfig.EVENTBUS_BRIDGE_PING_INTERVAL);
LoggingResourceManager loggingResourceManager = new LoggingResourceManager(vertx, storage, SERVER_ROOT + "/admin/v1/logging");
UserProfileHandler userProfileHandler = new UserProfileHandler(vertx, storage, RunConfig.buildUserProfileConfiguration());
RoleProfileHandler roleProfileHandler = new RoleProfileHandler(vertx, storage, SERVER_ROOT + "/roles/v1/([^/]+)/profile");
qosHandler = new QoSHandler(vertx, storage, SERVER_ROOT + "/admin/v1/qos", props, PREFIX);
Lock lock = new RedisBasedLock(redisClient);
QueueClient queueClient = new QueueClient(vertx, monitoringHandler);
ReducedPropagationManager reducedPropagationManager = new ReducedPropagationManager(vertx, new RedisReducedPropagationStorage(redisAPI), queueClient, lock);
reducedPropagationManager.startExpiredQueueProcessing(1000);
hookHandler = new HookHandler(vertx, selfClient, storage, loggingResourceManager, monitoringHandler, SERVER_ROOT + "/users/v1/%s/profile", ROOT + "/server/hooks/v1/", queueClient, false, reducedPropagationManager);
propertyHandler = new PropertyHandler(ROOT, props);
schedulerResourceManager = new SchedulerResourceManager(vertx, redisAPI, storage, monitoringHandler, SERVER_ROOT + "/admin/v1/schedulers");
ResetMetricsController resetMetricsController = new ResetMetricsController(vertx);
resetMetricsController.registerResetMetricsControlMBean(JMX_DOMAIN, PREFIX);
LogController logController = new LogController();
logController.registerLogConfiguratorMBean(JMX_DOMAIN);
ZipExtractHandler zipExtractHandler = new ZipExtractHandler(selfClient);
DelegateHandler delegateHandler = new DelegateHandler(vertx, selfClient, storage, monitoringHandler, DELEGATE_ROOT, props, null);
MergeHandler mergeHandler = new MergeHandler(selfClient);
cacheHandler = new CacheHandler(new DefaultCacheDataFetcher(new ClientRequestCreator(selfClient)), new RedisCacheStorage(vertx, lock, redisAPI, 60000), SERVER_ROOT + "/cache");
customHttpResponseHandler = new CustomHttpResponseHandler(RETURN_HTTP_STATUS_ROOT);
// ------
RuleProvider ruleProvider = new RuleProvider(vertx, RULES_ROOT, storage, props);
QueueCircuitBreakerRulePatternToCircuitMapping rulePatternToCircuitMapping = new QueueCircuitBreakerRulePatternToCircuitMapping();
QueueCircuitBreakerConfigurationResourceManager queueCircuitBreakerConfigurationResourceManager = new QueueCircuitBreakerConfigurationResourceManager(vertx, storage, SERVER_ROOT + "/admin/v1/circuitbreaker");
QueueCircuitBreakerStorage queueCircuitBreakerStorage = new RedisQueueCircuitBreakerStorage(redisAPI);
QueueCircuitBreakerHttpRequestHandler requestHandler = new QueueCircuitBreakerHttpRequestHandler(vertx, queueCircuitBreakerStorage, SERVER_ROOT + "/queuecircuitbreaker/circuit");
QueueCircuitBreaker queueCircuitBreaker = new QueueCircuitBreakerImpl(vertx, lock, Address.redisquesAddress(), queueCircuitBreakerStorage, ruleProvider, rulePatternToCircuitMapping, queueCircuitBreakerConfigurationResourceManager, requestHandler, CIRCUIT_BREAKER_REST_API_PORT);
new QueueProcessor(vertx, selfClient, monitoringHandler, queueCircuitBreaker);
final QueueBrowser queueBrowser = new QueueBrowser(vertx, SERVER_ROOT + "/queuing", Address.redisquesAddress(), monitoringHandler);
new CustomRedisMonitor(vertx, redisAPI, "main", "rest-storage", 10).start();
Router router = new Router(vertx, storage, props, loggingResourceManager, monitoringHandler, selfClient, SERVER_ROOT, SERVER_ROOT + "/admin/v1/routing/rules", SERVER_ROOT + "/users/v1/%s/profile", info, STORAGE_PORT, (Handler<Void>) aVoid -> {
System.out.println("Router initialized!");
hookHandler.init();
delegateHandler.init();
});
router.enableRoutingConfiguration(configurationResourceManager, SERVER_ROOT + "/admin/v1/routing/config");
System.setProperty("org.swisspush.gateleen.addcorsheaders", "true");
RunConfig runConfig = RunConfig.with().cacheHandler(cacheHandler).corsHandler(new CORSHandler()).deltaHandler(new DeltaHandler(redisAPI, selfClient, ruleProvider)).expansionHandler(new ExpansionHandler(vertx, storage, selfClient, props, ROOT, RULES_ROOT)).hookHandler(hookHandler).qosHandler(qosHandler).copyResourceHandler(new CopyResourceHandler(selfClient, SERVER_ROOT + "/v1/copy")).eventBusHandler(eventBusHandler).roleProfileHandler(roleProfileHandler).userProfileHandler(userProfileHandler).loggingResourceManager(loggingResourceManager).configurationResourceManager(configurationResourceManager).queueCircuitBreakerConfigurationResourceManager(queueCircuitBreakerConfigurationResourceManager).schedulerResourceManager(schedulerResourceManager).propertyHandler(propertyHandler).zipExtractHandler(zipExtractHandler).delegateHandler(delegateHandler).mergeHandler(mergeHandler).customHttpResponseHandler(customHttpResponseHandler).build(vertx, redisAPI, AbstractTest.class, router, monitoringHandler, queueBrowser);
Handler<RoutingContext> routingContextHandlerrNew = runConfig.buildRoutingContextHandler();
selfClient.setRoutingContexttHandler(routingContextHandlerrNew);
mainServer = vertx.createHttpServer();
io.vertx.ext.web.Router vertxRouter = io.vertx.ext.web.Router.router(vertx);
eventBusHandler.install(vertxRouter);
vertxRouter.route().handler(routingContextHandlerrNew);
mainServer.requestHandler(vertxRouter);
mainServer.listen(MAIN_PORT, event -> {
if (event.succeeded()) {
async.complete();
} else {
context.fail("Server not listening on port " + MAIN_PORT);
}
});
}
});
async.awaitSuccess();
}
use of org.swisspush.gateleen.logging.LoggingResourceManager in project gateleen by swisspush.
the class HookHandlerTest method setUp.
@Before
public void setUp() {
vertx = Vertx.vertx();
httpClient = Mockito.mock(HttpClient.class);
Mockito.when(httpClient.request(any(HttpMethod.class), anyString())).thenReturn(Mockito.mock(Future.class));
storage = new MockResourceStorage();
loggingResourceManager = Mockito.mock(LoggingResourceManager.class);
monitoringHandler = Mockito.mock(MonitoringHandler.class);
requestQueue = Mockito.mock(RequestQueue.class);
reducedPropagationManager = Mockito.mock(ReducedPropagationManager.class);
hookHandler = new HookHandler(vertx, httpClient, storage, loggingResourceManager, monitoringHandler, "userProfilePath", HOOK_ROOT_URI, requestQueue, false, reducedPropagationManager);
hookHandler.init();
}
use of org.swisspush.gateleen.logging.LoggingResourceManager in project gateleen by swisspush.
the class RouterTest method setUp.
@Before
public void setUp() {
// setup
vertx = Mockito.mock(Vertx.class);
Mockito.when(vertx.eventBus()).thenReturn(Mockito.mock(EventBus.class));
Mockito.when(vertx.createHttpClient()).thenReturn(Mockito.mock(HttpClient.class));
Mockito.when(vertx.sharedData()).thenReturn(Vertx.vertx().sharedData());
properties = new HashMap<>();
properties.put("gateleen.test.prop.valid", "http://someserver/");
loggingResourceManager = Mockito.mock(LoggingResourceManager.class);
Mockito.when(loggingResourceManager.getLoggingResource()).thenReturn(new LoggingResource());
monitoringHandler = Mockito.mock(MonitoringHandler.class);
httpClient = Mockito.mock(HttpClient.class);
serverUrl = "/gateleen/server";
rulesPath = serverUrl + "/admin/v1/routing/rules";
randomResourcePath = serverUrl + "/random/resource";
userProfilePath = serverUrl + "/users/v1/%s/profile";
info = new JsonObject();
storage = new MockResourceStorage(ImmutableMap.of(rulesPath, RULES_WITH_MISSING_PROPS, randomResourcePath, RANDOM_RESOURCE));
}
Aggregations