Skip to content

Commit 0484071

Browse files
authored
Merge pull request #99 from BennyFranciscus/fix/bad-method-validation
fix(nginx,h2o): reject unknown HTTP methods with 405
2 parents 5834b16 + e7b5a19 commit 0484071

3 files changed

Lines changed: 52 additions & 1 deletion

File tree

frameworks/h2o/src/main.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,33 @@ static int64_t sum_query_values(h2o_req_t *req)
5757
return sum;
5858
}
5959

60+
/* Method check helper — returns true if method is not GET/HEAD/POST */
61+
static inline int reject_bad_method(h2o_req_t *req)
62+
{
63+
if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET"))
64+
|| h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD"))
65+
|| h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST"))) {
66+
return 0;
67+
}
68+
req->res.status = 405;
69+
req->res.reason = "Method Not Allowed";
70+
req->res.content_length = 18;
71+
h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE,
72+
NULL, H2O_STRLIT("text/plain"));
73+
h2o_generator_t gen;
74+
memset(&gen, 0, sizeof(gen));
75+
h2o_iovec_t body = {H2O_STRLIT("Method Not Allowed")};
76+
h2o_start_response(req, &gen);
77+
h2o_send(req, &body, 1, H2O_SEND_STATE_FINAL);
78+
return 1;
79+
}
80+
6081
/* GET /pipeline — return "ok" (zero-copy static response) */
6182
static int on_pipeline(h2o_handler_t *h, h2o_req_t *req)
6283
{
6384
static h2o_iovec_t body = {H2O_STRLIT("ok")};
6485
(void)h;
86+
if (reject_bad_method(req)) return 0;
6587
h2o_generator_t gen;
6688
memset(&gen, 0, sizeof(gen));
6789
req->res.status = 200;
@@ -78,6 +100,7 @@ static int on_pipeline(h2o_handler_t *h, h2o_req_t *req)
78100
static int on_baseline11(h2o_handler_t *h, h2o_req_t *req)
79101
{
80102
(void)h;
103+
if (reject_bad_method(req)) return 0;
81104
int64_t sum = sum_query_values(req);
82105
if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST"))
83106
&& req->entity.len > 0) {
@@ -107,6 +130,7 @@ static int on_baseline11(h2o_handler_t *h, h2o_req_t *req)
107130
static int on_baseline2(h2o_handler_t *h, h2o_req_t *req)
108131
{
109132
(void)h;
133+
if (reject_bad_method(req)) return 0;
110134
int64_t sum = sum_query_values(req);
111135
char buf[32];
112136
int len = snprintf(buf, sizeof(buf), "%lld", (long long)sum);
@@ -127,6 +151,7 @@ static int on_baseline2(h2o_handler_t *h, h2o_req_t *req)
127151
static int on_json(h2o_handler_t *h, h2o_req_t *req)
128152
{
129153
(void)h;
154+
if (reject_bad_method(req)) return 0;
130155
if (!dataset_tree) {
131156
h2o_send_error_500(req, "Error", "No dataset", 0);
132157
return 0;
@@ -246,6 +271,7 @@ static int on_json(h2o_handler_t *h, h2o_req_t *req)
246271
static int on_static(h2o_handler_t *h, h2o_req_t *req)
247272
{
248273
(void)h;
274+
if (reject_bad_method(req)) return 0;
249275
/* path is /static/<filename>, extract filename after "/static/" (8 chars) */
250276
if (req->path_normalized.len <= 8) {
251277
h2o_send_error_404(req, "Not Found", "Not Found", 0);
@@ -302,6 +328,7 @@ static int on_upload(h2o_handler_t *h, h2o_req_t *req)
302328
static int on_compression(h2o_handler_t *h, h2o_req_t *req)
303329
{
304330
(void)h;
331+
if (reject_bad_method(req)) return 0;
305332
if (!json_large_response) {
306333
h2o_send_error_500(req, "Error", "No dataset", 0);
307334
return 0;
@@ -352,6 +379,7 @@ static void load_db_thread(void)
352379
static int on_db(h2o_handler_t *h, h2o_req_t *req)
353380
{
354381
(void)h;
382+
if (reject_bad_method(req)) return 0;
355383
if (!tl_db || !tl_db_stmt) {
356384
h2o_send_error_500(req, "Error", "DB not loaded", 0);
357385
return 0;

frameworks/nginx-openresty/nginx.conf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ http {
3535
server {
3636
listen 8080 reuseport;
3737

38+
# Reject unknown HTTP methods — only allow GET, HEAD, POST
39+
access_by_lua_block {
40+
local m = ngx.req.get_method()
41+
if m ~= "GET" and m ~= "HEAD" and m ~= "POST" then
42+
ngx.status = 405
43+
ngx.header["Content-Type"] = "text/plain"
44+
ngx.say("Method Not Allowed")
45+
return ngx.exit(405)
46+
end
47+
}
48+
3849
location /pipeline { content_by_lua_block { require("handler").pipeline() } }
3950
location /baseline11 { content_by_lua_block { require("handler").baseline11() } }
4051
location /baseline2 { content_by_lua_block { require("handler").baseline2() } }

frameworks/nginx/ngx_http_httparena_module.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,14 @@ ngx_http_httparena_handler(ngx_http_request_t *r)
317317
u_char *uri = r->uri.data;
318318
size_t uri_len = r->uri.len;
319319

320+
/* Reject unknown HTTP methods — only allow GET, HEAD, POST */
321+
if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_POST | NGX_HTTP_HEAD))) {
322+
ngx_http_discard_request_body(r);
323+
return send_resp(r, 405,
324+
(u_char *)"text/plain", 10,
325+
(u_char *)"Method Not Allowed", 18, 1);
326+
}
327+
320328
/* /db */
321329
if (uri_len == 3 && ngx_strncmp(uri, "/db", 3) == 0) {
322330
return on_db(r);
@@ -435,7 +443,11 @@ ngx_http_httparena_handler(ngx_http_request_t *r)
435443
(u_char *)"Not Found", 9, 0);
436444
}
437445

438-
return NGX_DECLINED;
446+
/* Unknown path — return 404 instead of falling through to nginx default */
447+
ngx_http_discard_request_body(r);
448+
return send_resp(r, 404,
449+
(u_char *)"text/plain", 10,
450+
(u_char *)"Not Found", 9, 1);
439451
}
440452

441453
/* ---------- Data loading ---------- */

0 commit comments

Comments
 (0)