http.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. # #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # <HTTPretty - HTTP client mock for Python>
  4. # Copyright (C) <2011-2018> Gabriel Falcao <gabriel@nacaolivre.org>
  5. #
  6. # Permission is hereby granted, free of charge, to any person
  7. # obtaining a copy of this software and associated documentation
  8. # files (the "Software"), to deal in the Software without
  9. # restriction, including without limitation the rights to use,
  10. # copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. # copies of the Software, and to permit persons to whom the
  12. # Software is furnished to do so, subject to the following
  13. # conditions:
  14. #
  15. # The above copyright notice and this permission notice shall be
  16. # included in all copies or substantial portions of the Software.
  17. #
  18. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  20. # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  22. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  23. # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  24. # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  25. # OTHER DEALINGS IN THE SOFTWARE.
  26. from __future__ import unicode_literals
  27. import re
  28. from .compat import BaseClass
  29. from .utils import decode_utf8
  30. STATUSES = {
  31. 100: "Continue",
  32. 101: "Switching Protocols",
  33. 102: "Processing",
  34. 200: "OK",
  35. 201: "Created",
  36. 202: "Accepted",
  37. 203: "Non-Authoritative Information",
  38. 204: "No Content",
  39. 205: "Reset Content",
  40. 206: "Partial Content",
  41. 207: "Multi-Status",
  42. 208: "Already Reported",
  43. 226: "IM Used",
  44. 300: "Multiple Choices",
  45. 301: "Moved Permanently",
  46. 302: "Found",
  47. 303: "See Other",
  48. 304: "Not Modified",
  49. 305: "Use Proxy",
  50. 306: "Switch Proxy",
  51. 307: "Temporary Redirect",
  52. 308: "Permanent Redirect",
  53. 400: "Bad Request",
  54. 401: "Unauthorized",
  55. 402: "Payment Required",
  56. 403: "Forbidden",
  57. 404: "Not Found",
  58. 405: "Method Not Allowed",
  59. 406: "Not Acceptable",
  60. 407: "Proxy Authentication Required",
  61. 408: "Request a Timeout",
  62. 409: "Conflict",
  63. 410: "Gone",
  64. 411: "Length Required",
  65. 412: "Precondition Failed",
  66. 413: "Request Entity Too Large",
  67. 414: "Request-URI Too Long",
  68. 415: "Unsupported Media Type",
  69. 416: "Requested Range Not Satisfiable",
  70. 417: "Expectation Failed",
  71. 418: "I'm a teapot",
  72. 420: "Enhance Your Calm",
  73. 422: "Unprocessable Entity",
  74. 423: "Locked",
  75. 424: "Failed Dependency",
  76. 425: "Unordered Collection",
  77. 426: "Upgrade Required",
  78. 428: "Precondition Required",
  79. 429: "Too Many Requests",
  80. 431: "Request Header Fields Too Large",
  81. 444: "No Response",
  82. 449: "Retry With",
  83. 450: "Blocked by Windows Parental Controls",
  84. 451: "Unavailable For Legal Reasons",
  85. 494: "Request Header Too Large",
  86. 495: "Cert Error",
  87. 496: "No Cert",
  88. 497: "HTTP to HTTPS",
  89. 499: "Client Closed Request",
  90. 500: "Internal Server Error",
  91. 501: "Not Implemented",
  92. 502: "Bad Gateway",
  93. 503: "Service Unavailable",
  94. 504: "Gateway Timeout",
  95. 505: "HTTP Version Not Supported",
  96. 506: "Variant Also Negotiates",
  97. 507: "Insufficient Storage",
  98. 508: "Loop Detected",
  99. 509: "Bandwidth Limit Exceeded",
  100. 510: "Not Extended",
  101. 511: "Network Authentication Required",
  102. 598: "Network read timeout error",
  103. 599: "Network connect timeout error",
  104. }
  105. class HttpBaseClass(BaseClass):
  106. GET = 'GET'
  107. PUT = 'PUT'
  108. POST = 'POST'
  109. DELETE = 'DELETE'
  110. HEAD = 'HEAD'
  111. PATCH = 'PATCH'
  112. OPTIONS = 'OPTIONS'
  113. CONNECT = 'CONNECT'
  114. METHODS = (GET, PUT, POST, DELETE, HEAD, PATCH, OPTIONS, CONNECT)
  115. def parse_requestline(s):
  116. """
  117. http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5
  118. >>> parse_requestline('GET / HTTP/1.0')
  119. ('GET', '/', '1.0')
  120. >>> parse_requestline('post /testurl htTP/1.1')
  121. ('POST', '/testurl', '1.1')
  122. >>> parse_requestline('Im not a RequestLine')
  123. Traceback (most recent call last):
  124. ...
  125. ValueError: Not a Request-Line
  126. """
  127. methods = '|'.join(HttpBaseClass.METHODS)
  128. m = re.match(r'(' + methods + r')\s+(.*)\s+HTTP/(1.[0|1])', s, re.I)
  129. if m:
  130. return m.group(1).upper(), m.group(2), m.group(3)
  131. else:
  132. raise ValueError('Not a Request-Line')
  133. def last_requestline(sent_data):
  134. """
  135. Find the last line in sent_data that can be parsed with parse_requestline
  136. """
  137. for line in reversed(sent_data):
  138. try:
  139. parse_requestline(decode_utf8(line))
  140. except ValueError:
  141. pass
  142. else:
  143. return line