You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

63 lines
2.3 KiB

  1. # -*- coding: utf-8 -*-
  2. import io
  3. # Werkzeug version bundled into odoo doesn't handle this kind of Transfer-Encoding
  4. # correctly. We copy the fix from https://github.com/pallets/werkzeug/pull/1198/files
  5. class DechunkedInput(io.RawIOBase):
  6. """An input stream that handles Transfer-Encoding 'chunked'"""
  7. def __init__(self, rfile):
  8. self._rfile = rfile
  9. self._done = False
  10. self._len = 0
  11. def readable(self):
  12. return True
  13. def read_chunk_len(self):
  14. try:
  15. line = self._rfile.readline().decode('latin1')
  16. _len = int(line.strip(), 16)
  17. except ValueError:
  18. raise IOError('Invalid chunk header')
  19. if _len < 0:
  20. raise IOError('Negative chunk length not allowed')
  21. return _len
  22. def readinto(self, buf):
  23. read = 0
  24. while not self._done and read < len(buf):
  25. if self._len == 0:
  26. # This is the first chunk or we fully consumed the previous
  27. # one. Read the next length of the next chunk
  28. self._len = self.read_chunk_len()
  29. if self._len == 0:
  30. # Found the final chunk of size 0. The stream is now exhausted,
  31. # but there is still a final newline that should be consumed
  32. self._done = True
  33. if self._len > 0:
  34. # There is data (left) in this chunk, so append it to the
  35. # buffer. If this operation fully consumes the chunk, this will
  36. # reset self._len to 0.
  37. n = min(len(buf), self._len)
  38. buf[read:read + n] = self._rfile.read(n)
  39. self._len -= n
  40. read += n
  41. if self._len == 0:
  42. # Skip the terminating newline of a chunk that has been fully
  43. # consumed. This also applies to the 0-sized final chunk
  44. terminator = self._rfile.readline()
  45. if terminator not in (b'\n', b'\r\n', b'\r'):
  46. raise IOError('Missing chunk terminating newline')
  47. return read
  48. def http_input_stream(request):
  49. if request.httprequest.headers.get('Transfer-Encoding') == 'chunked' \
  50. and not request.httprequest.environ.get('wsgi.input_terminated'):
  51. return DechunkedInput(request.httprequest.environ['wsgi.input'])
  52. return request.httprequest.stream