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;
}