1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef mozilla_net_Http2Compression_Internal_h 7 #define mozilla_net_Http2Compression_Internal_h 8 9 // HPACK - RFC 7541 10 // https://www.rfc-editor.org/rfc/rfc7541.txt 11 12 #include "mozilla/Attributes.h" 13 #include "nsDeque.h" 14 #include "nsString.h" 15 #include "mozilla/Telemetry.h" 16 17 namespace mozilla { 18 namespace net { 19 20 struct HuffmanIncomingTable; 21 22 void Http2CompressionCleanup(); 23 24 class nvPair { 25 public: nvPair(const nsACString & name,const nsACString & value)26 nvPair(const nsACString& name, const nsACString& value) 27 : mName(name), mValue(value) {} 28 Size()29 uint32_t Size() const { return mName.Length() + mValue.Length() + 32; } 30 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; 31 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; 32 33 nsCString mName; 34 nsCString mValue; 35 }; 36 37 class nvFIFO { 38 public: 39 nvFIFO(); 40 ~nvFIFO(); 41 void AddElement(const nsCString& name, const nsCString& value); 42 void AddElement(const nsCString& name); 43 void RemoveElement(); 44 uint32_t ByteCount() const; 45 uint32_t Length() const; 46 uint32_t VariableLength() const; 47 size_t StaticLength() const; 48 void Clear(); 49 const nvPair* operator[](size_t index) const; 50 51 private: 52 uint32_t mByteCount{0}; 53 nsDeque<nvPair> mTable; 54 }; 55 56 class HpackDynamicTableReporter; 57 58 class Http2BaseCompressor { 59 public: 60 Http2BaseCompressor(); 61 virtual ~Http2BaseCompressor(); 62 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 63 nsresult SetInitialMaxBufferSize(uint32_t maxBufferSize); 64 void SetDumpTables(bool dumpTables); 65 66 protected: 67 const static uint32_t kDefaultMaxBuffer = 4096; 68 69 virtual void ClearHeaderTable(); 70 virtual void MakeRoom(uint32_t amount, const char* direction); 71 virtual void DumpState(const char*); 72 virtual void SetMaxBufferSizeInternal(uint32_t maxBufferSize); 73 74 nsACString* mOutput{nullptr}; 75 nvFIFO mHeaderTable; 76 77 uint32_t mMaxBuffer{kDefaultMaxBuffer}; 78 uint32_t mMaxBufferSetting{kDefaultMaxBuffer}; 79 bool mSetInitialMaxBufferSizeAllowed{true}; 80 81 uint32_t mPeakSize{0}; 82 uint32_t mPeakCount{0}; 83 MOZ_INIT_OUTSIDE_CTOR 84 Telemetry::HistogramID mPeakSizeID; 85 MOZ_INIT_OUTSIDE_CTOR 86 Telemetry::HistogramID mPeakCountID; 87 88 bool mDumpTables{false}; 89 90 private: 91 RefPtr<HpackDynamicTableReporter> mDynamicReporter; 92 }; 93 94 class Http2Compressor; 95 96 class Http2Decompressor final : public Http2BaseCompressor { 97 public: Http2Decompressor()98 Http2Decompressor() { 99 mPeakSizeID = Telemetry::HPACK_PEAK_SIZE_DECOMPRESSOR; 100 mPeakCountID = Telemetry::HPACK_PEAK_COUNT_DECOMPRESSOR; 101 }; 102 virtual ~Http2Decompressor() = default; 103 104 // NS_OK: Produces the working set of HTTP/1 formatted headers 105 [[nodiscard]] nsresult DecodeHeaderBlock(const uint8_t* data, 106 uint32_t datalen, nsACString& output, 107 bool isPush); 108 GetStatus(nsACString & hdr)109 void GetStatus(nsACString& hdr) { hdr = mHeaderStatus; } GetHost(nsACString & hdr)110 void GetHost(nsACString& hdr) { hdr = mHeaderHost; } GetScheme(nsACString & hdr)111 void GetScheme(nsACString& hdr) { hdr = mHeaderScheme; } GetPath(nsACString & hdr)112 void GetPath(nsACString& hdr) { hdr = mHeaderPath; } GetMethod(nsACString & hdr)113 void GetMethod(nsACString& hdr) { hdr = mHeaderMethod; } 114 115 private: 116 [[nodiscard]] nsresult DoIndexed(); 117 [[nodiscard]] nsresult DoLiteralWithoutIndex(); 118 [[nodiscard]] nsresult DoLiteralWithIncremental(); 119 [[nodiscard]] nsresult DoLiteralInternal(nsACString&, nsACString&, uint32_t); 120 [[nodiscard]] nsresult DoLiteralNeverIndexed(); 121 [[nodiscard]] nsresult DoContextUpdate(); 122 123 [[nodiscard]] nsresult DecodeInteger(uint32_t prefixLen, uint32_t& accum); 124 [[nodiscard]] nsresult OutputHeader(uint32_t index); 125 [[nodiscard]] nsresult OutputHeader(const nsACString& name, 126 const nsACString& value); 127 128 [[nodiscard]] nsresult CopyHeaderString(uint32_t index, nsACString& name); 129 [[nodiscard]] nsresult CopyStringFromInput(uint32_t bytes, nsACString& val); 130 uint8_t ExtractByte(uint8_t bitsLeft, uint32_t& bytesConsumed); 131 [[nodiscard]] nsresult CopyHuffmanStringFromInput(uint32_t bytes, 132 nsACString& val); 133 [[nodiscard]] nsresult DecodeHuffmanCharacter( 134 const HuffmanIncomingTable* table, uint8_t& c, uint32_t& bytesConsumed, 135 uint8_t& bitsLeft); 136 [[nodiscard]] nsresult DecodeFinalHuffmanCharacter( 137 const HuffmanIncomingTable* table, uint8_t& c, uint8_t& bitsLeft); 138 139 nsCString mHeaderStatus; 140 nsCString mHeaderHost; 141 nsCString mHeaderScheme; 142 nsCString mHeaderPath; 143 nsCString mHeaderMethod; 144 145 // state variables when DecodeBlock() is on the stack 146 uint32_t mOffset{0}; 147 const uint8_t* mData{nullptr}; 148 uint32_t mDataLen{0}; 149 bool mSeenNonColonHeader{false}; 150 bool mIsPush{false}; 151 }; 152 153 class Http2Compressor final : public Http2BaseCompressor { 154 public: Http2Compressor()155 Http2Compressor() { 156 mPeakSizeID = Telemetry::HPACK_PEAK_SIZE_COMPRESSOR; 157 mPeakCountID = Telemetry::HPACK_PEAK_COUNT_COMPRESSOR; 158 }; 159 virtual ~Http2Compressor() = default; 160 161 // HTTP/1 formatted header block as input - HTTP/2 formatted 162 // header block as output 163 [[nodiscard]] nsresult EncodeHeaderBlock( 164 const nsCString& nvInput, const nsACString& method, 165 const nsACString& path, const nsACString& host, const nsACString& scheme, 166 const nsACString& protocol, bool simpleConnectForm, nsACString& output); 167 GetParsedContentLength()168 int64_t GetParsedContentLength() { 169 return mParsedContentLength; 170 } // -1 on not found 171 172 void SetMaxBufferSize(uint32_t maxBufferSize); 173 174 private: 175 enum outputCode { 176 kNeverIndexedLiteral, 177 kPlainLiteral, 178 kIndexedLiteral, 179 kIndex 180 }; 181 182 void DoOutput(Http2Compressor::outputCode code, const class nvPair* pair, 183 uint32_t index); 184 void EncodeInteger(uint32_t prefixLen, uint32_t val); 185 void ProcessHeader(const nvPair inputPair, bool noLocalIndex, 186 bool neverIndex); 187 void HuffmanAppend(const nsCString& value); 188 void EncodeTableSizeChange(uint32_t newMaxSize); 189 190 int64_t mParsedContentLength{-1}; 191 bool mBufferSizeChangeWaiting{false}; 192 uint32_t mLowestBufferSizeWaiting{0}; 193 }; 194 195 } // namespace net 196 } // namespace mozilla 197 198 #endif // mozilla_net_Http2Compression_Internal_h 199