@Override
 public DataFrame deserialize(InputStream inputStream) throws IOException {
   if (this.streamChecked == null) {
     this.nio = inputStream.getClass().getName().endsWith("TcpNioConnection$ChannelInputStream");
     this.streamAccessor = new DirectFieldAccessor(inputStream);
     this.streamChecked = Boolean.TRUE;
   }
   DataFrame frame = null;
   BasicState state = this.getState(inputStream);
   if (state != null) {
     frame = state.getPendingFrame();
   }
   while (frame == null || (frame.getPayload() == null && frame.getBinary() == null)) {
     frame = doDeserialize(inputStream, frame);
     if (frame.getPayload() == null && frame.getBinary() == null) {
       state.setPendingFrame(frame);
     }
   }
   return frame;
 }
  private DataFrame doDeserialize(InputStream inputStream, DataFrame protoFrame)
      throws IOException {
    List<DataFrame> headers = checkStreaming(inputStream);
    if (headers != null) {
      return headers.get(0);
    }
    int bite;
    if (logger.isDebugEnabled()) {
      logger.debug("Available to read:" + inputStream.available());
    }
    boolean done = false;
    int len = 0;
    int n = 0;
    int dataInx = 0;
    byte[] buffer = null;
    boolean fin = false;
    boolean ping = false;
    boolean pong = false;
    boolean close = false;
    boolean binary = false;
    boolean invalid = false;
    String invalidText = null;
    boolean fragmentedControl = false;
    int lenBytes = 0;
    byte[] mask = new byte[4];
    int maskInx = 0;
    int rsv = 0;
    while (!done) {
      bite = inputStream.read();
      //			logger.debug("Read:" + Integer.toHexString(bite));
      if (this.nio) {
        bite = checkclosed(bite, inputStream);
      }
      if (bite < 0 && n == 0) {
        throw new SoftEndOfStreamException("Stream closed between payloads");
      }
      checkClosure(bite);
      switch (n++) {
        case 0:
          fin = (bite & 0x80) > 0;
          rsv = (bite & 0x70) >> 4;
          bite &= 0x0f;
          switch (bite) {
            case 0x00:
              logger.debug("Continuation, fin=" + fin);
              if (protoFrame == null) {
                invalid = true;
                invalidText = "Unexpected continuation frame";
              } else {
                binary = protoFrame.getType() == WebSocketFrame.TYPE_DATA_BINARY;
              }
              this.getState(inputStream).setPendingFrame(null);
              break;
            case 0x01:
              logger.debug("Text, fin=" + fin);
              if (protoFrame != null) {
                invalid = true;
                invalidText = "Expected continuation frame";
              }
              break;
            case 0x02:
              logger.debug("Binary, fin=" + fin);
              if (protoFrame != null) {
                invalid = true;
                invalidText = "Expected continuation frame";
              }
              binary = true;
              break;
            case 0x08:
              logger.debug("Close, fin=" + fin);
              fragmentedControl = !fin;
              close = true;
              break;
            case 0x09:
              ping = true;
              binary = true;
              fragmentedControl = !fin;
              logger.debug("Ping, fin=" + fin);
              break;
            case 0x0a:
              pong = true;
              fragmentedControl = !fin;
              logger.debug("Pong, fin=" + fin);
              break;
            case 0x03:
            case 0x04:
            case 0x05:
            case 0x06:
            case 0x07:
            case 0x0b:
            case 0x0c:
            case 0x0d:
            case 0x0e:
            case 0x0f:
              invalid = true;
              invalidText = "Reserved opcode " + Integer.toHexString(bite);
              break;
            default:
              throw new IOException("Unexpected opcode " + Integer.toHexString(bite));
          }
          break;
        case 1:
          if (this.server) {
            if ((bite & 0x80) == 0) {
              throw new IOException("Illegal: Expected masked data from client");
            }
            bite &= 0x7f;
          }
          if ((bite & 0x80) > 0) {
            throw new IOException("Illegal: Received masked data from server");
          }
          if (bite < 126) {
            len = bite;
            buffer = new byte[len];
          } else if (bite == 126) {
            lenBytes = 2;
          } else {
            lenBytes = 8;
          }
          break;
        case 2:
        case 3:
        case 4:
        case 5:
          if (lenBytes > 4 && bite != 0) {
            throw new IOException("Max supported length exceeded");
          }
        case 6:
          if (lenBytes > 3 && (bite & 0x80) > 0) {
            throw new IOException("Max supported length exceeded");
          }
        case 7:
        case 8:
        case 9:
          if (lenBytes-- > 0) {
            len = len << 8 | (bite & 0xff);
            if (lenBytes == 0) {
              buffer = new byte[len];
            }
            break;
          }
        default:
          if (this.server && maskInx < 4) {
            mask[maskInx++] = (byte) bite;
          } else {
            if (this.server) {
              bite ^= mask[dataInx % 4];
            }
            buffer[dataInx++] = (byte) bite;
          }
          done = (server ? maskInx == 4 : true) && dataInx >= len;
      }
    }
    ;

    WebSocketFrame frame;

    if (fragmentedControl) {
      frame =
          new WebSocketFrame(
              WebSocketFrame.TYPE_FRAGMENTED_CONTROL, "Fragmented control frame", buffer);
    } else if (invalid) {
      frame = new WebSocketFrame(WebSocketFrame.TYPE_INVALID, invalidText, buffer);
    } else if (!fin) {
      List<byte[]> fragments = this.getState(inputStream).getFragments();
      fragments.add(buffer);
      logger.debug("Fragment");
      return new WebSocketFrame(
          binary ? WebSocketFrame.TYPE_DATA_BINARY : WebSocketFrame.TYPE_DATA, (String) null);
    } else if (ping) {
      frame = new WebSocketFrame(WebSocketFrame.TYPE_PING, buffer);
    } else if (pong) {
      String data = new String(buffer, "UTF-8");
      frame = new WebSocketFrame(WebSocketFrame.TYPE_PONG, data);
    } else if (close) {
      String data = new String(buffer, "UTF-8");
      if (data.length() >= 2) {
        data = data.substring(2);
      }
      WebSocketFrame closeFrame = new WebSocketFrame(WebSocketFrame.TYPE_CLOSE, data);
      short status = 1000;
      if (buffer.length >= 2) {
        status = (short) ((buffer[0] << 8) | (buffer[1] & 0xff));
        closeFrame.setStatus(status);
      }
      if (buffer.length == 1
          || buffer.length > 125
          || (buffer.length > 2 && !validateUtf8IfNecessary(buffer, 2, data))
          || status < 1000
          || INVALID_STATUS.contains(status)
          || (status >= 1016 && status < 3000)
          || status >= 5000) {
        // Simply close in this case; no close reply
        ((WebSocketState) this.getState(inputStream)).setCloseInitiated(true);
      }
      frame = closeFrame;
    } else {
      List<byte[]> fragments = this.getState(inputStream).getFragments();
      if (fragments.size() == 0) {
        if (binary) {
          frame = new WebSocketFrame(WebSocketFrame.TYPE_DATA_BINARY, buffer);
        } else {
          String data = new String(buffer, "UTF-8");
          if (!validateUtf8IfNecessary(buffer, 0, data)) {
            frame = new WebSocketFrame(WebSocketFrame.TYPE_INVALID_UTF8, "Invalid UTF-8", buffer);
          } else {
            frame = new WebSocketFrame(WebSocketFrame.TYPE_DATA, data);
          }
        }
      } else {
        fragments.add(buffer);
        int utf8Len = 0;
        for (byte[] fragment : fragments) {
          utf8Len += fragment.length;
        }
        byte[] reconstructed = new byte[utf8Len];
        int utf8Pos = 0;
        for (byte[] fragment : fragments) {
          System.arraycopy(fragment, 0, reconstructed, utf8Pos, fragment.length);
          utf8Pos += fragment.length;
        }
        fragments.clear();
        if (binary) {
          frame = new WebSocketFrame(WebSocketFrame.TYPE_DATA_BINARY, reconstructed);
        } else {
          String data = new String(reconstructed, "UTF-8");
          if (!validateUtf8IfNecessary(reconstructed, 0, data)) {
            frame =
                new WebSocketFrame(
                    WebSocketFrame.TYPE_INVALID_UTF8, "Invalid UTF-8", reconstructed);
          } else {
            frame = new WebSocketFrame(WebSocketFrame.TYPE_DATA, data);
          }
        }
      }
    }
    if (rsv > 0) {
      frame.setRsv(rsv);
    }
    return frame;
  }