Unverified Commit 4355267e authored by Dennis Jenkins's avatar Dennis Jenkins Committed by GitHub

Merge pull request #536 from dmorton-spirent/http-code-405

Add support for HTTP 405 responses from the REST server
parents 86a3e712 312dbfd0
......@@ -486,6 +486,12 @@ public:
* - movedPermantly -> 301
* - moved() -> 302
*/
Async::Promise<ssize_t> sendMethodNotAllowed(const std::vector<Http::Method>& supportedMethods) {
code_ = Http::Code::Method_Not_Allowed;
headers_.add(std::make_shared<Http::Header::Allow>(supportedMethods));
std::string body = codeString(Pistache::Http::Code::Method_Not_Allowed);
return putOnWire(body.c_str(), body.size());
}
Async::Promise<ssize_t> send(Code code) {
code_ = code;
......
......@@ -70,7 +70,7 @@ class Request;
struct Route {
enum class Result { Ok, Failure };
enum class Status { Match, NotFound };
enum class Status { Match, NotFound, NotAllowed };
typedef std::function<Result(const Request, Http::ResponseWriter)> Handler;
......
......@@ -441,6 +441,29 @@ Router::route(const Http::Request& req, Http::ResponseWriter response) {
if (handler1 == Route::Result::Ok) return Route::Status::Match;
}
//No route or custom handler found. Let's walk through the
// list of other methods and see if any of them support
// this resource.
//This will allow server to send a
// HTTP 405 (method not allowed) response.
//RFC 7231 requires HTTP 405 responses to include a list of
// supported methods for the requested resource.
std::vector<Http::Method> supportedMethods;
for (auto& methods: routes) {
if (methods.first == req.method()) continue;
auto res = methods.second.findRoute(path);
auto rte = std::get<0>(res);
if (rte != nullptr) {
supportedMethods.push_back(methods.first);
}
}
if (!supportedMethods.empty()) {
response.sendMethodNotAllowed(supportedMethods);
return Route::Status::NotAllowed;
}
if (hasNotFoundHandler()) {
invokeNotFoundHandler(req, std::move(response));
} else {
......
......@@ -81,3 +81,41 @@ TEST(rest_server_test, basic_test) {
stats.shutdown();
}
TEST(rest_server_test, response_status_code_test) {
int thr = 1;
Address addr(Ipv4::any(), Port(0));
StatsEndpoint stats(addr);
stats.init(thr);
stats.start();
Port port = stats.getPort();
cout << "Cores = " << hardware_concurrency() << endl;
cout << "Using " << thr << " threads" << endl;
cout << "Port = " << port << endl;
httplib::Client client("localhost", port);
//Code 404 - Not Found.
auto res = client.Get("/read/does_not_exist");
EXPECT_EQ(res->status, 404);
EXPECT_EQ(res->body, "Could not find a matching route");
//Code 405 - Method Not Allowed.
std::string body("body goes here");
res = client.Post("/read/function1", body, "text/plain");
EXPECT_EQ(res->status, 405);
EXPECT_EQ(res->body, "Method Not Allowed");
ASSERT_TRUE(res->has_header("Allow"));
EXPECT_EQ(res->get_header_value("Allow"), "GET");
//Code 415 - Unknown Media Type
res = client.Post("/read/function1", body, "invalid");
EXPECT_EQ(res->status, 415);
EXPECT_EQ(res->body, "Unknown Media Type");
stats.shutdown();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment