xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/spdy/core/spdy_framer.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2012 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_SPDY_CORE_SPDY_FRAMER_H_
6 #define QUICHE_SPDY_CORE_SPDY_FRAMER_H_
7 
8 #include <stddef.h>
9 
10 #include <cstdint>
11 #include <memory>
12 #include <string>
13 #include <utility>
14 
15 #include "quiche/common/platform/api/quiche_export.h"
16 #include "quiche/spdy/core/hpack/hpack_encoder.h"
17 #include "quiche/spdy/core/spdy_protocol.h"
18 #include "quiche/spdy/core/zero_copy_output_buffer.h"
19 
20 namespace spdy {
21 
22 namespace test {
23 
24 class SpdyFramerPeer;
25 class SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
26 class SpdyFramerTest_PushPromiseFramesWithIterator_Test;
27 
28 }  // namespace test
29 
30 class QUICHE_EXPORT SpdyFrameSequence {
31  public:
~SpdyFrameSequence()32   virtual ~SpdyFrameSequence() {}
33 
34   // Serializes the next frame in the sequence to |output|. Returns the number
35   // of bytes written to |output|.
36   virtual size_t NextFrame(ZeroCopyOutputBuffer* output) = 0;
37 
38   // Returns true iff there is at least one more frame in the sequence.
39   virtual bool HasNextFrame() const = 0;
40 
41   // Get SpdyFrameIR of the frame to be serialized.
42   virtual const SpdyFrameIR& GetIR() const = 0;
43 };
44 
45 class QUICHE_EXPORT SpdyFramer {
46  public:
47   enum CompressionOption {
48     ENABLE_COMPRESSION,
49     DISABLE_COMPRESSION,
50   };
51 
52   // Create a SpdyFrameSequence to serialize |frame_ir|.
53   static std::unique_ptr<SpdyFrameSequence> CreateIterator(
54       SpdyFramer* framer, std::unique_ptr<const SpdyFrameIR> frame_ir);
55 
56   // Gets the serialized flags for the given |frame|.
57   static uint8_t GetSerializedFlags(const SpdyFrameIR& frame);
58 
59   // Serialize a data frame.
60   static SpdySerializedFrame SerializeData(const SpdyDataIR& data_ir);
61   // Serializes the data frame header and optionally padding length fields,
62   // excluding actual data payload and padding.
63   static SpdySerializedFrame SerializeDataFrameHeaderWithPaddingLengthField(
64       const SpdyDataIR& data_ir);
65 
66   // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
67   // frame is used to implement per stream flow control.
68   static SpdySerializedFrame SerializeWindowUpdate(
69       const SpdyWindowUpdateIR& window_update);
70 
71   explicit SpdyFramer(CompressionOption option);
72 
73   virtual ~SpdyFramer();
74 
75   // Set debug callbacks to be called from the framer. The debug visitor is
76   // completely optional and need not be set in order for normal operation.
77   // If this is called multiple times, only the last visitor will be used.
78   void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor);
79 
80   SpdySerializedFrame SerializeRstStream(
81       const SpdyRstStreamIR& rst_stream) const;
82 
83   // Serializes a SETTINGS frame. The SETTINGS frame is
84   // used to communicate name/value pairs relevant to the communication channel.
85   SpdySerializedFrame SerializeSettings(const SpdySettingsIR& settings) const;
86 
87   // Serializes a PING frame. The unique_id is used to
88   // identify the ping request/response.
89   SpdySerializedFrame SerializePing(const SpdyPingIR& ping) const;
90 
91   // Serializes a GOAWAY frame. The GOAWAY frame is used
92   // prior to the shutting down of the TCP connection, and includes the
93   // stream_id of the last stream the sender of the frame is willing to process
94   // to completion.
95   SpdySerializedFrame SerializeGoAway(const SpdyGoAwayIR& goaway) const;
96 
97   // Serializes a HEADERS frame. The HEADERS frame is used
98   // for sending headers.
99   SpdySerializedFrame SerializeHeaders(const SpdyHeadersIR& headers);
100 
101   // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
102   // to inform the client that it will be receiving an additional stream
103   // in response to the original request. The frame includes synthesized
104   // headers to explain the upcoming data.
105   SpdySerializedFrame SerializePushPromise(
106       const SpdyPushPromiseIR& push_promise);
107 
108   // Serializes a CONTINUATION frame. The CONTINUATION frame is used
109   // to continue a sequence of header block fragments.
110   SpdySerializedFrame SerializeContinuation(
111       const SpdyContinuationIR& continuation) const;
112 
113   // Serializes an ALTSVC frame. The ALTSVC frame advertises the
114   // availability of an alternative service to the client.
115   SpdySerializedFrame SerializeAltSvc(const SpdyAltSvcIR& altsvc);
116 
117   // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
118   // the relative priority of the given stream.
119   SpdySerializedFrame SerializePriority(const SpdyPriorityIR& priority) const;
120 
121   // Serializes a PRIORITY_UPDATE frame.
122   // See https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html.
123   SpdySerializedFrame SerializePriorityUpdate(
124       const SpdyPriorityUpdateIR& priority_update) const;
125 
126   // Serializes an ACCEPT_CH frame.  See
127   // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02.
128   SpdySerializedFrame SerializeAcceptCh(const SpdyAcceptChIR& accept_ch) const;
129 
130   // Serializes an unknown frame given a frame header and payload.
131   SpdySerializedFrame SerializeUnknown(const SpdyUnknownIR& unknown) const;
132 
133   // Serialize a frame of unknown type.
134   SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame);
135 
136   // Serialize a data frame.
137   bool SerializeData(const SpdyDataIR& data,
138                      ZeroCopyOutputBuffer* output) const;
139 
140   // Serializes the data frame header and optionally padding length fields,
141   // excluding actual data payload and padding.
142   bool SerializeDataFrameHeaderWithPaddingLengthField(
143       const SpdyDataIR& data, ZeroCopyOutputBuffer* output) const;
144 
145   bool SerializeRstStream(const SpdyRstStreamIR& rst_stream,
146                           ZeroCopyOutputBuffer* output) const;
147 
148   // Serializes a SETTINGS frame. The SETTINGS frame is
149   // used to communicate name/value pairs relevant to the communication channel.
150   bool SerializeSettings(const SpdySettingsIR& settings,
151                          ZeroCopyOutputBuffer* output) const;
152 
153   // Serializes a PING frame. The unique_id is used to
154   // identify the ping request/response.
155   bool SerializePing(const SpdyPingIR& ping,
156                      ZeroCopyOutputBuffer* output) const;
157 
158   // Serializes a GOAWAY frame. The GOAWAY frame is used
159   // prior to the shutting down of the TCP connection, and includes the
160   // stream_id of the last stream the sender of the frame is willing to process
161   // to completion.
162   bool SerializeGoAway(const SpdyGoAwayIR& goaway,
163                        ZeroCopyOutputBuffer* output) const;
164 
165   // Serializes a HEADERS frame. The HEADERS frame is used
166   // for sending headers.
167   bool SerializeHeaders(const SpdyHeadersIR& headers,
168                         ZeroCopyOutputBuffer* output);
169 
170   // Serializes a WINDOW_UPDATE frame. The WINDOW_UPDATE
171   // frame is used to implement per stream flow control.
172   bool SerializeWindowUpdate(const SpdyWindowUpdateIR& window_update,
173                              ZeroCopyOutputBuffer* output) const;
174 
175   // Serializes a PUSH_PROMISE frame. The PUSH_PROMISE frame is used
176   // to inform the client that it will be receiving an additional stream
177   // in response to the original request. The frame includes synthesized
178   // headers to explain the upcoming data.
179   bool SerializePushPromise(const SpdyPushPromiseIR& push_promise,
180                             ZeroCopyOutputBuffer* output);
181 
182   // Serializes a CONTINUATION frame. The CONTINUATION frame is used
183   // to continue a sequence of header block fragments.
184   bool SerializeContinuation(const SpdyContinuationIR& continuation,
185                              ZeroCopyOutputBuffer* output) const;
186 
187   // Serializes an ALTSVC frame. The ALTSVC frame advertises the
188   // availability of an alternative service to the client.
189   bool SerializeAltSvc(const SpdyAltSvcIR& altsvc,
190                        ZeroCopyOutputBuffer* output);
191 
192   // Serializes a PRIORITY frame. The PRIORITY frame advises a change in
193   // the relative priority of the given stream.
194   bool SerializePriority(const SpdyPriorityIR& priority,
195                          ZeroCopyOutputBuffer* output) const;
196 
197   // Serializes a PRIORITY_UPDATE frame.
198   // See https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html.
199   bool SerializePriorityUpdate(const SpdyPriorityUpdateIR& priority_update,
200                                ZeroCopyOutputBuffer* output) const;
201 
202   // Serializes an ACCEPT_CH frame.  See
203   // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02.
204   bool SerializeAcceptCh(const SpdyAcceptChIR& accept_ch,
205                          ZeroCopyOutputBuffer* output) const;
206 
207   // Serializes an unknown frame given a frame header and payload.
208   bool SerializeUnknown(const SpdyUnknownIR& unknown,
209                         ZeroCopyOutputBuffer* output) const;
210 
211   // Serialize a frame of unknown type.
212   size_t SerializeFrame(const SpdyFrameIR& frame, ZeroCopyOutputBuffer* output);
213 
214   // Returns whether this SpdyFramer will compress header blocks using HPACK.
compression_enabled()215   bool compression_enabled() const {
216     return compression_option_ == ENABLE_COMPRESSION;
217   }
218 
SetHpackIndexingPolicy(HpackEncoder::IndexingPolicy policy)219   void SetHpackIndexingPolicy(HpackEncoder::IndexingPolicy policy) {
220     GetHpackEncoder()->SetIndexingPolicy(std::move(policy));
221   }
222 
223   // Updates the maximum size of the header encoder compression table.
224   void UpdateHeaderEncoderTableSize(uint32_t value);
225 
226   // Returns the maximum size of the header encoder compression table.
227   size_t header_encoder_table_size() const;
228 
229   // Get (and lazily initialize) the HPACK encoder state.
230   HpackEncoder* GetHpackEncoder();
231 
232   // Gets the HPACK encoder state. Returns nullptr if the encoder has not been
233   // initialized.
GetHpackEncoder()234   const HpackEncoder* GetHpackEncoder() const { return hpack_encoder_.get(); }
235 
236  protected:
237   friend class test::SpdyFramerPeer;
238   friend class test::SpdyFramerTest_MultipleContinuationFramesWithIterator_Test;
239   friend class test::SpdyFramerTest_PushPromiseFramesWithIterator_Test;
240 
241   // Iteratively converts a SpdyFrameIR into an appropriate sequence of Spdy
242   // frames.
243   // Example usage:
244   // std::unique_ptr<SpdyFrameSequence> it = CreateIterator(framer, frame_ir);
245   // while (it->HasNextFrame()) {
246   //   if(it->NextFrame(output) == 0) {
247   //     // Write failed;
248   //   }
249   // }
250   class QUICHE_EXPORT SpdyFrameIterator : public SpdyFrameSequence {
251    public:
252     // Creates an iterator with the provided framer.
253     // Does not take ownership of |framer|.
254     // |framer| must outlive this instance.
255     explicit SpdyFrameIterator(SpdyFramer* framer);
256     ~SpdyFrameIterator() override;
257 
258     // Serializes the next frame in the sequence to |output|. Returns the number
259     // of bytes written to |output|.
260     size_t NextFrame(ZeroCopyOutputBuffer* output) override;
261 
262     // Returns true iff there is at least one more frame in the sequence.
263     bool HasNextFrame() const override;
264 
265     // SpdyFrameIterator is neither copyable nor movable.
266     SpdyFrameIterator(const SpdyFrameIterator&) = delete;
267     SpdyFrameIterator& operator=(const SpdyFrameIterator&) = delete;
268 
269    protected:
270     virtual size_t GetFrameSizeSansBlock() const = 0;
271     virtual bool SerializeGivenEncoding(const std::string& encoding,
272                                         ZeroCopyOutputBuffer* output) const = 0;
273 
GetFramer()274     SpdyFramer* GetFramer() const { return framer_; }
275 
SetEncoder(const SpdyFrameWithHeaderBlockIR * ir)276     void SetEncoder(const SpdyFrameWithHeaderBlockIR* ir) {
277       encoder_ =
278           framer_->GetHpackEncoder()->EncodeHeaderSet(ir->header_block());
279     }
280 
has_next_frame()281     bool has_next_frame() const { return has_next_frame_; }
282 
283    private:
284     SpdyFramer* const framer_;
285     std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_;
286     bool is_first_frame_;
287     bool has_next_frame_;
288   };
289 
290   // Iteratively converts a SpdyHeadersIR (with a possibly huge
291   // Http2HeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
292   // write to the output.
293   class QUICHE_EXPORT SpdyHeaderFrameIterator : public SpdyFrameIterator {
294    public:
295     // Does not take ownership of |framer|. Take ownership of |headers_ir|.
296     SpdyHeaderFrameIterator(SpdyFramer* framer,
297                             std::unique_ptr<const SpdyHeadersIR> headers_ir);
298 
299     ~SpdyHeaderFrameIterator() override;
300 
301    private:
302     const SpdyFrameIR& GetIR() const override;
303     size_t GetFrameSizeSansBlock() const override;
304     bool SerializeGivenEncoding(const std::string& encoding,
305                                 ZeroCopyOutputBuffer* output) const override;
306 
307     const std::unique_ptr<const SpdyHeadersIR> headers_ir_;
308   };
309 
310   // Iteratively converts a SpdyPushPromiseIR (with a possibly huge
311   // Http2HeaderBlock) into an appropriate sequence of SpdySerializedFrames, and
312   // write to the output.
313   class QUICHE_EXPORT SpdyPushPromiseFrameIterator : public SpdyFrameIterator {
314    public:
315     // Does not take ownership of |framer|. Take ownership of |push_promise_ir|.
316     SpdyPushPromiseFrameIterator(
317         SpdyFramer* framer,
318         std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir);
319 
320     ~SpdyPushPromiseFrameIterator() override;
321 
322    private:
323     const SpdyFrameIR& GetIR() const override;
324     size_t GetFrameSizeSansBlock() const override;
325     bool SerializeGivenEncoding(const std::string& encoding,
326                                 ZeroCopyOutputBuffer* output) const override;
327 
328     const std::unique_ptr<const SpdyPushPromiseIR> push_promise_ir_;
329   };
330 
331   // Converts a SpdyFrameIR into one Spdy frame (a sequence of length 1), and
332   // write it to the output.
333   class QUICHE_EXPORT SpdyControlFrameIterator : public SpdyFrameSequence {
334    public:
335     SpdyControlFrameIterator(SpdyFramer* framer,
336                              std::unique_ptr<const SpdyFrameIR> frame_ir);
337     ~SpdyControlFrameIterator() override;
338 
339     size_t NextFrame(ZeroCopyOutputBuffer* output) override;
340 
341     bool HasNextFrame() const override;
342 
343     const SpdyFrameIR& GetIR() const override;
344 
345    private:
346     SpdyFramer* const framer_;
347     std::unique_ptr<const SpdyFrameIR> frame_ir_;
348     bool has_next_frame_ = true;
349   };
350 
351  private:
352   void SerializeHeadersBuilderHelper(const SpdyHeadersIR& headers,
353                                      uint8_t* flags, size_t* size,
354                                      std::string* hpack_encoding, int* weight,
355                                      size_t* length_field);
356   void SerializePushPromiseBuilderHelper(const SpdyPushPromiseIR& push_promise,
357                                          uint8_t* flags,
358                                          std::string* hpack_encoding,
359                                          size_t* size);
360 
361   std::unique_ptr<HpackEncoder> hpack_encoder_;
362 
363   SpdyFramerDebugVisitorInterface* debug_visitor_;
364 
365   // Determines whether HPACK compression is used.
366   const CompressionOption compression_option_;
367 };
368 
369 }  // namespace spdy
370 
371 #endif  // QUICHE_SPDY_CORE_SPDY_FRAMER_H_
372