blob: 3710415ae012c02b965261e605f13ae61b6e15fb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.camel.k.http;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.net.KeyCertOptions;
import io.vertx.core.net.TrustOptions;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import org.apache.camel.CamelContext;
import org.apache.camel.component.platform.http.PlatformHttpConstants;
import org.apache.camel.support.jsse.KeyManagersParameters;
import org.apache.camel.support.jsse.SSLContextParameters;
import org.apache.camel.support.jsse.TrustManagersParameters;
import org.apache.camel.support.service.ServiceSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class PlatformHttpServer extends ServiceSupport {
private static final Logger LOGGER = LoggerFactory.getLogger(PlatformHttpServer.class);
private final CamelContext context;
private final PlatformHttpServiceConfiguration configuration;
private final Vertx vertx;
private final Router router;
private final ExecutorService executor;
private HttpServer server;
public PlatformHttpServer(CamelContext context, PlatformHttpServiceConfiguration configuration, Vertx vertx, ExecutorService executor) {
this.context = context;
this.configuration = configuration;
this.vertx = vertx;
this.router = Router.router(vertx);
this.executor = executor;
}
@Override
protected void doInit() throws Exception {
final Router subRouter = Router.router(vertx);
if (configuration.getCors().isEnabled()) {
subRouter.route().handler(new org.apache.camel.k.http.support.CorsHandler(configuration));
}
router.mountSubRouter(configuration.getPath(), subRouter);
context.getRegistry().bind(
PlatformHttp.PLATFORM_HTTP_ROUTER_NAME,
new PlatformHttp(vertx, subRouter, Collections.singletonList(createBodyHandler()))
);
SSLContextParameters sslParameters = configuration.getSslContextParameters();
if (sslParameters == null && configuration.isUseGlobalSslContextParameters()) {
sslParameters = context.getSSLContextParameters();
}
HttpServerOptions options = new HttpServerOptions();
if (sslParameters != null) {
options.setSsl(true);
options.setKeyCertOptions(createKeyCertOptions(sslParameters));
options.setTrustOptions(createTrustOptions(sslParameters));
}
server = vertx.createHttpServer(options);
}
@Override
protected void doStart() throws Exception {
CompletableFuture.runAsync(
() -> {
CountDownLatch latch = new CountDownLatch(1);
server.requestHandler(router).listen(configuration.getBindPort(), configuration.getBindHost(), result -> {
try {
if (result.failed()) {
LOGGER.warn("Failed to start Vert.x HttpServer on {}:{}, reason: {}",
configuration.getBindHost(),
configuration.getBindPort(),
result.cause().getMessage()
);
throw new RuntimeException(result.cause());
}
LOGGER.info("Vert.x HttpServer started on {}:{}", configuration.getBindHost(), configuration.getBindPort());
} finally {
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},
executor
).toCompletableFuture().join();
}
@Override
protected void doStop() throws Exception {
try {
if (server != null) {
CompletableFuture.runAsync(
() -> {
CountDownLatch latch = new CountDownLatch(1);
// remove the platform-http component
context.removeComponent(PlatformHttpConstants.PLATFORM_HTTP_COMPONENT_NAME);
server.close(result -> {
try {
if (result.failed()) {
LOGGER.warn("Failed to close Vert.x HttpServer reason: {}",
result.cause().getMessage()
);
throw new RuntimeException(result.cause());
}
LOGGER.info("Vert.x HttpServer stopped");
} finally {
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},
executor
).toCompletableFuture().join();
}
} finally {
this.server = null;
}
}
private Handler<RoutingContext> createBodyHandler() {
BodyHandler bodyHandler = BodyHandler.create();
if (configuration.getMaxBodySize() != null) {
bodyHandler.setBodyLimit(configuration.getMaxBodySize().longValueExact());
}
bodyHandler.setHandleFileUploads(configuration.getBodyHandler().isHandleFileUploads());
bodyHandler.setUploadsDirectory(configuration.getBodyHandler().getUploadsDirectory());
bodyHandler.setDeleteUploadedFilesOnEnd(configuration.getBodyHandler().isDeleteUploadedFilesOnEnd());
bodyHandler.setMergeFormAttributes(configuration.getBodyHandler().isMergeFormAttributes());
bodyHandler.setPreallocateBodyBuffer(configuration.getBodyHandler().isPreallocateBodyBuffer());
return new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
event.request().resume();
bodyHandler.handle(event);
}
};
}
// *****************************
//
// SSL
//
// *****************************
private KeyCertOptions createKeyCertOptions(SSLContextParameters sslContextParameters) {
return new KeyCertOptions() {
@Override
public KeyManagerFactory getKeyManagerFactory(Vertx vertx) throws Exception {
return createKeyManagerFactory(sslContextParameters);
}
@Override
public KeyCertOptions clone() {
return this;
}
};
}
private KeyManagerFactory createKeyManagerFactory(SSLContextParameters sslContextParameters) throws GeneralSecurityException, IOException {
final KeyManagersParameters keyManagers = sslContextParameters.getKeyManagers();
if (keyManagers == null) {
return null;
}
String kmfAlgorithm = context.resolvePropertyPlaceholders(keyManagers.getAlgorithm());
if (kmfAlgorithm == null) {
kmfAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
}
KeyManagerFactory kmf;
if (keyManagers.getProvider() == null) {
kmf = KeyManagerFactory.getInstance(kmfAlgorithm);
} else {
kmf = KeyManagerFactory.getInstance(kmfAlgorithm, context.resolvePropertyPlaceholders(keyManagers.getProvider()));
}
char[] kmfPassword = null;
if (keyManagers.getKeyPassword() != null) {
kmfPassword = context.resolvePropertyPlaceholders(keyManagers.getKeyPassword()).toCharArray();
}
KeyStore ks = keyManagers.getKeyStore() == null ? null : keyManagers.getKeyStore().createKeyStore();
kmf.init(ks, kmfPassword);
return kmf;
}
private TrustOptions createTrustOptions(SSLContextParameters sslContextParameters) {
return new TrustOptions() {
@Override
public TrustOptions clone() {
return this;
}
@Override
public TrustManagerFactory getTrustManagerFactory(Vertx vertx) throws Exception {
return createTrustManagerFactory(sslContextParameters);
}
};
}
private TrustManagerFactory createTrustManagerFactory(SSLContextParameters sslContextParameters) throws GeneralSecurityException, IOException {
final TrustManagersParameters trustManagers = sslContextParameters.getTrustManagers();
if (trustManagers == null) {
return null;
}
TrustManagerFactory tmf = null;
if (trustManagers.getKeyStore() != null) {
String tmfAlgorithm = context.resolvePropertyPlaceholders(trustManagers.getAlgorithm());
if (tmfAlgorithm == null) {
tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
}
if (trustManagers.getProvider() == null) {
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
} else {
tmf = TrustManagerFactory.getInstance(tmfAlgorithm, context.resolvePropertyPlaceholders(trustManagers.getProvider()));
}
KeyStore ks = trustManagers.getKeyStore() == null ? null : trustManagers.getKeyStore().createKeyStore();
tmf.init(ks);
}
return tmf;
}
}