|
7 | 7 | // Official repository: https://github.com/cppalliance/http |
8 | 8 | // |
9 | 9 |
|
10 | | -#include "src/server/detail/any_router.hpp" |
| 10 | +#include "src/server/detail/router_base.hpp" |
11 | 11 | #include <boost/http/server/detail/router_base.hpp> |
12 | 12 | #include <boost/http/detail/except.hpp> |
13 | 13 | #include <boost/http/error.hpp> |
| 14 | +#include <boost/http/field.hpp> |
| 15 | +#include <boost/http/status.hpp> |
14 | 16 | #include <boost/url/grammar/ci_string.hpp> |
15 | 17 | #include <boost/url/grammar/hexdig_chars.hpp> |
16 | 18 | #include "src/server/detail/pct_decode.hpp" |
@@ -206,8 +208,8 @@ dispatch_loop(route_params& p, bool is_options) const |
206 | 208 | std::size_t last_matched = SIZE_MAX; |
207 | 209 | std::uint32_t current_depth = 0; |
208 | 210 |
|
209 | | - std::uint64_t options_methods = 0; |
210 | | - std::vector<std::string> options_custom_verbs; |
| 211 | + std::uint64_t matched_methods = 0; |
| 212 | + std::vector<std::string> matched_custom_verbs; |
211 | 213 |
|
212 | 214 | std::size_t path_stack[router_base::max_path_depth]; |
213 | 215 | path_stack[0] = 0; |
@@ -286,12 +288,12 @@ dispatch_loop(route_params& p, bool is_options) const |
286 | 288 | if(!ancestors_ok) |
287 | 289 | continue; |
288 | 290 |
|
289 | | - // Collect methods from matching end-route matchers for OPTIONS |
290 | | - if(is_options && m.end_) |
| 291 | + // Collect methods from matching end-route matchers |
| 292 | + if(m.end_) |
291 | 293 | { |
292 | | - options_methods |= m.allowed_methods_; |
| 294 | + matched_methods |= m.allowed_methods_; |
293 | 295 | for(auto const& v : m.custom_verbs_) |
294 | | - options_custom_verbs.push_back(v); |
| 296 | + matched_custom_verbs.push_back(v); |
295 | 297 | } |
296 | 298 |
|
297 | 299 | if(m.end_ && !e.match_method( |
@@ -364,12 +366,23 @@ dispatch_loop(route_params& p, bool is_options) const |
364 | 366 | co_return route_error(pv.ec_); |
365 | 367 |
|
366 | 368 | // OPTIONS fallback |
367 | | - if(is_options && options_methods != 0 && options_handler_) |
| 369 | + if(is_options && matched_methods != 0 && options_handler_) |
368 | 370 | { |
369 | | - std::string allow = build_allow_header(options_methods, options_custom_verbs); |
| 371 | + std::string allow = build_allow_header(matched_methods, matched_custom_verbs); |
370 | 372 | co_return co_await options_handler_->invoke(p, allow); |
371 | 373 | } |
372 | 374 |
|
| 375 | + // 405 fallback: path matched but method didn't |
| 376 | + if(!is_options && |
| 377 | + (matched_methods != 0 || !matched_custom_verbs.empty())) |
| 378 | + { |
| 379 | + std::string allow = build_allow_header(matched_methods, matched_custom_verbs); |
| 380 | + p.res.set(field::allow, allow); |
| 381 | + p.res.set_status(status::method_not_allowed); |
| 382 | + (void)(co_await p.send()); |
| 383 | + co_return route_done; |
| 384 | + } |
| 385 | + |
373 | 386 | co_return route_next; |
374 | 387 | } |
375 | 388 |
|
|
0 commit comments