void SaslNegotiationHandler::read(Context* ctx, BufAndHeader bufAndHeader) {
  if (protectionHandler_->getProtectionState() == ProtectionState::NONE) {
    // This handler should be removed from the pipeline after sasl
    // negotiation is completed. If it is still installed, it should
    // do nothing.
    ctx->fireRead(std::move(bufAndHeader));
  } else {
    if (handleSecurityMessage(std::move(bufAndHeader.first),
                              std::move(bufAndHeader.second))) {
      ctx->fireRead(std::move(bufAndHeader));
    }
  }
}
void HeaderServerChannel::messageReceived(unique_ptr<IOBuf>&& buf,
                                          unique_ptr<sample> sample) {
  DestructorGuard dg(this);

  buf = handleSecurityMessage(std::move(buf));

  if (!buf) {
    return;
  }

  uint32_t recvSeqId = header_->getSequenceNumber();
  bool outOfOrder = (header_->getFlags() & HEADER_FLAG_SUPPORT_OUT_OF_ORDER);
  if (!outOfOrder) {
    // Create a new seqid for in-order messages because they might not
    // be sequential.  This seqid is only used internally in HeaderServerChannel
    recvSeqId = arrivalSeqId_++;
  }

  bool clientExpectsStreaming = false;

  // Currently only HeaderClientChannel sets the stream flags.
  // It also sets HEADER_FLAG_SUPPRORT_OUT_OF_ORDER, and currently there
  // is no way for the client to unset this flag in the HeaderClientChannel,
  // so all streaming message will have outOfOrder == true
  if (outOfOrder) {
    uint16_t streamFlag = header_->getStreamFlag();
    header_->clearStreamFlag();

    if ((streamFlag == HEADER_FLAG_STREAM_PIECE) ||
        (streamFlag == HEADER_FLAG_STREAM_END)) {
      // since the client supports out of order, the sequenceId will be
      // unique to the stream
      auto streamIte = streams_.find(recvSeqId);
      if (streamIte != streams_.end()) {
        auto& stream = streamIte->second;
        stream->notifyReceive(std::move(buf));
      } else {
        // we didn't find the stream, possibly because it has errored on our
        // side and data is still being sent to us
        VLOG(5) << "no stream found with id " << recvSeqId;
      }

      return;
    }

    clientExpectsStreaming = (streamFlag == HEADER_FLAG_STREAM_BEGIN);
  }

  if (callback_) {
    Stream* streamPtr = nullptr;

    unique_ptr<Request> request(
        new HeaderRequest(recvSeqId, this, std::move(buf),
                          header_->getHeaders(),
                          header_->getTransforms(),
                          outOfOrder,
                          clientExpectsStreaming,
                          &streamPtr,
                          std::move(sample)));

    if (!outOfOrder) {
      if (inOrderRequests_.size() > MAX_REQUEST_SIZE) {
        // There is probably nothing useful we can do here.
        LOG(WARNING) << "Hit in order request buffer limit";
        TTransportException ex("Hit in order request buffer limit");
        messageReceiveError(make_exception_ptr(ex));
        return;
      }
    }

    try {
      callback_->requestReceived(std::move(request));
    } catch (const std::exception& e) {
      LOG(WARNING) << "Could not parse request: " << e.what();
    }

    if (streamPtr != nullptr) {
      CHECK(clientExpectsStreaming);
      auto inserted = streams_.insert(std::make_pair(recvSeqId, streamPtr));
      CHECK(inserted.second);
    }
  }
}