from __future__ import absolute_import
from . filepost import encode_multipart_formdata
from . packages . six . moves . urllib . parse import urlencode
__all__ = [ " RequestMethods " ]
class RequestMethods ( object ) :
"""
Convenience mixin for classes who implement a : meth : ` urlopen ` method , such
as : class : ` urllib3 . HTTPConnectionPool ` and
: class : ` urllib3 . 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 = { " DELETE " , " GET " , " HEAD " , " OPTIONS " }
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 NotImplementedError (
" 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 ( )
urlopen_kw [ " request_url " ] = url
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 , headers = 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 headers is None :
headers = self . headers
extra_kw = { " headers " : headers }
extra_kw . update ( urlopen_kw )
if fields :
url + = " ? " + urlencode ( fields )
return self . urlopen ( method , url , * * extra_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
: func : ` urllib3 . encode_multipart_formdata ` is used to encode
the payload with the appropriate content type . Otherwise
: func : ` urllib . parse . 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 mimic 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 headers is None :
headers = self . headers
extra_kw = { " headers " : { } }
if fields :
if " body " in urlopen_kw :
raise TypeError (
" request got values for both ' fields ' and ' body ' , can only specify one. "
)
if encode_multipart :
body , content_type = encode_multipart_formdata (
fields , boundary = multipart_boundary
)
else :
body , content_type = (
urlencode ( fields ) ,
" application/x-www-form-urlencoded " ,
)
extra_kw [ " body " ] = body
extra_kw [ " headers " ] = { " Content-Type " : content_type }
extra_kw [ " headers " ] . update ( headers )
extra_kw . update ( urlopen_kw )
return self . urlopen ( method , url , * * extra_kw )