Skip to content

Commit c10c20c

Browse files
authored
Merge pull request #931 from Iuliean/master
"crow::multipart::message throws when the boundary is empty or malformed
2 parents bd61a7d + 45a59c5 commit c10c20c

File tree

5 files changed

+79
-3
lines changed

5 files changed

+79
-3
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ if(CROW_AMALGAMATE)
101101
include/crow/ci_map.h
102102
include/crow/common.h
103103
include/crow/compression.h
104+
include/crow/exceptions.h
104105
include/crow/http_connection.h
105106
include/crow/http_parser_merged.h
106107
include/crow/http_request.h

include/crow/exceptions.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
#include <stdexcept>
3+
4+
namespace crow
5+
{
6+
struct bad_request : public std::runtime_error
7+
{
8+
bad_request(const std::string& what_arg)
9+
: std::runtime_error(what_arg) {}
10+
11+
bad_request(const char* what_arg)
12+
: std::runtime_error(what_arg) {}
13+
};
14+
}

include/crow/multipart.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "crow/http_request.h"
88
#include "crow/returnable.h"
99
#include "crow/ci_map.h"
10+
#include "crow/exceptions.h"
1011

1112
namespace crow
1213
{
@@ -147,8 +148,14 @@ namespace crow
147148
boundary(get_boundary(get_header_value("Content-Type")))
148149
{
149150
if (!boundary.empty())
151+
{
150152
content_type = "multipart/form-data; boundary=" + boundary;
151-
parse_body(req.body);
153+
parse_body(req.body);
154+
}
155+
else
156+
{
157+
throw bad_request("Empty boundary in multipart message");
158+
}
152159
}
153160

154161
private:
@@ -178,8 +185,8 @@ namespace crow
178185
size_t found = body.find(delimiter);
179186
if (found == std::string::npos)
180187
{
181-
// did not find delimiter; probably an ill-formed body; ignore the rest
182-
break;
188+
// did not find delimiter; probably an ill-formed body; throw to indicate the issue to user
189+
throw bad_request("Unable to find delimiter in multipart message. Probably ill-formed body");
183190
}
184191
std::string section = body.substr(0, found);
185192

include/crow/routing.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "crow/http_request.h"
1515
#include "crow/utility.h"
1616
#include "crow/logging.h"
17+
#include "crow/exceptions.h"
1718
#include "crow/websocket.h"
1819
#include "crow/mustache.h"
1920
#include "crow/middleware.h"
@@ -1813,6 +1814,11 @@ namespace crow // NOTE: Already documented in "crow/app.h"
18131814
{
18141815
throw;
18151816
}
1817+
catch (const bad_request& e)
1818+
{
1819+
res = response (400);
1820+
res.body = e.what();
1821+
}
18161822
catch (const std::exception& e)
18171823
{
18181824
CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what();

tests/unittest.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2510,6 +2510,54 @@ TEST_CASE("multipart")
25102510

25112511
CHECK(test_string == res.body);
25122512
}
2513+
2514+
//Test against empty boundary
2515+
{
2516+
request req;
2517+
response res;
2518+
req.url = "/multipart";
2519+
req.add_header("Content-Type", "multipart/form-data; boundary=");
2520+
req.body = test_string;
2521+
2522+
app.handle_full(req, res);
2523+
2524+
CHECK(res.code == 400);
2525+
CHECK(res.body == "Empty boundary in multipart message");
2526+
2527+
}
2528+
2529+
//Boundary that differs from actual boundary
2530+
{
2531+
const char alphabet[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
2532+
std::random_device dev;
2533+
std::mt19937 rng(dev());
2534+
std::uniform_int_distribution<std::mt19937::result_type> dist(0, sizeof(alphabet) - 2);
2535+
std::uniform_int_distribution<std::mt19937::result_type> boundary_sizes(1, 50);
2536+
std::array<std::string, 100> test_boundaries;
2537+
2538+
for (auto& boundary : test_boundaries)
2539+
{
2540+
const size_t boundary_size = boundary_sizes(rng);
2541+
boundary.reserve(boundary_size);
2542+
for (size_t idx = 0; idx < boundary_size; idx++)
2543+
boundary.push_back(alphabet[dist(rng)]);
2544+
}
2545+
2546+
for (const auto& boundary : test_boundaries)
2547+
{
2548+
request req;
2549+
response res;
2550+
2551+
req.url = "/multipart";
2552+
req.add_header("Content-Type", "multipart/form-data; boundary=" + boundary);
2553+
req.body = test_string;
2554+
2555+
app.handle_full(req, res);
2556+
2557+
CHECK(res.code == 400);
2558+
CHECK(res.body == "Unable to find delimiter in multipart message. Probably ill-formed body");
2559+
}
2560+
}
25132561
} // multipart
25142562

25152563
TEST_CASE("multipart_view")

0 commit comments

Comments
 (0)