Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.nettyhttpserver.server.util; import com.nettyhttpserver.domain.ConnectionInfoDTO; import com.nettyhttpserver.domain.RedirectRequestDTO; import com.nettyhttpserver.domain.ServerRequestDTO; import com.nettyhttpserver.server.NettyChannelTrafficShapingHandler; import com.nettyhttpserver.service.redirectrequest.RedirectRequestService; import com.nettyhttpserver.service.serverrequest.ServerRequestService; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.group.DefaultChannelGroup; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaders; import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION; import static io.netty.handler.codec.http.HttpHeaders.is100ContinueExpected; import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive; import io.netty.handler.codec.http.HttpRequest; import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE; import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static io.netty.handler.codec.http.HttpResponseStatus.FOUND; import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.util.CharsetUtil; import io.netty.util.HashedWheelTimer; import io.netty.util.Timeout; import io.netty.util.Timer; import io.netty.util.TimerTask; import java.net.InetSocketAddress; import java.sql.Timestamp; import java.util.List; import java.util.ListIterator; import java.util.concurrent.TimeUnit; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * * @author McKey */ public class HttpRequestHandler { private static ByteBuf content = null; private static DefaultChannelGroup allChannels; private static final Timer timer = new HashedWheelTimer(); private static final ApplicationContext context; private static final ServerRequestService serverRequestService; private static final RedirectRequestService redirectRequestService; static { context = new ClassPathXmlApplicationContext("nettyBeans.xml"); serverRequestService = context.getBean(ServerRequestService.class); redirectRequestService = context.getBean(RedirectRequestService.class); } private enum Requests { HELLO("/hello"), STATUS("/status"), REDIRECT("/redirect[?]url=.*"); private String val; Requests(String val) { this.val = val; } @Override public String toString() { return val; } }; private HttpRequestHandler() { } public static void handle(ChannelHandlerContext ctx, HttpRequest req, DefaultChannelGroup channels) { allChannels = channels; FullHttpResponse response = null; boolean keepAlive = isKeepAlive(req); String requestUri = req.getUri().toLowerCase(); /* * Write data about request to database */ ServerRequestDTO requestServiceDTO = new ServerRequestDTO(); requestServiceDTO.setIP(((InetSocketAddress) ctx.channel().remoteAddress()).getHostString()); requestServiceDTO.setLastTimestamp(new Timestamp(System.currentTimeMillis()).toString()); serverRequestService.setServerRequest(requestServiceDTO); if (is100ContinueExpected(req)) { ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE)); } /* * If request /hello */ if (Requests.HELLO.toString().equalsIgnoreCase(requestUri)) { content = Unpooled .unreleasableBuffer(Unpooled.copiedBuffer("<h1>Hello World!</h1>", CharsetUtil.UTF_8)); response = new DefaultFullHttpResponse(HTTP_1_1, OK, content.duplicate()); /* * Create timer for /hello page. */ timer.newTimeout(new ResponseTimerTask(ctx, response, keepAlive), 10, TimeUnit.SECONDS); writeToResponse(ctx, response, keepAlive); return; } /* * if request uri is /status */ if (Requests.STATUS.toString().equalsIgnoreCase(requestUri)) { content = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer(generateStatus(), CharsetUtil.UTF_8)); response = new DefaultFullHttpResponse(HTTP_1_1, OK, content.duplicate()); writeToResponse(ctx, response, keepAlive); return; } /* * If redirect */ if (requestUri.matches(Requests.REDIRECT.toString())) { QueryStringDecoder qsd = new QueryStringDecoder(requestUri); List<String> redirectUrl = qsd.parameters().get("url"); response = new DefaultFullHttpResponse(HTTP_1_1, FOUND); response.headers().set(LOCATION, redirectUrl); /* * Redirect database routine * Write url to database */ RedirectRequestDTO requestRedirectDTO = new RedirectRequestDTO(); requestRedirectDTO.setUrl(redirectUrl.get(0)); redirectRequestService.setRedirectRequest(requestRedirectDTO); } else { /* * If request URI is not handled by server. */ response = new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN); } writeToResponse(ctx, response, keepAlive); } private static void writeToResponse(ChannelHandlerContext ctx, FullHttpResponse response, boolean keepAlive) { response.headers().set(CONTENT_TYPE, "text/html"); response.headers().set(CONTENT_LENGTH, response.content().readableBytes()); if (!keepAlive) { ctx.write(response).addListener(ChannelFutureListener.CLOSE); } else { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE + ":timeout=10"); ctx.write(response); } } private static String generateStatus() { List<ServerRequestDTO> serverRequestList = serverRequestService.getServerRequest(); List<RedirectRequestDTO> redirectRequestList = redirectRequestService.getRedirectRequest(); StringBuilder sb = new StringBuilder(); sb.append( "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><head>") .append( /* * Table style */ "<head>") .append("<style>") .append("table, td {border: solid 1px grey;background-color: rgb(233, 233, 233); margin: 0 auto;") .append("}table {width:90%;text-align: left; font-size: 16pt; bont-weight: bolder;}td{padding: 10px;}") .append("</style>").append("</head>") /* * Requests count */ .append("<h3>Server request count: ").append(serverRequestService.getRequestCount()) .append("<br>Server unique requests count: ").append(serverRequestService.getUniqueRequestCount()) .append("</h3>").append("<br><h3>Open connections: ").append(allChannels.size()).append("</h3>") /* * Table of server requests */ .append("<br><table id=\"table\"><caption>Server requests(last 100 )</caption> ") .append("<thead><tr> <th>IP</th><th>Count</th>") .append("<th>Last Request</th> </tr></thead><tbody> "); for (ServerRequestDTO record : serverRequestList) { sb.append("<tr><td>").append(record.getIP()).append("</td><td>").append(record.getRequestCount()) .append("</td><td>").append(record.getLastTimestamp()).append("</td></tr>"); } sb.append("</tbody></table>"); /* * Table of redirect requests */ sb.append("<table id=\"table\"><caption>Redirect requests(last 100 )</caption> ") .append("<thead><tr><th>URL</th>").append("<th>Count</th> </tr></thead><tbody> "); for (RedirectRequestDTO record : redirectRequestList) { sb.append("<tr><td>").append(record.getUrl()).append("</td><td>").append(record.getCount()) .append("</td>"); } sb.append("</tbody></table>"); /* * Table of server connections columns src_ip, URI, timestamp, * sent_bytes, received_bytes, speed (bytes/sec) */ sb.append("<table id=\"table\"><caption>Last 16 connections").append("</caption>") .append("<tr> <th>IP</th><th>URI</th>") .append("<th>TimeStamp</th><th>Sent</th><th>Recieved</th><th>Speed</th> </tr> "); ListIterator<ConnectionInfoDTO> iterator = NettyChannelTrafficShapingHandler .getServerConnectionListIterator(); synchronized (iterator) { while (iterator.hasPrevious()) { ConnectionInfoDTO item = iterator.previous(); sb.append("<tr><td>").append(item.getIp()).append("</td><td>").append(item.getUri()) .append("</td><td>").append(item.getTimestamp().toLocalDateTime()).append("</td><td>") .append(item.getSentBytes()).append("</td><td>").append(item.getRecivedBytes()) .append("</td><td>").append(item.getSpeed()).append("</td></tr>"); } } sb.append("</table>"); return sb.toString(); } private static class ResponseTimerTask implements TimerTask { private final ChannelHandlerContext ctx; private final FullHttpResponse response; private final boolean keepAlive; public ResponseTimerTask(ChannelHandlerContext ctx, FullHttpResponse response, boolean keepAlive) { this.ctx = ctx; this.response = response; this.keepAlive = keepAlive; } @Override public void run(Timeout timeout) throws Exception { writeToResponse(ctx, response, keepAlive); ctx.flush(); } } }