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