summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quiche/spdy/core/metadata_extension.h
blob: a27ad165caa29166f3a4385fcaecb2730bbccb75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#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 "quiche/spdy/core/http2_frame_decoder_adapter.h"
#include "quiche/spdy/core/spdy_header_block.h"
#include "quiche/spdy/core/spdy_protocol.h"
#include "quiche/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_