// Copyright 2014 The Crashpad Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "util/net/http_body.h" #include #include "gtest/gtest.h" #include "test/test_paths.h" #include "util/misc/implicit_cast.h" #include "util/net/http_body_test_util.h" namespace crashpad { namespace test { namespace { void ExpectBufferSet(const uint8_t* actual, uint8_t expected_byte, size_t num_expected_bytes) { for (size_t i = 0; i < num_expected_bytes; ++i) { EXPECT_EQ(actual[i], expected_byte) << i; } } TEST(StringHTTPBodyStream, EmptyString) { uint8_t buf[32]; memset(buf, '!', sizeof(buf)); std::string empty_string; StringHTTPBodyStream stream(empty_string); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); ExpectBufferSet(buf, '!', sizeof(buf)); } TEST(StringHTTPBodyStream, SmallString) { uint8_t buf[32]; memset(buf, '!', sizeof(buf)); std::string string("Hello, world"); StringHTTPBodyStream stream(string); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), implicit_cast(string.length())); std::string actual(reinterpret_cast(buf), string.length()); EXPECT_EQ(actual, string); ExpectBufferSet(buf + string.length(), '!', sizeof(buf) - string.length()); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); } TEST(StringHTTPBodyStream, MultipleReads) { uint8_t buf[2]; memset(buf, '!', sizeof(buf)); { std::string string("test"); SCOPED_TRACE("aligned buffer boundary"); StringHTTPBodyStream stream(string); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 2); EXPECT_EQ(buf[0], 't'); EXPECT_EQ(buf[1], 'e'); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 2); EXPECT_EQ(buf[0], 's'); EXPECT_EQ(buf[1], 't'); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); EXPECT_EQ(buf[0], 's'); EXPECT_EQ(buf[1], 't'); } { std::string string("abc"); SCOPED_TRACE("unaligned buffer boundary"); StringHTTPBodyStream stream(string); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 2); EXPECT_EQ(buf[0], 'a'); EXPECT_EQ(buf[1], 'b'); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 1); EXPECT_EQ(buf[0], 'c'); EXPECT_EQ(buf[1], 'b'); // Unmodified from last read. EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); EXPECT_EQ(buf[0], 'c'); EXPECT_EQ(buf[1], 'b'); } } TEST(FileReaderHTTPBodyStream, ReadASCIIFile) { base::FilePath path = TestPaths::TestDataRoot().Append( FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt")); FileReader reader; ASSERT_TRUE(reader.Open(path)); FileReaderHTTPBodyStream stream(&reader); std::string contents = ReadStreamToString(&stream, 32); EXPECT_EQ(contents, "This is a test.\n"); // Make sure that the file is not read again after it has been read to // completion. uint8_t buf[8]; memset(buf, '!', sizeof(buf)); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); ExpectBufferSet(buf, '!', sizeof(buf)); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); ExpectBufferSet(buf, '!', sizeof(buf)); } TEST(FileReaderHTTPBodyStream, ReadBinaryFile) { // HEX contents of file: |FEEDFACE A11A15|. base::FilePath path = TestPaths::TestDataRoot().Append( FILE_PATH_LITERAL("util/net/testdata/binary_http_body.dat")); // This buffer size was chosen so that reading the file takes multiple reads. uint8_t buf[4]; FileReader reader; ASSERT_TRUE(reader.Open(path)); FileReaderHTTPBodyStream stream(&reader); memset(buf, '!', sizeof(buf)); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 4); EXPECT_EQ(buf[0], 0xfe); EXPECT_EQ(buf[1], 0xed); EXPECT_EQ(buf[2], 0xfa); EXPECT_EQ(buf[3], 0xce); memset(buf, '!', sizeof(buf)); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 3); EXPECT_EQ(buf[0], 0xa1); EXPECT_EQ(buf[1], 0x1a); EXPECT_EQ(buf[2], 0x15); EXPECT_EQ(buf[3], '!'); memset(buf, '!', sizeof(buf)); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); ExpectBufferSet(buf, '!', sizeof(buf)); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); ExpectBufferSet(buf, '!', sizeof(buf)); } TEST(CompositeHTTPBodyStream, TwoEmptyStrings) { std::vector parts; parts.push_back(new StringHTTPBodyStream(std::string())); parts.push_back(new StringHTTPBodyStream(std::string())); CompositeHTTPBodyStream stream(parts); uint8_t buf[5]; memset(buf, '!', sizeof(buf)); EXPECT_EQ(stream.GetBytesBuffer(buf, sizeof(buf)), 0); ExpectBufferSet(buf, '!', sizeof(buf)); } class CompositeHTTPBodyStreamBufferSize : public testing::TestWithParam { }; TEST_P(CompositeHTTPBodyStreamBufferSize, ThreeStringParts) { std::string string1("crashpad"); std::string string2("test"); std::string string3("foobar"); const size_t all_strings_length = string1.length() + string2.length() + string3.length(); std::string buf(all_strings_length + 3, '!'); std::vector parts; parts.push_back(new StringHTTPBodyStream(string1)); parts.push_back(new StringHTTPBodyStream(string2)); parts.push_back(new StringHTTPBodyStream(string3)); CompositeHTTPBodyStream stream(parts); std::string actual_string = ReadStreamToString(&stream, GetParam()); EXPECT_EQ(actual_string, string1 + string2 + string3); ExpectBufferSet(reinterpret_cast(&buf[all_strings_length]), '!', 3); } TEST_P(CompositeHTTPBodyStreamBufferSize, StringsAndFile) { std::string string1("Hello! "); std::string string2(" Goodbye :)"); std::vector parts; parts.push_back(new StringHTTPBodyStream(string1)); base::FilePath path = TestPaths::TestDataRoot().Append( FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt")); FileReader reader; ASSERT_TRUE(reader.Open(path)); parts.push_back(new FileReaderHTTPBodyStream(&reader)); parts.push_back(new StringHTTPBodyStream(string2)); CompositeHTTPBodyStream stream(parts); std::string expected_string = string1 + "This is a test.\n" + string2; std::string actual_string = ReadStreamToString(&stream, GetParam()); EXPECT_EQ(actual_string, expected_string); } INSTANTIATE_TEST_SUITE_P(VariableBufferSize, CompositeHTTPBodyStreamBufferSize, testing::Values(1, 2, 9, 16, 31, 128, 1024)); } // namespace } // namespace test } // namespace crashpad