图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
6.5 KiB

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