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