blob: 38ac53deb05e0490eff8e2cda19dadb611f94daf [file] [log] [blame]
Nan Zhou77665bd2022-10-12 20:28:58 +00001#include "http_request.hpp"
Nan Zhouca0cb4c2022-06-21 17:47:09 +00002#include "multipart_parser.hpp"
3
Nan Zhoud5c80ad2022-07-11 01:16:31 +00004#include <boost/beast/http/fields.hpp>
Nan Zhouca0cb4c2022-06-21 17:47:09 +00005#include <boost/beast/http/message.hpp>
6#include <boost/beast/http/string_body.hpp>
Ed Tanousaf4edf62020-07-21 08:46:25 -07007
Nan Zhoud5c80ad2022-07-11 01:16:31 +00008#include <memory>
9#include <string_view>
Nan Zhouca0cb4c2022-06-21 17:47:09 +000010#include <system_error>
Nan Zhoud5c80ad2022-07-11 01:16:31 +000011#include <vector>
Ed Tanousaf4edf62020-07-21 08:46:25 -070012
Nan Zhoud5c80ad2022-07-11 01:16:31 +000013#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>
Ed Tanousaf4edf62020-07-21 08:46:25 -070021
Nan Zhoue52d1562022-06-21 17:47:15 +000022namespace
23{
24using ::testing::Test;
25
26class MultipartTest : public Test
Ed Tanousaf4edf62020-07-21 08:46:25 -070027{
28 public:
29 boost::beast::http::request<boost::beast::http::string_body> req{};
30 MultipartParser parser;
31 std::error_code ec;
32};
33
34TEST_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
Nan Zhoucc606192022-06-21 17:47:19 +000055 EXPECT_EQ(parser.boundary,
Ed Tanousaf4edf62020-07-21 08:46:25 -070056 "\r\n-----------------------------d74496d66958873e");
Nan Zhoucc606192022-06-21 17:47:19 +000057 EXPECT_EQ(parser.mime_fields.size(), 3);
Ed Tanousaf4edf62020-07-21 08:46:25 -070058
Nan Zhoucc606192022-06-21 17:47:19 +000059 EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"),
Ed Tanousaf4edf62020-07-21 08:46:25 -070060 "form-data; name=\"Test1\"");
Nan Zhoucc606192022-06-21 17:47:19 +000061 EXPECT_EQ(parser.mime_fields[0].content,
Ed Tanousaf4edf62020-07-21 08:46:25 -070062 "111111111111111111111111112222222222222222222222222222222");
63
Nan Zhoucc606192022-06-21 17:47:19 +000064 EXPECT_EQ(parser.mime_fields[1].fields.at("Content-Disposition"),
Ed Tanousaf4edf62020-07-21 08:46:25 -070065 "form-data; name=\"Test2\"");
Nan Zhoucc606192022-06-21 17:47:19 +000066 EXPECT_EQ(parser.mime_fields[1].content,
Ed Tanousaf4edf62020-07-21 08:46:25 -070067 "{\r\n-----------------------------d74496d66958873e123456");
Nan Zhoucc606192022-06-21 17:47:19 +000068 EXPECT_EQ(parser.mime_fields[2].fields.at("Content-Disposition"),
Ed Tanousaf4edf62020-07-21 08:46:25 -070069 "form-data; name=\"Test3\"");
Nan Zhoucc606192022-06-21 17:47:19 +000070 EXPECT_EQ(parser.mime_fields[2].content, "{\r\n--------d74496d6695887}");
Ed Tanousaf4edf62020-07-21 08:46:25 -070071}
72
73TEST_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);
Ed Tanousaf4edf62020-07-21 08:46:25 -070086
Krzysztof Grobelny18e3f7f2022-08-24 09:24:33 +020087 EXPECT_EQ(rc, ParserError::ERROR_UNEXPECTED_END_OF_INPUT);
Ed Tanousaf4edf62020-07-21 08:46:25 -070088}
89
90TEST_F(MultipartTest, TestBadMultipartParser2)
91{
92 req.set("Content-Type",
93 "multipart/form-data; "
94 "boundary=---------------------------d74496d66958873e");
95
96 req.body() = "-----------------------------d74496d66958873e\r\n"
97 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
98 "abcd\r\n"
99 "-----------------------------d74496d66958873e-\r\n";
100
101 crow::Request reqIn(req, ec);
102 ParserError rc = parser.parse(reqIn);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700103
Krzysztof Grobelny18e3f7f2022-08-24 09:24:33 +0200104 EXPECT_EQ(rc, ParserError::ERROR_UNEXPECTED_END_OF_INPUT);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700105}
106
107TEST_F(MultipartTest, TestErrorBoundaryFormat)
108{
109 req.set("Content-Type",
110 "multipart/form-data; "
111 "boundary+=-----------------------------d74496d66958873e");
112
113 req.body() = "-----------------------------d74496d66958873e\r\n"
114 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
115 "{\"Key1\": 11223333333333333333333333333333333333333333}\r\n"
116 "-----------------------------d74496d66958873e\r\n"
117 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
118 "123456\r\n"
119 "-----------------------------d74496d66958873e--\r\n";
120
121 crow::Request reqIn(req, ec);
Nan Zhoucc606192022-06-21 17:47:19 +0000122 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_FORMAT);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700123}
124
125TEST_F(MultipartTest, TestErrorBoundaryCR)
126{
127 req.set("Content-Type",
128 "multipart/form-data; "
129 "boundary=---------------------------d74496d66958873e");
130
131 req.body() = "-----------------------------d74496d66958873e"
132 "Content-Disposition: form-data; name=\"Test1\"\r\n\r"
133 "{\"Key1\": 112233}\r\n"
134 "-----------------------------d74496d66958873e\r\n"
135 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
136 "123456\r\n"
137 "-----------------------------d74496d66958873e--\r\n";
138
139 crow::Request reqIn(req, ec);
Nan Zhoucc606192022-06-21 17:47:19 +0000140 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_CR);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700141}
142
143TEST_F(MultipartTest, TestErrorBoundaryLF)
144{
145 req.set("Content-Type",
146 "multipart/form-data; "
147 "boundary=---------------------------d74496d66958873e");
148
149 req.body() = "-----------------------------d74496d66958873e\r"
150 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
151 "{\"Key1\": 112233}\r\n"
152 "-----------------------------d74496d66958873e\r\n"
153 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
154 "123456\r\n"
155 "-----------------------------d74496d66958873e--\r\n";
156
157 crow::Request reqIn(req, ec);
Nan Zhoucc606192022-06-21 17:47:19 +0000158 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_LF);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700159}
160
161TEST_F(MultipartTest, TestErrorBoundaryData)
162{
163 req.set("Content-Type",
164 "multipart/form-data; "
165 "boundary=---------------------------d7449sd6d66958873e");
166
167 req.body() = "-----------------------------d74496d66958873e\r\n"
168 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
169 "{\"Key1\": 112233}\r\n"
170 "-----------------------------d74496d66958873e\r\n"
171 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
172 "123456\r\n"
173 "-----------------------------d74496d66958873e--\r\n";
174
175 crow::Request reqIn(req, ec);
Nan Zhoucc606192022-06-21 17:47:19 +0000176 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_DATA);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700177}
178
179TEST_F(MultipartTest, TestErrorEmptyHeader)
180{
181 req.set("Content-Type",
182 "multipart/form-data; "
183 "boundary=---------------------------d74496d66958873e");
184
185 req.body() = "-----------------------------d74496d66958873e\r\n"
186 ": form-data; name=\"Test1\"\r\n"
187 "{\"Key1\": 112233}\r\n"
188 "-----------------------------d74496d66958873e\r\n"
189 "Content-Disposition: form-data; name=\"Test2\"\r\n"
190 "123456\r\n"
191 "-----------------------------d74496d66958873e--\r\n";
192
193 crow::Request reqIn(req, ec);
Nan Zhoucc606192022-06-21 17:47:19 +0000194 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_EMPTY_HEADER);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700195}
196
197TEST_F(MultipartTest, TestErrorHeaderName)
198{
199 req.set("Content-Type",
200 "multipart/form-data; "
201 "boundary=---------------------------d74496d66958873e");
202
203 req.body() = "-----------------------------d74496d66958873e\r\n"
204 "Content-!!Disposition: form-data; name=\"Test1\"\r\n"
205 "{\"Key1\": 112233}\r\n"
206 "-----------------------------d74496d66958873e\r\n"
207 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
208 "123456\r\n"
209 "-----------------------------d74496d66958873e--\r\n";
210
211 crow::Request reqIn(req, ec);
Nan Zhoucc606192022-06-21 17:47:19 +0000212 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_NAME);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700213}
214
215TEST_F(MultipartTest, TestErrorHeaderValue)
216{
217 req.set("Content-Type",
218 "multipart/form-data; "
219 "boundary=---------------------------d74496d66958873e");
220
221 req.body() = "-----------------------------d74496d66958873e\r\n"
222 "Content-Disposition: form-data; name=\"Test1\"\r"
223 "{\"Key1\": 112233}\r\n"
224 "-----------------------------d74496d66958873e\r\n"
225 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
226 "123456\r\n"
227 "-----------------------------d74496d66958873e--\r\n";
228
229 crow::Request reqIn(req, ec);
Nan Zhoucc606192022-06-21 17:47:19 +0000230 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_VALUE);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700231}
232
233TEST_F(MultipartTest, TestErrorHeaderEnding)
234{
235 req.set("Content-Type",
236 "multipart/form-data; "
237 "boundary=---------------------------d74496d66958873e");
238
239 req.body() = "-----------------------------d74496d66958873e\r\n"
240 "Content-Disposition: form-data; name=\"Test1\"\r\n\r"
241 "{\"Key1\": 112233}\r\n"
242 "-----------------------------d74496d66958873e\r\n"
243 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
244 "123456\r\n"
245 "-----------------------------d74496d66958873e--\r\n";
246
247 crow::Request reqIn(req, ec);
Nan Zhoucc606192022-06-21 17:47:19 +0000248 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_ENDING);
Ed Tanousaf4edf62020-07-21 08:46:25 -0700249}
Krzysztof Grobelny18e3f7f2022-08-24 09:24:33 +0200250
251TEST_F(MultipartTest, TestGoodMultipartParserMultipleHeaders)
252{
253 req.set("Content-Type",
254 "multipart/form-data; "
255 "boundary=---------------------------d74496d66958873e");
256
257 req.body() = "-----------------------------d74496d66958873e\r\n"
258 "Content-Disposition: form-data; name=\"Test1\"\r\n"
259 "Other-Header: value=\"v1\"\r\n"
260 "\r\n"
261 "Data1\r\n"
262 "-----------------------------d74496d66958873e--";
263
264 crow::Request reqIn(req, ec);
265 ParserError rc = parser.parse(reqIn);
266 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS);
267
268 EXPECT_EQ(parser.boundary,
269 "\r\n-----------------------------d74496d66958873e");
270 ASSERT_EQ(parser.mime_fields.size(), 1);
271
272 EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"),
273 "form-data; name=\"Test1\"");
274 EXPECT_EQ(parser.mime_fields[0].fields.at("Other-Header"), "value=\"v1\"");
275 EXPECT_EQ(parser.mime_fields[0].content, "Data1");
276}
277
278TEST_F(MultipartTest, TestErrorHeaderWithoutColon)
279{
280 req.set("Content-Type", "multipart/form-data; "
281 "boundary=--end");
282
283 req.body() = "----end\r\n"
284 "abc\r\n"
285 "\r\n"
286 "Data1\r\n"
287 "----end--\r\n";
288
289 crow::Request reqIn(req, ec);
290 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_UNEXPECTED_END_OF_HEADER);
291}
292
293TEST_F(MultipartTest, TestUnknownHeaderIsCorrectlyParsed)
294{
295 req.set("Content-Type", "multipart/form-data; "
296 "boundary=--end");
297
298 req.body() =
299 "----end\r\n"
300 "t-DiPpcccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccgcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa\r\n"
301 "\r\n"
302 "Data1\r\n"
303 "----end--\r\n";
304
305 crow::Request reqIn(req, ec);
306 ParserError rc = parser.parse(reqIn);
307
308 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS);
309
310 EXPECT_EQ(parser.boundary, "\r\n----end");
311 ASSERT_EQ(parser.mime_fields.size(), 1);
312
313 EXPECT_EQ(
314 parser.mime_fields[0].fields.at("t-DiPpcccc"),
315 "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccgcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa");
316 EXPECT_EQ(parser.mime_fields[0].content, "Data1");
317}
318
319TEST_F(MultipartTest, TestErrorMissingSeparatorBetweenMimeFieldsAndData)
320{
321 req.set(
322 "Content-Type",
323 "multipart/form-data; boundary=---------------------------d74496d66958873e");
324
325 req.body() =
326 "-----------------------------d74496d66958873e\r\n"
327 "t-DiPpcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccgcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa\r\n"
328 "Data1"
329 "-----------------------------d74496d66958873e--";
330
331 crow::Request reqIn(req, ec);
332 ParserError rc = parser.parse(reqIn);
333
334 EXPECT_EQ(rc, ParserError::ERROR_UNEXPECTED_END_OF_HEADER);
335}
336
337TEST_F(MultipartTest, TestDataWithoutMimeFields)
338{
339 req.set(
340 "Content-Type",
341 "multipart/form-data; boundary=---------------------------d74496d66958873e");
342
343 req.body() = "-----------------------------d74496d66958873e\r\n"
344 "\r\n"
345 "Data1\r\n"
346 "-----------------------------d74496d66958873e--";
347
348 crow::Request reqIn(req, ec);
349 ParserError rc = parser.parse(reqIn);
350
351 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS);
352
353 EXPECT_EQ(parser.boundary,
354 "\r\n-----------------------------d74496d66958873e");
355 ASSERT_EQ(parser.mime_fields.size(), 1);
356
357 EXPECT_EQ(std::distance(parser.mime_fields[0].fields.begin(),
358 parser.mime_fields[0].fields.end()),
359 0);
360 EXPECT_EQ(parser.mime_fields[0].content, "Data1");
361}
362
363TEST_F(MultipartTest, TestErrorMissingFinalBoundry)
364{
365 req.set("Content-Type", "multipart/form-data; boundary=--XX");
366
367 req.body() =
368 "----XX\r\n"
369 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
370 "t-DiPpccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccAAAAAAAAAAAAAAABCDz\r\n"
371 "\335\r\n\r\n";
372
373 crow::Request reqIn(req, ec);
374 ParserError rc = parser.parse(reqIn);
375
376 EXPECT_EQ(rc, ParserError::ERROR_UNEXPECTED_END_OF_INPUT);
377}
378
379TEST_F(MultipartTest, TestIgnoreDataAfterFinalBoundary)
380{
381 req.set("Content-Type", "multipart/form-data; boundary=--XX");
382
383 req.body() = "----XX\r\n"
384 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
385 "Data1\r\n"
386 "----XX--\r\n"
387 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n"
388 "Data2\r\n"
389 "----XX--\r\n";
390
391 crow::Request reqIn(req, ec);
392 ParserError rc = parser.parse(reqIn);
393
394 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS);
395
396 EXPECT_EQ(parser.boundary, "\r\n----XX");
397 EXPECT_EQ(parser.mime_fields.size(), 1);
398
399 EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"),
400 "form-data; name=\"Test1\"");
401 EXPECT_EQ(parser.mime_fields[0].content, "Data1");
402}
403
404TEST_F(MultipartTest, TestFinalBoundaryIsCorrectlyRecognized)
405{
406 req.set("Content-Type", "multipart/form-data; boundary=--XX");
407
408 req.body() = "----XX\r\n"
409 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n"
410 "Data1\r\n"
411 "----XX-abc-\r\n"
412 "StillData1\r\n"
413 "----XX--\r\n";
414
415 crow::Request reqIn(req, ec);
416 ParserError rc = parser.parse(reqIn);
417
418 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS);
419
420 EXPECT_EQ(parser.boundary, "\r\n----XX");
421 EXPECT_EQ(parser.mime_fields.size(), 1);
422
423 EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"),
424 "form-data; name=\"Test1\"");
425 EXPECT_EQ(parser.mime_fields[0].content, "Data1\r\n"
426 "----XX-abc-\r\n"
427 "StillData1");
428}
429
430} // namespace