xref: /openbmc/bmcweb/test/http/http_response_test.cpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
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