summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.h
blob: e806ea0fd668ccb2226a9755b875903e0645ac3e (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef QUICHE_QUIC_CORE_QPACK_QPACK_PROGRESSIVE_DECODER_H_
#define QUICHE_QUIC_CORE_QPACK_QPACK_PROGRESSIVE_DECODER_H_

#include <cstdint>
#include <memory>
#include <string>

#include "absl/strings/string_view.h"
#include "quic/core/qpack/qpack_encoder_stream_receiver.h"
#include "quic/core/qpack/qpack_header_table.h"
#include "quic/core/qpack/qpack_instruction_decoder.h"
#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_export.h"

namespace quic {

class QpackHeaderTable;

// Class to decode a single header block.
class QUIC_EXPORT_PRIVATE QpackProgressiveDecoder
    : public QpackInstructionDecoder::Delegate,
      public QpackHeaderTable::Observer {
 public:
  // Interface for receiving decoded header block from the decoder.
  class QUIC_EXPORT_PRIVATE HeadersHandlerInterface {
   public:
    virtual ~HeadersHandlerInterface() {}

    // Called when a new header name-value pair is decoded.  Multiple values for
    // a given name will be emitted as multiple calls to OnHeader.
    virtual void OnHeaderDecoded(absl::string_view name,
                                 absl::string_view value) = 0;

    // Called when the header block is completely decoded.
    // Indicates the total number of bytes in this block.
    // The decoder will not access the handler after this call.
    // Note that this method might not be called synchronously when the header
    // block is received on the wire, in case decoding is blocked on receiving
    // entries on the encoder stream.
    virtual void OnDecodingCompleted() = 0;

    // Called when a decoding error has occurred.  No other methods will be
    // called afterwards.  Implementations are allowed to destroy
    // the QpackProgressiveDecoder instance synchronously.
    virtual void OnDecodingErrorDetected(absl::string_view error_message) = 0;
  };

  // Interface for keeping track of blocked streams for the purpose of enforcing
  // the limit communicated to peer via QPACK_BLOCKED_STREAMS settings.
  class QUIC_EXPORT_PRIVATE BlockedStreamLimitEnforcer {
   public:
    virtual ~BlockedStreamLimitEnforcer() {}

    // Called when the stream becomes blocked.  Returns true if allowed. Returns
    // false if limit is violated, in which case QpackProgressiveDecoder signals
    // an error.
    // Stream must not be already blocked.
    virtual bool OnStreamBlocked(QuicStreamId stream_id) = 0;

    // Called when the stream becomes unblocked.
    // Stream must be blocked.
    virtual void OnStreamUnblocked(QuicStreamId stream_id) = 0;
  };

  // Visitor to be notified when decoding is completed.
  class QUIC_EXPORT_PRIVATE DecodingCompletedVisitor {
   public:
    virtual ~DecodingCompletedVisitor() = default;

    // Called when decoding is completed, with Required Insert Count of the
    // decoded header block.  Required Insert Count is defined at
    // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#blocked-streams.
    virtual void OnDecodingCompleted(QuicStreamId stream_id,
                                     uint64_t required_insert_count) = 0;
  };

  QpackProgressiveDecoder() = delete;
  QpackProgressiveDecoder(QuicStreamId stream_id,
                          BlockedStreamLimitEnforcer* enforcer,
                          DecodingCompletedVisitor* visitor,
                          QpackHeaderTable* header_table,
                          HeadersHandlerInterface* handler);
  QpackProgressiveDecoder(const QpackProgressiveDecoder&) = delete;
  QpackProgressiveDecoder& operator=(const QpackProgressiveDecoder&) = delete;
  ~QpackProgressiveDecoder() override;

  // Provide a data fragment to decode.
  void Decode(absl::string_view data);

  // Signal that the entire header block has been received and passed in
  // through Decode().  No methods must be called afterwards.
  void EndHeaderBlock();

  // Called on error.
  void OnError(absl::string_view error_message);

  // QpackInstructionDecoder::Delegate implementation.
  bool OnInstructionDecoded(const QpackInstruction* instruction) override;
  void OnInstructionDecodingError(QpackInstructionDecoder::ErrorCode error_code,
                                  absl::string_view error_message) override;

  // QpackHeaderTable::Observer implementation.
  void OnInsertCountReachedThreshold() override;
  void Cancel() override;

 private:
  bool DoIndexedHeaderFieldInstruction();
  bool DoIndexedHeaderFieldPostBaseInstruction();
  bool DoLiteralHeaderFieldNameReferenceInstruction();
  bool DoLiteralHeaderFieldPostBaseInstruction();
  bool DoLiteralHeaderFieldInstruction();
  bool DoPrefixInstruction();

  // Called as soon as EndHeaderBlock() is called and decoding is not blocked.
  void FinishDecoding();

  // Calculates Base from |required_insert_count_|, which must be set before
  // calling this method, and sign bit and Delta Base in the Header Data Prefix,
  // which are passed in as arguments.  Returns true on success, false on
  // failure due to overflow/underflow.
  bool DeltaBaseToBase(bool sign, uint64_t delta_base, uint64_t* base);

  const QuicStreamId stream_id_;

  // |prefix_decoder_| only decodes a handful of bytes then it can be
  // destroyed to conserve memory.  |instruction_decoder_|, on the other hand,
  // is used until the entire header block is decoded.
  std::unique_ptr<QpackInstructionDecoder> prefix_decoder_;
  QpackInstructionDecoder instruction_decoder_;

  BlockedStreamLimitEnforcer* const enforcer_;
  DecodingCompletedVisitor* const visitor_;
  QpackHeaderTable* const header_table_;
  HeadersHandlerInterface* const handler_;

  // Required Insert Count and Base are decoded from the Header Data Prefix.
  uint64_t required_insert_count_;
  uint64_t base_;

  // Required Insert Count is one larger than the largest absolute index of all
  // referenced dynamic table entries, or zero if no dynamic table entries are
  // referenced.  |required_insert_count_so_far_| starts out as zero and keeps
  // track of the Required Insert Count based on entries decoded so far.
  // After decoding is completed, it is compared to |required_insert_count_|.
  uint64_t required_insert_count_so_far_;

  // False until prefix is fully read and decoded.
  bool prefix_decoded_;

  // True if waiting for dynamic table entries to arrive.
  bool blocked_;

  // Buffer the entire header block after the prefix while decoding is blocked.
  std::string buffer_;

  // True until EndHeaderBlock() is called.
  bool decoding_;

  // True if a decoding error has been detected.
  bool error_detected_;

  // True if QpackHeaderTable has been destroyed
  // while decoding is still blocked.
  bool cancelled_;
};

}  // namespace quic

#endif  // QUICHE_QUIC_CORE_QPACK_QPACK_PROGRESSIVE_DECODER_H_