mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-07 02:28:53 +08:00
Implement max settings option
This commit is contained in:
@@ -228,6 +228,13 @@ typedef struct {
|
||||
*/
|
||||
#define NGHTTP2_CLIENT_MAGIC_LEN 24
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* The default max number of settings per SETTINGS frame
|
||||
*/
|
||||
#define NGHTTP2_DEFAULT_MAX_SETTINGS 32
|
||||
|
||||
/**
|
||||
* @enum
|
||||
*
|
||||
@@ -398,6 +405,11 @@ typedef enum {
|
||||
* receives an other type of frame.
|
||||
*/
|
||||
NGHTTP2_ERR_SETTINGS_EXPECTED = -536,
|
||||
/**
|
||||
* When a local endpoint receives too many settings entries
|
||||
* in a single SETTINGS frame.
|
||||
*/
|
||||
NGHTTP2_ERR_TOO_MANY_SETTINGS = -537,
|
||||
/**
|
||||
* The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
|
||||
* under unexpected condition and processing was terminated (e.g.,
|
||||
@@ -2659,6 +2671,17 @@ NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option,
|
||||
NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option,
|
||||
size_t val);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* This function sets the maximum number of SETTINGS entries per
|
||||
* SETTINGS frame that will be accepted. If more than those entries
|
||||
* are received, the peer is considered to be misbehaving and session
|
||||
* will be closed. The default value is 32.
|
||||
*/
|
||||
NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option,
|
||||
size_t val);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
||||
@@ -334,6 +334,8 @@ const char *nghttp2_strerror(int error_code) {
|
||||
case NGHTTP2_ERR_FLOODED:
|
||||
return "Flooding was detected in this HTTP/2 session, and it must be "
|
||||
"closed";
|
||||
case NGHTTP2_ERR_TOO_MANY_SETTINGS:
|
||||
return "SETTINGS frame contained more than the maximum allowed entries";
|
||||
default:
|
||||
return "Unknown error code";
|
||||
}
|
||||
|
||||
@@ -121,3 +121,8 @@ void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
|
||||
option->max_outbound_ack = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
|
||||
option->max_settings = val;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ typedef enum {
|
||||
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
|
||||
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
|
||||
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
|
||||
NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
@@ -85,6 +86,10 @@ struct nghttp2_option {
|
||||
* NGHTTP2_OPT_MAX_OUTBOUND_ACK
|
||||
*/
|
||||
size_t max_outbound_ack;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_SETTINGS
|
||||
*/
|
||||
size_t max_settings;
|
||||
/**
|
||||
* Bitwise OR of nghttp2_option_flag to determine that which fields
|
||||
* are specified.
|
||||
|
||||
@@ -458,6 +458,7 @@ static int session_new(nghttp2_session **session_ptr,
|
||||
|
||||
(*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN;
|
||||
(*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
|
||||
(*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
|
||||
|
||||
if (option) {
|
||||
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
|
||||
@@ -521,6 +522,11 @@ static int session_new(nghttp2_session **session_ptr,
|
||||
if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) {
|
||||
(*session_ptr)->max_outbound_ack = option->max_outbound_ack;
|
||||
}
|
||||
|
||||
if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) &&
|
||||
option->max_settings) {
|
||||
(*session_ptr)->max_settings = option->max_settings;
|
||||
}
|
||||
}
|
||||
|
||||
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
|
||||
@@ -5657,6 +5663,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
||||
iframe->max_niv =
|
||||
iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
|
||||
|
||||
if (iframe->max_niv - 1 > session->max_settings) {
|
||||
rv = nghttp2_session_terminate_session_with_reason(
|
||||
session, NGHTTP2_ENHANCE_YOUR_CALM,
|
||||
"SETTINGS: too many setting entries");
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return (ssize_t)inlen;
|
||||
}
|
||||
|
||||
iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) *
|
||||
iframe->max_niv);
|
||||
|
||||
@@ -7425,6 +7441,11 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session,
|
||||
if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
/* SETTINGS frame contains too many settings */
|
||||
if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH
|
||||
> session->max_settings) {
|
||||
return NGHTTP2_ERR_TOO_MANY_SETTINGS;
|
||||
}
|
||||
rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload,
|
||||
settings_payloadlen, mem);
|
||||
if (rv != 0) {
|
||||
|
||||
@@ -267,6 +267,8 @@ struct nghttp2_session {
|
||||
/* The maximum length of header block to send. Calculated by the
|
||||
same way as nghttp2_hd_deflate_bound() does. */
|
||||
size_t max_send_header_block_length;
|
||||
/* The maximum number of settings accepted per SETTINGS frame. */
|
||||
size_t max_settings;
|
||||
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
||||
uint32_t next_stream_id;
|
||||
/* The last stream ID this session initiated. For client session,
|
||||
|
||||
Reference in New Issue
Block a user