Skip to content

Commit

Permalink
Content-Lenth and Content-Type in bodyless message
Browse files Browse the repository at this point in the history
RFC 9110 8.6:
A server MUST NOT send a Content-Length header field in
any response with a status code of 1xx (Informational)
or 204 (No Content).

Now for responses 1xx and 204 Tempesta FW treats
`Content-Length: 0` as the absence of a Content-Length
header. Some implementations send `Content-Length: 0`
within 204 (No Content) response, to be able to process
such messages the rule from RFC 9110 8.6 has been
relaxed.

For requests with bodyless methods such as HEAD, GET,
etc. Tempesta also treats `Content-Length: 0` as empty
body and considers such requests as valid.

Added directive `allow_empty_body_content_type` that
allows Tempesta FW to process requests with bodyless
methods. By default Tempesta FW drops such requests.
  • Loading branch information
const-t committed Feb 11, 2025
1 parent cc8e43c commit 3ea6f8b
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 16 deletions.
12 changes: 12 additions & 0 deletions etc/tempesta_fw.conf
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,18 @@
# http_max_header_list_size 4096;
#

# TAG: allow_empty_body_content_type
#
# This directive controls whether HTTP requests are allowed to include
# a Content-Type header even when the message body is empty.
#
# Syntax:
# allow_empty_body_content_type true|false
#
# Example:
# allow_empty_body_content_type true;
#

#
# Health monitoring configuration.
#
Expand Down
16 changes: 16 additions & 0 deletions fw/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ static struct {
* here, because it refers to HTTP layer.
*/
unsigned int max_header_list_size = 0;
bool allow_empty_body_content_type;

#define S_CRLFCRLF "\r\n\r\n"
#define S_HTTP "http://"
Expand Down Expand Up @@ -7904,6 +7905,12 @@ tfw_cfgop_cleanup_max_header_list_size(TfwCfgSpec *cs)
max_header_list_size = 0;
}

static void
tfw_cfgop_cleanup_allow_empty_body_content_type(TfwCfgSpec *cs)
{
allow_empty_body_content_type = false;
}

static TfwCfgSpec tfw_http_specs[] = {
{
.name = "block_action",
Expand Down Expand Up @@ -7991,6 +7998,15 @@ static TfwCfgSpec tfw_http_specs[] = {
.allow_none = true,
.cleanup = tfw_cfgop_cleanup_max_header_list_size,
},
{
.name = "http_allow_empty_body_content_type",
.deflt = "false",
.handler = tfw_cfg_set_bool,
.dest = &allow_empty_body_content_type,
.allow_none = true,
.allow_repeat = false,
.cleanup = tfw_cfgop_cleanup_allow_empty_body_content_type,
},
{
.name = "ja5h",
.deflt = NULL,
Expand Down
3 changes: 2 additions & 1 deletion fw/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Tempesta FW
*
* Copyright (C) 2014 NatSys Lab. ([email protected]).
* Copyright (C) 2015-2024 Tempesta Technologies, Inc.
* Copyright (C) 2015-2025 Tempesta Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -735,6 +735,7 @@ typedef void (*tfw_http_cache_cb_t)(TfwHttpMsg *);
(TFW_MSG_H2(hmmsg) ? HTTP2_EXTRA_HDR_OVERHEAD : 0)

extern unsigned int max_header_list_size;
extern bool allow_empty_body_content_type;

/* External HTTP functions. */
int tfw_http_msg_process(TfwConn *conn, struct sk_buff *skb,
Expand Down
40 changes: 25 additions & 15 deletions fw/http_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Tempesta FW
*
* Copyright (C) 2014 NatSys Lab. ([email protected]).
* Copyright (C) 2015-2024 Tempesta Technologies, Inc.
* Copyright (C) 2015-2025 Tempesta Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -1953,18 +1953,6 @@ __parse_content_length(TfwHttpMsg *hm, unsigned char *data, size_t len)
__FSM_REQUIRE_FIRST_DIGIT(I_ContLenBeg, I_ContLen);

__FSM_STATE(I_ContLen) {
/*
* A server MUST NOT send a Content-Length header field in any response
* with a status code of 1xx (Informational) or 204 (No Content).
* TODO: server MUST NOT send a Content-Length header field in any 2xx
* (Successful) response to a CONNECT request
*/
if (TFW_CONN_TYPE(msg->conn) & Conn_Srv) {
TfwHttpResp *resp = (TfwHttpResp *)msg;
if (resp->status - 100U < 100U || resp->status == 204)
return CSTR_NEQ;
}

/*
* According to RFC 7230 3.3.2, in cases of multiple Content-Length
* header fields with field-values consisting of the same decimal
Expand All @@ -1981,6 +1969,25 @@ __parse_content_length(TfwHttpMsg *hm, unsigned char *data, size_t len)
T_DBG3("%s: content_length=%lu\n", __func__, msg->content_length);
__set_bit(TFW_HTTP_B_REQ_CONTENT_LENGTH_PARSED, hm->flags);

/*
* A server MUST NOT send a Content-Length header field in any response
* with a status code of 1xx (Informational) or 204 (No Content).
* TODO: server MUST NOT send a Content-Length header field in any 2xx
* (Successful) response to a CONNECT request
*
* Treat `Content-Length: 0` as the absence of a Content-Length
* header. Some implementations send `Content-Length: 0` within
* 204 (No Content) or 1xx responses, to be able to process such
* messages the rule from RFC has been relaxed.
*/
if (TFW_CONN_TYPE(msg->conn) & Conn_Srv
&& msg->content_length > 0) {
TfwHttpResp *resp = (TfwHttpResp *)msg;

if (resp->status - 100U < 100U || resp->status == 204)
return CSTR_NEQ;
}

return r;
}
}
Expand Down Expand Up @@ -4867,8 +4874,11 @@ tfw_http_parse_check_bodyless_meth(TfwHttpReq *req)
{
TfwStr *tbl = req->h_tbl->tbl;

if (!TFW_STR_EMPTY(&tbl[TFW_HTTP_HDR_CONTENT_LENGTH])
|| !TFW_STR_EMPTY(&tbl[TFW_HTTP_HDR_CONTENT_TYPE]))
/* Treat 'Content-Length: 0' as the empty body. */
if ((!TFW_STR_EMPTY(&tbl[TFW_HTTP_HDR_CONTENT_LENGTH])
&& req->content_length > 0)
|| (!TFW_STR_EMPTY(&tbl[TFW_HTTP_HDR_CONTENT_TYPE])
&& !allow_empty_body_content_type))
{
/* Method override either honored or request message
* with method override header dropped later in processing */
Expand Down

0 comments on commit 3ea6f8b

Please sign in to comment.