// Copyright (c) 2019 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_DECODED_HEADERS_ACCUMULATOR_H_
#define QUICHE_QUIC_CORE_QPACK_QPACK_DECODED_HEADERS_ACCUMULATOR_H_

#include <cstddef>
#include <string>

#include "absl/strings/string_view.h"
#include "quiche/quic/core/http/quic_header_list.h"
#include "quiche/quic/core/qpack/qpack_progressive_decoder.h"
#include "quiche/quic/core/quic_error_codes.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_export.h"

namespace quic {

class QpackDecoder;

// A class that creates and owns a QpackProgressiveDecoder instance, accumulates
// decoded headers in a QuicHeaderList, and keeps track of uncompressed and
// compressed size so that it can be passed to
// QuicHeaderList::OnHeaderBlockEnd().
class QUICHE_EXPORT QpackDecodedHeadersAccumulator
    : public QpackProgressiveDecoder::HeadersHandlerInterface {
 public:
  // Visitor interface to signal success or error.
  // Exactly one method will be called.
  // Methods may be called synchronously from Decode() and EndHeaderBlock(),
  // or asynchronously.
  // Method implementations are allowed to destroy |this|.
  class QUICHE_EXPORT Visitor {
   public:
    virtual ~Visitor() = default;

    // Called when headers are successfully decoded.  If the uncompressed header
    // list size including an overhead for each header field exceeds the limit
    // specified via |max_header_list_size| in QpackDecodedHeadersAccumulator
    // constructor, then |header_list_size_limit_exceeded| will be true, and
    // |headers| will be empty but will still have the correct compressed and
    // uncompressed size
    // information.
    virtual void OnHeadersDecoded(QuicHeaderList headers,
                                  bool header_list_size_limit_exceeded) = 0;

    // Called when an error has occurred.
    virtual void OnHeaderDecodingError(QuicErrorCode error_code,
                                       absl::string_view error_message) = 0;
  };

  QpackDecodedHeadersAccumulator(QuicStreamId id, QpackDecoder* qpack_decoder,
                                 Visitor* visitor, size_t max_header_list_size);
  virtual ~QpackDecodedHeadersAccumulator() = default;

  // QpackProgressiveDecoder::HeadersHandlerInterface implementation.
  // These methods should only be called by |decoder_|.
  void OnHeaderDecoded(absl::string_view name,
                       absl::string_view value) override;
  void OnDecodingCompleted() override;
  void OnDecodingErrorDetected(QuicErrorCode error_code,
                               absl::string_view error_message) override;

  // Decode payload data.
  // Must not be called if an error has been detected.
  // Must not be called after EndHeaderBlock().
  void Decode(absl::string_view data);

  // Signal end of HEADERS frame.
  // Must not be called if an error has been detected.
  // Must not be called more that once.
  void EndHeaderBlock();

 private:
  std::unique_ptr<QpackProgressiveDecoder> decoder_;
  Visitor* visitor_;
  // Maximum header list size including overhead.
  size_t max_header_list_size_;
  // Uncompressed header list size including overhead, for enforcing the limit.
  size_t uncompressed_header_bytes_including_overhead_;
  QuicHeaderList quic_header_list_;
  // Uncompressed header list size with overhead,
  // for passing in to QuicHeaderList::OnHeaderBlockEnd().
  size_t uncompressed_header_bytes_without_overhead_;
  // Compressed header list size
  // for passing in to QuicHeaderList::OnHeaderBlockEnd().
  size_t compressed_header_bytes_;

  // True if the header size limit has been exceeded.
  // Input data is still fed to QpackProgressiveDecoder.
  bool header_list_size_limit_exceeded_;

  // The following two members are only used for QUICHE_DCHECKs.

  // True if headers have been completedly and successfully decoded.
  bool headers_decoded_;
  // True if an error has been detected during decoding.
  bool error_detected_;
};

}  // namespace quic

#endif  // QUICHE_QUIC_CORE_QPACK_QPACK_DECODED_HEADERS_ACCUMULATOR_H_
