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 {
addHeaders(crow::Response & res)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 }
verifyHeaders(crow::Response & res)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
getData(boost::beast::http::response<bmcweb::HttpBody> & m)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
TEST(HttpResponse,Headers)69 TEST(HttpResponse, Headers)
70 {
71 crow::Response res;
72 addHeaders(res);
73 verifyHeaders(res);
74 }
TEST(HttpResponse,StringBody)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 }
TEST(HttpResponse,HttpBody)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 }
TEST(HttpResponse,HttpBodyWithFd)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
TEST(HttpResponse,Base64HttpBodyWithFd)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
TEST(HttpResponse,BodyTransitions)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
generateBigdata()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
TEST(HttpResponse,StringBodyWriterLarge)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
TEST(HttpResponse,Base64HttpBodyWriter)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
TEST(HttpResponse,Base64HttpBodyWriterLarge)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
TEST(HttpResponse,HttpBodyWriterLarge)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