OLD | NEW |
| (Empty) |
1 # urllib3/request.py | |
2 # Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt) | |
3 # | |
4 # This module is part of urllib3 and is released under | |
5 # the MIT License: http://www.opensource.org/licenses/mit-license.php | |
6 | |
7 try: | |
8 from urllib.parse import urlencode | |
9 except ImportError: | |
10 from urllib import urlencode | |
11 | |
12 from .filepost import encode_multipart_formdata | |
13 | |
14 | |
15 __all__ = ['RequestMethods'] | |
16 | |
17 | |
18 class RequestMethods(object): | |
19 """ | |
20 Convenience mixin for classes who implement a :meth:`urlopen` method, such | |
21 as :class:`~urllib3.connectionpool.HTTPConnectionPool` and | |
22 :class:`~urllib3.poolmanager.PoolManager`. | |
23 | |
24 Provides behavior for making common types of HTTP request methods and | |
25 decides which type of request field encoding to use. | |
26 | |
27 Specifically, | |
28 | |
29 :meth:`.request_encode_url` is for sending requests whose fields are encoded | |
30 in the URL (such as GET, HEAD, DELETE). | |
31 | |
32 :meth:`.request_encode_body` is for sending requests whose fields are | |
33 encoded in the *body* of the request using multipart or www-form-urlencoded | |
34 (such as for POST, PUT, PATCH). | |
35 | |
36 :meth:`.request` is for making any kind of request, it will look up the | |
37 appropriate encoding format and use one of the above two methods to make | |
38 the request. | |
39 | |
40 Initializer parameters: | |
41 | |
42 :param headers: | |
43 Headers to include with all requests, unless other headers are given | |
44 explicitly. | |
45 """ | |
46 | |
47 _encode_url_methods = set(['DELETE', 'GET', 'HEAD', 'OPTIONS']) | |
48 _encode_body_methods = set(['PATCH', 'POST', 'PUT', 'TRACE']) | |
49 | |
50 def __init__(self, headers=None): | |
51 self.headers = headers or {} | |
52 | |
53 def urlopen(self, method, url, body=None, headers=None, | |
54 encode_multipart=True, multipart_boundary=None, | |
55 **kw): # Abstract | |
56 raise NotImplemented("Classes extending RequestMethods must implement " | |
57 "their own ``urlopen`` method.") | |
58 | |
59 def request(self, method, url, fields=None, headers=None, **urlopen_kw): | |
60 """ | |
61 Make a request using :meth:`urlopen` with the appropriate encoding of | |
62 ``fields`` based on the ``method`` used. | |
63 | |
64 This is a convenience method that requires the least amount of manual | |
65 effort. It can be used in most situations, while still having the option | |
66 to drop down to more specific methods when necessary, such as | |
67 :meth:`request_encode_url`, :meth:`request_encode_body`, | |
68 or even the lowest level :meth:`urlopen`. | |
69 """ | |
70 method = method.upper() | |
71 | |
72 if method in self._encode_url_methods: | |
73 return self.request_encode_url(method, url, fields=fields, | |
74 headers=headers, | |
75 **urlopen_kw) | |
76 else: | |
77 return self.request_encode_body(method, url, fields=fields, | |
78 headers=headers, | |
79 **urlopen_kw) | |
80 | |
81 def request_encode_url(self, method, url, fields=None, **urlopen_kw): | |
82 """ | |
83 Make a request using :meth:`urlopen` with the ``fields`` encoded in | |
84 the url. This is useful for request methods like GET, HEAD, DELETE, etc. | |
85 """ | |
86 if fields: | |
87 url += '?' + urlencode(fields) | |
88 return self.urlopen(method, url, **urlopen_kw) | |
89 | |
90 def request_encode_body(self, method, url, fields=None, headers=None, | |
91 encode_multipart=True, multipart_boundary=None, | |
92 **urlopen_kw): | |
93 """ | |
94 Make a request using :meth:`urlopen` with the ``fields`` encoded in | |
95 the body. This is useful for request methods like POST, PUT, PATCH, etc. | |
96 | |
97 When ``encode_multipart=True`` (default), then | |
98 :meth:`urllib3.filepost.encode_multipart_formdata` is used to encode the | |
99 payload with the appropriate content type. Otherwise | |
100 :meth:`urllib.urlencode` is used with the | |
101 'application/x-www-form-urlencoded' content type. | |
102 | |
103 Multipart encoding must be used when posting files, and it's reasonably | |
104 safe to use it in other times too. However, it may break request signing
, | |
105 such as with OAuth. | |
106 | |
107 Supports an optional ``fields`` parameter of key/value strings AND | |
108 key/filetuple. A filetuple is a (filename, data, MIME type) tuple where | |
109 the MIME type is optional. For example: :: | |
110 | |
111 fields = { | |
112 'foo': 'bar', | |
113 'fakefile': ('foofile.txt', 'contents of foofile'), | |
114 'realfile': ('barfile.txt', open('realfile').read()), | |
115 'typedfile': ('bazfile.bin', open('bazfile').read(), | |
116 'image/jpeg'), | |
117 'nonamefile': 'contents of nonamefile field', | |
118 } | |
119 | |
120 When uploading a file, providing a filename (the first parameter of the | |
121 tuple) is optional but recommended to best mimick behavior of browsers. | |
122 | |
123 Note that if ``headers`` are supplied, the 'Content-Type' header will be | |
124 overwritten because it depends on the dynamic random boundary string | |
125 which is used to compose the body of the request. The random boundary | |
126 string can be explicitly set with the ``multipart_boundary`` parameter. | |
127 """ | |
128 if encode_multipart: | |
129 body, content_type = encode_multipart_formdata(fields or {}, | |
130 boundary=multipart_boundary) | |
131 else: | |
132 body, content_type = (urlencode(fields or {}), | |
133 'application/x-www-form-urlencoded') | |
134 | |
135 if headers is None: | |
136 headers = self.headers | |
137 | |
138 headers_ = {'Content-Type': content_type} | |
139 headers_.update(headers) | |
140 | |
141 return self.urlopen(method, url, body=body, headers=headers_, | |
142 **urlopen_kw) | |
OLD | NEW |