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