QUICHE team | ee76274 | 2021-06-25 16:05:19 -0700 | [diff] [blame] | 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 "spdy/core/http2_frame_decoder_adapter.h" |
| 10 | #include "spdy/core/spdy_header_block.h" |
| 11 | #include "spdy/core/spdy_protocol.h" |
| 12 | #include "spdy/core/zero_copy_output_buffer.h" |
| 13 | |
| 14 | namespace spdy { |
| 15 | |
| 16 | // An implementation of the ExtensionVisitorInterface that can parse |
| 17 | // METADATA frames. METADATA is a non-standard HTTP/2 extension developed and |
| 18 | // used internally at Google. A peer advertises support for METADATA by sending |
| 19 | // a setting with a setting ID of kMetadataExtensionId and a value of 1. |
| 20 | // |
| 21 | // Metadata is represented as a HPACK header block with literal encoding. |
| 22 | class MetadataVisitor : public spdy::ExtensionVisitorInterface { |
| 23 | public: |
| 24 | using MetadataPayload = spdy::SpdyHeaderBlock; |
| 25 | |
| 26 | static_assert(!std::is_copy_constructible<MetadataPayload>::value, |
| 27 | "MetadataPayload should be a move-only type!"); |
| 28 | |
| 29 | using OnMetadataSupport = std::function<void(bool)>; |
| 30 | using OnCompletePayload = |
| 31 | std::function<void(spdy::SpdyStreamId, MetadataPayload)>; |
| 32 | |
| 33 | // The HTTP/2 SETTINGS ID that is used to indicate support for METADATA |
| 34 | // frames. |
| 35 | static const spdy::SpdySettingsId kMetadataExtensionId; |
| 36 | |
| 37 | // The 8-bit frame type code for a METADATA frame. |
| 38 | static const uint8_t kMetadataFrameType; |
| 39 | |
| 40 | // The flag that indicates the end of a logical metadata block. Due to frame |
| 41 | // size limits, a single metadata block may be emitted as several HTTP/2 |
| 42 | // frames. |
| 43 | static const uint8_t kEndMetadataFlag; |
| 44 | |
| 45 | // |on_payload| is invoked whenever a complete metadata payload is received. |
| 46 | // |on_support| is invoked whenever the peer's advertised support for metadata |
| 47 | // changes. |
| 48 | MetadataVisitor(OnCompletePayload on_payload, OnMetadataSupport on_support); |
| 49 | ~MetadataVisitor() override; |
| 50 | |
| 51 | MetadataVisitor(const MetadataVisitor&) = delete; |
| 52 | MetadataVisitor& operator=(const MetadataVisitor&) = delete; |
| 53 | |
| 54 | // Interprets the non-standard setting indicating support for METADATA. |
| 55 | void OnSetting(spdy::SpdySettingsId id, uint32_t value) override; |
| 56 | |
| 57 | // Returns true iff |type| indicates a METADATA frame. |
| 58 | bool OnFrameHeader(spdy::SpdyStreamId stream_id, size_t length, uint8_t type, |
| 59 | uint8_t flags) override; |
| 60 | |
| 61 | // Consumes a METADATA frame payload. Invokes the registered callback when a |
| 62 | // complete payload has been received. |
| 63 | void OnFramePayload(const char* data, size_t len) override; |
| 64 | |
| 65 | // Returns true if the peer has advertised support for METADATA via the |
| 66 | // appropriate setting. |
| 67 | bool PeerSupportsMetadata() const { |
| 68 | return peer_supports_metadata_ == MetadataSupportState::SUPPORTED; |
| 69 | } |
| 70 | |
| 71 | private: |
| 72 | enum class MetadataSupportState : uint8_t { |
| 73 | UNSPECIFIED, |
| 74 | SUPPORTED, |
| 75 | NOT_SUPPORTED, |
| 76 | }; |
| 77 | |
| 78 | struct MetadataPayloadState; |
| 79 | |
| 80 | using StreamMetadataMap = |
| 81 | absl::flat_hash_map<spdy::SpdyStreamId, |
| 82 | std::unique_ptr<MetadataPayloadState>>; |
| 83 | |
| 84 | OnCompletePayload on_payload_; |
| 85 | OnMetadataSupport on_support_; |
| 86 | StreamMetadataMap metadata_map_; |
| 87 | spdy::SpdyStreamId current_stream_; |
| 88 | MetadataSupportState peer_supports_metadata_; |
| 89 | }; |
| 90 | |
| 91 | // A class that serializes metadata blocks as sequences of frames. |
| 92 | class MetadataSerializer { |
| 93 | public: |
| 94 | using MetadataPayload = spdy::SpdyHeaderBlock; |
| 95 | |
| 96 | class FrameSequence { |
| 97 | public: |
| 98 | virtual ~FrameSequence() {} |
| 99 | |
| 100 | // Returns nullptr once the sequence has been exhausted. |
| 101 | virtual std::unique_ptr<spdy::SpdyFrameIR> Next() = 0; |
| 102 | }; |
| 103 | |
| 104 | MetadataSerializer() {} |
| 105 | |
| 106 | MetadataSerializer(const MetadataSerializer&) = delete; |
| 107 | MetadataSerializer& operator=(const MetadataSerializer&) = delete; |
| 108 | |
| 109 | // Returns nullptr on failure. |
| 110 | std::unique_ptr<FrameSequence> FrameSequenceForPayload( |
| 111 | spdy::SpdyStreamId stream_id, MetadataPayload payload); |
| 112 | }; |
| 113 | |
| 114 | } // namespace spdy |
| 115 | |
| 116 | #endif // QUICHE_SPDY_CORE_METADATA_EXTENSION_H_ |