@@ -77,8 +77,10 @@ class Protocol:
7777 Args: 
7878 side: :attr:`~Side.CLIENT` or :attr:`~Side.SERVER`. 
7979 state: Initial state of the WebSocket connection. 
80-  max_size: Maximum size of incoming messages in bytes; 
81-  :obj:`None` disables the limit. 
80+  max_size: Maximum size of incoming messages in bytes. 
81+  :obj:`None` disables the limit. You may pass a ``(max_message_size, 
82+  max_fragment_size)`` tuple to set different limits for messages and 
83+  fragments when you expect long messages sent in short fragments. 
8284 logger: Logger for this connection; depending on ``side``, 
8385 defaults to ``logging.getLogger("websockets.client")`` 
8486 or ``logging.getLogger("websockets.server")``; 
@@ -91,7 +93,7 @@ def __init__(
9193 side : Side ,
9294 * ,
9395 state : State  =  OPEN ,
94-  max_size : int  |  None  =  2 ** 20 ,
96+  max_size : tuple [ int   |   None ,  int   |   None ]  |   int  |  None  =  2 ** 20 ,
9597 logger : LoggerLike  |  None  =  None ,
9698 ) ->  None :
9799 # Unique identifier. For logs. 
@@ -114,11 +116,14 @@ def __init__(
114116 self .state  =  state 
115117
116118 # Maximum size of incoming messages in bytes. 
117-  self .max_size  =  max_size 
119+  if  isinstance (max_size , int ) or  max_size  is  None :
120+  self .max_message_size , self .max_fragment_size  =  max_size , None 
121+  else :
122+  self .max_message_size , self .max_fragment_size  =  max_size 
118123
119124 # Current size of incoming message in bytes. Only set while reading a 
120125 # fragmented message i.e. a data frames with the FIN bit not set. 
121-  self .cur_size : int  |  None  =  None 
126+  self .current_size : int  |  None  =  None 
122127
123128 # True while sending a fragmented message i.e. a data frames with the 
124129 # FIN bit not set. 
@@ -578,12 +583,19 @@ def parse(self) -> Generator[None]:
578583 # connection isn't closed cleanly. 
579584 raise  EOFError ("unexpected end of stream" )
580585
581-  if  self .max_size  is  None :
582-  max_size  =  None 
583-  elif  self .cur_size  is  None :
584-  max_size  =  self .max_size 
585-  else :
586-  max_size  =  self .max_size  -  self .cur_size 
586+  max_size  =  None 
587+ 
588+  if  self .max_message_size  is  not   None :
589+  if  self .current_size  is  None :
590+  max_size  =  self .max_message_size 
591+  else :
592+  max_size  =  self .max_message_size  -  self .current_size 
593+ 
594+  if  self .max_fragment_size  is  not   None :
595+  if  max_size  is  None :
596+  max_size  =  self .max_fragment_size 
597+  else :
598+  max_size  =  min (max_size , self .max_fragment_size )
587599
588600 # During a normal closure, execution ends here on the next 
589601 # iteration of the loop after receiving a close frame. At 
@@ -613,7 +625,7 @@ def parse(self) -> Generator[None]:
613625 self .parser_exc  =  exc 
614626
615627 except  PayloadTooBig  as  exc :
616-  exc .set_current_size (self .cur_size )
628+  exc .set_current_size (self .current_size )
617629 self .fail (CloseCode .MESSAGE_TOO_BIG , str (exc ))
618630 self .parser_exc  =  exc 
619631
@@ -664,18 +676,18 @@ def recv_frame(self, frame: Frame) -> None:
664676
665677 """ 
666678 if  frame .opcode  is  OP_TEXT  or  frame .opcode  is  OP_BINARY :
667-  if  self .cur_size  is  not   None :
679+  if  self .current_size  is  not   None :
668680 raise  ProtocolError ("expected a continuation frame" )
669681 if  not  frame .fin :
670-  self .cur_size  =  len (frame .data )
682+  self .current_size  =  len (frame .data )
671683
672684 elif  frame .opcode  is  OP_CONT :
673-  if  self .cur_size  is  None :
685+  if  self .current_size  is  None :
674686 raise  ProtocolError ("unexpected continuation frame" )
675687 if  frame .fin :
676-  self .cur_size  =  None 
688+  self .current_size  =  None 
677689 else :
678-  self .cur_size  +=  len (frame .data )
690+  self .current_size  +=  len (frame .data )
679691
680692 elif  frame .opcode  is  OP_PING :
681693 # 5.5.2. Ping: "Upon receipt of a Ping frame, an endpoint MUST 
@@ -696,7 +708,7 @@ def recv_frame(self, frame: Frame) -> None:
696708 assert  self .close_sent  is  not   None 
697709 self .close_rcvd_then_sent  =  False 
698710
699-  if  self .cur_size  is  not   None :
711+  if  self .current_size  is  not   None :
700712 raise  ProtocolError ("incomplete fragmented message" )
701713
702714 # 5.5.1 Close: "If an endpoint receives a Close frame and did 
0 commit comments