@@ -126,6 +126,8 @@ class Settings(MutableMapping[SettingCodes | int, int]):
126126 """
127127
128128 def __init__ (self , client : bool = True , initial_values : dict [SettingCodes , int ] | None = None ) -> None :
129+ self ._client = client
130+
129131 # Backing object for the settings. This is a dictionary of
130132 # (setting: [list of values]), where the first value in the list is the
131133 # current value of the setting. Strictly this doesn't use lists but
@@ -287,6 +289,23 @@ def __setitem__(self, key: SettingCodes | int, value: int) -> None:
287289
288290 items .append (value )
289291
292+ def validate_received_setting (self , setting : SettingCodes | int , value : int ) -> None :
293+ """
294+ Validate a setting received from the peer that owns this Settings
295+ object.
296+
297+ Servers may advertise ``ENABLE_PUSH`` only as ``0`` in received
298+ SETTINGS frames.
299+ """
300+ invalid = _validate_setting (setting , value , client = self ._client )
301+
302+ if invalid != ErrorCodes .NO_ERROR :
303+ msg = f"Setting { setting } has invalid value { value } "
304+ raise InvalidSettingsValueError (
305+ msg ,
306+ error_code = invalid ,
307+ )
308+
290309 def __delitem__ (self , key : SettingCodes | int ) -> None :
291310 del self ._settings [key ]
292311
@@ -311,13 +330,23 @@ def __ne__(self, other: object) -> bool:
311330 __hash__ = MutableMapping .__hash__
312331
313332
314- def _validate_setting (setting : SettingCodes | int , value : int ) -> ErrorCodes :
333+ def _validate_setting (
334+ setting : SettingCodes | int ,
335+ value : int ,
336+ * ,
337+ client : bool | None = None ,
338+ ) -> ErrorCodes :
315339 """
316340 Confirms that a specific setting has a well-formed value. If the setting is
317341 invalid, returns an error code. Otherwise, returns 0 (NO_ERROR).
342+
343+ If ``client`` is set, the setting originated from a peer with that role.
318344 """
319345 if setting == SettingCodes .ENABLE_PUSH :
320- if value not in (0 , 1 ):
346+ # RFC 9113 section 6.5.2: "A client MUST treat receipt of a
347+ # SETTINGS frame with SETTINGS_ENABLE_PUSH set to 1 as a connection
348+ # error (Section 5.4.1) of type PROTOCOL_ERROR."
349+ if value not in (0 , 1 ) or (client is False and value != 0 ):
321350 return ErrorCodes .PROTOCOL_ERROR
322351 elif setting == SettingCodes .INITIAL_WINDOW_SIZE :
323352 if not 0 <= value <= 2147483647 : # 2^31 - 1
0 commit comments