@@ -129,16 +129,22 @@ def decode(
129129 # Uncompress data. Protect against zip bombs by preventing zlib from
130130 # decompressing more than max_length bytes (except when the limit is
131131 # disabled with max_size = None).
132- data = frame .data
133- if frame .fin :
134- data += _EMPTY_UNCOMPRESSED_BLOCK
132+ if frame .fin and len (frame .data ) < 2044 :
133+ # Profiling shows that appending four bytes, which makes a copy, is
134+ # faster than calling decompress() again when data is less than 2kB.
135+ data = bytes (frame .data ) + _EMPTY_UNCOMPRESSED_BLOCK
136+ else :
137+ data = frame .data
135138 max_length = 0 if max_size is None else max_size
136139 try :
137140 data = self .decoder .decompress (data , max_length )
141+ if self .decoder .unconsumed_tail :
142+ raise PayloadTooBig (f"over size limit (? > { max_size } bytes)" )
143+ if frame .fin and len (frame .data ) >= 2044 :
144+ # This cannot generate additional data.
145+ self .decoder .decompress (_EMPTY_UNCOMPRESSED_BLOCK )
138146 except zlib .error as exc :
139147 raise ProtocolError ("decompression failed" ) from exc
140- if self .decoder .unconsumed_tail :
141- raise PayloadTooBig (f"over size limit (? > { max_size } bytes)" )
142148
143149 # Allow garbage collection of the decoder if it won't be reused.
144150 if frame .fin and self .remote_no_context_takeover :
@@ -176,11 +182,15 @@ def encode(self, frame: frames.Frame) -> frames.Frame:
176182
177183 # Compress data.
178184 data = self .encoder .compress (frame .data ) + self .encoder .flush (zlib .Z_SYNC_FLUSH )
179- if frame .fin and data [- 4 :] == _EMPTY_UNCOMPRESSED_BLOCK :
180- # Making a copy is faster than memoryview(a)[:-4] until about 2kB.
181- # On larger messages, it's slower but profiling shows that it's
182- # marginal compared to compress() and flush(). Keep it simple.
183- data = data [:- 4 ]
185+ if frame .fin :
186+ # Sync flush generates between 5 or 6 bytes, ending with the bytes
187+ # 0x00 0x00 0xff 0xff, which must be removed.
188+ assert data [- 4 :] == _EMPTY_UNCOMPRESSED_BLOCK
189+ # Making a copy is faster than memoryview(a)[:-4] until 2kB.
190+ if len (data ) < 2048 :
191+ data = data [:- 4 ]
192+ else :
193+ data = memoryview (data )[:- 4 ]
184194
185195 # Allow garbage collection of the encoder if it won't be reused.
186196 if frame .fin and self .local_no_context_takeover :
0 commit comments