1 #include "http_request.hpp" 2 #include "multipart_parser.hpp" 3 4 #include <boost/beast/http/fields.hpp> 5 6 #include <iterator> 7 #include <string_view> 8 #include <system_error> 9 #include <vector> 10 11 #include <gtest/gtest.h> 12 13 namespace 14 { 15 using ::testing::Test; 16 17 class MultipartTest : public Test 18 { 19 public: 20 MultipartParser parser; 21 std::error_code ec; 22 }; 23 24 TEST_F(MultipartTest, TestGoodMultipartParser) 25 { 26 std::string_view body = 27 "-----------------------------d74496d66958873e\r\n" 28 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" 29 "111111111111111111111111112222222222222222222222222222222\r\n" 30 "-----------------------------d74496d66958873e\r\n" 31 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 32 "{\r\n-----------------------------d74496d66958873e123456\r\n" 33 "-----------------------------d74496d66958873e\r\n" 34 "Content-Disposition: form-data; name=\"Test3\"\r\n\r\n" 35 "{\r\n--------d74496d6695887}\r\n" 36 "-----------------------------d74496d66958873e--\r\n"; 37 38 crow::Request reqIn(body, ec); 39 40 reqIn.addHeader("Content-Type", 41 "multipart/form-data; " 42 "boundary=---------------------------d74496d66958873e"); 43 44 ParserError rc = parser.parse(reqIn); 45 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); 46 47 EXPECT_EQ(parser.boundary, 48 "\r\n-----------------------------d74496d66958873e"); 49 EXPECT_EQ(parser.mime_fields.size(), 3); 50 51 EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"), 52 "form-data; name=\"Test1\""); 53 EXPECT_EQ(parser.mime_fields[0].content, 54 "111111111111111111111111112222222222222222222222222222222"); 55 56 EXPECT_EQ(parser.mime_fields[1].fields.at("Content-Disposition"), 57 "form-data; name=\"Test2\""); 58 EXPECT_EQ(parser.mime_fields[1].content, 59 "{\r\n-----------------------------d74496d66958873e123456"); 60 EXPECT_EQ(parser.mime_fields[2].fields.at("Content-Disposition"), 61 "form-data; name=\"Test3\""); 62 EXPECT_EQ(parser.mime_fields[2].content, "{\r\n--------d74496d6695887}"); 63 } 64 65 TEST_F(MultipartTest, TestBadMultipartParser1) 66 { 67 std::string_view body = 68 "-----------------------------d74496d66958873e\r\n" 69 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" 70 "1234567890\r\n" 71 "-----------------------------d74496d66958873e\r-\r\n"; 72 73 crow::Request reqIn(body, ec); 74 75 reqIn.addHeader("Content-Type", 76 "multipart/form-data; " 77 "boundary=---------------------------d74496d66958873e"); 78 79 ParserError rc = parser.parse(reqIn); 80 81 EXPECT_EQ(rc, ParserError::ERROR_UNEXPECTED_END_OF_INPUT); 82 } 83 84 TEST_F(MultipartTest, TestBadMultipartParser2) 85 { 86 std::string_view body = 87 "-----------------------------d74496d66958873e\r\n" 88 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" 89 "abcd\r\n" 90 "-----------------------------d74496d66958873e-\r\n"; 91 crow::Request reqIn(body, ec); 92 93 reqIn.addHeader("Content-Type", 94 "multipart/form-data; " 95 "boundary=---------------------------d74496d66958873e"); 96 97 ParserError rc = parser.parse(reqIn); 98 99 EXPECT_EQ(rc, ParserError::ERROR_UNEXPECTED_END_OF_INPUT); 100 } 101 102 TEST_F(MultipartTest, TestErrorBoundaryFormat) 103 { 104 std::string_view body = 105 "-----------------------------d74496d66958873e\r\n" 106 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" 107 "{\"Key1\": 11223333333333333333333333333333333333333333}\r\n" 108 "-----------------------------d74496d66958873e\r\n" 109 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 110 "123456\r\n" 111 "-----------------------------d74496d66958873e--\r\n"; 112 113 crow::Request reqIn(body, ec); 114 115 reqIn.addHeader("Content-Type", 116 "multipart/form-data; " 117 "boundary+=-----------------------------d74496d66958873e"); 118 119 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_FORMAT); 120 } 121 122 TEST_F(MultipartTest, TestErrorBoundaryCR) 123 { 124 std::string_view body = 125 "-----------------------------d74496d66958873e" 126 "Content-Disposition: form-data; name=\"Test1\"\r\n\r" 127 "{\"Key1\": 112233}\r\n" 128 "-----------------------------d74496d66958873e\r\n" 129 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 130 "123456\r\n" 131 "-----------------------------d74496d66958873e--\r\n"; 132 crow::Request reqIn(body, ec); 133 134 reqIn.addHeader("Content-Type", 135 "multipart/form-data; " 136 "boundary=---------------------------d74496d66958873e"); 137 138 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_CR); 139 } 140 141 TEST_F(MultipartTest, TestErrorBoundaryLF) 142 { 143 std::string_view body = 144 "-----------------------------d74496d66958873e\r" 145 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" 146 "{\"Key1\": 112233}\r\n" 147 "-----------------------------d74496d66958873e\r\n" 148 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 149 "123456\r\n" 150 "-----------------------------d74496d66958873e--\r\n"; 151 152 crow::Request reqIn(body, ec); 153 154 reqIn.addHeader("Content-Type", 155 "multipart/form-data; " 156 "boundary=---------------------------d74496d66958873e"); 157 158 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_LF); 159 } 160 161 TEST_F(MultipartTest, TestErrorBoundaryData) 162 { 163 std::string_view body = 164 "-----------------------------d74496d66958873e\r\n" 165 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" 166 "{\"Key1\": 112233}\r\n" 167 "-----------------------------d74496d66958873e\r\n" 168 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 169 "123456\r\n" 170 "-----------------------------d74496d66958873e--\r\n"; 171 172 crow::Request reqIn(body, ec); 173 174 reqIn.addHeader("Content-Type", 175 "multipart/form-data; " 176 "boundary=---------------------------d7449sd6d66958873e"); 177 178 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_BOUNDARY_DATA); 179 } 180 181 TEST_F(MultipartTest, TestErrorEmptyHeader) 182 { 183 std::string_view body = 184 "-----------------------------d74496d66958873e\r\n" 185 ": form-data; name=\"Test1\"\r\n" 186 "{\"Key1\": 112233}\r\n" 187 "-----------------------------d74496d66958873e\r\n" 188 "Content-Disposition: form-data; name=\"Test2\"\r\n" 189 "123456\r\n" 190 "-----------------------------d74496d66958873e--\r\n"; 191 crow::Request reqIn(body, ec); 192 193 reqIn.addHeader("Content-Type", 194 "multipart/form-data; " 195 "boundary=---------------------------d74496d66958873e"); 196 197 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_EMPTY_HEADER); 198 } 199 200 TEST_F(MultipartTest, TestErrorHeaderName) 201 { 202 std::string_view body = 203 "-----------------------------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 crow::Request reqIn(body, ec); 211 212 reqIn.addHeader("Content-Type", 213 "multipart/form-data; " 214 "boundary=---------------------------d74496d66958873e"); 215 216 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_NAME); 217 } 218 219 TEST_F(MultipartTest, TestErrorHeaderValue) 220 { 221 std::string_view body = 222 "-----------------------------d74496d66958873e\r\n" 223 "Content-Disposition: form-data; name=\"Test1\"\r" 224 "{\"Key1\": 112233}\r\n" 225 "-----------------------------d74496d66958873e\r\n" 226 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 227 "123456\r\n" 228 "-----------------------------d74496d66958873e--\r\n"; 229 230 crow::Request reqIn(body, ec); 231 232 reqIn.addHeader("Content-Type", 233 "multipart/form-data; " 234 "boundary=---------------------------d74496d66958873e"); 235 236 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_VALUE); 237 } 238 239 TEST_F(MultipartTest, TestErrorHeaderEnding) 240 { 241 std::string_view body = 242 "-----------------------------d74496d66958873e\r\n" 243 "Content-Disposition: form-data; name=\"Test1\"\r\n\r" 244 "{\"Key1\": 112233}\r\n" 245 "-----------------------------d74496d66958873e\r\n" 246 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 247 "123456\r\n" 248 "-----------------------------d74496d66958873e--\r\n"; 249 250 crow::Request reqIn(body, ec); 251 252 reqIn.addHeader("Content-Type", 253 "multipart/form-data; " 254 "boundary=---------------------------d74496d66958873e"); 255 256 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_HEADER_ENDING); 257 } 258 259 TEST_F(MultipartTest, TestGoodMultipartParserMultipleHeaders) 260 { 261 std::string_view body = 262 "-----------------------------d74496d66958873e\r\n" 263 "Content-Disposition: form-data; name=\"Test1\"\r\n" 264 "Other-Header: value=\"v1\"\r\n" 265 "\r\n" 266 "Data1\r\n" 267 "-----------------------------d74496d66958873e--"; 268 269 crow::Request reqIn(body, ec); 270 271 reqIn.addHeader("Content-Type", 272 "multipart/form-data; " 273 "boundary=---------------------------d74496d66958873e"); 274 275 ParserError rc = parser.parse(reqIn); 276 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); 277 278 EXPECT_EQ(parser.boundary, 279 "\r\n-----------------------------d74496d66958873e"); 280 ASSERT_EQ(parser.mime_fields.size(), 1); 281 282 EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"), 283 "form-data; name=\"Test1\""); 284 EXPECT_EQ(parser.mime_fields[0].fields.at("Other-Header"), "value=\"v1\""); 285 EXPECT_EQ(parser.mime_fields[0].content, "Data1"); 286 } 287 288 TEST_F(MultipartTest, TestErrorHeaderWithoutColon) 289 { 290 std::string_view body = 291 "----end\r\n" 292 "abc\r\n" 293 "\r\n" 294 "Data1\r\n" 295 "----end--\r\n"; 296 crow::Request reqIn(body, ec); 297 298 reqIn.addHeader("Content-Type", "multipart/form-data; " 299 "boundary=--end"); 300 301 EXPECT_EQ(parser.parse(reqIn), ParserError::ERROR_UNEXPECTED_END_OF_HEADER); 302 } 303 304 TEST_F(MultipartTest, TestUnknownHeaderIsCorrectlyParsed) 305 { 306 std::string_view body = 307 "----end\r\n" 308 "t-DiPpcccc:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccgcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa\r\n" 309 "\r\n" 310 "Data1\r\n" 311 "----end--\r\n"; 312 313 crow::Request reqIn(body, ec); 314 315 reqIn.addHeader("Content-Type", "multipart/form-data; " 316 "boundary=--end"); 317 ParserError rc = parser.parse(reqIn); 318 319 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); 320 321 EXPECT_EQ(parser.boundary, "\r\n----end"); 322 ASSERT_EQ(parser.mime_fields.size(), 1); 323 324 EXPECT_EQ( 325 parser.mime_fields[0].fields.at("t-DiPpcccc"), 326 "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccgcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa"); 327 EXPECT_EQ(parser.mime_fields[0].content, "Data1"); 328 } 329 330 TEST_F(MultipartTest, TestErrorMissingSeparatorBetweenMimeFieldsAndData) 331 { 332 std::string_view body = 333 "-----------------------------d74496d66958873e\r\n" 334 "t-DiPpcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccgcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa\r\n" 335 "Data1" 336 "-----------------------------d74496d66958873e--"; 337 338 crow::Request reqIn(body, ec); 339 340 reqIn.addHeader( 341 "Content-Type", 342 "multipart/form-data; boundary=---------------------------d74496d66958873e"); 343 344 ParserError rc = parser.parse(reqIn); 345 346 EXPECT_EQ(rc, ParserError::ERROR_UNEXPECTED_END_OF_HEADER); 347 } 348 349 TEST_F(MultipartTest, TestDataWithoutMimeFields) 350 { 351 std::string_view body = 352 "-----------------------------d74496d66958873e\r\n" 353 "\r\n" 354 "Data1\r\n" 355 "-----------------------------d74496d66958873e--"; 356 357 crow::Request reqIn(body, ec); 358 359 reqIn.addHeader( 360 "Content-Type", 361 "multipart/form-data; boundary=---------------------------d74496d66958873e"); 362 363 ParserError rc = parser.parse(reqIn); 364 365 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); 366 367 EXPECT_EQ(parser.boundary, 368 "\r\n-----------------------------d74496d66958873e"); 369 ASSERT_EQ(parser.mime_fields.size(), 1); 370 371 EXPECT_EQ(std::distance(parser.mime_fields[0].fields.begin(), 372 parser.mime_fields[0].fields.end()), 373 0); 374 EXPECT_EQ(parser.mime_fields[0].content, "Data1"); 375 } 376 377 TEST_F(MultipartTest, TestErrorMissingFinalBoundry) 378 { 379 std::string_view body = 380 "----XX\r\n" 381 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 382 "t-DiPpccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccAAAAAAAAAAAAAAABCDz\r\n" 383 "\335\r\n\r\n"; 384 385 crow::Request reqIn(body, ec); 386 387 reqIn.addHeader("Content-Type", "multipart/form-data; boundary=--XX"); 388 389 ParserError rc = parser.parse(reqIn); 390 391 EXPECT_EQ(rc, ParserError::ERROR_UNEXPECTED_END_OF_INPUT); 392 } 393 394 TEST_F(MultipartTest, TestIgnoreDataAfterFinalBoundary) 395 { 396 std::string_view body = 397 "----XX\r\n" 398 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" 399 "Data1\r\n" 400 "----XX--\r\n" 401 "Content-Disposition: form-data; name=\"Test2\"\r\n\r\n" 402 "Data2\r\n" 403 "----XX--\r\n"; 404 405 crow::Request reqIn(body, ec); 406 407 reqIn.addHeader("Content-Type", "multipart/form-data; boundary=--XX"); 408 409 ParserError rc = parser.parse(reqIn); 410 411 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); 412 413 EXPECT_EQ(parser.boundary, "\r\n----XX"); 414 EXPECT_EQ(parser.mime_fields.size(), 1); 415 416 EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"), 417 "form-data; name=\"Test1\""); 418 EXPECT_EQ(parser.mime_fields[0].content, "Data1"); 419 } 420 421 TEST_F(MultipartTest, TestFinalBoundaryIsCorrectlyRecognized) 422 { 423 std::string_view body = 424 "----XX\r\n" 425 "Content-Disposition: form-data; name=\"Test1\"\r\n\r\n" 426 "Data1\r\n" 427 "----XX-abc-\r\n" 428 "StillData1\r\n" 429 "----XX--\r\n"; 430 431 crow::Request reqIn(body, ec); 432 433 reqIn.addHeader("Content-Type", "multipart/form-data; boundary=--XX"); 434 435 ParserError rc = parser.parse(reqIn); 436 437 ASSERT_EQ(rc, ParserError::PARSER_SUCCESS); 438 439 EXPECT_EQ(parser.boundary, "\r\n----XX"); 440 EXPECT_EQ(parser.mime_fields.size(), 1); 441 442 EXPECT_EQ(parser.mime_fields[0].fields.at("Content-Disposition"), 443 "form-data; name=\"Test1\""); 444 EXPECT_EQ(parser.mime_fields[0].content, 445 "Data1\r\n" 446 "----XX-abc-\r\n" 447 "StillData1"); 448 } 449 450 } // namespace 451