xref: /openbmc/bmcweb/test/http/http_response_test.cpp (revision e5ab2df5a5c865719cf6111bea549ffa84801d7e)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #include "duplicatable_file_handle.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/serializer.hpp>
12 #include <boost/beast/http/status.hpp>
13 
14 #include <cstdio>
15 #include <filesystem>
16 #include <string>
17 
18 #include "gtest/gtest.h"
19 namespace crow
20 {
21 namespace
22 {
addHeaders(Response & res)23 void addHeaders(Response& res)
24 {
25     res.addHeader("myheader", "myvalue");
26     res.keepAlive(true);
27     res.result(boost::beast::http::status::ok);
28 }
verifyHeaders(Response & res)29 void verifyHeaders(Response& res)
30 {
31     EXPECT_EQ(res.getHeaderValue("myheader"), "myvalue");
32     EXPECT_EQ(res.keepAlive(), true);
33     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
34 }
35 
getData(boost::beast::http::response<bmcweb::HttpBody> & m)36 std::string getData(boost::beast::http::response<bmcweb::HttpBody>& m)
37 {
38     std::string ret;
39 
40     boost::beast::http::response_serializer<bmcweb::HttpBody> sr{m};
41     sr.split(true);
42     // Reads buffers into ret
43     auto reader =
44         [&sr, &ret](const boost::system::error_code& ec2, const auto& buffer) {
45             EXPECT_FALSE(ec2);
46             std::string ret2 = boost::beast::buffers_to_string(buffer);
47             sr.consume(ret2.size());
48             ret += ret2;
49         };
50     boost::system::error_code ec;
51 
52     // Read headers
53     while (!sr.is_header_done())
54     {
55         sr.next(ec, reader);
56         EXPECT_FALSE(ec);
57     }
58     ret.clear();
59 
60     // Read body
61     while (!sr.is_done())
62     {
63         sr.next(ec, reader);
64         EXPECT_FALSE(ec);
65     }
66 
67     return ret;
68 }
69 
TEST(HttpResponse,Headers)70 TEST(HttpResponse, Headers)
71 {
72     Response res;
73     addHeaders(res);
74     verifyHeaders(res);
75 }
TEST(HttpResponse,StringBody)76 TEST(HttpResponse, StringBody)
77 {
78     Response res;
79     addHeaders(res);
80     std::string_view bodyValue = "this is my new body";
81     res.write({bodyValue.data(), bodyValue.length()});
82     EXPECT_EQ(*res.body(), bodyValue);
83     verifyHeaders(res);
84 }
TEST(HttpResponse,HttpBody)85 TEST(HttpResponse, HttpBody)
86 {
87     Response res;
88     addHeaders(res);
89     DuplicatableFileHandle temporaryFile("sample text");
90     res.openFile(temporaryFile.filePath);
91 
92     verifyHeaders(res);
93 }
TEST(HttpResponse,HttpBodyWithFd)94 TEST(HttpResponse, HttpBodyWithFd)
95 {
96     Response res;
97     addHeaders(res);
98     DuplicatableFileHandle temporaryFile("sample text");
99     FILE* fd = fopen(temporaryFile.filePath.c_str(), "r+");
100     ASSERT_NE(fd, nullptr);
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     DuplicatableFileHandle temporaryFile("sample text");
111     FILE* fd = fopen(temporaryFile.filePath.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     DuplicatableFileHandle temporaryFile("sample text");
123     res.openFile(temporaryFile.filePath);
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     DuplicatableFileHandle temporaryFile(data);
154     FILE* f = fopen(temporaryFile.filePath.c_str(), "r+");
155     ASSERT_NE(f, nullptr);
156     res.openFd(fileno(f), bmcweb::EncodingType::Base64);
157     EXPECT_EQ(getData(res.response), "c2FtcGxlIHRleHQ=");
158     fclose(f);
159 }
160 
TEST(HttpResponse,Base64HttpBodyWriterLarge)161 TEST(HttpResponse, Base64HttpBodyWriterLarge)
162 {
163     Response res;
164     std::string data = generateBigdata();
165     DuplicatableFileHandle temporaryFile(data);
166 
167     boost::beast::file_posix file;
168     boost::system::error_code ec;
169     file.open(temporaryFile.filePath.c_str(), boost::beast::file_mode::read,
170               ec);
171     EXPECT_EQ(ec.value(), 0);
172     res.openFd(file.native_handle(), bmcweb::EncodingType::Base64);
173     EXPECT_EQ(getData(res.response), utility::base64encode(data));
174 }
175 
TEST(HttpResponse,HttpBodyWriterLarge)176 TEST(HttpResponse, HttpBodyWriterLarge)
177 {
178     Response res;
179     std::string data = generateBigdata();
180     DuplicatableFileHandle temporaryFile(data);
181 
182     boost::beast::file_posix file;
183     boost::system::error_code ec;
184     file.open(temporaryFile.filePath.c_str(), boost::beast::file_mode::read,
185               ec);
186     EXPECT_EQ(ec.value(), 0);
187     res.openFd(file.native_handle());
188     EXPECT_EQ(getData(res.response), data);
189 }
190 } // namespace
191 } // namespace crow
192