1 #include "http/http_request.hpp"
2 #include "multipart_parser.hpp"
3 
4 #include <boost/beast/http/fields.hpp>
5 #include <boost/beast/http/message.hpp>
6 #include <boost/beast/http/string_body.hpp>
7 
8 #include <memory>
9 #include <string_view>
10 #include <system_error>
11 #include <vector>
12 
13 #include <gtest/gtest.h> // IWYU pragma: keep
14 
15 // IWYU pragma: no_include <gtest/gtest-message.h>
16 // IWYU pragma: no_include <gtest/gtest-test-part.h>
17 // IWYU pragma: no_include "gtest/gtest_pred_impl.h"
18 // IWYU pragma: no_include <boost/beast/http/impl/fields.hpp>
19 // IWYU pragma: no_include <boost/intrusive/detail/list_iterator.hpp>
20 // IWYU pragma: no_include <boost/intrusive/detail/tree_iterator.hpp>
21 
22 namespace
23 {
24 using ::testing::Test;
25 
26 class MultipartTest : public Test
27 {
28   public:
29     boost::beast::http::request<boost::beast::http::string_body> req{};
30     MultipartParser parser;
31     std::error_code ec;
32 };
33 
34 TEST_F(MultipartTest, TestGoodMultipartParser)
35 {
36     req.set("Content-Type",
37             "multipart/form-data; "
38             "boundary=---------------------------d74496d66958873e");
39 
40     req.body() = "-----------------------------d74496d66958873e\r\n"
41                  "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
42                  "111111111111111111111111112222222222222222222222222222222\r\n"
43                  "-----------------------------d74496d66958873e\r\n"
44                  "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
45                  "{\r\n-----------------------------d74496d66958873e123456\r\n"
46                  "-----------------------------d74496d66958873e\r\n"
47                  "Content-Disposition: form-data; name=\"Test3\"\r\n\r\n"
48                  "{\r\n--------d74496d6695887}\r\n"
49                  "-----------------------------d74496d66958873e--\r\n";
50 
51     crow::Request reqIn(req, ec);
52     ParserError rc = parser.parse(reqIn);
53     ASSERT_EQ(rc, ParserError::PARSER_SUCCESS);
54 
55     EXPECT_EQ(parser.boundary,
56               "\r\n-----------------------------d74496d66958873e");
57     EXPECT_EQ(parser.mime_fields.size(), 3);
58 
59     EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"),
60               "form-data; name=\"Test1\"");
61     EXPECT_EQ(parser.mime_fields[0].content,
62               "111111111111111111111111112222222222222222222222222222222");
63 
64     EXPECT_EQ(parser.mime_fields[1].fields.at("Content-Disposition"),
65               "form-data; name=\"Test2\"");
66     EXPECT_EQ(parser.mime_fields[1].content,
67               "{\r\n-----------------------------d74496d66958873e123456");
68     EXPECT_EQ(parser.mime_fields[2].fields.at("Content-Disposition"),
69               "form-data; name=\"Test3\"");
70     EXPECT_EQ(parser.mime_fields[2].content, "{\r\n--------d74496d6695887}");
71 }
72 
73 TEST_F(MultipartTest, TestBadMultipartParser1)
74 {
75     req.set("Content-Type",
76             "multipart/form-data; "
77             "boundary=---------------------------d74496d66958873e");
78 
79     req.body() = "-----------------------------d74496d66958873e\r\n"
80                  "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
81                  "1234567890\r\n"
82                  "-----------------------------d74496d66958873e\r-\r\n";
83 
84     crow::Request reqIn(req, ec);
85     ParserError rc = parser.parse(reqIn);
86     ASSERT_EQ(rc, ParserError::PARSER_SUCCESS);
87 
88     EXPECT_EQ(parser.boundary,
89               "\r\n-----------------------------d74496d66958873e");
90     EXPECT_EQ(parser.mime_fields.size(), 1);
91 }
92 
93 TEST_F(MultipartTest, TestBadMultipartParser2)
94 {
95     req.set("Content-Type",
96             "multipart/form-data; "
97             "boundary=---------------------------d74496d66958873e");
98 
99     req.body() = "-----------------------------d74496d66958873e\r\n"
100                  "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
101                  "abcd\r\n"
102                  "-----------------------------d74496d66958873e-\r\n";
103 
104     crow::Request reqIn(req, ec);
105     ParserError rc = parser.parse(reqIn);
106     ASSERT_EQ(rc, ParserError::PARSER_SUCCESS);
107 
108     EXPECT_EQ(parser.boundary,
109               "\r\n-----------------------------d74496d66958873e");
110     EXPECT_EQ(parser.mime_fields.size(), 1);
111 }
112 
113 TEST_F(MultipartTest, TestErrorBoundaryFormat)
114 {
115     req.set("Content-Type",
116             "multipart/form-data; "
117             "boundary+=-----------------------------d74496d66958873e");
118 
119     req.body() = "-----------------------------d74496d66958873e\r\n"
120                  "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
121                  "{\"Key1\": 11223333333333333333333333333333333333333333}\r\n"
122                  "-----------------------------d74496d66958873e\r\n"
123                  "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
124                  "123456\r\n"
125                  "-----------------------------d74496d66958873e--\r\n";
126 
127     crow::Request reqIn(req, ec);
128     EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_FORMAT);
129 }
130 
131 TEST_F(MultipartTest, TestErrorBoundaryCR)
132 {
133     req.set("Content-Type",
134             "multipart/form-data; "
135             "boundary=---------------------------d74496d66958873e");
136 
137     req.body() = "-----------------------------d74496d66958873e"
138                  "Content-Disposition: form-data; name=\"Test1\"\r\n\r"
139                  "{\"Key1\": 112233}\r\n"
140                  "-----------------------------d74496d66958873e\r\n"
141                  "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
142                  "123456\r\n"
143                  "-----------------------------d74496d66958873e--\r\n";
144 
145     crow::Request reqIn(req, ec);
146     EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_CR);
147 }
148 
149 TEST_F(MultipartTest, TestErrorBoundaryLF)
150 {
151     req.set("Content-Type",
152             "multipart/form-data; "
153             "boundary=---------------------------d74496d66958873e");
154 
155     req.body() = "-----------------------------d74496d66958873e\r"
156                  "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
157                  "{\"Key1\": 112233}\r\n"
158                  "-----------------------------d74496d66958873e\r\n"
159                  "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
160                  "123456\r\n"
161                  "-----------------------------d74496d66958873e--\r\n";
162 
163     crow::Request reqIn(req, ec);
164     EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_LF);
165 }
166 
167 TEST_F(MultipartTest, TestErrorBoundaryData)
168 {
169     req.set("Content-Type",
170             "multipart/form-data; "
171             "boundary=---------------------------d7449sd6d66958873e");
172 
173     req.body() = "-----------------------------d74496d66958873e\r\n"
174                  "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
175                  "{\"Key1\": 112233}\r\n"
176                  "-----------------------------d74496d66958873e\r\n"
177                  "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
178                  "123456\r\n"
179                  "-----------------------------d74496d66958873e--\r\n";
180 
181     crow::Request reqIn(req, ec);
182     EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_DATA);
183 }
184 
185 TEST_F(MultipartTest, TestErrorEmptyHeader)
186 {
187     req.set("Content-Type",
188             "multipart/form-data; "
189             "boundary=---------------------------d74496d66958873e");
190 
191     req.body() = "-----------------------------d74496d66958873e\r\n"
192                  ": form-data; name=\"Test1\"\r\n"
193                  "{\"Key1\": 112233}\r\n"
194                  "-----------------------------d74496d66958873e\r\n"
195                  "Content-Disposition: form-data; name=\"Test2\"\r\n"
196                  "123456\r\n"
197                  "-----------------------------d74496d66958873e--\r\n";
198 
199     crow::Request reqIn(req, ec);
200     EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_EMPTY_HEADER);
201 }
202 
203 TEST_F(MultipartTest, TestErrorHeaderName)
204 {
205     req.set("Content-Type",
206             "multipart/form-data; "
207             "boundary=---------------------------d74496d66958873e");
208 
209     req.body() = "-----------------------------d74496d66958873e\r\n"
210                  "Content-!!Disposition: form-data; name=\"Test1\"\r\n"
211                  "{\"Key1\": 112233}\r\n"
212                  "-----------------------------d74496d66958873e\r\n"
213                  "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
214                  "123456\r\n"
215                  "-----------------------------d74496d66958873e--\r\n";
216 
217     crow::Request reqIn(req, ec);
218     EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_NAME);
219 }
220 
221 TEST_F(MultipartTest, TestErrorHeaderValue)
222 {
223     req.set("Content-Type",
224             "multipart/form-data; "
225             "boundary=---------------------------d74496d66958873e");
226 
227     req.body() = "-----------------------------d74496d66958873e\r\n"
228                  "Content-Disposition: form-data; name=\"Test1\"\r"
229                  "{\"Key1\": 112233}\r\n"
230                  "-----------------------------d74496d66958873e\r\n"
231                  "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
232                  "123456\r\n"
233                  "-----------------------------d74496d66958873e--\r\n";
234 
235     crow::Request reqIn(req, ec);
236     EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_VALUE);
237 }
238 
239 TEST_F(MultipartTest, TestErrorHeaderEnding)
240 {
241     req.set("Content-Type",
242             "multipart/form-data; "
243             "boundary=---------------------------d74496d66958873e");
244 
245     req.body() = "-----------------------------d74496d66958873e\r\n"
246                  "Content-Disposition: form-data; name=\"Test1\"\r\n\r"
247                  "{\"Key1\": 112233}\r\n"
248                  "-----------------------------d74496d66958873e\r\n"
249                  "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
250                  "123456\r\n"
251                  "-----------------------------d74496d66958873e--\r\n";
252 
253     crow::Request reqIn(req, ec);
254     EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_ENDING);
255 }
256 } // namespace