|
|
@@ -1812,8 +1812,8 @@ private:
|
|
|
const std::string &etag, time_t mtime) const;
|
|
|
bool check_if_range(Request &req, const std::string &etag,
|
|
|
time_t mtime) const;
|
|
|
- bool dispatch_request(Request &req, Response &res,
|
|
|
- const Handlers &handlers) const;
|
|
|
+ bool dispatch_request(Request &req, Response &res, const Handlers &handlers,
|
|
|
+ Stream &strm);
|
|
|
bool dispatch_request_for_content_reader(
|
|
|
Request &req, Response &res, ContentReader content_reader,
|
|
|
const HandlersForContentReader &handlers) const;
|
|
|
@@ -11955,26 +11955,26 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Read content into `req.body`
|
|
|
- if (!read_content(strm, req, res)) {
|
|
|
- output_error_log(Error::Read, &req);
|
|
|
- return false;
|
|
|
- }
|
|
|
+ // NOTE: `req.body` is not read here. For a regular handler the body is
|
|
|
+ // read inside dispatch_request(), after the route has matched and the
|
|
|
+ // pre-request handler has approved the request, so that a rejected
|
|
|
+ // request (e.g. failed authentication) never forces us to buffer a
|
|
|
+ // potentially large body.
|
|
|
}
|
|
|
|
|
|
// Regular handler
|
|
|
if (req.method == "GET" || req.method == "HEAD") {
|
|
|
- return dispatch_request(req, res, get_handlers_);
|
|
|
+ return dispatch_request(req, res, get_handlers_, strm);
|
|
|
} else if (req.method == "POST") {
|
|
|
- return dispatch_request(req, res, post_handlers_);
|
|
|
+ return dispatch_request(req, res, post_handlers_, strm);
|
|
|
} else if (req.method == "PUT") {
|
|
|
- return dispatch_request(req, res, put_handlers_);
|
|
|
+ return dispatch_request(req, res, put_handlers_, strm);
|
|
|
} else if (req.method == "DELETE") {
|
|
|
- return dispatch_request(req, res, delete_handlers_);
|
|
|
+ return dispatch_request(req, res, delete_handlers_, strm);
|
|
|
} else if (req.method == "OPTIONS") {
|
|
|
- return dispatch_request(req, res, options_handlers_);
|
|
|
+ return dispatch_request(req, res, options_handlers_, strm);
|
|
|
} else if (req.method == "PATCH") {
|
|
|
- return dispatch_request(req, res, patch_handlers_);
|
|
|
+ return dispatch_request(req, res, patch_handlers_, strm);
|
|
|
}
|
|
|
|
|
|
res.status = StatusCode::BadRequest_400;
|
|
|
@@ -11982,17 +11982,29 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) {
|
|
|
}
|
|
|
|
|
|
inline bool Server::dispatch_request(Request &req, Response &res,
|
|
|
- const Handlers &handlers) const {
|
|
|
+ const Handlers &handlers, Stream &strm) {
|
|
|
for (const auto &x : handlers) {
|
|
|
const auto &matcher = x.first;
|
|
|
const auto &handler = x.second;
|
|
|
|
|
|
if (matcher->match(req)) {
|
|
|
req.matched_route = matcher->pattern();
|
|
|
- if (!pre_request_handler_ ||
|
|
|
- pre_request_handler_(req, res) != HandlerResponse::Handled) {
|
|
|
- handler(req, res);
|
|
|
+
|
|
|
+ // Run the pre-request handler before reading the body so a rejected
|
|
|
+ // request (e.g. failed authentication) never forces us to buffer a
|
|
|
+ // potentially large body. `req.matched_route` is available here.
|
|
|
+ if (pre_request_handler_ &&
|
|
|
+ pre_request_handler_(req, res) == HandlerResponse::Handled) {
|
|
|
+ return true;
|
|
|
}
|
|
|
+
|
|
|
+ // The route matched and the request was approved; read the body now.
|
|
|
+ if (detail::expect_content(req) && !read_content(strm, req, res)) {
|
|
|
+ output_error_log(Error::Read, &req);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ handler(req, res);
|
|
|
return true;
|
|
|
}
|
|
|
}
|