1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-12 14:14:48 +02:00

relay/api: return HTTP error 405 (Method Not Allowed) when the method received is not allowed

This commit is contained in:
Sébastien Helleu
2025-06-23 18:51:02 +02:00
parent cd0486d5bb
commit 93ec10b563
5 changed files with 75 additions and 8 deletions
+1
View File
@@ -15,6 +15,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
- core: write configuration files on disk only if there are changes ([#2250](https://github.com/weechat/weechat/issues/2250))
- core: always enable partial completion for templates in option weechat.completion.partial_completion_templates, add option weechat.completion.partial_completion_auto_expand to expand word on new completion ([#2253](https://github.com/weechat/weechat/issues/2253))
- core: add script name in output of `/debug hooks <plugin>`
- relay/api: return HTTP error 405 (Method Not Allowed) when the method received is not allowed
### Added
+29 -8
View File
@@ -374,7 +374,7 @@ RELAY_API_PROTOCOL_CALLBACK(options)
relay_api_msg_send_json (
client,
RELAY_HTTP_204_NO_CONTENT,
"Access-Control-Allow-Methods: GET, POST, PUT, DELETE\r\n"
"Access-Control-Allow-Methods: " RELAY_API_ALLOWED_METHODS "\r\n"
"Access-Control-Allow-Headers: origin, content-type, accept, authorization",
NULL, /* body_type */
NULL); /* json_body */
@@ -1197,7 +1197,7 @@ relay_api_protocol_recv_json (struct t_relay_client *client, const char *json)
void
relay_api_protocol_recv_http (struct t_relay_client *client)
{
int i, num_args;
int i, num_args, match_method, match_resource;
char str_error[1024];
enum t_relay_api_protocol_rc return_code;
struct t_relay_api_protocol_cb protocol_cb[] = {
@@ -1238,18 +1238,22 @@ relay_api_protocol_recv_http (struct t_relay_client *client)
|| !client->http_req->path_items[1]
|| (strcmp (client->http_req->path_items[0], "api") != 0))
{
goto error_not_found;
goto resource_not_found;
}
num_args = client->http_req->num_path_items - 2;
for (i = 0; protocol_cb[i].resource; i++)
{
if (strcmp (protocol_cb[i].method, client->http_req->method) != 0)
continue;
match_method = (strcmp (protocol_cb[i].method, client->http_req->method) == 0);
if ((strcmp (protocol_cb[i].resource, "*") != 0)
&& (strcmp (protocol_cb[i].resource, client->http_req->path_items[1]) != 0))
match_resource = ((strcmp (protocol_cb[i].resource, "*") == 0)
|| (strcmp (protocol_cb[i].resource, client->http_req->path_items[1]) == 0));
if (!match_method && (strcmp (protocol_cb[i].resource, "*") != 0) && match_resource)
goto error_method_not_allowed;
if (!match_method || !match_resource)
continue;
if (protocol_cb[i].auth_required
@@ -1331,7 +1335,18 @@ relay_api_protocol_recv_http (struct t_relay_client *client)
}
}
goto error_not_found;
resource_not_found:
if ((strcmp (client->http_req->method, "GET") != 0)
&& (strcmp (client->http_req->method, "POST") != 0)
&& (strcmp (client->http_req->method, "PUT") != 0)
&& (strcmp (client->http_req->method, "DELETE") != 0))
{
goto error_method_not_allowed;
}
else
{
goto error_not_found;
}
error_bad_request:
relay_api_msg_send_error_json (client, RELAY_HTTP_400_BAD_REQUEST,
@@ -1343,6 +1358,12 @@ error_not_found:
NULL, RELAY_HTTP_ERROR_NOT_FOUND);
goto error;
error_method_not_allowed:
relay_api_msg_send_error_json (client, RELAY_HTTP_405_METHOD_NOT_ALLOWED,
"Allow: " RELAY_API_ALLOWED_METHODS,
RELAY_HTTP_ERROR_METHOD_NOT_ALLOWED);
goto error;
error_memory:
relay_api_msg_send_error_json (client, RELAY_HTTP_503_SERVICE_UNAVAILABLE,
NULL, RELAY_HTTP_ERROR_OUT_OF_MEMORY);
@@ -22,6 +22,8 @@
#ifndef WEECHAT_PLUGIN_RELAY_API_PROTOCOL_H
#define WEECHAT_PLUGIN_RELAY_API_PROTOCOL_H
#define RELAY_API_ALLOWED_METHODS "GET, POST, PUT, DELETE"
#define RELAY_API_CB(__command) &relay_api_protocol_cb_##__command
#define RELAY_API_PROTOCOL_CALLBACK(__command) \
enum t_relay_api_protocol_rc \
+2
View File
@@ -40,6 +40,7 @@ enum t_relay_client_http_status
#define RELAY_HTTP_401_UNAUTHORIZED 401, "Unauthorized"
#define RELAY_HTTP_403_FORBIDDEN 403, "Forbidden"
#define RELAY_HTTP_404_NOT_FOUND 404, "Not Found"
#define RELAY_HTTP_405_METHOD_NOT_ALLOWED 405, "Method Not Allowed"
#define RELAY_HTTP_500_INTERNAL_SERVER_ERROR 500, "Internal Server Error"
#define RELAY_HTTP_503_SERVICE_UNAVAILABLE 503, "Service Unavailable"
@@ -53,6 +54,7 @@ enum t_relay_client_http_status
#define RELAY_HTTP_ERROR_INVALID_ITERATIONS "Invalid number of iterations"
#define RELAY_HTTP_ERROR_BAD_REQUEST "Bad request"
#define RELAY_HTTP_ERROR_NOT_FOUND "Resource not found"
#define RELAY_HTTP_ERROR_METHOD_NOT_ALLOWED "Method Not Allowed"
#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory"
struct t_relay_http_request
@@ -1052,3 +1052,44 @@ TEST(RelayApiProtocolWithClient, RecvHttpInvalidPassword)
"{\"error\":\"Invalid password\"}",
data_sent[0]);
}
/*
* Tests functions:
* relay_api_protocol_recv_http (method not allowed)
*/
TEST(RelayApiProtocolWithClient, RecvHttpMethodNotAllowed)
{
/* method not allowed (PATCH) with existing resource (/api/ping) */
test_client_recv_http ("PATCH /api/ping", NULL, "{\"data\": \"abcdef\"}");
STRCMP_EQUAL("HTTP/1.1 405 Method Not Allowed\r\n"
"Allow: GET, POST, PUT, DELETE\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json; charset=utf-8\r\n"
"Content-Length: 30\r\n"
"\r\n"
"{\"error\":\"Method Not Allowed\"}",
data_sent[0]);
/* method not allowed (PATCH) with unknown resource (/api/unknown) */
test_client_recv_http ("PATCH /api/unknown", NULL, "{\"data\": \"abcdef\"}");
STRCMP_EQUAL("HTTP/1.1 405 Method Not Allowed\r\n"
"Allow: GET, POST, PUT, DELETE\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json; charset=utf-8\r\n"
"Content-Length: 30\r\n"
"\r\n"
"{\"error\":\"Method Not Allowed\"}",
data_sent[0]);
/* method not allowed (PATCH) with unknown resource (/unknown) */
test_client_recv_http ("PATCH /unknown", NULL, "{\"data\": \"abcdef\"}");
STRCMP_EQUAL("HTTP/1.1 405 Method Not Allowed\r\n"
"Allow: GET, POST, PUT, DELETE\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: application/json; charset=utf-8\r\n"
"Content-Length: 30\r\n"
"\r\n"
"{\"error\":\"Method Not Allowed\"}",
data_sent[0]);
}