unique_ptr THeader::removeHeader()

in thrift/lib/cpp/transport/THeader.cpp [288:416]


unique_ptr<IOBuf> THeader::removeHeader(
    IOBufQueue* queue,
    size_t& needed,
    StringToStringMap& persistentReadHeaders) {
  if (!queue || queue->empty()) {
    needed = 4;
    return nullptr;
  }
  Cursor c(queue->front());
  size_t remaining;
  if (queue->options().cacheChainLength) {
    remaining = queue->chainLength();
  } else {
    remaining = queue->front()->computeChainDataLength();
  }
  size_t frameSizeBytes = 4;
  needed = 0;

  if (remaining < 4) {
    needed = 4 - remaining;
    return nullptr;
  }

  // Use first word to check type.
  uint32_t sz32 = c.readBE<uint32_t>();
  remaining -= 4;

  if (forceClientType_) {
    // Make sure we have read the whole frame in.
    if (isFramed(clientType_) && (sz32 > remaining)) {
      needed = sz32 - remaining;
      return nullptr;
    }
    unique_ptr<IOBuf> buf =
        THeader::removeNonHeader(queue, needed, clientType_, sz32);
    if (buf) {
      return buf;
    }
  }

  auto clientT = THeader::analyzeFirst32bit(sz32);
  if (clientT) {
    clientType_ = *clientT;
    return THeader::removeNonHeader(queue, needed, *clientT, sz32);
  }

  size_t sz;
  if (sz32 > MAX_FRAME_SIZE) {
    if (sz32 == BIG_FRAME_MAGIC) {
      if (!allowBigFrames_) {
        throw TTransportException(
            TTransportException::INVALID_FRAME_SIZE, "Big frames not allowed");
      }
      if (8 > remaining) {
        needed = 8 - remaining;
        return nullptr;
      }
      sz = c.readBE<uint64_t>();
      remaining -= 8;
      frameSizeBytes += 8;
    } else if (
        sz32 == *reinterpret_cast<const uint32_t*>("coll") ||
        sz32 == *reinterpret_cast<const uint32_t*>("H pa")) {
      // special case for the most common question in user-group
      // this will probably saves hours of engineering effort.
      c.retreat(4);
      std::string err = "The Thrift server received an ASCII request '" +
          getReadableChars(c, 32) +
          "' and safely ignored it. "
          "In all likelihood, this isn't the reason of your problem "
          "(probably a local daemon sending HTTP content to all listening ports).";
      throw TTransportException(TTransportException::INVALID_FRAME_SIZE, err);
    } else {
      std::string err = folly::stringPrintf(
          "Header transport frame is too large: %u (hex 0x%08x", sz32, sz32);
      // does it look like ascii?
      if ( // all bytes 0x7f or less; all are > 0x1F
          ((sz32 & 0x7f7f7f7f) == sz32) && ((sz32 >> 24) & 0xff) >= 0x20 &&
          ((sz32 >> 16) & 0xff) >= 0x20 && ((sz32 >> 8) & 0xff) >= 0x20 &&
          ((sz32 >> 0) & 0xff) >= 0x20) {
        char buffer[5];
        uint32_t* asUint32 = reinterpret_cast<uint32_t*>(buffer);
        *asUint32 = folly::Endian::big(sz32);
        buffer[4] = 0;
        folly::stringAppendf(&err, ", ascii '%s'", buffer);
      }
      folly::stringAppendf(&err, ")");
      throw TTransportException(TTransportException::INVALID_FRAME_SIZE, err);
    }
  } else {
    sz = sz32;
  }

  // Make sure we have read the whole frame in.
  if (sz > remaining) {
    needed = sz - remaining;
    return nullptr;
  }

  // Could be header format or framed. Check next uint32
  uint32_t magic = c.readBE<uint32_t>();
  clientType_ = analyzeSecond32bit(magic);
  unique_ptr<IOBuf> buf =
      THeader::removeNonHeader(queue, needed, clientType_, sz);
  if (buf) {
    return buf;
  }

  if (clientType_ == THRIFT_UNKNOWN_CLIENT_TYPE) {
    throw TTransportException(
        TTransportException::BAD_ARGS,
        folly::stringPrintf(
            "Could not detect client transport type: magic 0x%08x", magic));
  }

  if (sz < 10) {
    throw TTransportException(
        TTransportException::INVALID_FRAME_SIZE,
        folly::stringPrintf("Header transport frame is too small: %zu", sz));
  }
  flags_ = magic & FLAGS_MASK;
  seqId_ = c.readBE<uint32_t>();

  // Trim off the frame size.
  queue->trimStart(frameSizeBytes);
  buf = readHeaderFormat(queue->split(sz), persistentReadHeaders);

  return buf;
}