<commit_before>// Copyright 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_COMMON_STRUCTURED_HEADERS_H_
#define QUICHE_COMMON_STRUCTURED_HEADERS_H_

#include <algorithm>
#include <map>
#include <string>
#include <tuple>
#include <vector>

#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/platform/api/quiche_logging.h"

namespace quiche {
namespace structured_headers {

// This file implements parsing of HTTP structured headers, as defined in
// RFC8941 (https://www.rfc-editor.org/rfc/rfc8941.html). For compatibility with
// the shipped implementation of Web Packaging, this file also supports a
// previous revision of the standard, referred to here as "Draft 9".
// (https://datatracker.ietf.org/doc/draft-ietf-httpbis-header-structure/09/)
//
// The major difference between the two revisions is in the various list
// formats: Draft 9 describes "parameterised lists" and "lists-of-lists", while
// the final RFC uses a single "list" syntax, whose members may be inner lists.
// There should be no ambiguity, however, as the code which calls this parser
// should be expecting only a single type for a given header.
//
// References within the code are tagged with either [SH09] or [RFC8941],
// depending on which revision they refer to.
//
// Currently supported data types are:
//  Item:
//   integer: 123
//   string: "abc"
//   token: abc
//   byte sequence: *YWJj*
//  Parameterised list: abc_123;a=1;b=2; cdef_456, ghi;q="9";r="w"
//  List-of-lists: "foo";"bar", "baz", "bat"; "one"
//  List: "foo", "bar", "It was the best of times."
//        ("foo" "bar"), ("baz"), ("bat" "one"), ()
//        abc;a=1;b=2; cde_456, (ghi jkl);q="9";r=w
//  Dictionary: a=(1 2), b=3, c=4;aa=bb, d=(5 6);valid=?0
//
// Functions are provided to parse each of these, which are intended to be
// called with the complete value of an HTTP header (that is, any
// sub-structure will be handled internally by the parser; the exported
// functions are not intended to be called on partial header strings.) Input
// values should be ASCII byte strings (non-ASCII characters should not be
// present in Structured Header values, and will cause the entire header to fail
// to parse.)

class QUICHE_EXPORT_PRIVATE Item {
 public:
  enum ItemType {
    kNullType,
    kIntegerType,
    kDecimalType,
    kStringType,
    kTokenType,
    kByteSequenceType,
    kBooleanType
  };
  Item();
  explicit Item(int64_t value);
  explicit Item(double value);
  explicit Item(bool value);

  // Constructors for string-like items: Strings, Tokens and Byte Sequences.
  Item(const char* value, Item::ItemType type = kStringType);
  Item(std::string value, Item::ItemType type = kStringType);

  QUICHE_EXPORT_PRIVATE friend bool operator==(const Item& lhs,
                                               const Item& rhs);
  inline friend bool operator!=(const Item& lhs, const Item& rhs) {
    return !(lhs == rhs);
  }

  bool is_null() const { return Type() == kNullType; }
  bool is_integer() const { return Type() == kIntegerType; }
  bool is_decimal() const { return Type() == kDecimalType; }
  bool is_string() const { return Type() == kStringType; }
  bool is_token() const { return Type() == kTokenType; }
  bool is_byte_sequence() const { return Type() == kByteSequenceType; }
  bool is_boolean() const { return Type() == kBooleanType; }

  int64_t GetInteger() const {
    const auto* value = absl::get_if<int64_t>(&value_);
    QUICHE_CHECK(value);
    return *value;
  }
  double GetDecimal() const {
    const auto* value = absl::get_if<double>(&value_);
    QUICHE_CHECK(value);
    return *value;
  }
  bool GetBoolean() const {
    const auto* value = absl::get_if<bool>(&value_);
    QUICHE_CHECK(value);
    return *value;
  }
  // TODO(iclelland): Split up accessors for String, Token and Byte Sequence.
  const std::string& GetString() const {
    struct Visitor {
      const std::string* operator()(const absl::monostate&) { return nullptr; }
      const std::string* operator()(const int64_t&) { return nullptr; }
      const std::string* operator()(const double&) { return nullptr; }
      const std::string* operator()(const std::string& value) { return &value; }
      const std::string* operator()(const bool&) { return nullptr; }
    };
    const std::string* value = absl::visit(Visitor(), value_);
    QUICHE_CHECK(value);
    return *value;
  }

  ItemType Type() const { return static_cast<ItemType>(value_.index()); }

 private:
  absl::variant<absl::monostate, int64_t, double, std::string, std::string,
                std::string, bool><commit_msg>Permit strings, tokens, and byte sequences to be moved out of Items<commit_after>// Copyright 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_COMMON_STRUCTURED_HEADERS_H_
#define QUICHE_COMMON_STRUCTURED_HEADERS_H_

#include <algorithm>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/platform/api/quiche_logging.h"

namespace quiche {
namespace structured_headers {

// This file implements parsing of HTTP structured headers, as defined in
// RFC8941 (https://www.rfc-editor.org/rfc/rfc8941.html). For compatibility with
// the shipped implementation of Web Packaging, this file also supports a
// previous revision of the standard, referred to here as "Draft 9".
// (https://datatracker.ietf.org/doc/draft-ietf-httpbis-header-structure/09/)
//
// The major difference between the two revisions is in the various list
// formats: Draft 9 describes "parameterised lists" and "lists-of-lists", while
// the final RFC uses a single "list" syntax, whose members may be inner lists.
// There should be no ambiguity, however, as the code which calls this parser
// should be expecting only a single type for a given header.
//
// References within the code are tagged with either [SH09] or [RFC8941],
// depending on which revision they refer to.
//
// Currently supported data types are:
//  Item:
//   integer: 123
//   string: "abc"
//   token: abc
//   byte sequence: *YWJj*
//  Parameterised list: abc_123;a=1;b=2; cdef_456, ghi;q="9";r="w"
//  List-of-lists: "foo";"bar", "baz", "bat"; "one"
//  List: "foo", "bar", "It was the best of times."
//        ("foo" "bar"), ("baz"), ("bat" "one"), ()
//        abc;a=1;b=2; cde_456, (ghi jkl);q="9";r=w
//  Dictionary: a=(1 2), b=3, c=4;aa=bb, d=(5 6);valid=?0
//
// Functions are provided to parse each of these, which are intended to be
// called with the complete value of an HTTP header (that is, any
// sub-structure will be handled internally by the parser; the exported
// functions are not intended to be called on partial header strings.) Input
// values should be ASCII byte strings (non-ASCII characters should not be
// present in Structured Header values, and will cause the entire header to fail
// to parse.)

class QUICHE_EXPORT_PRIVATE Item {
 public:
  enum ItemType {
    kNullType,
    kIntegerType,
    kDecimalType,
    kStringType,
    kTokenType,
    kByteSequenceType,
    kBooleanType
  };
  Item();
  explicit Item(int64_t value);
  explicit Item(double value);
  explicit Item(bool value);

  // Constructors for string-like items: Strings, Tokens and Byte Sequences.
  Item(const char* value, Item::ItemType type = kStringType);
  Item(std::string value, Item::ItemType type = kStringType);

  QUICHE_EXPORT_PRIVATE friend bool operator==(const Item& lhs,
                                               const Item& rhs);
  inline friend bool operator!=(const Item& lhs, const Item& rhs) {
    return !(lhs == rhs);
  }

  bool is_null() const { return Type() == kNullType; }
  bool is_integer() const { return Type() == kIntegerType; }
  bool is_decimal() const { return Type() == kDecimalType; }
  bool is_string() const { return Type() == kStringType; }
  bool is_token() const { return Type() == kTokenType; }
  bool is_byte_sequence() const { return Type() == kByteSequenceType; }
  bool is_boolean() const { return Type() == kBooleanType; }

  int64_t GetInteger() const {
    const auto* value = absl::get_if<int64_t>(&value_);
    QUICHE_CHECK(value);
    return *value;
  }
  double GetDecimal() const {
    const auto* value = absl::get_if<double>(&value_);
    QUICHE_CHECK(value);
    return *value;
  }
  bool GetBoolean() const {
    const auto* value = absl::get_if<bool>(&value_);
    QUICHE_CHECK(value);
    return *value;
  }
  // TODO(iclelland): Split up accessors for String, Token and Byte Sequence.
  const std::string& GetString() const {
    struct Visitor {
      const std::string* operator()(const absl::monostate&) { return nullptr; }
      const std::string* operator()(const int64_t&) { return nullptr; }
      const std::string* operator()(const double&) { return nullptr; }
      const std::string* operator()(const std::string& value) { return &value; }
      const std::string* operator()(const bool&) { return nullptr; }
    };
    const std::string* value = absl::visit(Visitor(), value_);
    QUICHE_CHECK(value);
    return *value;
  }

  // Transfers ownership of the underlying String, Token, or Byte Sequence.
  std::string TakeString() && {
    struct Visitor {
      std::string* operator()(absl::monostate&) { return nullptr; }
      std::string* operator()(int64_t&) { return nullptr; }
      std::string* operator()(double&) { return nullptr; }
      std::string* operator()(std::string& value) { return &value; }
      std::string* operator()(bool&) { return nullptr; }
    };
    std::string* value = absl::visit(Visitor(), value_);
    QUICHE_CHECK(value);
    return std::move(*value);
  }

  ItemType Type() const { return static_cast<ItemType>(value_.index()); }

 private:
  absl::variant<absl::monostate, int64_t, double, std::string, std::string,
                std::string, bool>
{'fraction_non_alphanumeric': 0.13068458467231472, 'fraction_numerical': 0.0112961339955205, 'mean_word_length': 3.734900875979714, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2868308', 'n_tokens_mistral': 3298, 'n_tokens_neox': 3178, 'n_words': 1052}