1 // Copyright 2023 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/web_transport/web_transport_headers.h"
6 
7 #include "absl/status/status.h"
8 #include "quiche/common/platform/api/quiche_test.h"
9 #include "quiche/common/test_tools/quiche_test_utils.h"
10 
11 namespace webtransport {
12 namespace {
13 
14 using ::quiche::test::IsOkAndHolds;
15 using ::quiche::test::StatusIs;
16 using ::testing::ElementsAre;
17 using ::testing::HasSubstr;
18 
TEST(WebTransportHeaders,ParseSubprotocolRequestHeader)19 TEST(WebTransportHeaders, ParseSubprotocolRequestHeader) {
20   EXPECT_THAT(ParseSubprotocolRequestHeader("test"),
21               IsOkAndHolds(ElementsAre("test")));
22   EXPECT_THAT(ParseSubprotocolRequestHeader("moqt-draft01, moqt-draft02"),
23               IsOkAndHolds(ElementsAre("moqt-draft01", "moqt-draft02")));
24   EXPECT_THAT(ParseSubprotocolRequestHeader("moqt-draft01; a=b, moqt-draft02"),
25               IsOkAndHolds(ElementsAre("moqt-draft01", "moqt-draft02")));
26   EXPECT_THAT(ParseSubprotocolRequestHeader("moqt-draft01, moqt-draft02; a=b"),
27               IsOkAndHolds(ElementsAre("moqt-draft01", "moqt-draft02")));
28   EXPECT_THAT(ParseSubprotocolRequestHeader("\"test\""),
29               StatusIs(absl::StatusCode::kInvalidArgument,
30                        HasSubstr("found string instead")));
31   EXPECT_THAT(ParseSubprotocolRequestHeader("42"),
32               StatusIs(absl::StatusCode::kInvalidArgument,
33                        HasSubstr("found integer instead")));
34   EXPECT_THAT(ParseSubprotocolRequestHeader("a, (b)"),
35               StatusIs(absl::StatusCode::kInvalidArgument,
36                        HasSubstr("found a nested list instead")));
37   EXPECT_THAT(ParseSubprotocolRequestHeader("a, (b c)"),
38               StatusIs(absl::StatusCode::kInvalidArgument,
39                        HasSubstr("found a nested list instead")));
40   EXPECT_THAT(ParseSubprotocolRequestHeader("foo, ?1, bar"),
41               StatusIs(absl::StatusCode::kInvalidArgument,
42                        HasSubstr("found boolean instead")));
43   EXPECT_THAT(ParseSubprotocolRequestHeader("(a"),
44               StatusIs(absl::StatusCode::kInvalidArgument,
45                        HasSubstr("parse the header as an sf-list")));
46 }
47 
TEST(WebTransportHeaders,SerializeSubprotocolRequestHeader)48 TEST(WebTransportHeaders, SerializeSubprotocolRequestHeader) {
49   EXPECT_THAT(SerializeSubprotocolRequestHeader({"test"}),
50               IsOkAndHolds("test"));
51   EXPECT_THAT(SerializeSubprotocolRequestHeader({"foo", "bar"}),
52               IsOkAndHolds("foo, bar"));
53   EXPECT_THAT(SerializeSubprotocolRequestHeader({"moqt-draft01", "a/b/c"}),
54               IsOkAndHolds("moqt-draft01, a/b/c"));
55   EXPECT_THAT(
56       SerializeSubprotocolRequestHeader({"abcd", "0123", "efgh"}),
57       StatusIs(absl::StatusCode::kInvalidArgument, "Invalid token: 0123"));
58 }
59 
TEST(WebTransportHeader,ParseSubprotocolResponseHeader)60 TEST(WebTransportHeader, ParseSubprotocolResponseHeader) {
61   EXPECT_THAT(ParseSubprotocolResponseHeader("foo"), IsOkAndHolds("foo"));
62   EXPECT_THAT(ParseSubprotocolResponseHeader("foo; a=b"), IsOkAndHolds("foo"));
63   EXPECT_THAT(
64       ParseSubprotocolResponseHeader("1234"),
65       StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("found integer")));
66   EXPECT_THAT(
67       ParseSubprotocolResponseHeader("(a"),
68       StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("parse sf-item")));
69 }
70 
TEST(WebTransportHeader,SerializeSubprotocolResponseHeader)71 TEST(WebTransportHeader, SerializeSubprotocolResponseHeader) {
72   EXPECT_THAT(SerializeSubprotocolResponseHeader("foo"), IsOkAndHolds("foo"));
73   EXPECT_THAT(SerializeSubprotocolResponseHeader("moqt-draft01"),
74               IsOkAndHolds("moqt-draft01"));
75   EXPECT_THAT(SerializeSubprotocolResponseHeader("123abc"),
76               StatusIs(absl::StatusCode::kInvalidArgument));
77 }
78 
TEST(WebTransportHeader,ParseInitHeader)79 TEST(WebTransportHeader, ParseInitHeader) {
80   WebTransportInitHeader expected_header;
81   expected_header.initial_unidi_limit = 100;
82   expected_header.initial_incoming_bidi_limit = 200;
83   expected_header.initial_outgoing_bidi_limit = 400;
84   EXPECT_THAT(ParseInitHeader("br=400, bl=200, u=100"),
85               IsOkAndHolds(expected_header));
86   EXPECT_THAT(ParseInitHeader("br=300, bl=200, u=100, br=400"),
87               IsOkAndHolds(expected_header));
88   EXPECT_THAT(ParseInitHeader("br=400, bl=200; foo=bar, u=100"),
89               IsOkAndHolds(expected_header));
90   EXPECT_THAT(ParseInitHeader("br=400, bl=200, u=100.0"),
91               StatusIs(absl::StatusCode::kInvalidArgument,
92                        HasSubstr("found decimal instead")));
93   EXPECT_THAT(ParseInitHeader("br=400, bl=200, u=?1"),
94               StatusIs(absl::StatusCode::kInvalidArgument,
95                        HasSubstr("found boolean instead")));
96   EXPECT_THAT(ParseInitHeader("br=400, bl=200, u=(a b)"),
97               StatusIs(absl::StatusCode::kInvalidArgument,
98                        HasSubstr("found a nested list instead")));
99   EXPECT_THAT(ParseInitHeader("br=400, bl=200, u=:abcd:"),
100               StatusIs(absl::StatusCode::kInvalidArgument,
101                        HasSubstr("found byte sequence instead")));
102   EXPECT_THAT(ParseInitHeader("br=400, bl=200, u=-1"),
103               StatusIs(absl::StatusCode::kInvalidArgument,
104                        HasSubstr("negative value")));
105   EXPECT_THAT(ParseInitHeader("br=400, bl=200, u=18446744073709551615"),
106               StatusIs(absl::StatusCode::kInvalidArgument,
107                        HasSubstr("Failed to parse")));
108 }
109 
TEST(WebTransportHeaders,SerializeInitHeader)110 TEST(WebTransportHeaders, SerializeInitHeader) {
111   EXPECT_THAT(SerializeInitHeader(WebTransportInitHeader{}),
112               IsOkAndHolds("u=0, bl=0, br=0"));
113 
114   WebTransportInitHeader test_header;
115   test_header.initial_unidi_limit = 100;
116   test_header.initial_incoming_bidi_limit = 200;
117   test_header.initial_outgoing_bidi_limit = 400;
118   EXPECT_THAT(SerializeInitHeader(test_header),
119               IsOkAndHolds("u=100, bl=200, br=400"));
120 }
121 
122 }  // namespace
123 }  // namespace webtransport
124