1 // Copyright (c) 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_COMMON_QUICHE_DATA_WRITER_H_ 6 #define QUICHE_COMMON_QUICHE_DATA_WRITER_H_ 7 8 #include <cstddef> 9 #include <cstdint> 10 #include <cstring> 11 #include <limits> 12 13 #include "absl/strings/string_view.h" 14 #include "quiche/common/platform/api/quiche_export.h" 15 #include "quiche/common/platform/api/quiche_logging.h" 16 #include "quiche/common/quiche_endian.h" 17 18 namespace quiche { 19 20 // Maximum value that can be properly encoded using RFC 9000 62-bit Variable 21 // Length Integer encoding. 22 enum : uint64_t { 23 kVarInt62MaxValue = UINT64_C(0x3fffffffffffffff), 24 }; 25 26 // RFC 9000 62-bit Variable Length Integer encoding masks 27 // If a uint64_t anded with a mask is not 0 then the value is encoded 28 // using that length (or is too big, in the case of kVarInt62ErrorMask). 29 // Values must be checked in order (error, 8-, 4-, and then 2- bytes) 30 // and if none are non-0, the value is encoded in 1 byte. 31 enum : uint64_t { 32 kVarInt62ErrorMask = UINT64_C(0xc000000000000000), 33 kVarInt62Mask8Bytes = UINT64_C(0x3fffffffc0000000), 34 kVarInt62Mask4Bytes = UINT64_C(0x000000003fffc000), 35 kVarInt62Mask2Bytes = UINT64_C(0x0000000000003fc0), 36 }; 37 38 // This class provides facilities for packing binary data. 39 // 40 // The QuicheDataWriter supports appending primitive values (int, string, etc) 41 // to a frame instance. The internal memory buffer is exposed as the "data" 42 // of the QuicheDataWriter. 43 class QUICHE_EXPORT QuicheDataWriter { 44 public: 45 // Creates a QuicheDataWriter where |buffer| is not owned 46 // using NETWORK_BYTE_ORDER endianness. 47 QuicheDataWriter(size_t size, char* buffer); 48 // Creates a QuicheDataWriter where |buffer| is not owned 49 // using the specified endianness. 50 QuicheDataWriter(size_t size, char* buffer, quiche::Endianness endianness); 51 QuicheDataWriter(const QuicheDataWriter&) = delete; 52 QuicheDataWriter& operator=(const QuicheDataWriter&) = delete; 53 54 ~QuicheDataWriter(); 55 56 // Returns the size of the QuicheDataWriter's data. length()57 size_t length() const { return length_; } 58 59 // Retrieves the buffer from the QuicheDataWriter without changing ownership. 60 char* data(); 61 62 // Methods for adding to the payload. These values are appended to the end 63 // of the QuicheDataWriter payload. 64 65 // Writes 8/16/32/64-bit unsigned integers. 66 bool WriteUInt8(uint8_t value); 67 bool WriteUInt16(uint16_t value); 68 bool WriteUInt32(uint32_t value); 69 bool WriteUInt64(uint64_t value); 70 71 // Writes least significant |num_bytes| of a 64-bit unsigned integer in the 72 // correct byte order. 73 bool WriteBytesToUInt64(size_t num_bytes, uint64_t value); 74 75 bool WriteStringPiece(absl::string_view val); 76 bool WriteStringPiece16(absl::string_view val); 77 bool WriteBytes(const void* data, size_t data_len); 78 bool WriteRepeatedByte(uint8_t byte, size_t count); 79 // Fills the remaining buffer with null characters. 80 void WritePadding(); 81 // Write padding of |count| bytes. 82 bool WritePaddingBytes(size_t count); 83 84 // Write tag as a 32-bit unsigned integer to the payload. As tags are already 85 // converted to big endian (e.g., CHLO is 'C','H','L','O') in memory by TAG or 86 // MakeQuicTag and tags are written in byte order, so tags on the wire are 87 // in big endian. 88 bool WriteTag(uint32_t tag); 89 90 // Write a 62-bit unsigned integer using RFC 9000 Variable Length Integer 91 // encoding. Returns false if the value is out of range or if there is no room 92 // in the buffer. 93 bool WriteVarInt62(uint64_t value); 94 95 // Same as WriteVarInt62(uint64_t), but forces an encoding size to write to. 96 // This is not as optimized as WriteVarInt62(uint64_t). Returns false if the 97 // value does not fit in the specified write_length or if there is no room in 98 // the buffer. 99 bool WriteVarInt62WithForcedLength( 100 uint64_t value, QuicheVariableLengthIntegerLength write_length); 101 102 // Writes a string piece as a consecutive length/content pair. The 103 // length uses RFC 9000 Variable Length Integer encoding. 104 bool WriteStringPieceVarInt62(const absl::string_view& string_piece); 105 106 // Utility function to return the number of bytes needed to encode 107 // the given value using IETF VarInt62 encoding. Returns the number 108 // of bytes required to encode the given integer or 0 if the value 109 // is too large to encode. 110 static QuicheVariableLengthIntegerLength GetVarInt62Len(uint64_t value); 111 112 // Advance the writer's position for writing by |length| bytes without writing 113 // anything. This method only makes sense to be used on a buffer that has 114 // already been written to (and is having certain parts rewritten). 115 bool Seek(size_t length); 116 capacity()117 size_t capacity() const { return capacity_; } 118 remaining()119 size_t remaining() const { return capacity_ - length_; } 120 121 std::string DebugString() const; 122 123 protected: 124 // Returns the location that the data should be written at, or nullptr if 125 // there is not enough room. Call EndWrite with the returned offset and the 126 // given length to pad out for the next write. 127 char* BeginWrite(size_t length); 128 endianness()129 quiche::Endianness endianness() const { return endianness_; } 130 buffer()131 char* buffer() const { return buffer_; } 132 IncreaseLength(size_t delta)133 void IncreaseLength(size_t delta) { 134 QUICHE_DCHECK_LE(length_, std::numeric_limits<size_t>::max() - delta); 135 QUICHE_DCHECK_LE(length_, capacity_ - delta); 136 length_ += delta; 137 } 138 139 private: 140 // TODO(fkastenholz, b/73004262) change buffer_, et al, to be uint8_t, not 141 // char. 142 char* buffer_; 143 size_t capacity_; // Allocation size of payload (or -1 if buffer is const). 144 size_t length_; // Current length of the buffer. 145 146 // The endianness to write integers and floating numbers. 147 quiche::Endianness endianness_; 148 }; 149 150 } // namespace quiche 151 152 #endif // QUICHE_COMMON_QUICHE_DATA_WRITER_H_ 153