mirror of
https://github.com/python/cpython.git
synced 2025-12-15 21:44:50 +00:00
Issue #21793: Added http.HTTPStatus enums (i.e. HTTPStatus.OK,
HTTPStatus.NOT_FOUND). Patch by Demian Brecht.
This commit is contained in:
parent
ab47932212
commit
e4db76967d
6 changed files with 352 additions and 215 deletions
|
|
@ -100,6 +100,8 @@ import urllib.parse
|
|||
import copy
|
||||
import argparse
|
||||
|
||||
from http import HTTPStatus
|
||||
|
||||
|
||||
# Default error message template
|
||||
DEFAULT_ERROR_MESSAGE = """\
|
||||
|
|
@ -278,7 +280,9 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
if len(words) == 3:
|
||||
command, path, version = words
|
||||
if version[:5] != 'HTTP/':
|
||||
self.send_error(400, "Bad request version (%r)" % version)
|
||||
self.send_error(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
"Bad request version (%r)" % version)
|
||||
return False
|
||||
try:
|
||||
base_version_number = version.split('/', 1)[1]
|
||||
|
|
@ -293,25 +297,31 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
raise ValueError
|
||||
version_number = int(version_number[0]), int(version_number[1])
|
||||
except (ValueError, IndexError):
|
||||
self.send_error(400, "Bad request version (%r)" % version)
|
||||
self.send_error(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
"Bad request version (%r)" % version)
|
||||
return False
|
||||
if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
|
||||
self.close_connection = 0
|
||||
if version_number >= (2, 0):
|
||||
self.send_error(505,
|
||||
"Invalid HTTP Version (%s)" % base_version_number)
|
||||
self.send_error(
|
||||
HTTPStatus.HTTP_VERSION_NOT_SUPPORTED,
|
||||
"Invalid HTTP Version (%s)" % base_version_number)
|
||||
return False
|
||||
elif len(words) == 2:
|
||||
command, path = words
|
||||
self.close_connection = 1
|
||||
if command != 'GET':
|
||||
self.send_error(400,
|
||||
"Bad HTTP/0.9 request type (%r)" % command)
|
||||
self.send_error(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
"Bad HTTP/0.9 request type (%r)" % command)
|
||||
return False
|
||||
elif not words:
|
||||
return False
|
||||
else:
|
||||
self.send_error(400, "Bad request syntax (%r)" % requestline)
|
||||
self.send_error(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
"Bad request syntax (%r)" % requestline)
|
||||
return False
|
||||
self.command, self.path, self.request_version = command, path, version
|
||||
|
||||
|
|
@ -320,7 +330,9 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
self.headers = http.client.parse_headers(self.rfile,
|
||||
_class=self.MessageClass)
|
||||
except http.client.LineTooLong:
|
||||
self.send_error(400, "Line too long")
|
||||
self.send_error(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
"Line too long")
|
||||
return False
|
||||
|
||||
conntype = self.headers.get('Connection', "")
|
||||
|
|
@ -352,7 +364,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
False.
|
||||
|
||||
"""
|
||||
self.send_response_only(100)
|
||||
self.send_response_only(HTTPStatus.CONTINUE)
|
||||
self.end_headers()
|
||||
return True
|
||||
|
||||
|
|
@ -370,7 +382,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
self.requestline = ''
|
||||
self.request_version = ''
|
||||
self.command = ''
|
||||
self.send_error(414)
|
||||
self.send_error(HTTPStatus.REQUEST_URI_TOO_LONG)
|
||||
return
|
||||
if not self.raw_requestline:
|
||||
self.close_connection = 1
|
||||
|
|
@ -380,7 +392,9 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
return
|
||||
mname = 'do_' + self.command
|
||||
if not hasattr(self, mname):
|
||||
self.send_error(501, "Unsupported method (%r)" % self.command)
|
||||
self.send_error(
|
||||
HTTPStatus.NOT_IMPLEMENTED,
|
||||
"Unsupported method (%r)" % self.command)
|
||||
return
|
||||
method = getattr(self, mname)
|
||||
method()
|
||||
|
|
@ -435,7 +449,11 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
self.send_header('Connection', 'close')
|
||||
self.send_header('Content-Length', int(len(body)))
|
||||
self.end_headers()
|
||||
if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
|
||||
|
||||
if (self.command != 'HEAD' and
|
||||
code >= 200 and
|
||||
code not in (
|
||||
HTTPStatus.NO_CONTENT, HTTPStatus.NOT_MODIFIED)):
|
||||
self.wfile.write(body)
|
||||
|
||||
def send_response(self, code, message=None):
|
||||
|
|
@ -579,82 +597,11 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
|
|||
# MessageClass used to parse headers
|
||||
MessageClass = http.client.HTTPMessage
|
||||
|
||||
# Table mapping response codes to messages; entries have the
|
||||
# form {code: (shortmessage, longmessage)}.
|
||||
# See RFC 2616 and 6585.
|
||||
# hack to maintain backwards compatibility
|
||||
responses = {
|
||||
100: ('Continue', 'Request received, please continue'),
|
||||
101: ('Switching Protocols',
|
||||
'Switching to new protocol; obey Upgrade header'),
|
||||
|
||||
200: ('OK', 'Request fulfilled, document follows'),
|
||||
201: ('Created', 'Document created, URL follows'),
|
||||
202: ('Accepted',
|
||||
'Request accepted, processing continues off-line'),
|
||||
203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
|
||||
204: ('No Content', 'Request fulfilled, nothing follows'),
|
||||
205: ('Reset Content', 'Clear input form for further input.'),
|
||||
206: ('Partial Content', 'Partial content follows.'),
|
||||
|
||||
300: ('Multiple Choices',
|
||||
'Object has several resources -- see URI list'),
|
||||
301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
|
||||
302: ('Found', 'Object moved temporarily -- see URI list'),
|
||||
303: ('See Other', 'Object moved -- see Method and URL list'),
|
||||
304: ('Not Modified',
|
||||
'Document has not changed since given time'),
|
||||
305: ('Use Proxy',
|
||||
'You must use proxy specified in Location to access this '
|
||||
'resource.'),
|
||||
307: ('Temporary Redirect',
|
||||
'Object moved temporarily -- see URI list'),
|
||||
|
||||
400: ('Bad Request',
|
||||
'Bad request syntax or unsupported method'),
|
||||
401: ('Unauthorized',
|
||||
'No permission -- see authorization schemes'),
|
||||
402: ('Payment Required',
|
||||
'No payment -- see charging schemes'),
|
||||
403: ('Forbidden',
|
||||
'Request forbidden -- authorization will not help'),
|
||||
404: ('Not Found', 'Nothing matches the given URI'),
|
||||
405: ('Method Not Allowed',
|
||||
'Specified method is invalid for this resource.'),
|
||||
406: ('Not Acceptable', 'URI not available in preferred format.'),
|
||||
407: ('Proxy Authentication Required', 'You must authenticate with '
|
||||
'this proxy before proceeding.'),
|
||||
408: ('Request Timeout', 'Request timed out; try again later.'),
|
||||
409: ('Conflict', 'Request conflict.'),
|
||||
410: ('Gone',
|
||||
'URI no longer exists and has been permanently removed.'),
|
||||
411: ('Length Required', 'Client must specify Content-Length.'),
|
||||
412: ('Precondition Failed', 'Precondition in headers is false.'),
|
||||
413: ('Request Entity Too Large', 'Entity is too large.'),
|
||||
414: ('Request-URI Too Long', 'URI is too long.'),
|
||||
415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
|
||||
416: ('Requested Range Not Satisfiable',
|
||||
'Cannot satisfy request range.'),
|
||||
417: ('Expectation Failed',
|
||||
'Expect condition could not be satisfied.'),
|
||||
428: ('Precondition Required',
|
||||
'The origin server requires the request to be conditional.'),
|
||||
429: ('Too Many Requests', 'The user has sent too many requests '
|
||||
'in a given amount of time ("rate limiting").'),
|
||||
431: ('Request Header Fields Too Large', 'The server is unwilling to '
|
||||
'process the request because its header fields are too large.'),
|
||||
|
||||
500: ('Internal Server Error', 'Server got itself in trouble'),
|
||||
501: ('Not Implemented',
|
||||
'Server does not support this operation'),
|
||||
502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
|
||||
503: ('Service Unavailable',
|
||||
'The server cannot process the request due to a high load'),
|
||||
504: ('Gateway Timeout',
|
||||
'The gateway server did not receive a timely response'),
|
||||
505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
|
||||
511: ('Network Authentication Required',
|
||||
'The client needs to authenticate to gain network access.'),
|
||||
}
|
||||
v: (v.phrase, v.description)
|
||||
for v in HTTPStatus.__members__.values()
|
||||
}
|
||||
|
||||
|
||||
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
|
|
@ -703,7 +650,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||
if os.path.isdir(path):
|
||||
if not self.path.endswith('/'):
|
||||
# redirect browser - doing basically what apache does
|
||||
self.send_response(301)
|
||||
self.send_response(HTTPStatus.MOVED_PERMANENTLY)
|
||||
self.send_header("Location", self.path + "/")
|
||||
self.end_headers()
|
||||
return None
|
||||
|
|
@ -718,10 +665,10 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||
try:
|
||||
f = open(path, 'rb')
|
||||
except OSError:
|
||||
self.send_error(404, "File not found")
|
||||
self.send_error(HTTPStatus.NOT_FOUND, "File not found")
|
||||
return None
|
||||
try:
|
||||
self.send_response(200)
|
||||
self.send_response(HTTPStatus.OK)
|
||||
self.send_header("Content-type", ctype)
|
||||
fs = os.fstat(f.fileno())
|
||||
self.send_header("Content-Length", str(fs[6]))
|
||||
|
|
@ -743,7 +690,9 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||
try:
|
||||
list = os.listdir(path)
|
||||
except OSError:
|
||||
self.send_error(404, "No permission to list directory")
|
||||
self.send_error(
|
||||
HTTPStatus.NOT_FOUND,
|
||||
"No permission to list directory")
|
||||
return None
|
||||
list.sort(key=lambda a: a.lower())
|
||||
r = []
|
||||
|
|
@ -782,7 +731,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||
f = io.BytesIO()
|
||||
f.write(encoded)
|
||||
f.seek(0)
|
||||
self.send_response(200)
|
||||
self.send_response(HTTPStatus.OK)
|
||||
self.send_header("Content-type", "text/html; charset=%s" % enc)
|
||||
self.send_header("Content-Length", str(len(encoded)))
|
||||
self.end_headers()
|
||||
|
|
@ -964,7 +913,9 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
|
|||
if self.is_cgi():
|
||||
self.run_cgi()
|
||||
else:
|
||||
self.send_error(501, "Can only POST to CGI scripts")
|
||||
self.send_error(
|
||||
HTTPStatus.NOT_IMPLEMENTED,
|
||||
"Can only POST to CGI scripts")
|
||||
|
||||
def send_head(self):
|
||||
"""Version of send_head that support CGI scripts"""
|
||||
|
|
@ -1042,17 +993,21 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
|
|||
scriptname = dir + '/' + script
|
||||
scriptfile = self.translate_path(scriptname)
|
||||
if not os.path.exists(scriptfile):
|
||||
self.send_error(404, "No such CGI script (%r)" % scriptname)
|
||||
self.send_error(
|
||||
HTTPStatus.NOT_FOUND,
|
||||
"No such CGI script (%r)" % scriptname)
|
||||
return
|
||||
if not os.path.isfile(scriptfile):
|
||||
self.send_error(403, "CGI script is not a plain file (%r)" %
|
||||
scriptname)
|
||||
self.send_error(
|
||||
HTTPStatus.FORBIDDEN,
|
||||
"CGI script is not a plain file (%r)" % scriptname)
|
||||
return
|
||||
ispy = self.is_python(scriptname)
|
||||
if self.have_fork or not ispy:
|
||||
if not self.is_executable(scriptfile):
|
||||
self.send_error(403, "CGI script is not executable (%r)" %
|
||||
scriptname)
|
||||
self.send_error(
|
||||
HTTPStatus.FORBIDDEN,
|
||||
"CGI script is not executable (%r)" % scriptname)
|
||||
return
|
||||
|
||||
# Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
|
||||
|
|
@ -1120,7 +1075,7 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
|
|||
'HTTP_USER_AGENT', 'HTTP_COOKIE', 'HTTP_REFERER'):
|
||||
env.setdefault(k, "")
|
||||
|
||||
self.send_response(200, "Script output follows")
|
||||
self.send_response(HTTPStatus.OK, "Script output follows")
|
||||
self.flush_headers()
|
||||
|
||||
decoded_query = query.replace('+', ' ')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue