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 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 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() { @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 HttptHandler(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; } }