proxygen
StructuredHeadersStandardTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
13 #include <boost/algorithm/string/trim.hpp>
14 
15 using namespace ::testing;
16 
17 namespace proxygen {
18 
19 /*
20  * These test cases were obtained from
21  * https://github.com/httpwg/structured-header-tests/commits/master, with a
22  * commit hash of 1881ee28edf4cd81a423ef7f2ca9252a48acb709
23  */
24 
25 static const std::vector<std::pair<std::string, std::string>>
27  {
28  {"\"foo\"", "foo"},
29  {"\"foo \\\"bar\\\"\"", "foo \"bar\""}
30  };
31 
32 static const std::vector<std::pair<std::string, std::string>>
34  {
35  {"*aGVsbG8=*", "NBSWY3DP"},
36  {"**", ""}
37  };
38 
39 static const std::vector<std::pair<std::string, int64_t>> kLegalIntTests =
40  {
41  {"42", 42},
42  {"0", 0},
43  {"00", 0},
44  {"-0", 0},
45  {"-42", -42},
46  {"042", 42},
47  {"-042", -42},
48  {"9223372036854775807", std::numeric_limits<int64_t>::max()},
49  {"-9223372036854775808", std::numeric_limits<int64_t>::min()}
50  };
51 
52 static const std::vector<std::pair<std::string, double>> kLegalFloatTests =
53  {
54  {"1.23", 1.23},
55  {"-1.23", -1.23}
56  };
57 
58 static const std::vector<std::string> kIllegalItemTests =
59  {
60  "'foo'",
61  "\"foo",
62  "\"foo \\,\"",
63  "\"foo \\",
64  "*aGVsbG8*",
65  "*aGVsbG8=",
66  "*aGVsb G8=*",
67  "*aGVsbG!8=*",
68  "*aGVsbG!8=!*",
69  "*iZ==*",
70  "a23",
71  "2,3",
72  "-a23",
73  "4-2",
74  "9223372036854775808",
75  "-9223372036854775809",
76  "1.5.4",
77  "1..4"
78  };
79 
80 static const std::vector<std::string> kIllegalListTests =
81  {
82  "1, 42,",
83  "1,,42"
84  };
85 
87 public:
88 
90 
91  uint32_t numBlocks = input.length() / 8;
92  uint32_t blockRemainder = input.length() % 8;
93 
94  std::string outputBuffer(5, '\0');
95 
96  // decode each whole block of the input
97  for (uint32_t j = 0; j < numBlocks; j++) {
98  if (!decode32Block(input, j, outputBuffer)) {
99  return false;
100  }
101  output += outputBuffer;
102  }
103 
104  std::string padding(8, '\0');
105  // set the initial bytes of the padding to be the trailing bytes of the
106  // input string that have been left over
107  for (uint32_t i = 0; i < blockRemainder; i++) {
108  padding[i] = input[input.size() - blockRemainder + i];
109  }
110 
111  if (!decode32Block(padding, 0, outputBuffer)) {
112  return false;
113  }
114 
115  // The second argument to the function is the size of the decoded content,
116  // where the encoded content is of size (blockRemainder * 5) / 8
117  outputBuffer = outputBuffer.substr(0, (blockRemainder * 5) / 8);
118  output += outputBuffer;
119 
120  return true;
121  }
122 
123 private:
124 
125  /*
126  * Applies the following transformation to the input to produce output:
127  * for each character in the input, convert it to the byte value of that
128  * character as per the base32 alphabet outlined in rfc4648
129  */
131  std::string base32CharSet("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567");
133 
134  for (char c : input) {
135  auto it = base32CharSet.find(c);
136  if (it == std::string::npos) {
137  return "";
138  } else {
139  // foundCharacter is the position within the base32CharSet where c
140  // was found
141  char foundCharacter = char(it);
142  output.push_back(foundCharacter);
143  }
144  }
145 
146  return output;
147  }
148 
149  /*
150  * Given an input string with length at least 8, and a block number
151  * specifying which specific block of the string we are decoding,
152  * it sets the outputBuffer to contain the decoded content (which is 5
153  * bytes in length). The function assumes that outputBuffer is a string of
154  * length 5.
155  */
157  uint32_t blockNum,
158  std::string& outputBuffer) {
159 
160  // Remove any padding and make each character of the input represent the
161  // byte value of that character, as per the rfc4648 encoding
162  boost::trim_right_if(input, [](char c){return c == '=';});
163  input = convertBase32ToBinary(input);
164 
165  // 8 byte buffer
166  int64_t buffer = 0;
167 
168  for(int i = 0; i < 8; i++) {
169 
170  if(input[i + blockNum * 8] >= 32) {
171  // a base32 value cannot be greater than or equal to 32
172  return false;
173  }
174 
175  buffer = (buffer << 5);
176  buffer = buffer | input[i + blockNum * 8];
177  }
178 
179  // set the contents of outputBuffer to contain the contents of buffer
180  for (int i = 0; i < 5; i++) {
181  outputBuffer[i] = char(buffer & 0xFF);
182  buffer = buffer >> 8;
183  }
184  // we perform a reversal because outputBuffer has the contents of buffer
185  // but in reverse order
186  std::reverse(outputBuffer.begin(), outputBuffer.end());
187 
188  return true;
189  }
190 };
191 
193  public ::testing::WithParamInterface<
194  std::pair<std::string, std::string>> {
195 };
196 
198  public ::testing::WithParamInterface<
199  std::pair<std::string, std::string>> {
200 };
201 
203  public ::testing::WithParamInterface<
204  std::pair<std::string, int64_t>> {
205 };
206 
208  public ::testing::WithParamInterface<
209  std::pair<std::string, double>> {
210 };
211 
213  public ::testing::WithParamInterface<std::string> {
214 };
215 
217  public ::testing::WithParamInterface<std::string> {
218 };
219 
220 TEST_P(LegalStringTests, LegalStrings) {
221  std::string input(GetParam().first);
222  StructuredHeadersDecoder shd(input);
224  auto err = shd.decodeItem(output);
227  EXPECT_EQ(output, GetParam().second);
228 }
229 
230 TEST_P(LegalBinaryContentTests, LegalBinaryContent) {
231  std::string input(GetParam().first);
232  std::string expectedOutputInBase32(GetParam().second);
233  std::string expectedOutput;
234  decode32(expectedOutputInBase32, expectedOutput);
235 
236  StructuredHeadersDecoder shd(input);
238  auto err = shd.decodeItem(output);
240  EXPECT_EQ(output.tag, StructuredHeaderItem::Type::BINARYCONTENT);
241  EXPECT_EQ(output, expectedOutput);
242 }
243 
244 TEST_P(LegalIntegerTests, LegalIntegers) {
245  std::string input(GetParam().first);
246  StructuredHeadersDecoder shd(input);
248  auto err = shd.decodeItem(output);
250  EXPECT_EQ(output.tag, StructuredHeaderItem::Type::INT64);
251  EXPECT_EQ(output, GetParam().second);
252 }
253 
254 TEST_P(LegalFloatTests, LegalFloats) {
255  std::string input(GetParam().first);
256  StructuredHeadersDecoder shd(input);
258  auto err = shd.decodeItem(output);
260  EXPECT_EQ(output.tag, StructuredHeaderItem::Type::DOUBLE);
261  EXPECT_EQ(output, GetParam().second);
262 }
263 
264 TEST_P(IllegalItemTest, IllegalItem) {
265  StructuredHeadersDecoder shd(GetParam());
267  auto err = shd.decodeItem(output);
269 }
270 
271 TEST_P(IllegalListTest, IllegalList) {
272  StructuredHeadersDecoder shd(GetParam());
273  std::vector<StructuredHeaderItem> output;
274  auto err = shd.decodeList(output);
276 }
277 
278 INSTANTIATE_TEST_CASE_P(TestLegalStrings, LegalStringTests,
279  ::testing::ValuesIn(kLegalStringTests));
280 
281 INSTANTIATE_TEST_CASE_P(TestLegalBinaryContent, LegalBinaryContentTests,
282  ::testing::ValuesIn(kLegalBinContentTests));
283 
285  ::testing::ValuesIn(kLegalIntTests));
286 
288  ::testing::ValuesIn(kLegalFloatTests));
289 
290 INSTANTIATE_TEST_CASE_P(TestIllegalItems, IllegalItemTest,
291  ::testing::ValuesIn(kIllegalItemTests));
292 
293 INSTANTIATE_TEST_CASE_P(TestIllegalLists, IllegalListTest,
294  ::testing::ValuesIn(kIllegalListTests));
295 
297  std::string input("1, 42");
298  StructuredHeadersDecoder shd(input);
299 
300  std::vector<StructuredHeaderItem> v;
301  auto err = shd.decodeList(v);
302  EXPECT_EQ(err, DecodeError::OK);
303 
304  EXPECT_EQ(v.size(), 2);
305 
306  EXPECT_EQ(v[0].tag, StructuredHeaderItem::Type::INT64);
307  EXPECT_EQ(v[1].tag, StructuredHeaderItem::Type::INT64);
308 
309  EXPECT_EQ(v[0], int64_t(1));
310  EXPECT_EQ(v[1], int64_t(42));
311 }
312 
313 TEST_F(StructuredHeadersStandardTest, TestSingleItemList) {
314  std::string input("42");
315  StructuredHeadersDecoder shd(input);
316 
317  std::vector<StructuredHeaderItem> v;
318  auto err = shd.decodeList(v);
319  EXPECT_EQ(err, DecodeError::OK);
320 
321  EXPECT_EQ(v.size(), 1);
322 
323  EXPECT_EQ(v[0].tag, StructuredHeaderItem::Type::INT64);
324 
325  EXPECT_EQ(v[0], int64_t(42));
326 }
327 
328 TEST_F(StructuredHeadersStandardTest, TestNoWhitespaceList) {
329  std::string input("1,42");
330  StructuredHeadersDecoder shd(input);
331 
332  std::vector<StructuredHeaderItem> v;
333  auto err = shd.decodeList(v);
334  EXPECT_EQ(err, DecodeError::OK);
335 
336  EXPECT_EQ(v.size(), 2);
337 
338  EXPECT_EQ(v[0].tag, StructuredHeaderItem::Type::INT64);
339  EXPECT_EQ(v[1].tag, StructuredHeaderItem::Type::INT64);
340 
341  EXPECT_EQ(v[0], int64_t(1));
342  EXPECT_EQ(v[1], int64_t(42));
343 }
344 
345 TEST_F(StructuredHeadersStandardTest, TestExtraWhitespaceList) {
346  std::string input("1 , 42");
347  StructuredHeadersDecoder shd(input);
348 
349  std::vector<StructuredHeaderItem> v;
350  auto err = shd.decodeList(v);
351  EXPECT_EQ(err, DecodeError::OK);
352 
353  EXPECT_EQ(v.size(), 2);
354 
355  EXPECT_EQ(v[0].tag, StructuredHeaderItem::Type::INT64);
356  EXPECT_EQ(v[1].tag, StructuredHeaderItem::Type::INT64);
357 
358  EXPECT_EQ(v[0], int64_t(1));
359  EXPECT_EQ(v[1], int64_t(42));
360 }
361 
362 }
std::vector< uint8_t > buffer(kBufferSize+16)
static const std::vector< std::string > kIllegalItemTests
auto v
bool decode32Block(std::string input, uint32_t blockNum, std::string &outputBuffer)
LogLevel max
Definition: LogLevel.cpp:31
static const std::vector< std::pair< std::string, std::string > > kLegalStringTests
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static const std::vector< std::pair< std::string, std::string > > kLegalBinContentTests
#define STRING
static const std::vector< std::pair< std::string, int64_t > > kLegalIntTests
TEST_P(RFC1867CR, Test)
LogLevel min
Definition: LogLevel.cpp:30
std::string convertBase32ToBinary(const std::string &input)
static const std::vector< std::string > kIllegalListTests
bool decode32(std::string input, std::string &output)
StructuredHeaders::DecodeError decodeList(std::vector< StructuredHeaderItem > &result)
const char * string
Definition: Conv.cpp:212
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
StructuredHeaders::DecodeError decodeItem(StructuredHeaderItem &result)
TEST_F(HeaderTableTests, IndexTranslation)
char c
INSTANTIATE_TEST_CASE_P(ValueTest, RFC1867CR,::testing::Values(string("zyx\r\nwvu", 8), string("\rzyxwvut", 8), string("zyxwvut\r", 8), string("\nzyxwvut", 8), string("zyxwvut\n", 8), string("\r\n\r\n\r\n\r\n", 8), string("\r\r\r\r\r\r\r\r", 8)))
constexpr detail::First first
Definition: Base-inl.h:2553
static const std::vector< std::pair< std::string, double > > kLegalFloatTests