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