1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
9 #pragma once
10 
11 #include <memory>
12 #include <proxygen/lib/http/codec/TransportDirection.h>
13 #include <proxygen/lib/http/codec/compress/HPACKCodec.h> // table info
14 #include <proxygen/lib/http/codec/compress/HeaderCodec.h>
15 #include <proxygen/lib/http/codec/compress/HeaderIndexingStrategy.h>
16 #include <proxygen/lib/http/codec/compress/QPACKDecoder.h>
17 #include <proxygen/lib/http/codec/compress/QPACKEncoder.h>
18 #include <string>
19 #include <vector>
20 
21 namespace folly { namespace io {
22 class Cursor;
23 }} // namespace folly::io
24 
25 namespace proxygen {
26 
27 class HPACKHeader;
28 
29 /*
30  * Current version of the wire protocol. When we're making changes to the wire
31  * protocol we need to change this version and the ALPN string so that old
32  * clients will not be able to negotiate it anymore.
33  */
34 
35 class QPACKCodec : public HeaderCodec {
36  public:
37   QPACKCodec();
~QPACKCodec()38   ~QPACKCodec() override {
39   }
40 
41   // QPACK encode: id is used for internal tracking of references
42   QPACKEncoder::EncodeResult encode(
43       std::vector<compress::Header>& headers,
44       uint64_t id,
45       uint32_t maxEncoderStreamBytes =
46           std::numeric_limits<uint32_t>::max()) noexcept;
47 
48   std::unique_ptr<folly::IOBuf> encodeHTTP(
49       folly::IOBufQueue& controlQueue,
50       const HTTPMessage& msg,
51       bool includeDate,
52       uint64_t id,
53       uint32_t maxEncoderStreamBytes = std::numeric_limits<uint32_t>::max(),
54       const folly::Optional<HTTPHeaders>& extraHeaders = folly::none) noexcept;
55 
decodeEncoderStream(std::unique_ptr<folly::IOBuf> buf)56   HPACK::DecodeError decodeEncoderStream(std::unique_ptr<folly::IOBuf> buf) {
57     // stats?
58     return decoder_.decodeEncoderStream(std::move(buf));
59   }
60 
encoderStreamEnd()61   HPACK::DecodeError encoderStreamEnd() {
62     return decoder_.encoderStreamEnd();
63   }
64 
65   // QPACK blocking decode.  The decoder may queue the block if there are
66   // unsatisfied dependencies
67   void decodeStreaming(uint64_t streamId,
68                        std::unique_ptr<folly::IOBuf> block,
69                        uint32_t length,
70                        HPACK::StreamingCallback* streamingCb) noexcept;
71 
72   // This function sets both the decoder's advertised max and the size the
73   // encoder will use.  The encoder has a limit of 64k.  This function can
74   // only be called once with a unique non-zero value.
75   //
76   // Returns false if it was previously called with a different non-zero value.
77   bool setEncoderHeaderTableSize(uint32_t size, bool updateMax = true) {
78     VLOG(4) << __func__ << " size=" << size;
79     return encoder_.setHeaderTableSize(size, updateMax);
80   }
81 
setDecoderHeaderTableMaxSize(uint32_t size)82   void setDecoderHeaderTableMaxSize(uint32_t size) {
83     decoder_.setHeaderTableMaxSize(size);
84   }
85 
86   // Process bytes on the decoder stream
decodeDecoderStream(std::unique_ptr<folly::IOBuf> buf)87   HPACK::DecodeError decodeDecoderStream(std::unique_ptr<folly::IOBuf> buf) {
88     return encoder_.decodeDecoderStream(std::move(buf));
89   }
90 
decoderStreamEnd()91   HPACK::DecodeError decoderStreamEnd() {
92     return encoder_.decoderStreamEnd();
93   }
94 
95   // QPACK when a stream is reset.  Clears all reference counts for outstanding
96   // blocks
onStreamReset(uint64_t streamId)97   void onStreamReset(uint64_t streamId) {
98     encoder_.onHeaderAck(streamId, true);
99   }
100 
encodeInsertCountInc()101   std::unique_ptr<folly::IOBuf> encodeInsertCountInc() {
102     return decoder_.encodeInsertCountInc();
103   }
104 
encodeHeaderAck(uint64_t streamId)105   std::unique_ptr<folly::IOBuf> encodeHeaderAck(uint64_t streamId) {
106     return decoder_.encodeHeaderAck(streamId);
107   }
108 
encodeCancelStream(uint64_t streamId)109   std::unique_ptr<folly::IOBuf> encodeCancelStream(uint64_t streamId) {
110     return decoder_.encodeCancelStream(streamId);
111   }
112 
113   void describe(std::ostream& os) const;
114 
setMaxUncompressed(uint64_t maxUncompressed)115   void setMaxUncompressed(uint64_t maxUncompressed) override {
116     HeaderCodec::setMaxUncompressed(maxUncompressed);
117     decoder_.setMaxUncompressed(maxUncompressed);
118   }
119 
getCompressionInfo()120   CompressionInfo getCompressionInfo() const {
121     return CompressionInfo(encoder_.getTableSize(),
122                            encoder_.getBytesStored(),
123                            encoder_.getHeadersStored(),
124                            encoder_.getInsertCount(),
125                            encoder_.getBlockedInserts(),
126                            encoder_.getDuplications(),
127                            encoder_.getStaticRefs(),
128                            decoder_.getTableSize(),
129                            decoder_.getBytesStored(),
130                            decoder_.getHeadersStored(),
131                            decoder_.getInsertCount(),
132                            0, // decoder can't track blocked inserts
133                            decoder_.getDuplications(),
134                            decoder_.getStaticRefs());
135   }
136 
setHeaderIndexingStrategy(const HeaderIndexingStrategy * indexingStrat)137   void setHeaderIndexingStrategy(const HeaderIndexingStrategy* indexingStrat) {
138     encoder_.setHeaderIndexingStrategy(indexingStrat);
139   }
getHeaderIndexingStrategy()140   const HeaderIndexingStrategy* getHeaderIndexingStrategy() const {
141     return encoder_.getHeaderIndexingStrategy();
142   }
143 
getHolBlockCount()144   uint64_t getHolBlockCount() const {
145     return decoder_.getHolBlockCount();
146   }
147 
getQueuedBytes()148   uint64_t getQueuedBytes() const {
149     return decoder_.getQueuedBytes();
150   }
151 
setMaxVulnerable(uint32_t maxVulnerable)152   void setMaxVulnerable(uint32_t maxVulnerable) {
153     encoder_.setMaxVulnerable(maxVulnerable);
154   }
155 
setMaxBlocking(uint32_t maxBlocking)156   void setMaxBlocking(uint32_t maxBlocking) {
157     decoder_.setMaxBlocking(maxBlocking);
158   }
159 
setMaxNumOutstandingBlocks(uint32_t value)160   void setMaxNumOutstandingBlocks(uint32_t value) {
161     encoder_.setMaxNumOutstandingBlocks(value);
162   }
163 
164  protected:
165   QPACKEncoder encoder_;
166   QPACKDecoder decoder_;
167 
168  private:
169   void recordCompressedSize(const folly::IOBuf* stream, size_t controlSize);
170 
171   std::vector<HPACKHeader> decodedHeaders_;
172 };
173 
174 std::ostream& operator<<(std::ostream& os, const QPACKCodec& codec);
175 } // namespace proxygen
176