EncryptedReadRecordLayer::ReadResult EncryptedReadRecordLayer::read()

in fizz/record/EncryptedRecordLayer.cpp [112:163]


EncryptedReadRecordLayer::ReadResult<TLSMessage> EncryptedReadRecordLayer::read(
    folly::IOBufQueue& buf,
    Aead::AeadOptions options) {
  auto decryptedBuf = getDecryptedBuf(buf, std::move(options));
  if (!decryptedBuf) {
    return ReadResult<TLSMessage>::noneWithSizeHint(decryptedBuf.sizeHint);
  }

  TLSMessage msg{};
  // Iterate over the buffers while trying to find
  // the first non-zero octet. This is much faster than
  // first iterating and then trimming.
  auto currentBuf = decryptedBuf->get();
  bool nonZeroFound = false;
  do {
    currentBuf = currentBuf->prev();
    size_t i = currentBuf->length();
    while (i > 0 && !nonZeroFound) {
      nonZeroFound = (currentBuf->data()[i - 1] != 0);
      i--;
    }
    if (nonZeroFound) {
      msg.type = static_cast<ContentType>(currentBuf->data()[i]);
    }
    currentBuf->trimEnd(currentBuf->length() - i);
  } while (!nonZeroFound && currentBuf != decryptedBuf->get());
  if (!nonZeroFound) {
    throw std::runtime_error("No content type found");
  }
  msg.fragment = std::move(*decryptedBuf);

  switch (msg.type) {
    case ContentType::handshake:
    case ContentType::alert:
    case ContentType::application_data:
      break;
    default:
      throw std::runtime_error(folly::to<std::string>(
          "received encrypted content type ",
          static_cast<ContentTypeType>(msg.type)));
  }

  if (!msg.fragment || msg.fragment->empty()) {
    if (msg.type == ContentType::application_data) {
      msg.fragment = folly::IOBuf::create(0);
    } else {
      throw std::runtime_error("received empty fragment");
    }
  }

  return ReadResult<TLSMessage>::from(std::move(msg));
}