Commit 7614655e authored by Ian Clelland's avatar Ian Clelland Committed by Commit Bot

Structured Headers: Dictionary members default to True

This implements the change in
https://github.com/httpwg/http-extensions/issues/1083, where dictionary
members are specified to default to boolean True if their value is
omitted from headers, and are required to be omitted from serialization
if their value is True, even if they have associated parameters.

This allows dictionary headers of the form

    Header: key;param=value

where 'key' will be assigned the value 'true' by default.

Bug: 1069784
Change-Id: I1d08ef812bf7316fd69b36094e4ea932ac367be2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2091712Reviewed-by: default avatarAsanka Herath <asanka@chromium.org>
Commit-Queue: Ian Clelland <iclelland@chromium.org>
Cr-Commit-Position: refs/heads/master@{#763330}
parent 3badd35d
...@@ -178,7 +178,11 @@ class StructuredHeaderParser { ...@@ -178,7 +178,11 @@ class StructuredHeaderParser {
if (!member) if (!member)
return base::nullopt; return base::nullopt;
} else { } else {
member = ParameterizedMember{Item(true), {}}; base::Optional<Parameters> parameters;
parameters = ReadParameters();
if (!parameters)
return base::nullopt;
member = ParameterizedMember{Item(true), std::move(*parameters)};
} }
members[*key] = std::move(*member); members[*key] = std::move(*member);
SkipWhitespaces(); SkipWhitespaces();
...@@ -666,13 +670,16 @@ class StructuredHeaderSerializer { ...@@ -666,13 +670,16 @@ class StructuredHeaderSerializer {
if (!WriteKey(dict.first)) if (!WriteKey(dict.first))
return false; return false;
first = false; first = false;
if (dict_member.params.empty() && !dict_member.member_is_inner_list && if (!dict_member.member_is_inner_list &&
dict_member.member.front().item.is_boolean() && dict_member.member.front().item.is_boolean() &&
dict_member.member.front().item.GetBoolean()) dict_member.member.front().item.GetBoolean()) {
continue; if (!WriteParameters(dict_member.params))
output_ << "="; return false;
if (!WriteParameterizedMember(dict_member)) } else {
return false; output_ << "=";
if (!WriteParameterizedMember(dict_member))
return false;
}
} }
return true; return true;
} }
......
...@@ -73,12 +73,6 @@ std::pair<std::string, Item> TokenParam(std::string key, std::string value) { ...@@ -73,12 +73,6 @@ std::pair<std::string, Item> TokenParam(std::string key, std::string value) {
// TODO(https://crbug.com/1069785): Parameters and keys can start with "*". // TODO(https://crbug.com/1069785): Parameters and keys can start with "*".
// * "0x2a starting a parameterised list key", // * "0x2a starting a parameterised list key",
// * "0x2a starting an dictionary key", // * "0x2a starting an dictionary key",
// TODO(https://crbug.com/1069784): Dictionary entries with missing values
// should be True.
// * "0x3b in dictionary key",
// * "Example-DictHeader",
// * "explicit true value with params dictionary",
// * "missing value with params dictionary",
const struct ParameterizedItemTestCase { const struct ParameterizedItemTestCase {
const char* name; const char* name;
...@@ -2902,6 +2896,17 @@ const struct DictionaryTestCase { ...@@ -2902,6 +2896,17 @@ const struct DictionaryTestCase {
{"end missing value dictionary", {"end missing value dictionary",
"a=1, b", "a=1, b",
{Dictionary{{{"a", {Integer(1), {}}}, {"b", {Item(true), {}}}}}}}, {Dictionary{{{"a", {Integer(1), {}}}, {"b", {Item(true), {}}}}}}},
{"missing value with params dictionary",
"a=1, b;foo=9, c=3",
{Dictionary{{{"a", {Integer(1), {}}},
{"b", {Item(true), {Param("foo", 9)}}},
{"c", {Integer(3), {}}}}}}},
{"explicit true value with params dictionary",
"a=1, b=?1;foo=9, c=3",
{Dictionary{{{"a", {Integer(1), {}}},
{"b", {Item(true), {Param("foo", 9)}}},
{"c", {Integer(3), {}}}}}},
"a=1, b;foo=9, c=3"},
{"trailing comma dictionary", "a=1, b=2,", base::nullopt}, {"trailing comma dictionary", "a=1, b=2,", base::nullopt},
{"empty item dictionary", "a=1,,b=2,", base::nullopt}, {"empty item dictionary", "a=1,,b=2,", base::nullopt},
{"duplicate key dictionary", {"duplicate key dictionary",
...@@ -2911,6 +2916,18 @@ const struct DictionaryTestCase { ...@@ -2911,6 +2916,18 @@ const struct DictionaryTestCase {
{"numeric key dictionary", "a=1,1b=2,a=1", base::nullopt}, {"numeric key dictionary", "a=1,1b=2,a=1", base::nullopt},
{"uppercase key dictionary", "a=1,B=2,a=1", base::nullopt}, {"uppercase key dictionary", "a=1,B=2,a=1", base::nullopt},
{"bad key dictionary", "a=1,b!=2,a=1", base::nullopt}, {"bad key dictionary", "a=1,b!=2,a=1", base::nullopt},
{"Example-DictHeader",
"en=\"Applepie\", da=:w4ZibGV0w6ZydGU=:",
{Dictionary{
{{"en", {Item("Applepie"), {}}},
{"da",
{Item("\303\206blet\303\246rte", Item::kByteSequenceType), {}}}}}}},
{"Example-DictHeader",
"a=?0, b, c; foo=bar",
{Dictionary{{{"a", {Item(false), {}}},
{"b", {Item(true), {}}},
{"c", {Item(true), {TokenParam("foo", "bar")}}}}}},
"a=?0, b, c;foo=bar"},
{"Example-DictListHeader", {"Example-DictListHeader",
"rating=1.5, feelings=(joy sadness)", "rating=1.5, feelings=(joy sadness)",
{Dictionary{{{"rating", {Item(1.500000), {}}}, {Dictionary{{{"rating", {Item(1.500000), {}}},
...@@ -3021,6 +3038,9 @@ const struct DictionaryTestCase { ...@@ -3021,6 +3038,9 @@ const struct DictionaryTestCase {
"a9a=1", "a9a=1",
{Dictionary{{{"a9a", {Integer(1), {}}}}}}}, {Dictionary{{{"a9a", {Integer(1), {}}}}}}},
{"0x3a in dictionary key", "a:a=1", base::nullopt}, {"0x3a in dictionary key", "a:a=1", base::nullopt},
{"0x3b in dictionary key",
"a;a=1",
{Dictionary{{{"a", {Item(true), {Param("a", 1)}}}}}}},
{"0x3c in dictionary key", "a<a=1", base::nullopt}, {"0x3c in dictionary key", "a<a=1", base::nullopt},
{"0x3d in dictionary key", "a=a=1", base::nullopt}, {"0x3d in dictionary key", "a=a=1", base::nullopt},
{"0x3e in dictionary key", "a>a=1", base::nullopt}, {"0x3e in dictionary key", "a>a=1", base::nullopt},
......
...@@ -238,7 +238,7 @@ const struct DictionaryTestCase { ...@@ -238,7 +238,7 @@ const struct DictionaryTestCase {
{"da", {Item("hello", Item::kByteSequenceType), {}}}}}}}, {"da", {Item("hello", Item::kByteSequenceType), {}}}}}}},
{"tab separated dictionary", "a=1\t,\tb=2", base::nullopt}, {"tab separated dictionary", "a=1\t,\tb=2", base::nullopt},
{"missing value with params dictionary", {"missing value with params dictionary",
"a=1, b=?1;foo=9, c=3", "a=1, b;foo=9, c=3",
{Dictionary{{{"a", {Integer(1L), {}}}, {Dictionary{{{"a", {Integer(1L), {}}},
{"b", {Item(true), {Param("foo", 9)}}}, {"b", {Item(true), {Param("foo", 9)}}},
{"c", {Integer(3L), {}}}}}}}, {"c", {Integer(3L), {}}}}}}},
...@@ -249,6 +249,16 @@ const struct DictionaryTestCase { ...@@ -249,6 +249,16 @@ const struct DictionaryTestCase {
{{{Item("1"), {Param("b", 1), BooleanParam("c", false)}}, {{{Item("1"), {Param("b", 1), BooleanParam("c", false)}},
{Item("2"), {}}}, {Item("2"), {}}},
{Param("d", "e")}}}}}}}, {Param("d", "e")}}}}}}},
{"explicit true value with parameter",
"a=?1;b=1",
{Dictionary{{{"a", {Item(true), {Param("b", 1)}}}}}},
"a;b=1"},
{"implicit true value with parameter",
"a;b=1",
{Dictionary{{{"a", {Item(true), {Param("b", 1)}}}}}}},
{"implicit true value with implicitly-valued parameter",
"a;b",
{Dictionary{{{"a", {Item(true), {BooleanParam("b", true)}}}}}}},
}; };
} // namespace } // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment