108 lines
4.7 KiB
Java
108 lines
4.7 KiB
Java
package com.eactive.httpmockserver.client.service;
|
|
|
|
import com.eactive.httpmockserver.client.dto.ApiRequestDTO;
|
|
import com.eactive.httpmockserver.client.dto.ApiRequestKeyValueDTO;
|
|
import com.eactive.httpmockserver.client.dto.ApiResponse;
|
|
import com.eactive.httpmockserver.common.exception.ServerNotFoundException;
|
|
import com.eactive.httpmockserver.server.entity.Server;
|
|
import com.eactive.httpmockserver.server.entity.ServerRepository;
|
|
import io.netty.bootstrap.Bootstrap;
|
|
import io.netty.buffer.ByteBuf;
|
|
import io.netty.buffer.Unpooled;
|
|
import io.netty.channel.Channel;
|
|
import io.netty.channel.ChannelInitializer;
|
|
import io.netty.channel.ChannelOption;
|
|
import io.netty.channel.EventLoopGroup;
|
|
import io.netty.channel.nio.NioEventLoopGroup;
|
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
|
import io.netty.handler.codec.http.*;
|
|
import io.netty.handler.ssl.SslContext;
|
|
import io.netty.handler.ssl.SslContextBuilder;
|
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
|
import io.netty.util.CharsetUtil;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import javax.net.ssl.SSLException;
|
|
import java.nio.file.Paths;
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
@Service
|
|
public class NettyApiClient {
|
|
|
|
@Autowired
|
|
ServerRepository serverRepository;
|
|
|
|
public CompletableFuture<ApiResponse> handleRequest(ApiRequestDTO apiRequest) throws InterruptedException {
|
|
|
|
Server server = serverRepository.findById(apiRequest.getServer()).orElseThrow(() -> new ServerNotFoundException("Server not found"));
|
|
String host = server.getHostname();
|
|
int port = server.getPort();
|
|
|
|
CompletableFuture<ApiResponse> responseFuture = new CompletableFuture<>();
|
|
EventLoopGroup group = new NioEventLoopGroup();
|
|
try {
|
|
Bootstrap b = new Bootstrap()
|
|
.group(group)
|
|
.channel(NioSocketChannel.class)
|
|
.option(ChannelOption.TCP_NODELAY, true)
|
|
.handler(new ChannelInitializer<Channel>() {
|
|
@Override
|
|
public void initChannel(Channel ch) throws SSLException {
|
|
if (server.getScheme().equalsIgnoreCase("https")) {
|
|
final SslContext sslCtx = SslContextBuilder.forClient()
|
|
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
|
|
ch.pipeline().addLast(sslCtx.newHandler(ch.alloc(), host, port));// Add SSL handler
|
|
}
|
|
|
|
ch.pipeline().addLast(new HttpClientCodec());
|
|
ch.pipeline().addLast(new HttpObjectAggregator(65536));
|
|
ch.pipeline().addLast(new HttpContentDecompressor());
|
|
ch.pipeline().addLast(new HttpHandler(responseFuture));
|
|
}
|
|
});
|
|
|
|
Channel ch = b.connect(host, port).sync().channel();
|
|
ByteBuf content = null;
|
|
if (StringUtils.isNotEmpty(apiRequest.getRequestBody())) {
|
|
content = Unpooled.copiedBuffer(apiRequest.getRequestBody(), CharsetUtil.UTF_8);
|
|
} else {
|
|
content = Unpooled.EMPTY_BUFFER;
|
|
}
|
|
|
|
String basePath = server.getBasePath();
|
|
String fullPath = Paths.get(basePath, apiRequest.getPath()).toString();
|
|
|
|
HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(apiRequest.getMethod()), fullPath, content);
|
|
|
|
request.headers().set("Host", host);
|
|
request.headers().set("Connection", HttpHeaderValues.CLOSE);
|
|
request.headers().set("Accept-Encoding", HttpHeaderValues.GZIP);
|
|
|
|
if (StringUtils.isNotEmpty(apiRequest.getRequestBody())) {
|
|
request.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
|
|
}
|
|
|
|
if (!apiRequest.getHeaders().isEmpty()) {
|
|
HttpHeaders customHeaders = new DefaultHttpHeaders();
|
|
apiRequest.getHeaders().stream().filter(ApiRequestKeyValueDTO::isEnabled).forEach(header -> {
|
|
if (StringUtils.isNotEmpty(header.getKey()) && StringUtils.isNotEmpty(header.getValue())) {
|
|
customHeaders.set(header.getKey(), header.getValue());
|
|
}
|
|
});
|
|
request.headers().add(customHeaders);
|
|
}
|
|
|
|
ch.writeAndFlush(request);
|
|
ch.closeFuture().sync();
|
|
} finally {
|
|
group.shutdownGracefully();
|
|
}
|
|
|
|
return responseFuture;
|
|
}
|
|
|
|
|
|
}
|