request.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. # SPDX-License-Identifier: MIT
  2. from __future__ import absolute_import
  3. from base64 import b64encode
  4. from ..packages.six import b, integer_types
  5. from ..exceptions import UnrewindableBodyError
  6. ACCEPT_ENCODING = 'gzip,deflate'
  7. _FAILEDTELL = object()
  8. def make_headers(keep_alive=None, accept_encoding=None, user_agent=None,
  9. basic_auth=None, proxy_basic_auth=None, disable_cache=None):
  10. """
  11. Shortcuts for generating request headers.
  12. :param keep_alive:
  13. If ``True``, adds 'connection: keep-alive' header.
  14. :param accept_encoding:
  15. Can be a boolean, list, or string.
  16. ``True`` translates to 'gzip,deflate'.
  17. List will get joined by comma.
  18. String will be used as provided.
  19. :param user_agent:
  20. String representing the user-agent you want, such as
  21. "python-urllib3/0.6"
  22. :param basic_auth:
  23. Colon-separated username:password string for 'authorization: basic ...'
  24. auth header.
  25. :param proxy_basic_auth:
  26. Colon-separated username:password string for 'proxy-authorization: basic ...'
  27. auth header.
  28. :param disable_cache:
  29. If ``True``, adds 'cache-control: no-cache' header.
  30. Example::
  31. >>> make_headers(keep_alive=True, user_agent="Batman/1.0")
  32. {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'}
  33. >>> make_headers(accept_encoding=True)
  34. {'accept-encoding': 'gzip,deflate'}
  35. """
  36. headers = {}
  37. if accept_encoding:
  38. if isinstance(accept_encoding, str):
  39. pass
  40. elif isinstance(accept_encoding, list):
  41. accept_encoding = ','.join(accept_encoding)
  42. else:
  43. accept_encoding = ACCEPT_ENCODING
  44. headers['accept-encoding'] = accept_encoding
  45. if user_agent:
  46. headers['user-agent'] = user_agent
  47. if keep_alive:
  48. headers['connection'] = 'keep-alive'
  49. if basic_auth:
  50. headers['authorization'] = 'Basic ' + \
  51. b64encode(b(basic_auth)).decode('utf-8')
  52. if proxy_basic_auth:
  53. headers['proxy-authorization'] = 'Basic ' + \
  54. b64encode(b(proxy_basic_auth)).decode('utf-8')
  55. if disable_cache:
  56. headers['cache-control'] = 'no-cache'
  57. return headers
  58. def set_file_position(body, pos):
  59. """
  60. If a position is provided, move file to that point.
  61. Otherwise, we'll attempt to record a position for future use.
  62. """
  63. if pos is not None:
  64. rewind_body(body, pos)
  65. elif getattr(body, 'tell', None) is not None:
  66. try:
  67. pos = body.tell()
  68. except (IOError, OSError):
  69. # This differentiates from None, allowing us to catch
  70. # a failed `tell()` later when trying to rewind the body.
  71. pos = _FAILEDTELL
  72. return pos
  73. def rewind_body(body, body_pos):
  74. """
  75. Attempt to rewind body to a certain position.
  76. Primarily used for request redirects and retries.
  77. :param body:
  78. File-like object that supports seek.
  79. :param int pos:
  80. Position to seek to in file.
  81. """
  82. body_seek = getattr(body, 'seek', None)
  83. if body_seek is not None and isinstance(body_pos, integer_types):
  84. try:
  85. body_seek(body_pos)
  86. except (IOError, OSError):
  87. raise UnrewindableBodyError("An error occurred when rewinding request "
  88. "body for redirect/retry.")
  89. elif body_pos is _FAILEDTELL:
  90. raise UnrewindableBodyError("Unable to record file position for rewinding "
  91. "request body during a redirect/retry.")
  92. else:
  93. raise ValueError("body_pos must be of type integer, "
  94. "instead it was %s." % type(body_pos))