• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef QUICHE_SPDY_CORE_METADATA_EXTENSION_H_
2 #define QUICHE_SPDY_CORE_METADATA_EXTENSION_H_
3 
4 #include <memory>
5 #include <string>
6 #include <vector>
7 
8 #include "absl/container/flat_hash_map.h"
9 #include "quiche/common/platform/api/quiche_export.h"
10 #include "quiche/spdy/core/hpack/hpack_encoder.h"
11 #include "quiche/spdy/core/http2_frame_decoder_adapter.h"
12 #include "quiche/spdy/core/http2_header_block.h"
13 #include "quiche/spdy/core/spdy_protocol.h"
14 #include "quiche/spdy/core/zero_copy_output_buffer.h"
15 
16 namespace spdy {
17 
18 // An implementation of the ExtensionVisitorInterface that can parse
19 // METADATA frames. METADATA is a non-standard HTTP/2 extension developed and
20 // used internally at Google. A peer advertises support for METADATA by sending
21 // a setting with a setting ID of kMetadataExtensionId and a value of 1.
22 //
23 // Metadata is represented as a HPACK header block with literal encoding.
24 class QUICHE_EXPORT MetadataVisitor : public spdy::ExtensionVisitorInterface {
25  public:
26   using MetadataPayload = spdy::Http2HeaderBlock;
27 
28   static_assert(!std::is_copy_constructible<MetadataPayload>::value,
29                 "MetadataPayload should be a move-only type!");
30 
31   using OnMetadataSupport = std::function<void(bool)>;
32   using OnCompletePayload =
33       std::function<void(spdy::SpdyStreamId, MetadataPayload)>;
34 
35   // The HTTP/2 SETTINGS ID that is used to indicate support for METADATA
36   // frames.
37   static const spdy::SpdySettingsId kMetadataExtensionId;
38 
39   // The 8-bit frame type code for a METADATA frame.
40   static const uint8_t kMetadataFrameType;
41 
42   // The flag that indicates the end of a logical metadata block. Due to frame
43   // size limits, a single metadata block may be emitted as several HTTP/2
44   // frames.
45   static const uint8_t kEndMetadataFlag;
46 
47   // |on_payload| is invoked whenever a complete metadata payload is received.
48   // |on_support| is invoked whenever the peer's advertised support for metadata
49   // changes.
50   MetadataVisitor(OnCompletePayload on_payload, OnMetadataSupport on_support);
51   ~MetadataVisitor() override;
52 
53   MetadataVisitor(const MetadataVisitor&) = delete;
54   MetadataVisitor& operator=(const MetadataVisitor&) = delete;
55 
56   // Interprets the non-standard setting indicating support for METADATA.
57   void OnSetting(spdy::SpdySettingsId id, uint32_t value) override;
58 
59   // Returns true iff |type| indicates a METADATA frame.
60   bool OnFrameHeader(spdy::SpdyStreamId stream_id, size_t length, uint8_t type,
61                      uint8_t flags) override;
62 
63   // Consumes a METADATA frame payload. Invokes the registered callback when a
64   // complete payload has been received.
65   void OnFramePayload(const char* data, size_t len) override;
66 
67   // Returns true if the peer has advertised support for METADATA via the
68   // appropriate setting.
PeerSupportsMetadata()69   bool PeerSupportsMetadata() const {
70     return peer_supports_metadata_ == MetadataSupportState::SUPPORTED;
71   }
72 
73  private:
74   enum class MetadataSupportState : uint8_t {
75     UNSPECIFIED,
76     SUPPORTED,
77     NOT_SUPPORTED,
78   };
79 
80   struct MetadataPayloadState;
81 
82   using StreamMetadataMap =
83       absl::flat_hash_map<spdy::SpdyStreamId,
84                           std::unique_ptr<MetadataPayloadState>>;
85 
86   OnCompletePayload on_payload_;
87   OnMetadataSupport on_support_;
88   StreamMetadataMap metadata_map_;
89   spdy::SpdyStreamId current_stream_;
90   MetadataSupportState peer_supports_metadata_;
91 };
92 
93 // This class uses an HpackEncoder to serialize a METADATA block as a series of
94 // METADATA frames.
95 class QUICHE_EXPORT MetadataFrameSequence {
96  public:
97   MetadataFrameSequence(SpdyStreamId stream_id, spdy::Http2HeaderBlock payload);
98 
99   // Copies are not allowed.
100   MetadataFrameSequence(const MetadataFrameSequence& other) = delete;
101   MetadataFrameSequence& operator=(const MetadataFrameSequence& other) = delete;
102 
103   // True if Next() would return non-nullptr.
104   bool HasNext() const;
105 
106   // Returns the next HTTP/2 METADATA frame for this block, unless the block has
107   // been entirely serialized in frames returned by previous calls of Next(), in
108   // which case returns nullptr.
109   std::unique_ptr<spdy::SpdyFrameIR> Next();
110 
stream_id()111   SpdyStreamId stream_id() const { return stream_id_; }
112 
113  private:
114   SpdyStreamId stream_id_;
115   Http2HeaderBlock payload_;
116   HpackEncoder encoder_;
117   std::unique_ptr<HpackEncoder::ProgressiveEncoder> progressive_encoder_;
118 };
119 
120 }  // namespace spdy
121 
122 #endif  // QUICHE_SPDY_CORE_METADATA_EXTENSION_H_
123