void HTTPSession::onGoaway(uint64_t lastGoodStreamID,
                           ErrorCode code,
                           std::unique_ptr<folly::IOBuf> debugData) {
  DestructorGuard g(this);
  VLOG(4) << "GOAWAY on " << *this << ", code=" << getErrorCodeString(code);

  setCloseReason(ConnectionCloseReason::GOAWAY);

  // Drain active transactions and prevent new transactions
  drain();

  // We give the less-forceful onGoaway() first so that transactions have
  // a chance to do stat tracking before potentially getting a forceful
  // onError().
  invokeOnAllTransactions(&HTTPTransaction::onGoaway, code);

  // Abort transactions which have been initiated but not created
  // successfully at the remote end. Upstream transactions are created
  // with odd transaction IDs and downstream transactions with even IDs.
  vector<HTTPCodec::StreamID> ids;
  auto firstStream = HTTPCodec::NoStream;

  for (const auto& txn: transactions_) {
    auto streamID = txn.first;
    if (((bool)(streamID & 0x01) == isUpstream()) &&
        (streamID > lastGoodStreamID)) {
      if (firstStream == HTTPCodec::NoStream) {
        // transactions_ is a set so it should be sorted by stream id.
        // We will defer adding the firstStream to the id list until
        // we can determine whether we have a codec error code.
        firstStream = streamID;
        continue;
      }

      ids.push_back(streamID);
    }
  }


  if (firstStream != HTTPCodec::NoStream && code != ErrorCode::NO_ERROR) {
    // If we get a codec error, we will attempt to blame the first stream
    // by delivering a specific error to it and let the rest of the streams
    // get a normal unacknowledged stream error.
    ProxygenError err = kErrorStreamUnacknowledged;
    string debugInfo = (debugData) ?
      folly::to<string>(" with debug info: ", (char*)debugData->data()) : "";
    HTTPException ex(HTTPException::Direction::INGRESS_AND_EGRESS,
      folly::to<std::string>(getErrorString(err),
        " on transaction id: ", *firstStream,
        " with codec error: ", getErrorCodeString(code),
        debugInfo));
    ex.setProxygenError(err);
    errorOnTransactionId(*firstStream, std::move(ex));
  } else if (firstStream != HTTPCodec::NoStream) {
    ids.push_back(*firstStream);
  }

  errorOnTransactionIds(ids, kErrorStreamUnacknowledged);
}
void HTTPSession::onGoaway(uint64_t lastGoodStreamID,
                           ErrorCode code,
                           std::unique_ptr<folly::IOBuf> debugData) {
  DestructorGuard g(this);
  VLOG(4) << "GOAWAY on " << *this << ", code=" << getErrorCodeString(code);

  setCloseReason(ConnectionCloseReason::GOAWAY);

   
  drain();

   
   
   
  invokeOnAllTransactions(&HTTPTransaction::onGoaway, code);

   
   
   
  vector<HTTPCodec::StreamID> ids;
  auto firstStream = HTTPCodec::NoStream;

  for (const auto& txn: transactions_) {
    auto streamID = txn.first;
    if (((bool)(streamID & 0x01) == isUpstream()) &&
        (streamID > lastGoodStreamID)) {
      if (firstStream == HTTPCodec::NoStream) {
         
         
         
        firstStream = streamID;
        continue;
      }

      ids.push_back(streamID);
    }
  }


  if (firstStream != HTTPCodec::NoStream && code != ErrorCode::NO_ERROR) {
     
     
     
    ProxygenError err = kErrorStreamUnacknowledged;
    string debugInfo = (debugData) ?
      folly::to<string>(" with debug info: ", (char*)debugData->data()) : "";
    HTTPException ex(HTTPException::Direction::INGRESS_AND_EGRESS,
      folly::to<std::string>(getErrorString(err),
        " on transaction id: ", *firstStream,
        " with codec error: ", getErrorCodeString(code),
        debugInfo));
    ex.setProxygenError(err);
    errorOnTransactionId(*firstStream, std::move(ex));
  } else if (firstStream != HTTPCodec::NoStream) {
    ids.push_back(*firstStream);
  }

  errorOnTransactionIds(ids, kErrorStreamUnacknowledged);
}