You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.7 KiB
Python
143 lines
5.7 KiB
Python
# urllib3/request.py
|
|
# Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
|
|
#
|
|
# This module is part of urllib3 and is released under
|
|
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
|
|
|
try:
|
|
from urllib.parse import urlencode
|
|
except ImportError:
|
|
from urllib import urlencode
|
|
|
|
from .filepost import encode_multipart_formdata
|
|
|
|
|
|
__all__ = ['RequestMethods']
|
|
|
|
|
|
class RequestMethods(object):
|
|
"""
|
|
Convenience mixin for classes who implement a :meth:`urlopen` method, such
|
|
as :class:`~urllib3.connectionpool.HTTPConnectionPool` and
|
|
:class:`~urllib3.poolmanager.PoolManager`.
|
|
|
|
Provides behavior for making common types of HTTP request methods and
|
|
decides which type of request field encoding to use.
|
|
|
|
Specifically,
|
|
|
|
:meth:`.request_encode_url` is for sending requests whose fields are encoded
|
|
in the URL (such as GET, HEAD, DELETE).
|
|
|
|
:meth:`.request_encode_body` is for sending requests whose fields are
|
|
encoded in the *body* of the request using multipart or www-form-urlencoded
|
|
(such as for POST, PUT, PATCH).
|
|
|
|
:meth:`.request` is for making any kind of request, it will look up the
|
|
appropriate encoding format and use one of the above two methods to make
|
|
the request.
|
|
|
|
Initializer parameters:
|
|
|
|
:param headers:
|
|
Headers to include with all requests, unless other headers are given
|
|
explicitly.
|
|
"""
|
|
|
|
_encode_url_methods = set(['DELETE', 'GET', 'HEAD', 'OPTIONS'])
|
|
_encode_body_methods = set(['PATCH', 'POST', 'PUT', 'TRACE'])
|
|
|
|
def __init__(self, headers=None):
|
|
self.headers = headers or {}
|
|
|
|
def urlopen(self, method, url, body=None, headers=None,
|
|
encode_multipart=True, multipart_boundary=None,
|
|
**kw): # Abstract
|
|
raise NotImplemented("Classes extending RequestMethods must implement "
|
|
"their own ``urlopen`` method.")
|
|
|
|
def request(self, method, url, fields=None, headers=None, **urlopen_kw):
|
|
"""
|
|
Make a request using :meth:`urlopen` with the appropriate encoding of
|
|
``fields`` based on the ``method`` used.
|
|
|
|
This is a convenience method that requires the least amount of manual
|
|
effort. It can be used in most situations, while still having the option
|
|
to drop down to more specific methods when necessary, such as
|
|
:meth:`request_encode_url`, :meth:`request_encode_body`,
|
|
or even the lowest level :meth:`urlopen`.
|
|
"""
|
|
method = method.upper()
|
|
|
|
if method in self._encode_url_methods:
|
|
return self.request_encode_url(method, url, fields=fields,
|
|
headers=headers,
|
|
**urlopen_kw)
|
|
else:
|
|
return self.request_encode_body(method, url, fields=fields,
|
|
headers=headers,
|
|
**urlopen_kw)
|
|
|
|
def request_encode_url(self, method, url, fields=None, **urlopen_kw):
|
|
"""
|
|
Make a request using :meth:`urlopen` with the ``fields`` encoded in
|
|
the url. This is useful for request methods like GET, HEAD, DELETE, etc.
|
|
"""
|
|
if fields:
|
|
url += '?' + urlencode(fields)
|
|
return self.urlopen(method, url, **urlopen_kw)
|
|
|
|
def request_encode_body(self, method, url, fields=None, headers=None,
|
|
encode_multipart=True, multipart_boundary=None,
|
|
**urlopen_kw):
|
|
"""
|
|
Make a request using :meth:`urlopen` with the ``fields`` encoded in
|
|
the body. This is useful for request methods like POST, PUT, PATCH, etc.
|
|
|
|
When ``encode_multipart=True`` (default), then
|
|
:meth:`urllib3.filepost.encode_multipart_formdata` is used to encode the
|
|
payload with the appropriate content type. Otherwise
|
|
:meth:`urllib.urlencode` is used with the
|
|
'application/x-www-form-urlencoded' content type.
|
|
|
|
Multipart encoding must be used when posting files, and it's reasonably
|
|
safe to use it in other times too. However, it may break request signing,
|
|
such as with OAuth.
|
|
|
|
Supports an optional ``fields`` parameter of key/value strings AND
|
|
key/filetuple. A filetuple is a (filename, data, MIME type) tuple where
|
|
the MIME type is optional. For example: ::
|
|
|
|
fields = {
|
|
'foo': 'bar',
|
|
'fakefile': ('foofile.txt', 'contents of foofile'),
|
|
'realfile': ('barfile.txt', open('realfile').read()),
|
|
'typedfile': ('bazfile.bin', open('bazfile').read(),
|
|
'image/jpeg'),
|
|
'nonamefile': 'contents of nonamefile field',
|
|
}
|
|
|
|
When uploading a file, providing a filename (the first parameter of the
|
|
tuple) is optional but recommended to best mimick behavior of browsers.
|
|
|
|
Note that if ``headers`` are supplied, the 'Content-Type' header will be
|
|
overwritten because it depends on the dynamic random boundary string
|
|
which is used to compose the body of the request. The random boundary
|
|
string can be explicitly set with the ``multipart_boundary`` parameter.
|
|
"""
|
|
if encode_multipart:
|
|
body, content_type = encode_multipart_formdata(fields or {},
|
|
boundary=multipart_boundary)
|
|
else:
|
|
body, content_type = (urlencode(fields or {}),
|
|
'application/x-www-form-urlencoded')
|
|
|
|
if headers is None:
|
|
headers = self.headers
|
|
|
|
headers_ = {'Content-Type': content_type}
|
|
headers_.update(headers)
|
|
|
|
return self.urlopen(method, url, body=body, headers=headers_,
|
|
**urlopen_kw)
|