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