276 | | # These fields are to do sanity checking to make sure we don't |
277 | | # have infinite loops getting/ungetting from the stream. The |
278 | | # purpose overall is to raise an exception if we perform lots |
279 | | # of stream get/unget gymnastics without getting |
280 | | # anywhere. Naturally this is not sound, but most probably |
281 | | # would indicate a bug if the exception is raised. |
| 276 | # This field does some sanity checking to see if we have |
| 277 | # pushed back the same number of bytes |
| 278 | # in one chunk. |
| 279 | # If we unget the same number of bytes a lot of times, |
| 280 | # we're most likely in an infinite loop of some sort. |
| 281 | self._unget_history = [] |
357 | | def _set_position(self, value): |
358 | | if value > self._largest_position: |
359 | | self._modifications_since = 0 |
360 | | self._largest_position = value |
361 | | else: |
362 | | self._modifications_since += 1 |
363 | | if self._modifications_since > 500: |
364 | | raise SuspiciousOperation( |
365 | | "The multipart parser got stuck, which shouldn't happen with" |
366 | | " normal uploaded files. Check for malicious upload activity;" |
367 | | " if there is none, report this to the Django developers." |
| 352 | def _update_unget_history(self, num_bytes): |
| 353 | """ |
| 354 | Updates the unget history .. storing 50 previous ungets |
| 355 | to make sure that they are different enough. |
| 356 | """ |
| 357 | self._unget_history = [num_bytes] + self._unget_history[:49] |
| 358 | number_equal = len([current_number for current_number in self._unget_history |
| 359 | if current_number == num_bytes]) |
| 360 | |
| 361 | if number_equal > 40: |
| 362 | raise SuspiciousOperation( |
| 363 | "The multipart parser got stuck, which shouldn't happen with" |
| 364 | " normal uploaded files. Check for malicious upload activity;" |
| 365 | " if there is none, report this to the Django developers." |