|  | #ifndef QUICHE_SPDY_CORE_METADATA_EXTENSION_H_ | 
|  | #define QUICHE_SPDY_CORE_METADATA_EXTENSION_H_ | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/container/flat_hash_map.h" | 
|  | #include "spdy/core/http2_frame_decoder_adapter.h" | 
|  | #include "spdy/core/spdy_header_block.h" | 
|  | #include "spdy/core/spdy_protocol.h" | 
|  | #include "spdy/core/zero_copy_output_buffer.h" | 
|  |  | 
|  | namespace spdy { | 
|  |  | 
|  | // An implementation of the ExtensionVisitorInterface that can parse | 
|  | // METADATA frames. METADATA is a non-standard HTTP/2 extension developed and | 
|  | // used internally at Google. A peer advertises support for METADATA by sending | 
|  | // a setting with a setting ID of kMetadataExtensionId and a value of 1. | 
|  | // | 
|  | // Metadata is represented as a HPACK header block with literal encoding. | 
|  | class MetadataVisitor : public spdy::ExtensionVisitorInterface { | 
|  | public: | 
|  | using MetadataPayload = spdy::SpdyHeaderBlock; | 
|  |  | 
|  | static_assert(!std::is_copy_constructible<MetadataPayload>::value, | 
|  | "MetadataPayload should be a move-only type!"); | 
|  |  | 
|  | using OnMetadataSupport = std::function<void(bool)>; | 
|  | using OnCompletePayload = | 
|  | std::function<void(spdy::SpdyStreamId, MetadataPayload)>; | 
|  |  | 
|  | // The HTTP/2 SETTINGS ID that is used to indicate support for METADATA | 
|  | // frames. | 
|  | static const spdy::SpdySettingsId kMetadataExtensionId; | 
|  |  | 
|  | // The 8-bit frame type code for a METADATA frame. | 
|  | static const uint8_t kMetadataFrameType; | 
|  |  | 
|  | // The flag that indicates the end of a logical metadata block. Due to frame | 
|  | // size limits, a single metadata block may be emitted as several HTTP/2 | 
|  | // frames. | 
|  | static const uint8_t kEndMetadataFlag; | 
|  |  | 
|  | // |on_payload| is invoked whenever a complete metadata payload is received. | 
|  | // |on_support| is invoked whenever the peer's advertised support for metadata | 
|  | // changes. | 
|  | MetadataVisitor(OnCompletePayload on_payload, OnMetadataSupport on_support); | 
|  | ~MetadataVisitor() override; | 
|  |  | 
|  | MetadataVisitor(const MetadataVisitor&) = delete; | 
|  | MetadataVisitor& operator=(const MetadataVisitor&) = delete; | 
|  |  | 
|  | // Interprets the non-standard setting indicating support for METADATA. | 
|  | void OnSetting(spdy::SpdySettingsId id, uint32_t value) override; | 
|  |  | 
|  | // Returns true iff |type| indicates a METADATA frame. | 
|  | bool OnFrameHeader(spdy::SpdyStreamId stream_id, size_t length, uint8_t type, | 
|  | uint8_t flags) override; | 
|  |  | 
|  | // Consumes a METADATA frame payload. Invokes the registered callback when a | 
|  | // complete payload has been received. | 
|  | void OnFramePayload(const char* data, size_t len) override; | 
|  |  | 
|  | // Returns true if the peer has advertised support for METADATA via the | 
|  | // appropriate setting. | 
|  | bool PeerSupportsMetadata() const { | 
|  | return peer_supports_metadata_ == MetadataSupportState::SUPPORTED; | 
|  | } | 
|  |  | 
|  | private: | 
|  | enum class MetadataSupportState : uint8_t { | 
|  | UNSPECIFIED, | 
|  | SUPPORTED, | 
|  | NOT_SUPPORTED, | 
|  | }; | 
|  |  | 
|  | struct MetadataPayloadState; | 
|  |  | 
|  | using StreamMetadataMap = | 
|  | absl::flat_hash_map<spdy::SpdyStreamId, | 
|  | std::unique_ptr<MetadataPayloadState>>; | 
|  |  | 
|  | OnCompletePayload on_payload_; | 
|  | OnMetadataSupport on_support_; | 
|  | StreamMetadataMap metadata_map_; | 
|  | spdy::SpdyStreamId current_stream_; | 
|  | MetadataSupportState peer_supports_metadata_; | 
|  | }; | 
|  |  | 
|  | // A class that serializes metadata blocks as sequences of frames. | 
|  | class MetadataSerializer { | 
|  | public: | 
|  | using MetadataPayload = spdy::SpdyHeaderBlock; | 
|  |  | 
|  | class FrameSequence { | 
|  | public: | 
|  | virtual ~FrameSequence() {} | 
|  |  | 
|  | // Returns nullptr once the sequence has been exhausted. | 
|  | virtual std::unique_ptr<spdy::SpdyFrameIR> Next() = 0; | 
|  | }; | 
|  |  | 
|  | MetadataSerializer() {} | 
|  |  | 
|  | MetadataSerializer(const MetadataSerializer&) = delete; | 
|  | MetadataSerializer& operator=(const MetadataSerializer&) = delete; | 
|  |  | 
|  | // Returns nullptr on failure. | 
|  | std::unique_ptr<FrameSequence> FrameSequenceForPayload( | 
|  | spdy::SpdyStreamId stream_id, MetadataPayload payload); | 
|  | }; | 
|  |  | 
|  | }  // namespace spdy | 
|  |  | 
|  | #endif  // QUICHE_SPDY_CORE_METADATA_EXTENSION_H_ |