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 {
addHeaders(Response & res)24 void addHeaders(Response& res)
25 {
26 res.addHeader("myheader", "myvalue");
27 res.keepAlive(true);
28 res.result(boost::beast::http::status::ok);
29 }
verifyHeaders(Response & res)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
getData(boost::beast::http::response<bmcweb::HttpBody> & m)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
TEST(HttpResponse,Headers)71 TEST(HttpResponse, Headers)
72 {
73 Response res;
74 addHeaders(res);
75 verifyHeaders(res);
76 }
TEST(HttpResponse,StringBody)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 }
TEST(HttpResponse,HttpBody)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 }
TEST(HttpResponse,HttpBodyWithFd)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
TEST(HttpResponse,Base64HttpBodyWithFd)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
TEST(HttpResponse,BodyTransitions)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
generateBigdata()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
TEST(HttpResponse,StringBodyWriterLarge)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
TEST(HttpResponse,Base64HttpBodyWriter)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
TEST(HttpResponse,Base64HttpBodyWriterLarge)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
TEST(HttpResponse,HttpBodyWriterLarge)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