Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/urllib3/request.py: 39%

46 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:51 +0000

1from __future__ import absolute_import 

2 

3import sys 

4 

5from .filepost import encode_multipart_formdata 

6from .packages import six 

7from .packages.six.moves.urllib.parse import urlencode 

8 

9__all__ = ["RequestMethods"] 

10 

11 

12class RequestMethods(object): 

13 """ 

14 Convenience mixin for classes who implement a :meth:`urlopen` method, such 

15 as :class:`urllib3.HTTPConnectionPool` and 

16 :class:`urllib3.PoolManager`. 

17 

18 Provides behavior for making common types of HTTP request methods and 

19 decides which type of request field encoding to use. 

20 

21 Specifically, 

22 

23 :meth:`.request_encode_url` is for sending requests whose fields are 

24 encoded in the URL (such as GET, HEAD, DELETE). 

25 

26 :meth:`.request_encode_body` is for sending requests whose fields are 

27 encoded in the *body* of the request using multipart or www-form-urlencoded 

28 (such as for POST, PUT, PATCH). 

29 

30 :meth:`.request` is for making any kind of request, it will look up the 

31 appropriate encoding format and use one of the above two methods to make 

32 the request. 

33 

34 Initializer parameters: 

35 

36 :param headers: 

37 Headers to include with all requests, unless other headers are given 

38 explicitly. 

39 """ 

40 

41 _encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"} 

42 

43 def __init__(self, headers=None): 

44 self.headers = headers or {} 

45 

46 def urlopen( 

47 self, 

48 method, 

49 url, 

50 body=None, 

51 headers=None, 

52 encode_multipart=True, 

53 multipart_boundary=None, 

54 **kw 

55 ): # Abstract 

56 raise NotImplementedError( 

57 "Classes extending RequestMethods must implement " 

58 "their own ``urlopen`` method." 

59 ) 

60 

61 def request(self, method, url, fields=None, headers=None, **urlopen_kw): 

62 """ 

63 Make a request using :meth:`urlopen` with the appropriate encoding of 

64 ``fields`` based on the ``method`` used. 

65 

66 This is a convenience method that requires the least amount of manual 

67 effort. It can be used in most situations, while still having the 

68 option to drop down to more specific methods when necessary, such as 

69 :meth:`request_encode_url`, :meth:`request_encode_body`, 

70 or even the lowest level :meth:`urlopen`. 

71 """ 

72 method = method.upper() 

73 

74 urlopen_kw["request_url"] = url 

75 

76 if method in self._encode_url_methods: 

77 return self.request_encode_url( 

78 method, url, fields=fields, headers=headers, **urlopen_kw 

79 ) 

80 else: 

81 return self.request_encode_body( 

82 method, url, fields=fields, headers=headers, **urlopen_kw 

83 ) 

84 

85 def request_encode_url(self, method, url, fields=None, headers=None, **urlopen_kw): 

86 """ 

87 Make a request using :meth:`urlopen` with the ``fields`` encoded in 

88 the url. This is useful for request methods like GET, HEAD, DELETE, etc. 

89 """ 

90 if headers is None: 

91 headers = self.headers 

92 

93 extra_kw = {"headers": headers} 

94 extra_kw.update(urlopen_kw) 

95 

96 if fields: 

97 url += "?" + urlencode(fields) 

98 

99 return self.urlopen(method, url, **extra_kw) 

100 

101 def request_encode_body( 

102 self, 

103 method, 

104 url, 

105 fields=None, 

106 headers=None, 

107 encode_multipart=True, 

108 multipart_boundary=None, 

109 **urlopen_kw 

110 ): 

111 """ 

112 Make a request using :meth:`urlopen` with the ``fields`` encoded in 

113 the body. This is useful for request methods like POST, PUT, PATCH, etc. 

114 

115 When ``encode_multipart=True`` (default), then 

116 :func:`urllib3.encode_multipart_formdata` is used to encode 

117 the payload with the appropriate content type. Otherwise 

118 :func:`urllib.parse.urlencode` is used with the 

119 'application/x-www-form-urlencoded' content type. 

120 

121 Multipart encoding must be used when posting files, and it's reasonably 

122 safe to use it in other times too. However, it may break request 

123 signing, such as with OAuth. 

124 

125 Supports an optional ``fields`` parameter of key/value strings AND 

126 key/filetuple. A filetuple is a (filename, data, MIME type) tuple where 

127 the MIME type is optional. For example:: 

128 

129 fields = { 

130 'foo': 'bar', 

131 'fakefile': ('foofile.txt', 'contents of foofile'), 

132 'realfile': ('barfile.txt', open('realfile').read()), 

133 'typedfile': ('bazfile.bin', open('bazfile').read(), 

134 'image/jpeg'), 

135 'nonamefile': 'contents of nonamefile field', 

136 } 

137 

138 When uploading a file, providing a filename (the first parameter of the 

139 tuple) is optional but recommended to best mimic behavior of browsers. 

140 

141 Note that if ``headers`` are supplied, the 'Content-Type' header will 

142 be overwritten because it depends on the dynamic random boundary string 

143 which is used to compose the body of the request. The random boundary 

144 string can be explicitly set with the ``multipart_boundary`` parameter. 

145 """ 

146 if headers is None: 

147 headers = self.headers 

148 

149 extra_kw = {"headers": {}} 

150 

151 if fields: 

152 if "body" in urlopen_kw: 

153 raise TypeError( 

154 "request got values for both 'fields' and 'body', can only specify one." 

155 ) 

156 

157 if encode_multipart: 

158 body, content_type = encode_multipart_formdata( 

159 fields, boundary=multipart_boundary 

160 ) 

161 else: 

162 body, content_type = ( 

163 urlencode(fields), 

164 "application/x-www-form-urlencoded", 

165 ) 

166 

167 extra_kw["body"] = body 

168 extra_kw["headers"] = {"Content-Type": content_type} 

169 

170 extra_kw["headers"].update(headers) 

171 extra_kw.update(urlopen_kw) 

172 

173 return self.urlopen(method, url, **extra_kw) 

174 

175 

176if not six.PY2: 

177 

178 class RequestModule(sys.modules[__name__].__class__): 

179 def __call__(self, *args, **kwargs): 

180 """ 

181 If user tries to call this module directly urllib3 v2.x style raise an error to the user 

182 suggesting they may need urllib3 v2 

183 """ 

184 raise TypeError( 

185 "'module' object is not callable\n" 

186 "urllib3.request() method is not supported in this release, " 

187 "upgrade to urllib3 v2 to use it\n" 

188 "see https://urllib3.readthedocs.io/en/stable/v2-migration-guide.html" 

189 ) 

190 

191 sys.modules[__name__].__class__ = RequestModule