package net.iponweb.disthene.reader.server;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import net.iponweb.disthene.reader.exceptions.EvaluationException;
import net.iponweb.disthene.reader.handler.DistheneReaderHandler;
import org.apache.log4j.Logger;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
/**
* @author Andrei Ivanov
*/
public class ReaderServerHandler extends ChannelInboundHandlerAdapter {
final static Logger logger = Logger.getLogger(ReaderServerHandler.class);
private Map<Pattern, DistheneReaderHandler> handlers = new HashMap<>();
public ReaderServerHandler(Map<Pattern, DistheneReaderHandler> handlers) {
this.handlers = handlers;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object message) {
try {
HttpRequest request = (HttpRequest) message;
boolean keepAlive = HttpHeaders.isKeepAlive(request);
FullHttpResponse response;
if (DefaultHttpHeaders.is100ContinueExpected(request)) {
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
}
logger.debug("Got request: " + ((HttpRequest) message).getMethod() + " " + ((HttpRequest) message).getUri());
byte[] bytes = new byte[((HttpContent) message).content().readableBytes()];
((HttpContent) message).content().readBytes(bytes);
logger.debug("Request content: " + new String(bytes));
String path = new QueryStringDecoder(((HttpRequest) message).getUri()).path();
DistheneReaderHandler handler = null;
for(Map.Entry<Pattern,DistheneReaderHandler> entry : handlers.entrySet()) {
if (entry.getKey().matcher(path).matches()) {
handler = entry.getValue();
break;
}
}
if (handler != null) {
response = handler.handle(request);
} else {
response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
}
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
if (keepAlive) {
response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
ctx.write(response);
} else {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
}
} catch (EvaluationException e) {
FullHttpResponse response;
if (e.getCause() != null) {
response = new DefaultFullHttpResponse(HTTP_1_1, REQUEST_ENTITY_TOO_LARGE, Unpooled.wrappedBuffer(("Ohoho.. We have a problem: " + e.getCause().getMessage()).getBytes()));
} else {
response = new DefaultFullHttpResponse(HTTP_1_1, REQUEST_ENTITY_TOO_LARGE, Unpooled.wrappedBuffer(("Ohoho.. We have a problem: " + e.getMessage()).getBytes()));
}
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} catch (Exception e) {
logger.error("Invalid request: " + e.getMessage());
logger.debug("Invalid request: ", e);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR, Unpooled.wrappedBuffer(("Ohoho.. We have a problem: " + e.getMessage()).getBytes()));
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
logger.error("Exception while processing request", cause);
ctx.close();
}
}