package com.alecgorge.minecraft.jsonapi.packets.netty; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import java.util.List; import java.util.NoSuchElementException; import com.alecgorge.minecraft.jsonapi.JSONAPI; public class JSONAPIChannelDecoder extends ByteToMessageDecoder { private JSONAPI api; public JSONAPIChannelDecoder(JSONAPI api) { this.api = api; } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> list) throws Exception { // use 4 bytes to detect HTTP or abort if (buf.readableBytes() < 4) { return; } buf.retain(2); final int magic1 = buf.getUnsignedByte(buf.readerIndex()); final int magic2 = buf.getUnsignedByte(buf.readerIndex() + 1); final int magic3 = buf.getUnsignedByte(buf.readerIndex() + 2); final int magic4 = buf.getUnsignedByte(buf.readerIndex() + 3); ChannelPipeline p = ctx.channel().pipeline(); if (isHttp(magic1, magic2, magic3, magic4)) { ByteBuf copy = buf.copy(); ctx.channel().config().setOption(ChannelOption.TCP_NODELAY, true); try { while (p.removeLast() != null); } catch (NoSuchElementException e) { } p.addLast("codec-http", new HttpServerCodec()); p.addLast("aggregator", new HttpObjectAggregator(65536)); p.addLast("handler", new JSONAPIHandler(api)); p.fireChannelRead(copy); buf.release(); buf.release(); } else { try { p.remove(this); } catch (NoSuchElementException e) { // probably okay, it just needs to be off System.out.println("NoSuchElementException"); } buf.release(); buf.release(); } } private boolean isHttp(int magic1, int magic2, int magic3, int magic4) { return magic1 == 'G' && magic2 == 'E' && magic3 == 'T' && magic4 == ' ' || // GET magic1 == 'P' && magic2 == 'O' && magic3 == 'S' && magic4 == 'T' || // POST magic1 == 'P' && magic2 == 'U' && magic3 == 'T' && magic4 == ' ' || // PUT magic1 == 'H' && magic2 == 'E' && magic3 == 'A' && magic4 == 'D' || // HEAD magic1 == 'O' && magic2 == 'P' && magic3 == 'T' && magic4 == 'I' || // OPTIONS magic1 == 'P' && magic2 == 'A' && magic3 == 'T' && magic4 == 'C' || // PATCH magic1 == 'D' && magic2 == 'E' && magic3 == 'L' && magic4 == 'E' || // DELETE magic1 == 'T' && magic2 == 'R' && magic3 == 'C' && magic4 == 'C' || // TRACE magic1 == 'C' && magic2 == 'O' && magic3 == 'N' && magic4 == 'N'; // CONNECT } }