com.github.lontime.exthttp.container.HttpServerService Maven / Gradle / Ivy
package com.github.lontime.exthttp.container;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import com.github.lontime.base.commonj.components.ComponentInterfaceHelper;
import com.github.lontime.base.commonj.components.Lifecycle;
import com.github.lontime.base.commonj.utils.CollectionHelper;
import com.github.lontime.base.commonj.utils.LoggerHelper;
import com.github.lontime.base.commonj.utils.StringHelper;
import com.github.lontime.exthttp.common.ConfigKey;
import com.github.lontime.exthttp.configuration.CertificateSpec;
import com.github.lontime.exthttp.configuration.OptionResolver;
import com.github.lontime.exthttp.configuration.ServerOption;
import com.github.lontime.exthttp.configuration.WiretapSpec;
import io.netty.channel.ChannelOption;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.util.AttributeKey;
import reactor.netty.DisposableServer;
import reactor.netty.http.Http11SslContextSpec;
import reactor.netty.http.Http2SslContextSpec;
import reactor.netty.http.server.HttpServer;
import reactor.netty.tcp.SslProvider;
/**
* ServerContainer.
*
* @author lontime
* @since 1.0
*/
public class HttpServerService implements Lifecycle {
private List servers = new ArrayList<>();
private ExecutorService executorService;
public void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
@Override
public void initialize() {
servers.addAll(OptionResolver.getInstance().getServerOptions()
.stream().map(this::loadServer).filter(Objects::nonNull)
.collect(Collectors.toList()));
}
@Override
public void start() {
if (executorService == null) {
return;
}
executorService.execute(() -> servers.stream()
.filter(DisposableServerWrapper::getAutoStart).forEach(s -> {
LoggerHelper.infov("{0}@start: server start on port {1}...",
getClass().getName(), s.getOption().getPort());
s.setBlocked(true);
s.getDisposableServer().onDispose().block();
}));
}
@Override
public void stop() {
servers.stream().filter(DisposableServerWrapper::getAutoStart).forEach(s -> {
final DisposableServer server = s.getDisposableServer();
LoggerHelper.infov("{0}@stop: server stop on port {1}...",
getClass().getName(), s.getOption().getPort());
server.disposeNow(s.getOption().getDisposeTimeout());
});
}
public DisposableServerWrapper getServer(String name) {
return servers.stream().filter(s -> s.getName().equals(name))
.findAny().orElse(null);
}
private DisposableServerWrapper loadServer(ServerOption option) {
HttpServer server = HttpServer.create();
final List listeners = ComponentInterfaceHelper.get(HttpRouteInterface.class, option.getName());
if (CollectionHelper.isEmpty(listeners)) {
return null;
}
server = server.route(r -> listeners.forEach(s -> {
try {
s.handle(r);
} catch (Exception e) {
LoggerHelper.warnv(e, "{0}@loadServer: route is error", HttpServerService.class.getName());
}
}));
if (option.getPort() != null) {
server = server.port(option.getPort());
}
if (StringHelper.hasText(option.getHost())) {
server = server.host(option.getHost());
}
if (option.getCompressSize() != null) {
server = server.compress(option.getCompressSize());
} else if (option.getEnableCompress() != null) {
server = server.compress(option.getEnableCompress());
}
if (option.getIdleTimeout() != null) {
server = server.idleTimeout(option.getIdleTimeout());
}
if (option.getNoSSL() != null && option.getNoSSL()) {
server = server.noSSL();
}
if (option.getRequestDecoder() != null) {
server = server.httpRequestDecoder(spec -> {
final ServerOption.RequestDecoder requestDecoder = option.getRequestDecoder();
if (requestDecoder.getMaxChunkSize() != null) {
spec.maxChunkSize(requestDecoder.getMaxChunkSize());
}
if (requestDecoder.getMaxHeaderSize() != null) {
spec.maxHeaderSize(requestDecoder.getMaxHeaderSize());
}
if (requestDecoder.getMaxInitialLineLength() != null) {
spec.maxInitialLineLength(requestDecoder.getMaxInitialLineLength());
}
if (requestDecoder.getValidateHeaders() != null) {
spec.validateHeaders(requestDecoder.getValidateHeaders());
}
if (requestDecoder.getInitialBufferSize() != null) {
spec.initialBufferSize(requestDecoder.getInitialBufferSize());
}
if (requestDecoder.getAllowDuplicateContentLengths() != null) {
spec.allowDuplicateContentLengths(requestDecoder.getAllowDuplicateContentLengths());
}
if (requestDecoder.getH2cMaxContentLength() != null) {
spec.h2cMaxContentLength(requestDecoder.getH2cMaxContentLength());
}
return spec;
});
}
if (option.getHttp11Certificate() != null) {
final Optional contextSpecOptional =
buildHttp11SslContextSpec(option.getHttp2Certificate());
if (contextSpecOptional.isPresent()) {
server = server.secure(spec -> spec.sslContext(contextSpecOptional.get()));
}
}
if (option.getHttp2Certificate() != null) {
final Optional contextSpecOptional2 =
buildHttp2SslContextSpec(option.getHttp2Certificate());
if (contextSpecOptional2.isPresent()) {
server = server.secure(spec -> spec.sslContext(contextSpecOptional2.get()));
}
}
if (option.getAccessLog() != null) {
server = server.accessLog(option.getAccessLog());
}
if (option.getForwarded() != null) {
server = server.forwarded(option.getForwarded());
}
if (option.getWiretapEnabled() != null) {
server = server.wiretap(option.getWiretapEnabled());
}
if (option.getWiretapSpec() != null) {
final WiretapSpec wiretapSpec = option.getWiretapSpec();
server = server.wiretap(wiretapSpec.getCategory(), wiretapSpec.getLevel(),
wiretapSpec.getFormat(), wiretapSpec.getCharset());
}
if (CollectionHelper.isNotEmpty(option.getChannelOptions())) {
for (Map.Entry entry : option.getChannelOptions().entrySet()) {
final ConfigKey configKey = entry.getKey();
server = server.option(ChannelOption.valueOf(configKey.getKey()), configKey.parseValue(entry.getValue()));
}
}
if (CollectionHelper.isNotEmpty(option.getEpollChannelOptions())) {
for (Map.Entry entry : option.getEpollChannelOptions().entrySet()) {
final ConfigKey configKey = entry.getKey();
server = server.option(EpollChannelOption.valueOf(configKey.getKey()), configKey.parseValue(entry.getValue()));
}
}
if (CollectionHelper.isNotEmpty(option.getNioChannelOptions())) {
for (Map.Entry entry : option.getNioChannelOptions().entrySet()) {
final ConfigKey configKey = entry.getKey();
server = server.option(NioChannelOption.valueOf(configKey.getKey()), configKey.parseValue(entry.getValue()));
}
}
if (option.getProxyType() != null) {
server = server.proxyProtocol(option.getProxyType());
}
if (CollectionHelper.isNotEmpty(option.getAttrs())) {
for (Map.Entry entry : option.getNioChannelOptions().entrySet()) {
final ConfigKey configKey = entry.getKey();
server = server.attr(AttributeKey.valueOf(configKey.getKey()), configKey.parseValue(entry.getValue()));
}
}
if (option.getWarmup() != null && option.getWarmup()) {
server.warmup().block();
}
return new DisposableServerWrapper(server.bindNow(option.getBindTimeout()), option);
}
private Optional buildHttp11SslContextSpec(CertificateSpec certificate) {
if (certificate.getTesting()) {
try {
final SelfSignedCertificate cert = new SelfSignedCertificate();
return Optional.of(Http11SslContextSpec.forServer(cert.certificate(), cert.privateKey()));
} catch (CertificateException e) {
return Optional.empty();
}
}
if (certificate.getKeyCertChainFile() == null || certificate.getKeyFile() == null) {
return Optional.empty();
}
if (certificate.getKeyPassword() == null) {
return Optional.of(Http11SslContextSpec.forServer(certificate.getKeyCertChainFile(), certificate.getKeyFile()));
} else {
return Optional.of(Http11SslContextSpec.forServer(certificate.getKeyCertChainFile(), certificate.getKeyFile(),
certificate.getKeyPassword()));
}
}
private Optional buildHttp2SslContextSpec(CertificateSpec certificate) {
if (certificate.getTesting()) {
try {
final SelfSignedCertificate cert = new SelfSignedCertificate();
return Optional.of(Http2SslContextSpec.forServer(cert.certificate(), cert.privateKey()));
} catch (CertificateException e) {
return Optional.empty();
}
}
if (certificate.getKeyCertChainFile() == null || certificate.getKeyFile() == null) {
return Optional.empty();
}
if (certificate.getKeyPassword() == null) {
return Optional.of(Http2SslContextSpec.forServer(certificate.getKeyCertChainFile(), certificate.getKeyFile()));
} else {
return Optional.of(Http2SslContextSpec.forServer(certificate.getKeyCertChainFile(), certificate.getKeyFile(),
certificate.getKeyPassword()));
}
}
}