void HTTPSession::onError(HTTPCodec::StreamID streamID,
                          const HTTPException& error, bool newTxn) {
  DestructorGuard dg(this);
  // The codec detected an error in the ingress stream, possibly bad
  // syntax, a truncated message, or bad semantics in the frame.  If reads
  // are paused, queue up the event; otherwise, process it now.
  VLOG(4) << "Error on " << *this << ", streamID=" << streamID
          << ", " << error;

  if (ingressError_) {
    return;
  }
  if (!codec_->supportsParallelRequests()) {
    // this error should only prevent us from reading/handling more errors
    // on serial streams
    ingressError_ = true;
    setCloseReason(ConnectionCloseReason::SESSION_PARSE_ERROR);
  }
  if ((streamID == 0) && infoCallback_) {
    infoCallback_->onIngressError(*this, kErrorMessage);
  }

  if (!streamID) {
    ingressError_ = true;
    onSessionParseError(error);
    return;
  }

  HTTPTransaction* txn = findTransaction(streamID);
  if (!txn) {
    if (error.hasHttpStatusCode() && streamID != 0) {
      // If the error has an HTTP code, then parsing was fine, it just was
      // illegal in a higher level way
      txn = createTransaction(streamID, HTTPCodec::NoStream,
                              HTTPCodec::NoExAttributes);
      if (infoCallback_) {
        infoCallback_->onRequestBegin(*this);
      }
      if (txn) {
        handleErrorDirectly(txn, error);
      }
    } else if (newTxn) {
      onNewTransactionParseError(streamID, error);
    } else {
      VLOG(4) << *this << " parse error with invalid transaction";
      invalidStream(streamID);
    }
    return;
  }

  if (!txn->getHandler() &&
      txn->getEgressState() == HTTPTransactionEgressSM::State::Start) {
    handleErrorDirectly(txn, error);
    return;
  }

  txn->onError(error);
  if (!codec_->isReusable() && transactions_.empty()) {
    VLOG(4) << *this << "shutdown from onError";
    setCloseReason(ConnectionCloseReason::SESSION_PARSE_ERROR);
    shutdownTransport(true, true);
  }
}
void HTTPSession::onError(HTTPCodec::StreamID streamID,
                          const HTTPException& error, bool newTxn) {
  DestructorGuard dg(this);
   
   
   
  VLOG(4) << "Error on " << *this << ", streamID=" << streamID
          << ", " << error;

  if (ingressError_) {
    return;
  }
  if (!codec_->supportsParallelRequests()) {
     
     
    ingressError_ = true;
    setCloseReason(ConnectionCloseReason::SESSION_PARSE_ERROR);
  }
  if ((streamID == 0) && infoCallback_) {
    infoCallback_->onIngressError(*this, kErrorMessage);
  }

  if (!streamID) {
    ingressError_ = true;
    onSessionParseError(error);
    return;
  }

  HTTPTransaction* txn = findTransaction(streamID);
  if (!txn) {
    if (error.hasHttpStatusCode() && streamID != 0) {
       
       
      txn = createTransaction(streamID, HTTPCodec::NoStream,
                              HTTPCodec::NoExAttributes);
      if (infoCallback_) {
        infoCallback_->onRequestBegin(*this);
      }
      if (txn) {
        handleErrorDirectly(txn, error);
      }
    } else if (newTxn) {
      onNewTransactionParseError(streamID, error);
    } else {
      VLOG(4) << *this << " parse error with invalid transaction";
      invalidStream(streamID);
    }
    return;
  }

  if (!txn->getHandler() &&
      txn->getEgressState() == HTTPTransactionEgressSM::State::Start) {
    handleErrorDirectly(txn, error);
    return;
  }

  txn->onError(error);
  if (!codec_->isReusable() && transactions_.empty()) {
    VLOG(4) << *this << "shutdown from onError";
    setCloseReason(ConnectionCloseReason::SESSION_PARSE_ERROR);
    shutdownTransport(true, true);
  }
}