com.nettyhttpserver.server.util.HttpRequestHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.nettyhttpserver.server.util.HttpRequestHandler.java

Source

/*
 * 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();
        }
    }
}