147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko// Copyright 2014 The Chromium OS Authors. All rights reserved.
247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be
347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko// found in the LICENSE file.
447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_form_data.h>
647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko#include <set>
847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko#include <base/files/file_util.h>
1047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko#include <base/files/scoped_temp_dir.h>
119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/mime_utils.h>
129ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/streams/file_stream.h>
139ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/streams/input_stream_set.h>
1447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko#include <gtest/gtest.h>
1547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
169ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo {
1747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenkonamespace http {
1880663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenkonamespace {
1980663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenkostd::string GetFormFieldData(FormField* field) {
2080663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  std::vector<StreamPtr> streams;
2180663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  CHECK(field->ExtractDataStreams(&streams));
2280663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  StreamPtr stream = InputStreamSet::Create(std::move(streams), nullptr);
2380663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko
2480663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  std::vector<uint8_t> data(stream->GetSize());
2580663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  EXPECT_TRUE(stream->ReadAllBlocking(data.data(), data.size(), nullptr));
2680663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  return std::string{data.begin(), data.end()};
2780663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko}
2880663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko}  // anonymous namespace
2947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
3047e9a9dd3dce9d197820ee4241135e6859f95360Alex VakulenkoTEST(HttpFormData, TextFormField) {
3147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  TextFormField form_field{"field1", "abcdefg", mime::text::kPlain, "7bit"};
3247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  const char expected_header[] =
3347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"field1\"\r\n"
3447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Type: text/plain\r\n"
3547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Transfer-Encoding: 7bit\r\n"
3647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n";
3747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  EXPECT_EQ(expected_header, form_field.GetContentHeader());
3880663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  EXPECT_EQ("abcdefg", GetFormFieldData(&form_field));
3947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko}
4047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
4147e9a9dd3dce9d197820ee4241135e6859f95360Alex VakulenkoTEST(HttpFormData, FileFormField) {
4247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  base::ScopedTempDir dir;
4347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  ASSERT_TRUE(dir.CreateUniqueTempDir());
4447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::string file_content{"text line1\ntext line2\n"};
45324b9515118eca1ac9b579af6dd4d9ffc33a023cJay Civelli  base::FilePath file_name = dir.GetPath().Append("sample.txt");
4647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  ASSERT_EQ(file_content.size(),
4705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko            static_cast<size_t>(base::WriteFile(
4805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                file_name, file_content.data(), file_content.size())));
4947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
5080663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  StreamPtr stream = FileStream::Open(file_name, Stream::AccessMode::READ,
5180663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko                                      FileStream::Disposition::OPEN_EXISTING,
5280663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko                                      nullptr);
5380663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  ASSERT_NE(nullptr, stream);
5405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  FileFormField form_field{"test_file",
5580663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko                           std::move(stream),
5605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                           "sample.txt",
5747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko                           content_disposition::kFormData,
5805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                           mime::text::kPlain,
5905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                           ""};
6047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  const char expected_header[] =
6147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"test_file\";"
6247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      " filename=\"sample.txt\"\r\n"
6347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Type: text/plain\r\n"
6447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n";
6547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  EXPECT_EQ(expected_header, form_field.GetContentHeader());
6680663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  EXPECT_EQ(file_content, GetFormFieldData(&form_field));
6747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko}
6847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
6947e9a9dd3dce9d197820ee4241135e6859f95360Alex VakulenkoTEST(HttpFormData, MultiPartFormField) {
7047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  base::ScopedTempDir dir;
7147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  ASSERT_TRUE(dir.CreateUniqueTempDir());
7247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::string file1{"text line1\ntext line2\n"};
73324b9515118eca1ac9b579af6dd4d9ffc33a023cJay Civelli  base::FilePath filename1 = dir.GetPath().Append("sample.txt");
7447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  ASSERT_EQ(file1.size(),
7505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko            static_cast<size_t>(
7605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                base::WriteFile(filename1, file1.data(), file1.size())));
7747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::string file2{"\x01\x02\x03\x04\x05"};
78324b9515118eca1ac9b579af6dd4d9ffc33a023cJay Civelli  base::FilePath filename2 = dir.GetPath().Append("test.bin");
7947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  ASSERT_EQ(file2.size(),
8005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko            static_cast<size_t>(
8105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                base::WriteFile(filename2, file2.data(), file2.size())));
8247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
8347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  MultiPartFormField form_field{"foo", mime::multipart::kFormData, "Delimiter"};
8447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  form_field.AddTextField("name", "John Doe");
8505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  EXPECT_TRUE(form_field.AddFileField("file1",
8605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                      filename1,
8747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko                                      content_disposition::kFormData,
8805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                      mime::text::kPlain,
8905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                      nullptr));
9005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  EXPECT_TRUE(form_field.AddFileField("file2",
9105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                      filename2,
9247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko                                      content_disposition::kFormData,
9347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko                                      mime::application::kOctet_stream,
9447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko                                      nullptr));
9547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  const char expected_header[] =
9647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"foo\"\r\n"
9747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Type: multipart/form-data; boundary=\"Delimiter\"\r\n"
9847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n";
9947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  EXPECT_EQ(expected_header, form_field.GetContentHeader());
10047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  const char expected_data[] =
10147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--Delimiter\r\n"
10247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"name\"\r\n"
10347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
10447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "John Doe\r\n"
10547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--Delimiter\r\n"
10647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"file1\";"
10747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      " filename=\"sample.txt\"\r\n"
10847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Type: text/plain\r\n"
10947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Transfer-Encoding: binary\r\n"
11047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
11147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "text line1\ntext line2\n\r\n"
11247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--Delimiter\r\n"
11347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"file2\";"
11447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      " filename=\"test.bin\"\r\n"
11547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Type: application/octet-stream\r\n"
11647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Transfer-Encoding: binary\r\n"
11747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
11847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\x01\x02\x03\x04\x05\r\n"
11947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--Delimiter--";
12080663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  EXPECT_EQ(expected_data, GetFormFieldData(&form_field));
12147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko}
12247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
12347e9a9dd3dce9d197820ee4241135e6859f95360Alex VakulenkoTEST(HttpFormData, MultiPartBoundary) {
12447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  const int count = 10;
12547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::set<std::string> boundaries;
12647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  for (int i = 0; i < count; i++) {
12747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko    MultiPartFormField field{""};
12847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko    std::string boundary = field.GetBoundary();
12947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko    boundaries.insert(boundary);
13047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko    // Our generated boundary must be 16 character long and contain lowercase
13147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko    // hexadecimal digits only.
13247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko    EXPECT_EQ(16u, boundary.size());
13347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko    EXPECT_EQ(std::string::npos,
13447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko              boundary.find_first_not_of("0123456789abcdef"));
13547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  }
13647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  // Now make sure the boundary strings were generated at random, so we should
13747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  // get |count| unique boundary strings. However since the strings are random,
13847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  // there is a very slim change of generating the same string twice, so
13947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  // expect at least 90% of unique strings. 90% is picked arbitrarily here.
14047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  int expected_min_unique = count * 9 / 10;
14147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  EXPECT_GE(boundaries.size(), expected_min_unique);
14247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko}
14347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
14447e9a9dd3dce9d197820ee4241135e6859f95360Alex VakulenkoTEST(HttpFormData, FormData) {
14547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  base::ScopedTempDir dir;
14647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  ASSERT_TRUE(dir.CreateUniqueTempDir());
14747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::string file1{"text line1\ntext line2\n"};
148324b9515118eca1ac9b579af6dd4d9ffc33a023cJay Civelli  base::FilePath filename1 = dir.GetPath().Append("sample.txt");
14947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  ASSERT_EQ(file1.size(),
15005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko            static_cast<size_t>(
15105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                base::WriteFile(filename1, file1.data(), file1.size())));
15247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::string file2{"\x01\x02\x03\x04\x05"};
153324b9515118eca1ac9b579af6dd4d9ffc33a023cJay Civelli  base::FilePath filename2 = dir.GetPath().Append("test.bin");
15447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  ASSERT_EQ(file2.size(),
15505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko            static_cast<size_t>(
15605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                base::WriteFile(filename2, file2.data(), file2.size())));
15747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
15847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  FormData form_data{"boundary1"};
15947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  form_data.AddTextField("name", "John Doe");
16047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::unique_ptr<MultiPartFormField> files{
16147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      new MultiPartFormField{"files", "", "boundary2"}};
16205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  EXPECT_TRUE(files->AddFileField(
16305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      "", filename1, content_disposition::kFile, mime::text::kPlain, nullptr));
16405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  EXPECT_TRUE(files->AddFileField("",
16505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                  filename2,
16647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko                                  content_disposition::kFile,
16747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko                                  mime::application::kOctet_stream,
16847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko                                  nullptr));
16947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  form_data.AddCustomField(std::move(files));
17047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  EXPECT_EQ("multipart/form-data; boundary=\"boundary1\"",
17147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko            form_data.GetContentType());
17280663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko
17380663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  StreamPtr stream = form_data.ExtractDataStream();
17480663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  std::vector<uint8_t> data(stream->GetSize());
17580663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  EXPECT_TRUE(stream->ReadAllBlocking(data.data(), data.size(), nullptr));
17647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  const char expected_data[] =
17747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary1\r\n"
17847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"name\"\r\n"
17947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
18047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "John Doe\r\n"
18147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary1\r\n"
18247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"files\"\r\n"
18347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Type: multipart/mixed; boundary=\"boundary2\"\r\n"
18447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
18547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary2\r\n"
18647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: file; filename=\"sample.txt\"\r\n"
18747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Type: text/plain\r\n"
18847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Transfer-Encoding: binary\r\n"
18947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
19047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "text line1\ntext line2\n\r\n"
19147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary2\r\n"
19247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: file; filename=\"test.bin\"\r\n"
19347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Type: application/octet-stream\r\n"
19447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Transfer-Encoding: binary\r\n"
19547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
19647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\x01\x02\x03\x04\x05\r\n"
19747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary2--\r\n"
19847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary1--";
19980663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  EXPECT_EQ(expected_data, (std::string{data.begin(), data.end()}));
20047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko}
20147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko}  // namespace http
2029ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko}  // namespace brillo
203