1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 #include "file_test_utilities.hpp" 4 #include "http/http_body.hpp" 5 #include "http/http_response.hpp" 6 #include "utility.hpp" 7 8 #include <boost/beast/core/buffers_to_string.hpp> 9 #include <boost/beast/core/file_base.hpp> 10 #include <boost/beast/core/file_posix.hpp> 11 #include <boost/beast/http/message.hpp> 12 #include <boost/beast/http/serializer.hpp> 13 #include <boost/beast/http/status.hpp> 14 15 #include <cstdio> 16 #include <filesystem> 17 #include <string> 18 19 #include "gtest/gtest.h" 20 namespace crow 21 { 22 namespace 23 { 24 void addHeaders(Response& res) 25 { 26 res.addHeader("myheader", "myvalue"); 27 res.keepAlive(true); 28 res.result(boost::beast::http::status::ok); 29 } 30 void verifyHeaders(Response& res) 31 { 32 EXPECT_EQ(res.getHeaderValue("myheader"), "myvalue"); 33 EXPECT_EQ(res.keepAlive(), true); 34 EXPECT_EQ(res.result(), boost::beast::http::status::ok); 35 } 36 37 std::string getData(boost::beast::http::response<bmcweb::HttpBody>& m) 38 { 39 std::string ret; 40 41 boost::beast::http::response_serializer<bmcweb::HttpBody> sr{m}; 42 sr.split(true); 43 // Reads buffers into ret 44 auto reader = 45 [&sr, &ret](const boost::system::error_code& ec2, const auto& buffer) { 46 EXPECT_FALSE(ec2); 47 std::string ret2 = boost::beast::buffers_to_string(buffer); 48 sr.consume(ret2.size()); 49 ret += ret2; 50 }; 51 boost::system::error_code ec; 52 53 // Read headers 54 while (!sr.is_header_done()) 55 { 56 sr.next(ec, reader); 57 EXPECT_FALSE(ec); 58 } 59 ret.clear(); 60 61 // Read body 62 while (!sr.is_done()) 63 { 64 sr.next(ec, reader); 65 EXPECT_FALSE(ec); 66 } 67 68 return ret; 69 } 70 71 TEST(HttpResponse, Headers) 72 { 73 Response res; 74 addHeaders(res); 75 verifyHeaders(res); 76 } 77 TEST(HttpResponse, StringBody) 78 { 79 Response res; 80 addHeaders(res); 81 std::string_view bodyValue = "this is my new body"; 82 res.write({bodyValue.data(), bodyValue.length()}); 83 EXPECT_EQ(*res.body(), bodyValue); 84 verifyHeaders(res); 85 } 86 TEST(HttpResponse, HttpBody) 87 { 88 Response res; 89 addHeaders(res); 90 TemporaryFileHandle temporaryFile("sample text"); 91 res.openFile(temporaryFile.stringPath); 92 93 verifyHeaders(res); 94 } 95 TEST(HttpResponse, HttpBodyWithFd) 96 { 97 Response res; 98 addHeaders(res); 99 TemporaryFileHandle temporaryFile("sample text"); 100 FILE* fd = fopen(temporaryFile.stringPath.c_str(), "r+"); 101 res.openFd(fileno(fd)); 102 verifyHeaders(res); 103 fclose(fd); 104 } 105 106 TEST(HttpResponse, Base64HttpBodyWithFd) 107 { 108 Response res; 109 addHeaders(res); 110 TemporaryFileHandle temporaryFile("sample text"); 111 FILE* fd = fopen(temporaryFile.stringPath.c_str(), "r"); 112 ASSERT_NE(fd, nullptr); 113 res.openFd(fileno(fd), bmcweb::EncodingType::Base64); 114 verifyHeaders(res); 115 fclose(fd); 116 } 117 118 TEST(HttpResponse, BodyTransitions) 119 { 120 Response res; 121 addHeaders(res); 122 TemporaryFileHandle temporaryFile("sample text"); 123 res.openFile(temporaryFile.stringPath); 124 125 verifyHeaders(res); 126 res.write("body text"); 127 128 verifyHeaders(res); 129 } 130 131 std::string generateBigdata() 132 { 133 std::string result; 134 while (result.size() < 10000) 135 { 136 result += "sample text"; 137 } 138 return result; 139 } 140 141 TEST(HttpResponse, StringBodyWriterLarge) 142 { 143 Response res; 144 std::string data = generateBigdata(); 145 res.write(std::string(data)); 146 EXPECT_EQ(getData(res.response), data); 147 } 148 149 TEST(HttpResponse, Base64HttpBodyWriter) 150 { 151 Response res; 152 std::string data = "sample text"; 153 TemporaryFileHandle temporaryFile(data); 154 FILE* f = fopen(temporaryFile.stringPath.c_str(), "r+"); 155 res.openFd(fileno(f), bmcweb::EncodingType::Base64); 156 EXPECT_EQ(getData(res.response), "c2FtcGxlIHRleHQ="); 157 } 158 159 TEST(HttpResponse, Base64HttpBodyWriterLarge) 160 { 161 Response res; 162 std::string data = generateBigdata(); 163 TemporaryFileHandle temporaryFile(data); 164 165 boost::beast::file_posix file; 166 boost::system::error_code ec; 167 file.open(temporaryFile.stringPath.c_str(), boost::beast::file_mode::read, 168 ec); 169 EXPECT_EQ(ec.value(), 0); 170 res.openFd(file.native_handle(), bmcweb::EncodingType::Base64); 171 EXPECT_EQ(getData(res.response), utility::base64encode(data)); 172 } 173 174 TEST(HttpResponse, HttpBodyWriterLarge) 175 { 176 Response res; 177 std::string data = generateBigdata(); 178 TemporaryFileHandle temporaryFile(data); 179 180 boost::beast::file_posix file; 181 boost::system::error_code ec; 182 file.open(temporaryFile.stringPath.c_str(), boost::beast::file_mode::read, 183 ec); 184 EXPECT_EQ(ec.value(), 0); 185 res.openFd(file.native_handle()); 186 EXPECT_EQ(getData(res.response), data); 187 } 188 } // namespace 189 } // namespace crow 190