docs: private void processCompleteHeaders(boolean isPush) throws CompressionException, ProtocolException {
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "processCompleteHeaders entry: stream " + myID);
          }
          if (this.headerBlock != null) {
              //Leave this to maintain current functionality, but passing a buffer
              //down to the channel is not necessary. H2 Headers will be stored in the H2
              //inbound link wrap.
              WsByteBufferPoolManager bufManager = HttpDispatcher.getBufferManager();
              WsByteBuffer buf = bufManager.allocate(getByteCount(headerBlock));
  
              int firstBlockLength = headerBlock.get(0).length;
              for (byte[] byteArray : headerBlock) {
                  buf.put(byteArray);
              }
              buf.flip();
              headerBlock = null;
  
              //Get ready to decode headers
              boolean isFirstLineComplete = false;
              HashMap<String, String> pseudoHeaders = new HashMap<String, String>();
              ArrayList<H2HeaderField> headers = new ArrayList<H2HeaderField>();
              H2HeaderField current = null;
              boolean isFirstHeaderBlock;
              boolean isFirstHeader = true;
              boolean processTrailerHeaders = headersCompleted;
  
              //Decode headers until we reach the end of the buffer
              while (buf.hasRemaining()) {
                  isFirstHeaderBlock = buf.position() < firstBlockLength;
                  try {
                      current = (H2Headers.decodeHeader(buf, this.muxLink.getReadTable(), isFirstHeader && isFirstHeaderBlock,
                                                        processTrailerHeaders && !isPush, this.muxLink.getLocalConnectionSettings()));
                  } catch (Http2Exception e) {
                      buf.release();
                      throw e;
                  }
                  if (current == null) {
                      // processed a dynamic table size update; go to the next header
                      continue;
                  }
                  isFirstHeader = false;
                  if (!isFirstLineComplete) {
                      //Is this a Pseudo-Header?
                      if (current.getName().startsWith(":")) {
                          //Verify if this is a valid pseudo-header. In the case that this pseudo-header had
                          //already been decoded (two pseudo-headers with same name), throw a decompression
                          //exception and invalidate the table.
                          if (pseudoHeaders.get(current.getName()) != null) {
                              this.muxLink.getReadTable().setDynamicTableValidity(false);
                              buf.release();
                              throw new CompressionException("Invalid pseudo-header for decompression context: " + current.toString());
                          }
                          pseudoHeaders.put(current.getName(), current.getValue());
                      }
                      //If it doesn't start with colon, it is a regular header
                      //so mark this as the beginning of the parsing headers
                      //state and try to set the decoded first line.
                      else {
                          isFirstLineComplete = true;
                          if (H2Headers.getContentLengthValue(current) > -1) {
                              expectedContentLength = H2Headers.getContentLengthValue(current);
                          }
                          headers.add(current);
                      }
                  } else {
                      //If header starts with ':' throw error
                      if (current.getName().startsWith(":")) {
                          this.muxLink.getReadTable().setDynamicTableValidity(false);
                          buf.release();
                          throw new CompressionException("Invalid pseudo-header decoded: all pseudo-headers must appear " +
                                                         "in the header block before regular header fields.");
                      }
                      if (H2Headers.getContentLengthValue(current) > -1) {
                          expectedContentLength = H2Headers.getContentLengthValue(current);
                      }
                      headers.add(current);
                  }
              }
              buf.release();
              // only set headers on the link once
              if ((isPush || !processTrailerHeaders) && h2HttpInboundLinkWrap.getHeadersLength() == 0) {
                  if (!isValidH2Request(pseudoHeaders)) {
                      muxLink.setContinuationExpected(false);
                      muxLink.setWriteContinuationExpected(false);
                      ProtocolException e = new ProtocolException("An invalid request was received on stream-id: " + myID);
                      e.setConnectionError(false); // mark this as a stream error so we'll generate an RST_STREAM
                      throw e;
                  }
                  if (pseudoHeaders.get(HpackConstants.AUTHORITY) != null) {
                      muxLink.setAuthority(pseudoHeaders.get(HpackConstants.AUTHORITY));
                  }
                  //Add all decoded pseudo-headers and headers
                  this.h2HttpInboundLinkWrap.setReadHeaders(headers);
                  this.h2HttpInboundLinkWrap.setReadPseudoHeaders(pseudoHeaders);
              }
          } else {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "processCompleteHeaders no header block set: stream " + myID);
              }
          }
      }