// Copyright 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.

#include <fuzzer/FuzzedDataProvider.h>

#include <cstddef>
#include <cstdint>

#include "absl/strings/string_view.h"
#include "quiche/quic/core/qpack/qpack_encoder_stream_receiver.h"
#include "quiche/quic/platform/api/quic_logging.h"

namespace quic {
namespace test {
namespace {

// A QpackEncoderStreamReceiver::Delegate implementation that ignores all
// decoded instructions but keeps track of whether an error has been detected.
class NoOpDelegate : public QpackEncoderStreamReceiver::Delegate {
 public:
  NoOpDelegate() : error_detected_(false) {}
  ~NoOpDelegate() override = default;

  void OnInsertWithNameReference(bool /*is_static*/, uint64_t /*name_index*/,
                                 absl::string_view /*value*/) override {}
  void OnInsertWithoutNameReference(absl::string_view /*name*/,
                                    absl::string_view /*value*/) override {}
  void OnDuplicate(uint64_t /*index*/) override {}
  void OnSetDynamicTableCapacity(uint64_t /*capacity*/) override {}
  void OnErrorDetected(QuicErrorCode /*error_code*/,
                       absl::string_view /*error_message*/) override {
    error_detected_ = true;
  }

  bool error_detected() const { return error_detected_; }

 private:
  bool error_detected_;
};

}  // namespace

// This fuzzer exercises QpackEncoderStreamReceiver.
// Note that since string literals may be encoded with or without Huffman
// encoding, one could not expect identical encoded data if the decoded
// instructions were fed into QpackEncoderStreamSender.  Therefore there is no
// point in extending this fuzzer into a round-trip test.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  NoOpDelegate delegate;
  QpackEncoderStreamReceiver receiver(&delegate);

  FuzzedDataProvider provider(data, size);

  while (!delegate.error_detected() && provider.remaining_bytes() != 0) {
    // Process up to 64 kB fragments at a time.  Too small upper bound might not
    // provide enough coverage, too large might make fuzzing too inefficient.
    size_t fragment_size = provider.ConsumeIntegralInRange<uint16_t>(
        0, std::numeric_limits<uint16_t>::max());
    receiver.Decode(provider.ConsumeRandomLengthString(fragment_size));
  }

  return 0;
}

}  // namespace test
}  // namespace quic
