private void readPingFrame(
     ChannelHandlerContext ctx, ByteBuf payload, Http2FrameObserver observer)
     throws Http2Exception {
   ByteBuf data = payload.readSlice(payload.readableBytes());
   if (flags.ack()) {
     observer.onPingAckRead(ctx, data);
   } else {
     observer.onPingRead(ctx, data);
   }
 }
 private void verifySettingsFrame() throws Http2Exception {
   verifyNotProcessingHeaders();
   verifyPayloadLength(payloadLength);
   if (streamId != 0) {
     throw protocolError("A stream ID must be zero.");
   }
   if (flags.ack() && payloadLength > 0) {
     throw protocolError("Ack settings frame must have an empty payload.");
   }
   if (payloadLength % SETTING_ENTRY_LENGTH > 0) {
     throw protocolError("Frame length %d invalid.", payloadLength);
   }
 }
 private void readSettingsFrame(
     ChannelHandlerContext ctx, ByteBuf payload, Http2FrameObserver observer)
     throws Http2Exception {
   if (flags.ack()) {
     observer.onSettingsAckRead(ctx);
   } else {
     int numSettings = payloadLength / SETTING_ENTRY_LENGTH;
     Http2Settings settings = new Http2Settings();
     for (int index = 0; index < numSettings; ++index) {
       short id = payload.readUnsignedByte();
       long value = payload.readUnsignedInt();
       switch (id) {
         case SETTINGS_HEADER_TABLE_SIZE:
           if (value < 0 || value > Integer.MAX_VALUE) {
             throw protocolError("Invalid value for HEADER_TABLE_SIZE: %d", value);
           }
           settings.maxHeaderTableSize((int) value);
           break;
         case SETTINGS_COMPRESS_DATA:
           if (value != 0 && value != 1) {
             throw protocolError("Invalid value for COMPRESS_DATA: %d", value);
           }
           settings.allowCompressedData(value == 1);
           break;
         case SETTINGS_ENABLE_PUSH:
           if (value != 0 && value != 1) {
             throw protocolError("Invalid value for ENABLE_PUSH: %d", value);
           }
           settings.pushEnabled(value == 1);
           break;
         case SETTINGS_INITIAL_WINDOW_SIZE:
           if (value < 0 || value > Integer.MAX_VALUE) {
             throw protocolError("Invalid value for INITIAL_WINDOW_SIZE: %d", value);
           }
           settings.initialWindowSize((int) value);
           break;
         case SETTINGS_MAX_CONCURRENT_STREAMS:
           if (value < 0 || value > Integer.MAX_VALUE) {
             throw protocolError("Invalid value for MAX_CONCURRENT_STREAMS: %d", value);
           }
           settings.maxConcurrentStreams((int) value);
           break;
         default:
           throw protocolError("Unsupport setting: %d", id);
       }
     }
     observer.onSettingsRead(ctx, settings);
   }
 }