docs: @Override
      public VirtualConnection finishRequestMessage(WsByteBuffer[] body, InterChannelCallback callback, boolean bForce) throws MessageSentException {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.entry(tc, "finishRequestMessage(async)");
          }
  
          if (isMessageSent()) {
              throw new MessageSentException("Message already sent");
          }
  
          // if headers haven't been sent and chunked encoding is not explicitly
          // configured, then set this up for Content-Length
          if (!headersSent()) {
              if (!getRequestImpl().isChunkedEncodingSet()) {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Setting partial body false");
                  }
                  setPartialBody(false);
              }
          }
  
          if (getHttpConfig().runningOnZOS()) {
              // @LIDB3187-27.1
              // add this to notify the xmem channel of our final request write
              getVC().getStateMap().put(HttpConstants.FINAL_WRITE_MARK, "true");
          }
          setForceAsync(bForce);
          getLink().setAllowReconnect(true);
          setAppWriteCallback(callback);
          VirtualConnection vc = sendFullOutgoing(body, getRequestImpl(), HttpOSCWriteCallback.getRef());
          if (null != vc) {
              // Note: if forcequeue is true, then we will not get a VC object as
              // the lower layer will use the callback and return null
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "Request write completed immediately.");
              }
              // LI4335 - if early reads are going, then do not bother with response
              // message information here
              if (this.bEarlyReads) {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                      Tr.exit(tc, "finishRequestMessage(async): early read is active");
                  }
                  return getVC();
              }
  
              // if headers are parsed and this is a final response, exit out.
              // if a temp response and using temps, return out. If temp and not
              // using temps, keep reading for final
              if (headersParsed()) {
                  if (this.bTempResponsesUsed || !getResponseImpl().isTemporaryStatusCode()) {
                      // app channel wants to see all the responses
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                          Tr.exit(tc, "finishRequestMessage(async): already parsed");
                      }
                      return getVC();
                  }
                  // the app channel does not want to see the previously parsed msg
                  resetRead();
                  readAsyncResponse();
                  vc = null;
              } else {
                  // start the read for the first response
                  vc = startResponseRead();
              }
          }
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.exit(tc, "finishRequestMessage(async): " + vc);
          }
          return vc;
      }