APITester 기본 기능 완료

This commit is contained in:
현성필
2023-05-09 14:36:33 +09:00
parent 6f6b9cde1d
commit f2f235d2ee
12 changed files with 639 additions and 188 deletions
@@ -0,0 +1,69 @@
package com.eactive.httpmockserver.client.service;
import com.eactive.httpmockserver.client.dto.ApiHeaderDTO;
import com.eactive.httpmockserver.client.dto.ApiResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.util.CharsetUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class HttptHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
private final CompletableFuture<ApiResponse> responseFuture;
public HttptHandler(CompletableFuture<ApiResponse> responseFuture) {
this.responseFuture = responseFuture;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) {
ApiResponse apiResponse = new ApiResponse();
apiResponse.setStatus(response.status().code());
apiResponse.setHeaders(convertHttpHeadersToList(response.headers()));
apiResponse.setBody(response.content().toString(CharsetUtil.UTF_8));
int headerSize = calculateHeaderSize(response.headers());
int contentSize = response.content().readableBytes();
int totalSize = headerSize + contentSize;
apiResponse.setSize(totalSize);
responseFuture.complete(apiResponse);
}
private int calculateHeaderSize(HttpHeaders headers) {
int headerSize = 0;
for (Map.Entry<String, String> entry : headers.entries()) {
headerSize += entry.getKey().length() + entry.getValue().length() + 4; // Add 2 for ': ' and 2 for '\r\n'
}
// Add 2 for the final '\r\n' after the headers
headerSize += 2;
return headerSize;
}
public List<ApiHeaderDTO> convertHttpHeadersToList(HttpHeaders headers) {
List<ApiHeaderDTO> headerList = new ArrayList<>();
for (Map.Entry<String, String> entry : headers.entries()) {
ApiHeaderDTO header = new ApiHeaderDTO();
header.setKey(entry.getKey());
header.setValue(entry.getValue());
headerList.add(header);
}
return headerList;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
responseFuture.completeExceptionally(cause);
ctx.close();
}
}
@@ -0,0 +1,67 @@
package com.eactive.httpmockserver.client.service;
import com.eactive.httpmockserver.client.dto.ApiRequestDTO;
import com.eactive.httpmockserver.client.dto.ApiResponse;
import com.eactive.httpmockserver.client.entity.Server;
import com.eactive.httpmockserver.client.repository.ServerRepository;
import io.netty.bootstrap.Bootstrap;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class NettyApiClient {
@Autowired
ServerRepository serverRepository;
public CompletableFuture<ApiResponse> handleRequest(ApiRequestDTO apiRequest) throws Exception {
Server server = serverRepository.findById(apiRequest.getServer()).orElseThrow(() -> new Exception("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) {
ch.pipeline().addLast(new HttpClientCodec());
ch.pipeline().addLast(new HttpObjectAggregator(65536));
ch.pipeline().addLast(new HttpContentDecompressor());
ch.pipeline().addLast(new HttptHandler(responseFuture));
}
});
Channel ch = b.connect(host, port).sync().channel();
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(apiRequest.getMethod()),
apiRequest.getPath(), Unpooled.EMPTY_BUFFER);
request.headers().set("Host", host);
request.headers().set("Connection", "close");
request.headers().set("Accept-Encoding", "gzip");
ch.writeAndFlush(request);
ch.closeFuture().sync();
} finally {
group.shutdownGracefully();
}
return responseFuture;
}
}