@@ -115,6 +115,34 @@ def prepare_response_headers(
115115 return headers
116116
117117
118+ def _read_body_with_content_length (
119+ environ : WSGIEnvironment , content_length : int
120+ ) -> bytes :
121+ input_stream : BytesIO = environ ["wsgi.input" ]
122+
123+ # Many app servers buffer the entire request before executing the app
124+ # so do an optimistic read before looping.
125+ chunk = input_stream .read (content_length )
126+ if len (chunk ) == content_length :
127+ return chunk
128+
129+ bytes_read = len (chunk )
130+ chunks = [chunk ]
131+ while bytes_read < content_length :
132+ to_read = content_length - bytes_read
133+ chunk = input_stream .read (to_read )
134+ if not chunk :
135+ break
136+ chunks .append (chunk )
137+ bytes_read += len (chunk )
138+ if bytes_read < content_length :
139+ raise ConnectError (
140+ Code .INVALID_ARGUMENT ,
141+ f"request truncated, expected { content_length } bytes but only received { bytes_read } bytes" ,
142+ )
143+ return b"" .join (chunks )
144+
145+
118146def _read_body (environ : WSGIEnvironment ) -> Iterator [bytes ]:
119147 input_stream : BytesIO = environ ["wsgi.input" ]
120148 while True :
@@ -257,7 +285,7 @@ def _handle_post_request(
257285 content_length = environ .get ("CONTENT_LENGTH" )
258286 content_length = 0 if not content_length else int (content_length )
259287 if content_length > 0 :
260- req_body = environ [ "wsgi.input" ]. read ( content_length )
288+ req_body = _read_body_with_content_length ( environ , content_length )
261289 else :
262290 req_body = b"" .join (_read_body (environ ))
263291
0 commit comments