| 275 | | |
|---|
| 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. |
|---|
| 282 | | |
|---|
| 283 | | # largest position tell us how far this lazystream has ever |
|---|
| 284 | | # been advanced |
|---|
| 285 | | self._largest_position = 0 |
|---|
| 286 | | |
|---|
| 287 | | # "modifications since" will start at zero and increment every |
|---|
| 288 | | # time the position is modified but a new largest position is |
|---|
| 289 | | # not achieved. |
|---|
| 290 | | self._modifications_since = 0 |
|---|
| | 275 | 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." |
|---|
| 368 | | ) |
|---|
| 369 | | |
|---|
| 370 | | self._position = value |
|---|
| 371 | | |
|---|
| 372 | | position = property(lambda self: self._position, _set_position) |
|---|
| | 346 | def _update_unget_history(self, num_bytes): |
|---|
| | 347 | """ |
|---|
| | 348 | Updates the unget history as a sanity check to see if we've pushed |
|---|
| | 349 | back the same number of bytes in one chunk. If we keep ungetting the |
|---|
| | 350 | same number of bytes many times (here, 50), we're mostly likely in an |
|---|
| | 351 | infinite loop of some sort. This is usually caused by a |
|---|
| | 352 | maliciously-malformed MIME request. |
|---|
| | 353 | """ |
|---|
| | 354 | self._unget_history = [num_bytes] + self._unget_history[:49] |
|---|
| | 355 | number_equal = len([current_number for current_number in self._unget_history |
|---|
| | 356 | if current_number == num_bytes]) |
|---|
| | 357 | |
|---|
| | 358 | if number_equal > 40: |
|---|
| | 359 | raise SuspiciousOperation( |
|---|
| | 360 | "The multipart parser got stuck, which shouldn't happen with" |
|---|
| | 361 | " normal uploaded files. Check for malicious upload activity;" |
|---|
| | 362 | " if there is none, report this to the Django developers." |
|---|
| | 363 | ) |
|---|