blob: e806ea0fd668ccb2226a9755b875903e0645ac3e [file] [log] [blame]
// 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_