// 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 <cstddef> #include <cstdint> #include <map> #include <optional> #include <string> #include <tuple> #include <utility> #include <vector> #include "absl/strings/string_view.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 Item { … }; // Returns a human-readable representation of an ItemType. QUICHE_EXPORT absl::string_view ItemTypeToString(Item::ItemType type); // Returns `true` if the string is a valid Token value. QUICHE_EXPORT bool IsValidToken(absl::string_view str); // Holds a ParameterizedIdentifier (draft 9 only). The contained Item must be a // Token, and there may be any number of parameters. Parameter ordering is not // significant. struct QUICHE_EXPORT ParameterisedIdentifier { … }; inline bool operator==(const ParameterisedIdentifier& lhs, const ParameterisedIdentifier& rhs) { … } Parameters; struct QUICHE_EXPORT ParameterizedItem { … }; inline bool operator==(const ParameterizedItem& lhs, const ParameterizedItem& rhs) { … } inline bool operator!=(const ParameterizedItem& lhs, const ParameterizedItem& rhs) { … } // Holds a ParameterizedMember, which may be either an single Item, or an Inner // List of ParameterizedItems, along with any number of parameters. Parameter // ordering is significant. struct QUICHE_EXPORT ParameterizedMember { … }; inline bool operator==(const ParameterizedMember& lhs, const ParameterizedMember& rhs) { … } DictionaryMember; // Structured Headers RFC8941 Dictionary. class QUICHE_EXPORT Dictionary { … }; inline bool operator==(const Dictionary& lhs, const Dictionary& rhs) { … } inline bool operator!=(const Dictionary& lhs, const Dictionary& rhs) { … } // Structured Headers Draft 09 Parameterised List. ParameterisedList; // Structured Headers Draft 09 List of Lists. ListOfLists; // Structured Headers RFC8941 List. List; // Returns the result of parsing the header value as an Item, if it can be // parsed as one, or nullopt if it cannot. Note that this uses the Draft 15 // parsing rules, and so applies tighter range limits to integers. QUICHE_EXPORT std::optional<ParameterizedItem> ParseItem(absl::string_view str); // Returns the result of parsing the header value as an Item with no parameters, // or nullopt if it cannot. Note that this uses the Draft 15 parsing rules, and // so applies tighter range limits to integers. QUICHE_EXPORT std::optional<Item> ParseBareItem(absl::string_view str); // Returns the result of parsing the header value as a Parameterised List, if it // can be parsed as one, or nullopt if it cannot. Note that parameter keys will // be returned as strings, which are guaranteed to be ASCII-encoded. List items, // as well as parameter values, will be returned as Items. This method uses the // Draft 09 parsing rules for Items, so integers have the 64-bit int range. // Structured-Headers Draft 09 only. QUICHE_EXPORT std::optional<ParameterisedList> ParseParameterisedList( absl::string_view str); // Returns the result of parsing the header value as a List of Lists, if it can // be parsed as one, or nullopt if it cannot. Inner list items will be returned // as Items. This method uses the Draft 09 parsing rules for Items, so integers // have the 64-bit int range. // Structured-Headers Draft 09 only. QUICHE_EXPORT std::optional<ListOfLists> ParseListOfLists( absl::string_view str); // Returns the result of parsing the header value as a general List, if it can // be parsed as one, or nullopt if it cannot. // Structured-Headers Draft 15 only. QUICHE_EXPORT std::optional<List> ParseList(absl::string_view str); // Returns the result of parsing the header value as a general Dictionary, if it // can be parsed as one, or nullopt if it cannot. Structured-Headers Draft 15 // only. QUICHE_EXPORT std::optional<Dictionary> ParseDictionary(absl::string_view str); // Serialization is implemented for Structured-Headers Draft 15 only. QUICHE_EXPORT std::optional<std::string> SerializeItem(const Item& value); QUICHE_EXPORT std::optional<std::string> SerializeItem( const ParameterizedItem& value); QUICHE_EXPORT std::optional<std::string> SerializeList(const List& value); QUICHE_EXPORT std::optional<std::string> SerializeDictionary( const Dictionary& value); } // namespace structured_headers } // namespace quiche #endif // QUICHE_COMMON_STRUCTURED_HEADERS_H_