content: 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
      }
  }
  