@Override
 protected void handleData(ByteBuffer resource, Http2FrameHeaderParser header) throws IOException {
   boolean continuationFramesComing =
       Bits.anyAreClear(header.flags, Http2Channel.HEADERS_FLAG_END_HEADERS);
   if (frameRemaining == -1) {
     frameRemaining = header.length;
   }
   final boolean moreDataThisFrame = resource.remaining() < frameRemaining;
   final int pos = resource.position();
   try {
     if (!beforeHeadersHandled) {
       if (!handleBeforeHeader(resource, header)) {
         return;
       }
     }
     beforeHeadersHandled = true;
     decoder.setHeaderEmitter(this);
     try {
       decoder.decode(resource, moreDataThisFrame);
     } catch (HpackException e) {
       throw new ConnectionErrorException(Http2Channel.ERROR_COMPRESSION_ERROR, e);
     }
   } finally {
     int used = resource.position() - pos;
     frameRemaining -= used;
   }
 }
 void handleFinalFrame(Http2FrameHeaderParser headerData) {
   Http2FrameHeaderParser data = headerData;
   if (data.type == Http2Channel.FRAME_TYPE_DATA) {
     if (Bits.anyAreSet(data.flags, Http2Channel.DATA_FLAG_END_STREAM)) {
       this.lastFrame();
     }
   } else if (data.type == Http2Channel.FRAME_TYPE_HEADERS) {
     if (Bits.allAreSet(data.flags, Http2Channel.HEADERS_FLAG_END_STREAM)) {
       if (Bits.allAreSet(data.flags, Http2Channel.HEADERS_FLAG_END_HEADERS)) {
         this.lastFrame();
       } else {
         // continuation frames are coming, then we end the stream
         headersEndStream = true;
       }
     }
   } else if (headersEndStream && data.type == Http2Channel.FRAME_TYPE_CONTINUATION) {
     if (Bits.anyAreSet(data.flags, Http2Channel.CONTINUATION_FLAG_END_HEADERS)) {
       this.lastFrame();
     }
   }
 }