Allow 8192 header max to be breached (#2155)
* Allow 8192 header max to be breached * Add REQUEST_MAX_HEADER_SIZE as config value * remove queue size
This commit is contained in:
@@ -183,7 +183,6 @@ class Sanic(BaseSanic):
|
||||
|
||||
if register is not None:
|
||||
self.config.REGISTER = register
|
||||
|
||||
if self.config.REGISTER:
|
||||
self.__class__.register_app(self)
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ from pathlib import Path
|
||||
from typing import Any, Dict, Optional, Union
|
||||
from warnings import warn
|
||||
|
||||
from sanic.http import Http
|
||||
|
||||
from .utils import load_module_from_file_location, str_to_bool
|
||||
|
||||
|
||||
@@ -28,6 +30,7 @@ DEFAULT_CONFIG = {
|
||||
"REAL_IP_HEADER": None,
|
||||
"REGISTER": True,
|
||||
"REQUEST_BUFFER_SIZE": 65536, # 64 KiB
|
||||
"REQUEST_MAX_HEADER_SIZE": 8192, # 8 KiB, but cannot exceed 16384
|
||||
"REQUEST_ID_HEADER": "X-Request-ID",
|
||||
"REQUEST_MAX_SIZE": 100000000, # 100 megabytes
|
||||
"REQUEST_TIMEOUT": 60, # 60 seconds
|
||||
@@ -42,12 +45,36 @@ DEFAULT_CONFIG = {
|
||||
|
||||
|
||||
class Config(dict):
|
||||
ACCESS_LOG: bool
|
||||
EVENT_AUTOREGISTER: bool
|
||||
FALLBACK_ERROR_FORMAT: str
|
||||
FORWARDED_FOR_HEADER: str
|
||||
FORWARDED_SECRET: Optional[str]
|
||||
GRACEFUL_SHUTDOWN_TIMEOUT: float
|
||||
KEEP_ALIVE_TIMEOUT: int
|
||||
KEEP_ALIVE: bool
|
||||
PROXIES_COUNT: Optional[int]
|
||||
REAL_IP_HEADER: Optional[str]
|
||||
REGISTER: bool
|
||||
REQUEST_BUFFER_SIZE: int
|
||||
REQUEST_MAX_HEADER_SIZE: int
|
||||
REQUEST_ID_HEADER: str
|
||||
REQUEST_MAX_SIZE: int
|
||||
REQUEST_TIMEOUT: int
|
||||
RESPONSE_TIMEOUT: int
|
||||
WEBSOCKET_MAX_QUEUE: int
|
||||
WEBSOCKET_MAX_SIZE: int
|
||||
WEBSOCKET_PING_INTERVAL: int
|
||||
WEBSOCKET_PING_TIMEOUT: int
|
||||
WEBSOCKET_READ_LIMIT: int
|
||||
WEBSOCKET_WRITE_LIMIT: int
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
defaults: Dict[str, Union[str, bool, int, float, None]] = None,
|
||||
load_env: Optional[Union[bool, str]] = True,
|
||||
env_prefix: Optional[str] = SANIC_PREFIX,
|
||||
keep_alive: Optional[int] = None,
|
||||
keep_alive: Optional[bool] = None,
|
||||
):
|
||||
defaults = defaults or {}
|
||||
super().__init__({**DEFAULT_CONFIG, **defaults})
|
||||
@@ -72,6 +99,8 @@ class Config(dict):
|
||||
else:
|
||||
self.load_environment_vars(SANIC_PREFIX)
|
||||
|
||||
self._configure_header_size()
|
||||
|
||||
def __getattr__(self, attr):
|
||||
try:
|
||||
return self[attr]
|
||||
@@ -80,6 +109,19 @@ class Config(dict):
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
self[attr] = value
|
||||
if attr in (
|
||||
"REQUEST_MAX_HEADER_SIZE",
|
||||
"REQUEST_BUFFER_SIZE",
|
||||
"REQUEST_MAX_SIZE",
|
||||
):
|
||||
self._configure_header_size()
|
||||
|
||||
def _configure_header_size(self):
|
||||
Http.set_header_max_size(
|
||||
self.REQUEST_MAX_HEADER_SIZE,
|
||||
self.REQUEST_BUFFER_SIZE - 4096,
|
||||
self.REQUEST_MAX_SIZE,
|
||||
)
|
||||
|
||||
def load_environment_vars(self, prefix=SANIC_PREFIX):
|
||||
"""
|
||||
|
||||
@@ -64,6 +64,9 @@ class Http:
|
||||
:raises RuntimeError:
|
||||
"""
|
||||
|
||||
HEADER_CEILING = 16_384
|
||||
HEADER_MAX_SIZE = 0
|
||||
|
||||
__slots__ = [
|
||||
"_send",
|
||||
"_receive_more",
|
||||
@@ -169,7 +172,6 @@ class Http:
|
||||
"""
|
||||
Receive and parse request header into self.request.
|
||||
"""
|
||||
HEADER_MAX_SIZE = min(8192, self.request_max_size)
|
||||
# Receive until full header is in buffer
|
||||
buf = self.recv_buffer
|
||||
pos = 0
|
||||
@@ -180,12 +182,12 @@ class Http:
|
||||
break
|
||||
|
||||
pos = max(0, len(buf) - 3)
|
||||
if pos >= HEADER_MAX_SIZE:
|
||||
if pos >= self.HEADER_MAX_SIZE:
|
||||
break
|
||||
|
||||
await self._receive_more()
|
||||
|
||||
if pos >= HEADER_MAX_SIZE:
|
||||
if pos >= self.HEADER_MAX_SIZE:
|
||||
raise PayloadTooLarge("Request header exceeds the size limit")
|
||||
|
||||
# Parse header content
|
||||
@@ -541,3 +543,10 @@ class Http:
|
||||
@property
|
||||
def send(self):
|
||||
return self.response_func
|
||||
|
||||
@classmethod
|
||||
def set_header_max_size(cls, *sizes: int):
|
||||
cls.HEADER_MAX_SIZE = min(
|
||||
*sizes,
|
||||
cls.HEADER_CEILING,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user