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