void CompressionCorruptionTest::runSimpleTest(const DataHolder& dh) { constexpr uint64_t uncompressedLength = 42; auto original = IOBuf::wrapBuffer(dh.data(uncompressedLength)); auto compressed = codec_->compress(original.get()); if (!codec_->needsUncompressedLength()) { auto uncompressed = codec_->uncompress(compressed.get()); EXPECT_EQ(uncompressedLength, uncompressed->computeChainDataLength()); EXPECT_EQ(dh.hash(uncompressedLength), hashIOBuf(uncompressed.get())); } { auto uncompressed = codec_->uncompress(compressed.get(), uncompressedLength); EXPECT_EQ(uncompressedLength, uncompressed->computeChainDataLength()); EXPECT_EQ(dh.hash(uncompressedLength), hashIOBuf(uncompressed.get())); } EXPECT_THROW(codec_->uncompress(compressed.get(), uncompressedLength + 1), std::runtime_error); // Corrupt the first character ++(compressed->writableData()[0]); if (!codec_->needsUncompressedLength()) { EXPECT_THROW(codec_->uncompress(compressed.get()), std::runtime_error); } EXPECT_THROW(codec_->uncompress(compressed.get(), uncompressedLength), std::runtime_error); }
fbstring IOBuf::moveToFbString() { // malloc-allocated buffers are just fine, everything else needs // to be turned into one. if (!sharedInfo() || // user owned, not ours to give up sharedInfo()->freeFn || // not malloc()-ed headroom() != 0 || // malloc()-ed block doesn't start at beginning tailroom() == 0 || // no room for NUL terminator isShared() || // shared isChained()) { // chained // We might as well get rid of all head and tailroom if we're going // to reallocate; we need 1 byte for NUL terminator. coalesceAndReallocate(0, computeChainDataLength(), this, 1); } // Ensure NUL terminated *writableTail() = 0; fbstring str(reinterpret_cast<char*>(writableData()), length(), capacity(), AcquireMallocatedString()); if (flags() & kFlagFreeSharedInfo) { delete sharedInfo(); } // Reset to a state where we can be deleted cleanly flagsAndSharedInfo_ = 0; buf_ = nullptr; clear(); return str; }
IOBuf IOBuf::cloneCoalescedAsValue() const { if (!isChained()) { return cloneOneAsValue(); } // Coalesce into newBuf const uint64_t newLength = computeChainDataLength(); const uint64_t newHeadroom = headroom(); const uint64_t newTailroom = prev()->tailroom(); const uint64_t newCapacity = newLength + newHeadroom + newTailroom; IOBuf newBuf{CREATE, newCapacity}; newBuf.advance(newHeadroom); auto current = this; do { if (current->length() > 0) { DCHECK_NOTNULL(current->data()); DCHECK_LE(current->length(), newBuf.tailroom()); memcpy(newBuf.writableTail(), current->data(), current->length()); newBuf.append(current->length()); } current = current->next(); } while (current != this); DCHECK_EQ(newLength, newBuf.length()); DCHECK_EQ(newHeadroom, newBuf.headroom()); DCHECK_LE(newTailroom, newBuf.tailroom()); return newBuf; }
void CompressionVarintTest::runSimpleTest(const DataHolder& dh) { auto original = IOBuf::wrapBuffer(dh.data(uncompressedLength_)); auto compressed = codec_->compress(original.get()); auto breakPoint = 1UL + Random::rand64(std::max(9UL, oneBasedMsbPos(uncompressedLength_)) / 9UL); auto tinyBuf = IOBuf::copyBuffer(compressed->data(), std::min(compressed->length(), breakPoint)); compressed->trimStart(breakPoint); tinyBuf->prependChain(std::move(compressed)); compressed = std::move(tinyBuf); auto uncompressed = codec_->uncompress(compressed.get()); EXPECT_EQ(uncompressedLength_, uncompressed->computeChainDataLength()); EXPECT_EQ(dh.hash(uncompressedLength_), hashIOBuf(uncompressed.get())); }
unique_ptr<IOBuf> HPACKCodec::encode(vector<Header>& headers, bool& eviction) noexcept { // convert to HPACK API format vector<HPACKHeader> converted; converted.reserve(headers.size()); uint32_t uncompressed = 0; for (const auto& h : headers) { // HPACKHeader automatically lowercases converted.emplace_back(*h.name, *h.value); auto& header = converted.back(); uncompressed += header.name.size() + header.value.size() + 2; } auto buf = encoder_.encode(converted, encodeHeadroom_, &eviction); encodedSize_.compressed = 0; if (buf) { encodedSize_.compressed = buf->computeChainDataLength(); } encodedSize_.uncompressed = uncompressed; if (stats_) { stats_->recordEncode(Type::HPACK, encodedSize_); } return buf; }
unique_ptr<IOBuf> HPACKCodec::encode(vector<Header>& headers) noexcept { vector<HPACKHeader> converted; // convert to HPACK API format uint32_t uncompressed = 0; for (const auto& h : headers) { HPACKHeader header(*h.name, *h.value); // This is ugly but since we're not changing the size // of the string I'm assuming this is OK char* mutableName = const_cast<char*>(header.name.data()); folly::toLowerAscii(mutableName, header.name.size()); converted.push_back(header); uncompressed += header.name.size() + header.value.size() + 2; } auto buf = encoder_->encode(converted, encodeHeadroom_); encodedSize_.compressed = 0; if (buf) { encodedSize_.compressed = buf->computeChainDataLength(); } encodedSize_.uncompressed = uncompressed; if (stats_) { stats_->recordEncode(Type::HPACK, encodedSize_); } return std::move(buf); }