package rfx.server.http; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.QueryStringDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; import rfx.server.http.common.NettyHttpUtil; import rfx.server.http.data.HttpRequestEvent; /** * the public handler for all Netty's message, transform to HttpRequestEvent and routing all matched processors * * @author trieu * */ public class PublicHttpProcessorRoutingHandler extends SimpleChannelInboundHandler<Object> { private static final Map<String, HttpProcessorManager> handlers = new HashMap<>(); //TODO move to config file final static String MAIN_PACKAGE = "ambient.delivery"; public static final int PATTERN_INDEX = 2; public static int DEFAULT_MAX_POOL_SIZE = 20000; public PublicHttpProcessorRoutingHandler(){} public static void init(String mainPackage, int processorPoolSize) throws Exception{ handlers.putAll(HttpProcessorManager.initProcessorPool(mainPackage, HttpProcessorConfig.PUBLIC_ACCESS, processorPoolSize)); } public static void init(String mainPackage) throws Exception{ init(mainPackage, DEFAULT_MAX_POOL_SIZE); } @Override protected void channelRead0(ChannelHandlerContext ctx, Object msg) { if (msg instanceof HttpRequest) { HttpRequest request = (HttpRequest) msg; //TODO filter DDOS/bad/attacking requests String uri = request.getUri(); String remoteIp = NettyHttpUtil.getRemoteIP(ctx, request); String localIp = NettyHttpUtil.getLocalIP(ctx); System.out.println(request.getMethod().name() + "==> uri: " + uri); if (uri.equalsIgnoreCase(NettyHttpUtil.FAVICON_URI)) { NettyHttpUtil.response1pxGifImage(ctx); } else { FullHttpResponse response = null; QueryStringDecoder qDecoder = new QueryStringDecoder(uri); Map<String, List<String>> params = qDecoder.parameters(); //boolean isPOSTMethod = "POST".equals(request.getMethod().name()); HttpProcessorManager processorManager = HttpProcessorManager.routingForUriPath(handlers,qDecoder); HttpRequestEvent requestEvent = null; if(processorManager != null){ requestEvent = new HttpRequestEvent(localIp, remoteIp, uri, params, request); response = processorManager.doProcessing(requestEvent); } else { processorManager = HttpProcessorManager.routingForUriPattern(handlers,qDecoder, PATTERN_INDEX); if(processorManager != null){ requestEvent = new HttpRequestEvent(localIp, remoteIp, uri, params, request); response = processorManager.doProcessing(requestEvent); } else { String s = "Not found HttpProcessor for URI: "+uri; response = NettyHttpUtil.theHttpContent(s, HttpResponseStatus.NOT_FOUND); } } //set version to response header response.headers().add("Server", HttpServer.SERVER_INFO_VERSION); // Write the response. ChannelFuture future = ctx.write(response); ctx.flush().close(); //callback and free resources if(requestEvent != null){ requestEvent.clear(); } //Close the non-keep-alive connection after the write operation is done. future.addListener(ChannelFutureListener.CLOSE); } } if (msg instanceof HttpContent) { if (msg instanceof LastHttpContent) { NettyHttpUtil.response1pxGifImage(ctx); } } } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { ctx.flush().close(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.flush().close(); } }