Lift generic functionality from QuicDataReader/QuicDataWriter into Quiche The QUIC-specific functions stay in QuicDataReader/QuicDataWriter. Generally useful functions are moved into QuicheDataReader/QuicheDataWriter. gfe-relnote: n/a, no functional change PiperOrigin-RevId: 288584295 Change-Id: I53b102f56f43019a89db0aa624898ed44bb6ec11
diff --git a/common/quiche_data_reader.cc b/common/quiche_data_reader.cc new file mode 100644 index 0000000..9842add --- /dev/null +++ b/common/quiche_data_reader.cc
@@ -0,0 +1,189 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/common/quiche_data_reader.h" + +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_logging.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quiche { + +QuicheDataReader::QuicheDataReader(quiche::QuicheStringPiece data) + : QuicheDataReader(data.data(), data.length(), quiche::NETWORK_BYTE_ORDER) { +} + +QuicheDataReader::QuicheDataReader(const char* data, const size_t len) + : QuicheDataReader(data, len, quiche::NETWORK_BYTE_ORDER) {} + +QuicheDataReader::QuicheDataReader(const char* data, + const size_t len, + quiche::Endianness endianness) + : data_(data), len_(len), pos_(0), endianness_(endianness) {} + +bool QuicheDataReader::ReadUInt8(uint8_t* result) { + return ReadBytes(result, sizeof(*result)); +} + +bool QuicheDataReader::ReadUInt16(uint16_t* result) { + if (!ReadBytes(result, sizeof(*result))) { + return false; + } + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + *result = quiche::QuicheEndian::NetToHost16(*result); + } + return true; +} + +bool QuicheDataReader::ReadUInt32(uint32_t* result) { + if (!ReadBytes(result, sizeof(*result))) { + return false; + } + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + *result = quiche::QuicheEndian::NetToHost32(*result); + } + return true; +} + +bool QuicheDataReader::ReadUInt64(uint64_t* result) { + if (!ReadBytes(result, sizeof(*result))) { + return false; + } + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + *result = quiche::QuicheEndian::NetToHost64(*result); + } + return true; +} + +bool QuicheDataReader::ReadBytesToUInt64(size_t num_bytes, uint64_t* result) { + *result = 0u; + if (num_bytes > sizeof(*result)) { + return false; + } + if (endianness_ == quiche::HOST_BYTE_ORDER) { + return ReadBytes(result, num_bytes); + } + + if (!ReadBytes(reinterpret_cast<char*>(result) + sizeof(*result) - num_bytes, + num_bytes)) { + return false; + } + *result = quiche::QuicheEndian::NetToHost64(*result); + return true; +} + +bool QuicheDataReader::ReadStringPiece16(quiche::QuicheStringPiece* result) { + // Read resultant length. + uint16_t result_len; + if (!ReadUInt16(&result_len)) { + // OnFailure() already called. + return false; + } + + return ReadStringPiece(result, result_len); +} + +bool QuicheDataReader::ReadStringPiece(quiche::QuicheStringPiece* result, + size_t size) { + // Make sure that we have enough data to read. + if (!CanRead(size)) { + OnFailure(); + return false; + } + + // Set result. + *result = quiche::QuicheStringPiece(data_ + pos_, size); + + // Iterate. + pos_ += size; + + return true; +} + +bool QuicheDataReader::ReadTag(uint32_t* tag) { + return ReadBytes(tag, sizeof(*tag)); +} + +quiche::QuicheStringPiece QuicheDataReader::ReadRemainingPayload() { + quiche::QuicheStringPiece payload = PeekRemainingPayload(); + pos_ = len_; + return payload; +} + +quiche::QuicheStringPiece QuicheDataReader::PeekRemainingPayload() const { + return quiche::QuicheStringPiece(data_ + pos_, len_ - pos_); +} + +quiche::QuicheStringPiece QuicheDataReader::FullPayload() const { + return quiche::QuicheStringPiece(data_, len_); +} + +bool QuicheDataReader::ReadBytes(void* result, size_t size) { + // Make sure that we have enough data to read. + if (!CanRead(size)) { + OnFailure(); + return false; + } + + // Read into result. + memcpy(result, data_ + pos_, size); + + // Iterate. + pos_ += size; + + return true; +} + +bool QuicheDataReader::Seek(size_t size) { + if (!CanRead(size)) { + OnFailure(); + return false; + } + pos_ += size; + return true; +} + +bool QuicheDataReader::IsDoneReading() const { + return len_ == pos_; +} + +size_t QuicheDataReader::BytesRemaining() const { + return len_ - pos_; +} + +bool QuicheDataReader::TruncateRemaining(size_t truncation_length) { + if (truncation_length > BytesRemaining()) { + return false; + } + len_ = pos_ + truncation_length; + return true; +} + +bool QuicheDataReader::CanRead(size_t bytes) const { + return bytes <= (len_ - pos_); +} + +void QuicheDataReader::OnFailure() { + // Set our iterator to the end of the buffer so that further reads fail + // immediately. + pos_ = len_; +} + +uint8_t QuicheDataReader::PeekByte() const { + if (pos_ >= len_) { + QUICHE_LOG(FATAL) + << "Reading is done, cannot peek next byte. Tried to read pos = " + << pos_ << " buffer length = " << len_; + return 0; + } + return data_[pos_]; +} + +std::string QuicheDataReader::DebugString() const { + return quiche::QuicheStrCat(" { length: ", len_, ", position: ", pos_, " }"); +} + +#undef ENDPOINT // undef for jumbo builds +} // namespace quiche
diff --git a/common/quiche_data_reader.h b/common/quiche_data_reader.h new file mode 100644 index 0000000..45c0961 --- /dev/null +++ b/common/quiche_data_reader.h
@@ -0,0 +1,173 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_COMMON_QUICHE_DATA_READER_H_ +#define QUICHE_COMMON_QUICHE_DATA_READER_H_ + +#include <cstddef> +#include <cstdint> +#include <limits> + +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quiche { + +// To use, simply construct a QuicheDataReader using the underlying buffer that +// you'd like to read fields from, then call one of the Read*() methods to +// actually do some reading. +// +// This class keeps an internal iterator to keep track of what's already been +// read and each successive Read*() call automatically increments said iterator +// on success. On failure, internal state of the QuicheDataReader should not be +// trusted and it is up to the caller to throw away the failed instance and +// handle the error as appropriate. None of the Read*() methods should ever be +// called after failure, as they will also fail immediately. +class QUICHE_EXPORT_PRIVATE QuicheDataReader { + public: + // Constructs a reader using NETWORK_BYTE_ORDER endianness. + // Caller must provide an underlying buffer to work on. + explicit QuicheDataReader(quiche::QuicheStringPiece data); + // Constructs a reader using NETWORK_BYTE_ORDER endianness. + // Caller must provide an underlying buffer to work on. + QuicheDataReader(const char* data, const size_t len); + // Constructs a reader using the specified endianness. + // Caller must provide an underlying buffer to work on. + QuicheDataReader(const char* data, + const size_t len, + quiche::Endianness endianness); + QuicheDataReader(const QuicheDataReader&) = delete; + QuicheDataReader& operator=(const QuicheDataReader&) = delete; + + // Empty destructor. + ~QuicheDataReader() {} + + // Reads an 8/16/32/64-bit unsigned integer into the given output + // parameter. Forwards the internal iterator on success. Returns true on + // success, false otherwise. + bool ReadUInt8(uint8_t* result); + bool ReadUInt16(uint16_t* result); + bool ReadUInt32(uint32_t* result); + bool ReadUInt64(uint64_t* result); + + // Set |result| to 0, then read |num_bytes| bytes in the correct byte order + // into least significant bytes of |result|. + bool ReadBytesToUInt64(size_t num_bytes, uint64_t* result); + + // Reads a string prefixed with 16-bit length into the given output parameter. + // + // NOTE: Does not copy but rather references strings in the underlying buffer. + // This should be kept in mind when handling memory management! + // + // Forwards the internal iterator on success. + // Returns true on success, false otherwise. + bool ReadStringPiece16(quiche::QuicheStringPiece* result); + + // Reads a given number of bytes into the given buffer. The buffer + // must be of adequate size. + // Forwards the internal iterator on success. + // Returns true on success, false otherwise. + bool ReadStringPiece(quiche::QuicheStringPiece* result, size_t size); + + // Reads tag represented as 32-bit unsigned integer into given output + // parameter. Tags are in big endian on the wire (e.g., CHLO is + // 'C','H','L','O') and are read in byte order, so tags in memory are in big + // endian. + bool ReadTag(uint32_t* tag); + + // Returns the remaining payload as a quiche::QuicheStringPiece. + // + // NOTE: Does not copy but rather references strings in the underlying buffer. + // This should be kept in mind when handling memory management! + // + // Forwards the internal iterator. + quiche::QuicheStringPiece ReadRemainingPayload(); + + // Returns the remaining payload as a quiche::QuicheStringPiece. + // + // NOTE: Does not copy but rather references strings in the underlying buffer. + // This should be kept in mind when handling memory management! + // + // DOES NOT forward the internal iterator. + quiche::QuicheStringPiece PeekRemainingPayload() const; + + // Returns the entire payload as a quiche::QuicheStringPiece. + // + // NOTE: Does not copy but rather references strings in the underlying buffer. + // This should be kept in mind when handling memory management! + // + // DOES NOT forward the internal iterator. + quiche::QuicheStringPiece FullPayload() const; + + // Reads a given number of bytes into the given buffer. The buffer + // must be of adequate size. + // Forwards the internal iterator on success. + // Returns true on success, false otherwise. + bool ReadBytes(void* result, size_t size); + + // Skips over |size| bytes from the buffer and forwards the internal iterator. + // Returns true if there are at least |size| bytes remaining to read, false + // otherwise. + bool Seek(size_t size); + + // Returns true if the entirety of the underlying buffer has been read via + // Read*() calls. + bool IsDoneReading() const; + + // Returns the number of bytes remaining to be read. + size_t BytesRemaining() const; + + // Truncates the reader down by reducing its internal length. + // If called immediately after calling this, BytesRemaining will + // return |truncation_length|. If truncation_length is less than the + // current value of BytesRemaining, this does nothing and returns false. + bool TruncateRemaining(size_t truncation_length); + + // Returns the next byte that to be read. Must not be called when there are no + // bytes to be read. + // + // DOES NOT forward the internal iterator. + uint8_t PeekByte() const; + + std::string DebugString() const; + + protected: + // Returns true if the underlying buffer has enough room to read the given + // amount of bytes. + bool CanRead(size_t bytes) const; + + // To be called when a read fails for any reason. + void OnFailure(); + + const char* data() const { return data_; } + + size_t pos() const { return pos_; } + + void AdvancePos(size_t amount) { + DCHECK_LE(pos_, std::numeric_limits<size_t>::max() - amount); + DCHECK_LE(pos_, len_ - amount); + pos_ += amount; + } + + quiche::Endianness endianness() const { return endianness_; } + + private: + // TODO(fkastenholz, b/73004262) change buffer_, et al, to be uint8_t, not + // char. The data buffer that we're reading from. + const char* data_; + + // The length of the data buffer that we're reading from. + size_t len_; + + // The location of the next read from our data buffer. + size_t pos_; + + // The endianness to read integers and floating numbers. + quiche::Endianness endianness_; +}; + +} // namespace quiche + +#endif // QUICHE_COMMON_QUICHE_DATA_READER_H_
diff --git a/common/quiche_data_writer.cc b/common/quiche_data_writer.cc new file mode 100644 index 0000000..4488f72 --- /dev/null +++ b/common/quiche_data_writer.cc
@@ -0,0 +1,152 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/common/quiche_data_writer.h" + +#include <algorithm> +#include <limits> + +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quiche { + +QuicheDataWriter::QuicheDataWriter(size_t size, char* buffer) + : QuicheDataWriter(size, buffer, quiche::NETWORK_BYTE_ORDER) {} + +QuicheDataWriter::QuicheDataWriter(size_t size, + char* buffer, + quiche::Endianness endianness) + : buffer_(buffer), capacity_(size), length_(0), endianness_(endianness) {} + +QuicheDataWriter::~QuicheDataWriter() {} + +char* QuicheDataWriter::data() { + return buffer_; +} + +bool QuicheDataWriter::WriteUInt8(uint8_t value) { + return WriteBytes(&value, sizeof(value)); +} + +bool QuicheDataWriter::WriteUInt16(uint16_t value) { + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + value = quiche::QuicheEndian::HostToNet16(value); + } + return WriteBytes(&value, sizeof(value)); +} + +bool QuicheDataWriter::WriteUInt32(uint32_t value) { + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + value = quiche::QuicheEndian::HostToNet32(value); + } + return WriteBytes(&value, sizeof(value)); +} + +bool QuicheDataWriter::WriteUInt64(uint64_t value) { + if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + value = quiche::QuicheEndian::HostToNet64(value); + } + return WriteBytes(&value, sizeof(value)); +} + +bool QuicheDataWriter::WriteBytesToUInt64(size_t num_bytes, uint64_t value) { + if (num_bytes > sizeof(value)) { + return false; + } + if (endianness_ == quiche::HOST_BYTE_ORDER) { + return WriteBytes(&value, num_bytes); + } + + value = quiche::QuicheEndian::HostToNet64(value); + return WriteBytes(reinterpret_cast<char*>(&value) + sizeof(value) - num_bytes, + num_bytes); +} + +bool QuicheDataWriter::WriteStringPiece16(quiche::QuicheStringPiece val) { + if (val.size() > std::numeric_limits<uint16_t>::max()) { + return false; + } + if (!WriteUInt16(static_cast<uint16_t>(val.size()))) { + return false; + } + return WriteBytes(val.data(), val.size()); +} + +bool QuicheDataWriter::WriteStringPiece(quiche::QuicheStringPiece val) { + return WriteBytes(val.data(), val.size()); +} + +char* QuicheDataWriter::BeginWrite(size_t length) { + if (length_ > capacity_) { + return nullptr; + } + + if (capacity_ - length_ < length) { + return nullptr; + } + +#ifdef ARCH_CPU_64_BITS + DCHECK_LE(length, std::numeric_limits<uint32_t>::max()); +#endif + + return buffer_ + length_; +} + +bool QuicheDataWriter::WriteBytes(const void* data, size_t data_len) { + char* dest = BeginWrite(data_len); + if (!dest) { + return false; + } + + memcpy(dest, data, data_len); + + length_ += data_len; + return true; +} + +bool QuicheDataWriter::WriteRepeatedByte(uint8_t byte, size_t count) { + char* dest = BeginWrite(count); + if (!dest) { + return false; + } + + memset(dest, byte, count); + + length_ += count; + return true; +} + +void QuicheDataWriter::WritePadding() { + DCHECK_LE(length_, capacity_); + if (length_ > capacity_) { + return; + } + memset(buffer_ + length_, 0x00, capacity_ - length_); + length_ = capacity_; +} + +bool QuicheDataWriter::WritePaddingBytes(size_t count) { + return WriteRepeatedByte(0x00, count); +} + +bool QuicheDataWriter::WriteTag(uint32_t tag) { + return WriteBytes(&tag, sizeof(tag)); +} + +bool QuicheDataWriter::Seek(size_t length) { + if (!BeginWrite(length)) { + return false; + } + length_ += length; + return true; +} + +std::string QuicheDataWriter::DebugString() const { + return quiche::QuicheStrCat(" { capacity: ", capacity_, ", length: ", length_, + " }"); +} + +} // namespace quiche
diff --git a/common/quiche_data_writer.h b/common/quiche_data_writer.h new file mode 100644 index 0000000..8df1f90 --- /dev/null +++ b/common/quiche_data_writer.h
@@ -0,0 +1,110 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_COMMON_QUICHE_DATA_WRITER_H_ +#define QUICHE_COMMON_QUICHE_DATA_WRITER_H_ + +#include <cstddef> +#include <cstdint> +#include <limits> + +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_export.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quiche { + +// This class provides facilities for packing binary data. +// +// The QuicheDataWriter supports appending primitive values (int, string, etc) +// to a frame instance. The internal memory buffer is exposed as the "data" +// of the QuicheDataWriter. +class QUICHE_EXPORT_PRIVATE QuicheDataWriter { + public: + // Creates a QuicheDataWriter where |buffer| is not owned + // using NETWORK_BYTE_ORDER endianness. + QuicheDataWriter(size_t size, char* buffer); + // Creates a QuicheDataWriter where |buffer| is not owned + // using the specified endianness. + QuicheDataWriter(size_t size, char* buffer, quiche::Endianness endianness); + QuicheDataWriter(const QuicheDataWriter&) = delete; + QuicheDataWriter& operator=(const QuicheDataWriter&) = delete; + + ~QuicheDataWriter(); + + // Returns the size of the QuicheDataWriter's data. + size_t length() const { return length_; } + + // Retrieves the buffer from the QuicheDataWriter without changing ownership. + char* data(); + + // Methods for adding to the payload. These values are appended to the end + // of the QuicheDataWriter payload. + + // Writes 8/16/32/64-bit unsigned integers. + bool WriteUInt8(uint8_t value); + bool WriteUInt16(uint16_t value); + bool WriteUInt32(uint32_t value); + bool WriteUInt64(uint64_t value); + + // Writes least significant |num_bytes| of a 64-bit unsigned integer in the + // correct byte order. + bool WriteBytesToUInt64(size_t num_bytes, uint64_t value); + + bool WriteStringPiece(quiche::QuicheStringPiece val); + bool WriteStringPiece16(quiche::QuicheStringPiece val); + bool WriteBytes(const void* data, size_t data_len); + bool WriteRepeatedByte(uint8_t byte, size_t count); + // Fills the remaining buffer with null characters. + void WritePadding(); + // Write padding of |count| bytes. + bool WritePaddingBytes(size_t count); + + // Write tag as a 32-bit unsigned integer to the payload. As tags are already + // converted to big endian (e.g., CHLO is 'C','H','L','O') in memory by TAG or + // MakeQuicTag and tags are written in byte order, so tags on the wire are + // in big endian. + bool WriteTag(uint32_t tag); + + // Advance the writer's position for writing by |length| bytes without writing + // anything. This method only makes sense to be used on a buffer that has + // already been written to (and is having certain parts rewritten). + bool Seek(size_t length); + + size_t capacity() const { return capacity_; } + + size_t remaining() const { return capacity_ - length_; } + + std::string DebugString() const; + + protected: + // Returns the location that the data should be written at, or nullptr if + // there is not enough room. Call EndWrite with the returned offset and the + // given length to pad out for the next write. + char* BeginWrite(size_t length); + + quiche::Endianness endianness() const { return endianness_; } + + char* buffer() const { return buffer_; } + + void IncreaseLength(size_t delta) { + DCHECK_LE(length_, std::numeric_limits<size_t>::max() - delta); + DCHECK_LE(length_, capacity_ - delta); + length_ += delta; + } + + private: + // TODO(fkastenholz, b/73004262) change buffer_, et al, to be uint8_t, not + // char. + char* buffer_; + size_t capacity_; // Allocation size of payload (or -1 if buffer is const). + size_t length_; // Current length of the buffer. + + // The endianness to write integers and floating numbers. + quiche::Endianness endianness_; +}; + +} // namespace quiche + +#endif // QUICHE_COMMON_QUICHE_DATA_WRITER_H_
diff --git a/common/quiche_data_writer_test.cc b/common/quiche_data_writer_test.cc new file mode 100644 index 0000000..78f8abf --- /dev/null +++ b/common/quiche_data_writer_test.cc
@@ -0,0 +1,419 @@ +// Copyright (c) 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/third_party/quiche/src/common/quiche_data_writer.h" + +#include <cstdint> +#include <cstring> + +#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_test.h" +#include "net/third_party/quiche/src/common/quiche_data_reader.h" +#include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h" + +namespace quiche { +namespace test { +namespace { + +char* AsChars(unsigned char* data) { + return reinterpret_cast<char*>(data); +} + +struct TestParams { + explicit TestParams(quiche::Endianness endianness) : endianness(endianness) {} + + quiche::Endianness endianness; +}; + +// Used by ::testing::PrintToStringParamName(). +std::string PrintToString(const TestParams& p) { + return quiche::QuicheStrCat( + (p.endianness == quiche::NETWORK_BYTE_ORDER ? "Network" : "Host"), + "ByteOrder"); +} + +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + for (quiche::Endianness endianness : + {quiche::NETWORK_BYTE_ORDER, quiche::HOST_BYTE_ORDER}) { + params.push_back(TestParams(endianness)); + } + return params; +} + +class QuicheDataWriterTest : public QuicheTestWithParam<TestParams> {}; + +INSTANTIATE_TEST_SUITE_P(QuicheDataWriterTests, + QuicheDataWriterTest, + ::testing::ValuesIn(GetTestParams()), + ::testing::PrintToStringParamName()); + +TEST_P(QuicheDataWriterTest, Write16BitUnsignedIntegers) { + char little_endian16[] = {0x22, 0x11}; + char big_endian16[] = {0x11, 0x22}; + char buffer16[2]; + { + uint16_t in_memory16 = 0x1122; + QuicheDataWriter writer(2, buffer16, GetParam().endianness); + writer.WriteUInt16(in_memory16); + test::CompareCharArraysWithHexError( + "uint16_t", buffer16, 2, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian16 + : little_endian16, + 2); + + uint16_t read_number16; + QuicheDataReader reader(buffer16, 2, GetParam().endianness); + reader.ReadUInt16(&read_number16); + EXPECT_EQ(in_memory16, read_number16); + } + + { + uint64_t in_memory16 = 0x0000000000001122; + QuicheDataWriter writer(2, buffer16, GetParam().endianness); + writer.WriteBytesToUInt64(2, in_memory16); + test::CompareCharArraysWithHexError( + "uint16_t", buffer16, 2, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian16 + : little_endian16, + 2); + + uint64_t read_number16; + QuicheDataReader reader(buffer16, 2, GetParam().endianness); + reader.ReadBytesToUInt64(2, &read_number16); + EXPECT_EQ(in_memory16, read_number16); + } +} + +TEST_P(QuicheDataWriterTest, Write24BitUnsignedIntegers) { + char little_endian24[] = {0x33, 0x22, 0x11}; + char big_endian24[] = {0x11, 0x22, 0x33}; + char buffer24[3]; + uint64_t in_memory24 = 0x0000000000112233; + QuicheDataWriter writer(3, buffer24, GetParam().endianness); + writer.WriteBytesToUInt64(3, in_memory24); + test::CompareCharArraysWithHexError( + "uint24", buffer24, 3, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian24 + : little_endian24, + 3); + + uint64_t read_number24; + QuicheDataReader reader(buffer24, 3, GetParam().endianness); + reader.ReadBytesToUInt64(3, &read_number24); + EXPECT_EQ(in_memory24, read_number24); +} + +TEST_P(QuicheDataWriterTest, Write32BitUnsignedIntegers) { + char little_endian32[] = {0x44, 0x33, 0x22, 0x11}; + char big_endian32[] = {0x11, 0x22, 0x33, 0x44}; + char buffer32[4]; + { + uint32_t in_memory32 = 0x11223344; + QuicheDataWriter writer(4, buffer32, GetParam().endianness); + writer.WriteUInt32(in_memory32); + test::CompareCharArraysWithHexError( + "uint32_t", buffer32, 4, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian32 + : little_endian32, + 4); + + uint32_t read_number32; + QuicheDataReader reader(buffer32, 4, GetParam().endianness); + reader.ReadUInt32(&read_number32); + EXPECT_EQ(in_memory32, read_number32); + } + + { + uint64_t in_memory32 = 0x11223344; + QuicheDataWriter writer(4, buffer32, GetParam().endianness); + writer.WriteBytesToUInt64(4, in_memory32); + test::CompareCharArraysWithHexError( + "uint32_t", buffer32, 4, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian32 + : little_endian32, + 4); + + uint64_t read_number32; + QuicheDataReader reader(buffer32, 4, GetParam().endianness); + reader.ReadBytesToUInt64(4, &read_number32); + EXPECT_EQ(in_memory32, read_number32); + } +} + +TEST_P(QuicheDataWriterTest, Write40BitUnsignedIntegers) { + uint64_t in_memory40 = 0x0000001122334455; + char little_endian40[] = {0x55, 0x44, 0x33, 0x22, 0x11}; + char big_endian40[] = {0x11, 0x22, 0x33, 0x44, 0x55}; + char buffer40[5]; + QuicheDataWriter writer(5, buffer40, GetParam().endianness); + writer.WriteBytesToUInt64(5, in_memory40); + test::CompareCharArraysWithHexError( + "uint40", buffer40, 5, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian40 + : little_endian40, + 5); + + uint64_t read_number40; + QuicheDataReader reader(buffer40, 5, GetParam().endianness); + reader.ReadBytesToUInt64(5, &read_number40); + EXPECT_EQ(in_memory40, read_number40); +} + +TEST_P(QuicheDataWriterTest, Write48BitUnsignedIntegers) { + uint64_t in_memory48 = 0x0000112233445566; + char little_endian48[] = {0x66, 0x55, 0x44, 0x33, 0x22, 0x11}; + char big_endian48[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + char buffer48[6]; + QuicheDataWriter writer(6, buffer48, GetParam().endianness); + writer.WriteBytesToUInt64(6, in_memory48); + test::CompareCharArraysWithHexError( + "uint48", buffer48, 6, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian48 + : little_endian48, + 6); + + uint64_t read_number48; + QuicheDataReader reader(buffer48, 6, GetParam().endianness); + reader.ReadBytesToUInt64(6., &read_number48); + EXPECT_EQ(in_memory48, read_number48); +} + +TEST_P(QuicheDataWriterTest, Write56BitUnsignedIntegers) { + uint64_t in_memory56 = 0x0011223344556677; + char little_endian56[] = {0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11}; + char big_endian56[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + char buffer56[7]; + QuicheDataWriter writer(7, buffer56, GetParam().endianness); + writer.WriteBytesToUInt64(7, in_memory56); + test::CompareCharArraysWithHexError( + "uint56", buffer56, 7, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER ? big_endian56 + : little_endian56, + 7); + + uint64_t read_number56; + QuicheDataReader reader(buffer56, 7, GetParam().endianness); + reader.ReadBytesToUInt64(7, &read_number56); + EXPECT_EQ(in_memory56, read_number56); +} + +TEST_P(QuicheDataWriterTest, Write64BitUnsignedIntegers) { + uint64_t in_memory64 = 0x1122334455667788; + unsigned char little_endian64[] = {0x88, 0x77, 0x66, 0x55, + 0x44, 0x33, 0x22, 0x11}; + unsigned char big_endian64[] = {0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, 0x77, 0x88}; + char buffer64[8]; + QuicheDataWriter writer(8, buffer64, GetParam().endianness); + writer.WriteBytesToUInt64(8, in_memory64); + test::CompareCharArraysWithHexError( + "uint64_t", buffer64, 8, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER + ? AsChars(big_endian64) + : AsChars(little_endian64), + 8); + + uint64_t read_number64; + QuicheDataReader reader(buffer64, 8, GetParam().endianness); + reader.ReadBytesToUInt64(8, &read_number64); + EXPECT_EQ(in_memory64, read_number64); + + QuicheDataWriter writer2(8, buffer64, GetParam().endianness); + writer2.WriteUInt64(in_memory64); + test::CompareCharArraysWithHexError( + "uint64_t", buffer64, 8, + GetParam().endianness == quiche::NETWORK_BYTE_ORDER + ? AsChars(big_endian64) + : AsChars(little_endian64), + 8); + read_number64 = 0u; + QuicheDataReader reader2(buffer64, 8, GetParam().endianness); + reader2.ReadUInt64(&read_number64); + EXPECT_EQ(in_memory64, read_number64); +} + +TEST_P(QuicheDataWriterTest, WriteIntegers) { + char buf[43]; + uint8_t i8 = 0x01; + uint16_t i16 = 0x0123; + uint32_t i32 = 0x01234567; + uint64_t i64 = 0x0123456789ABCDEF; + QuicheDataWriter writer(46, buf, GetParam().endianness); + for (size_t i = 0; i < 10; ++i) { + switch (i) { + case 0u: + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 1u: + EXPECT_TRUE(writer.WriteUInt8(i8)); + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 2u: + EXPECT_TRUE(writer.WriteUInt16(i16)); + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 3u: + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 4u: + EXPECT_TRUE(writer.WriteUInt32(i32)); + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + case 5u: + case 6u: + case 7u: + case 8u: + EXPECT_TRUE(writer.WriteBytesToUInt64(i, i64)); + break; + default: + EXPECT_FALSE(writer.WriteBytesToUInt64(i, i64)); + } + } + + QuicheDataReader reader(buf, 46, GetParam().endianness); + for (size_t i = 0; i < 10; ++i) { + uint8_t read8; + uint16_t read16; + uint32_t read32; + uint64_t read64; + switch (i) { + case 0u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0u, read64); + break; + case 1u: + EXPECT_TRUE(reader.ReadUInt8(&read8)); + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(i8, read8); + EXPECT_EQ(0xEFu, read64); + break; + case 2u: + EXPECT_TRUE(reader.ReadUInt16(&read16)); + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(i16, read16); + EXPECT_EQ(0xCDEFu, read64); + break; + case 3u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0xABCDEFu, read64); + break; + case 4u: + EXPECT_TRUE(reader.ReadUInt32(&read32)); + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(i32, read32); + EXPECT_EQ(0x89ABCDEFu, read64); + break; + case 5u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0x6789ABCDEFu, read64); + break; + case 6u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0x456789ABCDEFu, read64); + break; + case 7u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0x23456789ABCDEFu, read64); + break; + case 8u: + EXPECT_TRUE(reader.ReadBytesToUInt64(i, &read64)); + EXPECT_EQ(0x0123456789ABCDEFu, read64); + break; + default: + EXPECT_FALSE(reader.ReadBytesToUInt64(i, &read64)); + } + } +} + +TEST_P(QuicheDataWriterTest, WriteBytes) { + char bytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + char buf[QUICHE_ARRAYSIZE(bytes)]; + QuicheDataWriter writer(QUICHE_ARRAYSIZE(buf), buf, GetParam().endianness); + EXPECT_TRUE(writer.WriteBytes(bytes, QUICHE_ARRAYSIZE(bytes))); + for (unsigned int i = 0; i < QUICHE_ARRAYSIZE(bytes); ++i) { + EXPECT_EQ(bytes[i], buf[i]); + } +} + +TEST_P(QuicheDataWriterTest, Seek) { + char buffer[3] = {}; + QuicheDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, + GetParam().endianness); + EXPECT_TRUE(writer.WriteUInt8(42)); + EXPECT_TRUE(writer.Seek(1)); + EXPECT_TRUE(writer.WriteUInt8(3)); + + char expected[] = {42, 0, 3}; + for (size_t i = 0; i < QUICHE_ARRAYSIZE(expected); ++i) { + EXPECT_EQ(buffer[i], expected[i]); + } +} + +TEST_P(QuicheDataWriterTest, SeekTooFarFails) { + char buffer[20]; + + // Check that one can seek to the end of the writer, but not past. + { + QuicheDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, + GetParam().endianness); + EXPECT_TRUE(writer.Seek(20)); + EXPECT_FALSE(writer.Seek(1)); + } + + // Seeking several bytes past the end fails. + { + QuicheDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, + GetParam().endianness); + EXPECT_FALSE(writer.Seek(100)); + } + + // Seeking so far that arithmetic overflow could occur also fails. + { + QuicheDataWriter writer(QUICHE_ARRAYSIZE(buffer), buffer, + GetParam().endianness); + EXPECT_TRUE(writer.Seek(10)); + EXPECT_FALSE(writer.Seek(std::numeric_limits<size_t>::max())); + } +} + +TEST_P(QuicheDataWriterTest, PayloadReads) { + char buffer[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + char expected_first_read[4] = {1, 2, 3, 4}; + char expected_remaining[12] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + QuicheDataReader reader(buffer, sizeof(buffer)); + char first_read_buffer[4] = {}; + EXPECT_TRUE(reader.ReadBytes(first_read_buffer, sizeof(first_read_buffer))); + test::CompareCharArraysWithHexError( + "first read", first_read_buffer, sizeof(first_read_buffer), + expected_first_read, sizeof(expected_first_read)); + quiche::QuicheStringPiece peeked_remaining_payload = + reader.PeekRemainingPayload(); + test::CompareCharArraysWithHexError( + "peeked_remaining_payload", peeked_remaining_payload.data(), + peeked_remaining_payload.length(), expected_remaining, + sizeof(expected_remaining)); + quiche::QuicheStringPiece full_payload = reader.FullPayload(); + test::CompareCharArraysWithHexError("full_payload", full_payload.data(), + full_payload.length(), buffer, + sizeof(buffer)); + quiche::QuicheStringPiece read_remaining_payload = + reader.ReadRemainingPayload(); + test::CompareCharArraysWithHexError( + "read_remaining_payload", read_remaining_payload.data(), + read_remaining_payload.length(), expected_remaining, + sizeof(expected_remaining)); + EXPECT_TRUE(reader.IsDoneReading()); + quiche::QuicheStringPiece full_payload2 = reader.FullPayload(); + test::CompareCharArraysWithHexError("full_payload2", full_payload2.data(), + full_payload2.length(), buffer, + sizeof(buffer)); +} + +} // namespace +} // namespace test +} // namespace quiche
diff --git a/quic/core/quic_data_reader.cc b/quic/core/quic_data_reader.cc index 3982cc9..882573d 100644 --- a/quic/core/quic_data_reader.cc +++ b/quic/core/quic_data_reader.cc
@@ -15,7 +15,7 @@ namespace quic { QuicDataReader::QuicDataReader(quiche::QuicheStringPiece data) - : QuicDataReader(data.data(), data.length(), quiche::NETWORK_BYTE_ORDER) {} + : quiche::QuicheDataReader(data) {} QuicDataReader::QuicDataReader(const char* data, const size_t len) : QuicDataReader(data, len, quiche::NETWORK_BYTE_ORDER) {} @@ -23,58 +23,7 @@ QuicDataReader::QuicDataReader(const char* data, const size_t len, quiche::Endianness endianness) - : data_(data), len_(len), pos_(0), endianness_(endianness) {} - -bool QuicDataReader::ReadUInt8(uint8_t* result) { - return ReadBytes(result, sizeof(*result)); -} - -bool QuicDataReader::ReadUInt16(uint16_t* result) { - if (!ReadBytes(result, sizeof(*result))) { - return false; - } - if (endianness_ == quiche::NETWORK_BYTE_ORDER) { - *result = quiche::QuicheEndian::NetToHost16(*result); - } - return true; -} - -bool QuicDataReader::ReadUInt32(uint32_t* result) { - if (!ReadBytes(result, sizeof(*result))) { - return false; - } - if (endianness_ == quiche::NETWORK_BYTE_ORDER) { - *result = quiche::QuicheEndian::NetToHost32(*result); - } - return true; -} - -bool QuicDataReader::ReadUInt64(uint64_t* result) { - if (!ReadBytes(result, sizeof(*result))) { - return false; - } - if (endianness_ == quiche::NETWORK_BYTE_ORDER) { - *result = quiche::QuicheEndian::NetToHost64(*result); - } - return true; -} - -bool QuicDataReader::ReadBytesToUInt64(size_t num_bytes, uint64_t* result) { - *result = 0u; - if (num_bytes > sizeof(*result)) { - return false; - } - if (endianness_ == quiche::HOST_BYTE_ORDER) { - return ReadBytes(result, num_bytes); - } - - if (!ReadBytes(reinterpret_cast<char*>(result) + sizeof(*result) - num_bytes, - num_bytes)) { - return false; - } - *result = quiche::QuicheEndian::NetToHost64(*result); - return true; -} + : quiche::QuicheDataReader(data, len, endianness) {} bool QuicDataReader::ReadUFloat16(uint64_t* result) { uint16_t value; @@ -109,34 +58,6 @@ return true; } -bool QuicDataReader::ReadStringPiece16(quiche::QuicheStringPiece* result) { - // Read resultant length. - uint16_t result_len; - if (!ReadUInt16(&result_len)) { - // OnFailure() already called. - return false; - } - - return ReadStringPiece(result, result_len); -} - -bool QuicDataReader::ReadStringPiece(quiche::QuicheStringPiece* result, - size_t size) { - // Make sure that we have enough data to read. - if (!CanRead(size)) { - OnFailure(); - return false; - } - - // Set result. - *result = quiche::QuicheStringPiece(data_ + pos_, size); - - // Iterate. - pos_ += size; - - return true; -} - bool QuicDataReader::ReadConnectionId(QuicConnectionId* connection_id, uint8_t length) { if (!GetQuicRestartFlag(quic_allow_very_long_connection_ids)) { @@ -180,57 +101,10 @@ return ReadConnectionId(connection_id, connection_id_length); } -bool QuicDataReader::ReadTag(uint32_t* tag) { - return ReadBytes(tag, sizeof(*tag)); -} - -quiche::QuicheStringPiece QuicDataReader::ReadRemainingPayload() { - quiche::QuicheStringPiece payload = PeekRemainingPayload(); - pos_ = len_; - return payload; -} - -quiche::QuicheStringPiece QuicDataReader::PeekRemainingPayload() const { - return quiche::QuicheStringPiece(data_ + pos_, len_ - pos_); -} - -quiche::QuicheStringPiece QuicDataReader::FullPayload() const { - return quiche::QuicheStringPiece(data_, len_); -} - -bool QuicDataReader::ReadBytes(void* result, size_t size) { - // Make sure that we have enough data to read. - if (!CanRead(size)) { - OnFailure(); - return false; - } - - // Read into result. - memcpy(result, data_ + pos_, size); - - // Iterate. - pos_ += size; - - return true; -} - -bool QuicDataReader::Seek(size_t size) { - if (!CanRead(size)) { - OnFailure(); - return false; - } - pos_ += size; - return true; -} - -bool QuicDataReader::IsDoneReading() const { - return len_ == pos_; -} - QuicVariableLengthIntegerLength QuicDataReader::PeekVarInt62Length() { - DCHECK_EQ(endianness_, quiche::NETWORK_BYTE_ORDER); + DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); const unsigned char* next = - reinterpret_cast<const unsigned char*>(data_ + pos_); + reinterpret_cast<const unsigned char*>(data() + pos()); if (BytesRemaining() == 0) { return VARIABLE_LENGTH_INTEGER_LENGTH_0; } @@ -238,37 +112,6 @@ 1 << ((*next & 0b11000000) >> 6)); } -size_t QuicDataReader::BytesRemaining() const { - return len_ - pos_; -} - -bool QuicDataReader::TruncateRemaining(size_t truncation_length) { - if (truncation_length > BytesRemaining()) { - return false; - } - len_ = pos_ + truncation_length; - return true; -} - -bool QuicDataReader::CanRead(size_t bytes) const { - return bytes <= (len_ - pos_); -} - -void QuicDataReader::OnFailure() { - // Set our iterator to the end of the buffer so that further reads fail - // immediately. - pos_ = len_; -} - -uint8_t QuicDataReader::PeekByte() const { - if (pos_ >= len_) { - QUIC_BUG << "Reading is done, cannot peek next byte. Tried to read pos = " - << pos_ << " buffer length = " << len_; - return 0; - } - return data_[pos_]; -} - // Read an IETF/QUIC formatted 62-bit Variable Length Integer. // // Performance notes @@ -286,11 +129,11 @@ // Low-level optimization is useful here because this function will be // called frequently, leading to outsize benefits. bool QuicDataReader::ReadVarInt62(uint64_t* result) { - DCHECK_EQ(endianness_, quiche::NETWORK_BYTE_ORDER); + DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); size_t remaining = BytesRemaining(); const unsigned char* next = - reinterpret_cast<const unsigned char*>(data_ + pos_); + reinterpret_cast<const unsigned char*>(data() + pos()); if (remaining != 0) { switch (*next & 0xc0) { case 0xc0: @@ -304,7 +147,7 @@ (static_cast<uint64_t>(*(next + 5)) << 16) + (static_cast<uint64_t>(*(next + 6)) << 8) + (static_cast<uint64_t>(*(next + 7)) << 0); - pos_ += 8; + AdvancePos(8); return true; } return false; @@ -314,7 +157,7 @@ if (remaining >= 4) { *result = (((*(next)) & 0x3f) << 24) + (((*(next + 1)) << 16)) + (((*(next + 2)) << 8)) + (((*(next + 3)) << 0)); - pos_ += 4; + AdvancePos(4); return true; } return false; @@ -323,7 +166,7 @@ // Leading 0b01...... is 2 byte encoding if (remaining >= 2) { *result = (((*(next)) & 0x3f) << 8) + (*(next + 1)); - pos_ += 2; + AdvancePos(2); return true; } return false; @@ -331,7 +174,7 @@ case 0x00: // Leading 0b00...... is 1 byte encoding *result = (*next) & 0x3f; - pos_++; + AdvancePos(1); return true; } } @@ -352,9 +195,5 @@ return true; } -std::string QuicDataReader::DebugString() const { - return quiche::QuicheStrCat(" { length: ", len_, ", position: ", pos_, " }"); -} - #undef ENDPOINT // undef for jumbo builds } // namespace quic
diff --git a/quic/core/quic_data_reader.h b/quic/core/quic_data_reader.h index 40ad4fc..08366b9 100644 --- a/quic/core/quic_data_reader.h +++ b/quic/core/quic_data_reader.h
@@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/quiche_data_reader.h" namespace quic { @@ -29,7 +30,7 @@ // trusted and it is up to the caller to throw away the failed instance and // handle the error as appropriate. None of the Read*() methods should ever be // called after failure, as they will also fail immediately. -class QUIC_EXPORT_PRIVATE QuicDataReader { +class QUIC_EXPORT_PRIVATE QuicDataReader : public quiche::QuicheDataReader { public: // Constructs a reader using NETWORK_BYTE_ORDER endianness. // Caller must provide an underlying buffer to work on. @@ -48,38 +49,11 @@ // Empty destructor. ~QuicDataReader() {} - // Reads an 8/16/32/64-bit unsigned integer into the given output - // parameter. Forwards the internal iterator on success. Returns true on - // success, false otherwise. - bool ReadUInt8(uint8_t* result); - bool ReadUInt16(uint16_t* result); - bool ReadUInt32(uint32_t* result); - bool ReadUInt64(uint64_t* result); - - // Set |result| to 0, then read |num_bytes| bytes in the correct byte order - // into least significant bytes of |result|. - bool ReadBytesToUInt64(size_t num_bytes, uint64_t* result); - // Reads a 16-bit unsigned float into the given output parameter. // Forwards the internal iterator on success. // Returns true on success, false otherwise. bool ReadUFloat16(uint64_t* result); - // Reads a string prefixed with 16-bit length into the given output parameter. - // - // NOTE: Does not copy but rather references strings in the underlying buffer. - // This should be kept in mind when handling memory management! - // - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadStringPiece16(quiche::QuicheStringPiece* result); - - // Reads a given number of bytes into the given buffer. The buffer - // must be of adequate size. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadStringPiece(quiche::QuicheStringPiece* result, size_t len); - // Reads connection ID into the given output parameter. // Forwards the internal iterator on success. // Returns true on success, false otherwise. @@ -90,70 +64,10 @@ // Returns true on success, false otherwise. bool ReadLengthPrefixedConnectionId(QuicConnectionId* connection_id); - // Reads tag represented as 32-bit unsigned integer into given output - // parameter. Tags are in big endian on the wire (e.g., CHLO is - // 'C','H','L','O') and are read in byte order, so tags in memory are in big - // endian. - bool ReadTag(uint32_t* tag); - - // Returns the remaining payload as a quiche::QuicheStringPiece. - // - // NOTE: Does not copy but rather references strings in the underlying buffer. - // This should be kept in mind when handling memory management! - // - // Forwards the internal iterator. - quiche::QuicheStringPiece ReadRemainingPayload(); - - // Returns the remaining payload as a quiche::QuicheStringPiece. - // - // NOTE: Does not copy but rather references strings in the underlying buffer. - // This should be kept in mind when handling memory management! - // - // DOES NOT forward the internal iterator. - quiche::QuicheStringPiece PeekRemainingPayload() const; - - // Returns the entire payload as a quiche::QuicheStringPiece. - // - // NOTE: Does not copy but rather references strings in the underlying buffer. - // This should be kept in mind when handling memory management! - // - // DOES NOT forward the internal iterator. - quiche::QuicheStringPiece FullPayload() const; - - // Reads a given number of bytes into the given buffer. The buffer - // must be of adequate size. - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadBytes(void* result, size_t size); - - // Skips over |size| bytes from the buffer and forwards the internal iterator. - // Returns true if there are at least |size| bytes remaining to read, false - // otherwise. - bool Seek(size_t size); - - // Returns true if the entirety of the underlying buffer has been read via - // Read*() calls. - bool IsDoneReading() const; - // Returns the length in bytes of a variable length integer based on the next // two bits available. Returns 1, 2, 4, or 8 on success, and 0 on failure. QuicVariableLengthIntegerLength PeekVarInt62Length(); - // Returns the number of bytes remaining to be read. - size_t BytesRemaining() const; - - // Truncates the reader down by reducing its internal length. - // If called immediately after calling this, BytesRemaining will - // return |truncation_length|. If truncation_length is less than the - // current value of BytesRemaining, this does nothing and returns false. - bool TruncateRemaining(size_t truncation_length); - - // Returns the next byte that to be read. Must not be called when there are no - // bytes to be read. - // - // DOES NOT forward the internal iterator. - uint8_t PeekByte() const; - // Read an IETF-encoded Variable Length Integer and place the result // in |*result|. // Returns true if it works, false if not. The only error is that @@ -168,29 +82,6 @@ // returns false if there is a read error or if the value is // greater than (2^32)-1. bool ReadVarIntU32(uint32_t* result); - - std::string DebugString() const; - - private: - // Returns true if the underlying buffer has enough room to read the given - // amount of bytes. - bool CanRead(size_t bytes) const; - - // To be called when a read fails for any reason. - void OnFailure(); - - // TODO(fkastenholz, b/73004262) change buffer_, et al, to be uint8_t, not - // char. The data buffer that we're reading from. - const char* data_; - - // The length of the data buffer that we're reading from. - size_t len_; - - // The location of the next read from our data buffer. - size_t pos_; - - // The endianness to read integers and floating numbers. - quiche::Endianness endianness_; }; } // namespace quic
diff --git a/quic/core/quic_data_writer.cc b/quic/core/quic_data_writer.cc index 28af68b..41c374c 100644 --- a/quic/core/quic_data_writer.cc +++ b/quic/core/quic_data_writer.cc
@@ -18,57 +18,15 @@ namespace quic { QuicDataWriter::QuicDataWriter(size_t size, char* buffer) - : QuicDataWriter(size, buffer, quiche::NETWORK_BYTE_ORDER) {} + : quiche::QuicheDataWriter(size, buffer) {} QuicDataWriter::QuicDataWriter(size_t size, char* buffer, quiche::Endianness endianness) - : buffer_(buffer), capacity_(size), length_(0), endianness_(endianness) {} + : quiche::QuicheDataWriter(size, buffer, endianness) {} QuicDataWriter::~QuicDataWriter() {} -char* QuicDataWriter::data() { - return buffer_; -} - -bool QuicDataWriter::WriteUInt8(uint8_t value) { - return WriteBytes(&value, sizeof(value)); -} - -bool QuicDataWriter::WriteUInt16(uint16_t value) { - if (endianness_ == quiche::NETWORK_BYTE_ORDER) { - value = quiche::QuicheEndian::HostToNet16(value); - } - return WriteBytes(&value, sizeof(value)); -} - -bool QuicDataWriter::WriteUInt32(uint32_t value) { - if (endianness_ == quiche::NETWORK_BYTE_ORDER) { - value = quiche::QuicheEndian::HostToNet32(value); - } - return WriteBytes(&value, sizeof(value)); -} - -bool QuicDataWriter::WriteUInt64(uint64_t value) { - if (endianness_ == quiche::NETWORK_BYTE_ORDER) { - value = quiche::QuicheEndian::HostToNet64(value); - } - return WriteBytes(&value, sizeof(value)); -} - -bool QuicDataWriter::WriteBytesToUInt64(size_t num_bytes, uint64_t value) { - if (num_bytes > sizeof(value)) { - return false; - } - if (endianness_ == quiche::HOST_BYTE_ORDER) { - return WriteBytes(&value, num_bytes); - } - - value = quiche::QuicheEndian::HostToNet64(value); - return WriteBytes(reinterpret_cast<char*>(&value) + sizeof(value) - num_bytes, - num_bytes); -} - bool QuicDataWriter::WriteUFloat16(uint64_t value) { uint16_t result; if (value < (UINT64_C(1) << kUFloat16MantissaEffectiveBits)) { @@ -105,79 +63,12 @@ result = static_cast<uint16_t>(value + (exponent << kUFloat16MantissaBits)); } - if (endianness_ == quiche::NETWORK_BYTE_ORDER) { + if (endianness() == quiche::NETWORK_BYTE_ORDER) { result = quiche::QuicheEndian::HostToNet16(result); } return WriteBytes(&result, sizeof(result)); } -bool QuicDataWriter::WriteStringPiece16(quiche::QuicheStringPiece val) { - if (val.size() > std::numeric_limits<uint16_t>::max()) { - return false; - } - if (!WriteUInt16(static_cast<uint16_t>(val.size()))) { - return false; - } - return WriteBytes(val.data(), val.size()); -} - -bool QuicDataWriter::WriteStringPiece(quiche::QuicheStringPiece val) { - return WriteBytes(val.data(), val.size()); -} - -char* QuicDataWriter::BeginWrite(size_t length) { - if (length_ > capacity_) { - return nullptr; - } - - if (capacity_ - length_ < length) { - return nullptr; - } - -#ifdef ARCH_CPU_64_BITS - DCHECK_LE(length, std::numeric_limits<uint32_t>::max()); -#endif - - return buffer_ + length_; -} - -bool QuicDataWriter::WriteBytes(const void* data, size_t data_len) { - char* dest = BeginWrite(data_len); - if (!dest) { - return false; - } - - memcpy(dest, data, data_len); - - length_ += data_len; - return true; -} - -bool QuicDataWriter::WriteRepeatedByte(uint8_t byte, size_t count) { - char* dest = BeginWrite(count); - if (!dest) { - return false; - } - - memset(dest, byte, count); - - length_ += count; - return true; -} - -void QuicDataWriter::WritePadding() { - DCHECK_LE(length_, capacity_); - if (length_ > capacity_) { - return; - } - memset(buffer_ + length_, 0x00, capacity_ - length_); - length_ = capacity_; -} - -bool QuicDataWriter::WritePaddingBytes(size_t count) { - return WriteRepeatedByte(0x00, count); -} - bool QuicDataWriter::WriteConnectionId(QuicConnectionId connection_id) { if (connection_id.IsEmpty()) { return true; @@ -190,10 +81,6 @@ return WriteUInt8(connection_id.length()) && WriteConnectionId(connection_id); } -bool QuicDataWriter::WriteTag(uint32_t tag) { - return WriteBytes(&tag, sizeof(tag)); -} - bool QuicDataWriter::WriteRandomBytes(QuicRandom* random, size_t length) { char* dest = BeginWrite(length); if (!dest) { @@ -201,17 +88,10 @@ } random->RandBytes(dest, length); - length_ += length; + IncreaseLength(length); return true; } -bool QuicDataWriter::Seek(size_t length) { - if (!BeginWrite(length)) { - return false; - } - length_ += length; - return true; -} // Converts a uint64_t into an IETF/Quic formatted Variable Length // Integer. IETF Variable Length Integers have 62 significant bits, so @@ -231,10 +111,10 @@ // Low-level optimization is useful here because this function will be // called frequently, leading to outsize benefits. bool QuicDataWriter::WriteVarInt62(uint64_t value) { - DCHECK_EQ(endianness_, quiche::NETWORK_BYTE_ORDER); + DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); - size_t remaining = capacity_ - length_; - char* next = buffer_ + length_; + size_t remaining_bytes = remaining(); + char* next = buffer() + length(); if ((value & kVarInt62ErrorMask) == 0) { // We know the high 2 bits are 0 so |value| is legal. @@ -242,7 +122,7 @@ if ((value & kVarInt62Mask8Bytes) != 0) { // Someplace in the high-4 bytes is a 1-bit. Do an 8-byte // encoding. - if (remaining >= 8) { + if (remaining_bytes >= 8) { *(next + 0) = ((value >> 56) & 0x3f) + 0xc0; *(next + 1) = (value >> 48) & 0xff; *(next + 2) = (value >> 40) & 0xff; @@ -251,7 +131,7 @@ *(next + 5) = (value >> 16) & 0xff; *(next + 6) = (value >> 8) & 0xff; *(next + 7) = value & 0xff; - length_ += 8; + IncreaseLength(8); return true; } return false; @@ -261,12 +141,12 @@ if ((value & kVarInt62Mask4Bytes) != 0) { // The encoding will not fit into 2 bytes, Do a 4-byte // encoding. - if (remaining >= 4) { + if (remaining_bytes >= 4) { *(next + 0) = ((value >> 24) & 0x3f) + 0x80; *(next + 1) = (value >> 16) & 0xff; *(next + 2) = (value >> 8) & 0xff; *(next + 3) = value & 0xff; - length_ += 4; + IncreaseLength(4); return true; } return false; @@ -279,18 +159,18 @@ // are not 0) if ((value & kVarInt62Mask2Bytes) != 0) { // Do 2-byte encoding - if (remaining >= 2) { + if (remaining_bytes >= 2) { *(next + 0) = ((value >> 8) & 0x3f) + 0x40; *(next + 1) = (value)&0xff; - length_ += 2; + IncreaseLength(2); return true; } return false; } - if (remaining >= 1) { + if (remaining_bytes >= 1) { // Do 1-byte encoding *next = (value & 0x3f); - length_ += 1; + IncreaseLength(1); return true; } return false; @@ -302,10 +182,10 @@ bool QuicDataWriter::WriteVarInt62( uint64_t value, QuicVariableLengthIntegerLength write_length) { - DCHECK_EQ(endianness_, quiche::NETWORK_BYTE_ORDER); + DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); - size_t remaining = capacity_ - length_; - if (remaining < write_length) { + size_t remaining_bytes = remaining(); + if (remaining_bytes < write_length) { return false; } @@ -366,9 +246,4 @@ return true; } -std::string QuicDataWriter::DebugString() const { - return quiche::QuicheStrCat(" { capacity: ", capacity_, ", length: ", length_, - " }"); -} - } // namespace quic
diff --git a/quic/core/quic_data_writer.h b/quic/core/quic_data_writer.h index 7d90f39..3926c1a 100644 --- a/quic/core/quic_data_writer.h +++ b/quic/core/quic_data_writer.h
@@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" +#include "net/third_party/quiche/src/common/quiche_data_writer.h" namespace quic { @@ -35,7 +36,7 @@ // The QuicDataWriter supports appending primitive values (int, string, etc) // to a frame instance. The internal memory buffer is exposed as the "data" // of the QuicDataWriter. -class QUIC_EXPORT_PRIVATE QuicDataWriter { +class QUIC_EXPORT_PRIVATE QuicDataWriter : public quiche::QuicheDataWriter { public: // Creates a QuicDataWriter where |buffer| is not owned // using NETWORK_BYTE_ORDER endianness. @@ -48,21 +49,9 @@ ~QuicDataWriter(); - // Returns the size of the QuicDataWriter's data. - size_t length() const { return length_; } - - // Retrieves the buffer from the QuicDataWriter without changing ownership. - char* data(); - // Methods for adding to the payload. These values are appended to the end // of the QuicDataWriter payload. - // Writes 8/16/32/64-bit unsigned integers. - bool WriteUInt8(uint8_t value); - bool WriteUInt16(uint16_t value); - bool WriteUInt32(uint32_t value); - bool WriteUInt64(uint64_t value); - // Write an unsigned-integer value per the IETF QUIC/Variable Length // Integer encoding rules (see draft-ietf-quic-transport-08.txt). // IETF Variable Length Integers have 62 significant bits, so the @@ -88,63 +77,18 @@ // is too large to encode. static QuicVariableLengthIntegerLength GetVarInt62Len(uint64_t value); - // Writes least significant |num_bytes| of a 64-bit unsigned integer in the - // correct byte order. - bool WriteBytesToUInt64(size_t num_bytes, uint64_t value); - // Write unsigned floating point corresponding to the value. Large values are // clamped to the maximum representable (kUFloat16MaxValue). Values that can // not be represented directly are rounded down. bool WriteUFloat16(uint64_t value); - bool WriteStringPiece(quiche::QuicheStringPiece val); - bool WriteStringPiece16(quiche::QuicheStringPiece val); - bool WriteBytes(const void* data, size_t data_len); - bool WriteRepeatedByte(uint8_t byte, size_t count); - // Fills the remaining buffer with null characters. - void WritePadding(); - // Write padding of |count| bytes. - bool WritePaddingBytes(size_t count); - // Write connection ID to the payload. bool WriteConnectionId(QuicConnectionId connection_id); // Write 8-bit length followed by connection ID to the payload. bool WriteLengthPrefixedConnectionId(QuicConnectionId connection_id); - // Write tag as a 32-bit unsigned integer to the payload. As tags are already - // converted to big endian (e.g., CHLO is 'C','H','L','O') in memory by TAG or - // MakeQuicTag and tags are written in byte order, so tags on the wire are - // in big endian. - bool WriteTag(uint32_t tag); - // Write |length| random bytes generated by |random|. bool WriteRandomBytes(QuicRandom* random, size_t length); - - // Advance the writer's position for writing by |length| bytes without writing - // anything. This method only makes sense to be used on a buffer that has - // already been written to (and is having certain parts rewritten). - bool Seek(size_t length); - - size_t capacity() const { return capacity_; } - - size_t remaining() const { return capacity_ - length_; } - - std::string DebugString() const; - - private: - // Returns the location that the data should be written at, or nullptr if - // there is not enough room. Call EndWrite with the returned offset and the - // given length to pad out for the next write. - char* BeginWrite(size_t length); - - // TODO(fkastenholz, b/73004262) change buffer_, et al, to be uint8_t, not - // char. - char* buffer_; - size_t capacity_; // Allocation size of payload (or -1 if buffer is const). - size_t length_; // Current length of the buffer. - - // The endianness to write integers and floating numbers. - quiche::Endianness endianness_; }; } // namespace quic