| // 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_ |