code: private ChannelFuture writeContinuationFrames(ChannelHandlerContext ctx, int streamId,
              ByteBuf headerBlock, int padding, SimpleChannelPromiseAggregator promiseAggregator) {
          Http2Flags flags = new Http2Flags().paddingPresent(padding > 0);
          int maxFragmentLength = maxFrameSize - padding;
          // TODO: same padding is applied to all frames, is this desired?
          if (maxFragmentLength <= 0) {
              return promiseAggregator.setFailure(new IllegalArgumentException(
                      "Padding [" + padding + "] is too large for max frame size [" + maxFrameSize + "]"));
          }
  
          if (headerBlock.isReadable()) {
              // The frame header (and padding) only changes on the last frame, so allocate it once and re-use
              int fragmentReadableBytes = min(headerBlock.readableBytes(), maxFragmentLength);
              int payloadLength = fragmentReadableBytes + padding;
              ByteBuf buf = ctx.alloc().buffer(CONTINUATION_FRAME_HEADER_LENGTH);
              writeFrameHeaderInternal(buf, payloadLength, CONTINUATION, flags, streamId);
              writePaddingLength(buf, padding);
  
              do {
                  fragmentReadableBytes = min(headerBlock.readableBytes(), maxFragmentLength);
                  ByteBuf fragment = headerBlock.readRetainedSlice(fragmentReadableBytes);
  
                  payloadLength = fragmentReadableBytes + padding;
                  if (headerBlock.isReadable()) {
                      ctx.write(buf.retain(), promiseAggregator.newPromise());
                  } else {
                      // The frame header is different for the last frame, so re-allocate and release the old buffer
                      flags = flags.endOfHeaders(true);
                      buf.release();
                      buf = ctx.alloc().buffer(CONTINUATION_FRAME_HEADER_LENGTH);
                      writeFrameHeaderInternal(buf, payloadLength, CONTINUATION, flags, streamId);
                      writePaddingLength(buf, padding);
                      ctx.write(buf, promiseAggregator.newPromise());
                  }
  
                  ctx.write(fragment, promiseAggregator.newPromise());
  
                  // Write out the padding, if any.
                  if (paddingBytes(padding) > 0) {
                      ctx.write(ZERO_BUFFER.slice(0, paddingBytes(padding)), promiseAggregator.newPromise());
                  }
              } while (headerBlock.isReadable());
          }
          return promiseAggregator;
      }
docs: Writes as many continuation frames as needed until {@code padding} and {@code headerBlock} are consumed.