BaseHTTPServer.py (11188B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\BaseHTTPServer.py 2 __version__ = '0.3' 3 __all__ = ['HTTPServer', 'BaseHTTPRequestHandler'] 4 import sys 5 import time 6 import socket 7 from warnings import filterwarnings, catch_warnings 8 with catch_warnings(): 9 if sys.py3kwarning: 10 filterwarnings('ignore', '.*mimetools has been removed', DeprecationWarning) 11 import mimetools 12 import SocketServer 13 DEFAULT_ERROR_MESSAGE = '<head>\n<title>Error response</title>\n</head>\n<body>\n<h1>Error response</h1>\n<p>Error code %(code)d.\n<p>Message: %(message)s.\n<p>Error code explanation: %(code)s = %(explain)s.\n</body>\n' 14 DEFAULT_ERROR_CONTENT_TYPE = 'text/html' 15 16 def _quote_html(html): 17 return html.replace('&', '&').replace('<', '<').replace('>', '>') 18 19 20 class HTTPServer(SocketServer.TCPServer): 21 allow_reuse_address = 1 22 23 def server_bind(self): 24 SocketServer.TCPServer.server_bind(self) 25 host, port = self.socket.getsockname()[:2] 26 self.server_name = socket.getfqdn(host) 27 self.server_port = port 28 29 30 class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): 31 sys_version = 'Python/' + sys.version.split()[0] 32 server_version = 'BaseHTTP/' + __version__ 33 default_request_version = 'HTTP/0.9' 34 35 def parse_request(self): 36 self.command = None 37 self.request_version = version = self.default_request_version 38 self.close_connection = 1 39 requestline = self.raw_requestline 40 if requestline[-2:] == '\r\n': 41 requestline = requestline[:-2] 42 elif requestline[-1:] == '\n': 43 requestline = requestline[:-1] 44 self.requestline = requestline 45 words = requestline.split() 46 if len(words) == 3: 47 command, path, version = words 48 if version[:5] != 'HTTP/': 49 self.send_error(400, 'Bad request version (%r)' % version) 50 return False 51 try: 52 base_version_number = version.split('/', 1)[1] 53 version_number = base_version_number.split('.') 54 if len(version_number) != 2: 55 raise ValueError 56 version_number = (int(version_number[0]), int(version_number[1])) 57 except (ValueError, IndexError): 58 self.send_error(400, 'Bad request version (%r)' % version) 59 return False 60 61 if version_number >= (1, 1) and self.protocol_version >= 'HTTP/1.1': 62 self.close_connection = 0 63 if version_number >= (2, 0): 64 self.send_error(505, 'Invalid HTTP Version (%s)' % base_version_number) 65 return False 66 elif len(words) == 2: 67 command, path = words 68 self.close_connection = 1 69 if command != 'GET': 70 self.send_error(400, 'Bad HTTP/0.9 request type (%r)' % command) 71 return False 72 else: 73 if not words: 74 return False 75 self.send_error(400, 'Bad request syntax (%r)' % requestline) 76 return False 77 self.command, self.path, self.request_version = command, path, version 78 self.headers = self.MessageClass(self.rfile, 0) 79 conntype = self.headers.get('Connection', '') 80 if conntype.lower() == 'close': 81 self.close_connection = 1 82 elif conntype.lower() == 'keep-alive' and self.protocol_version >= 'HTTP/1.1': 83 self.close_connection = 0 84 return True 85 86 def handle_one_request(self): 87 try: 88 self.raw_requestline = self.rfile.readline() 89 if not self.raw_requestline: 90 self.close_connection = 1 91 return 92 if not self.parse_request(): 93 return 94 mname = 'do_' + self.command 95 if not hasattr(self, mname): 96 self.send_error(501, 'Unsupported method (%r)' % self.command) 97 return 98 method = getattr(self, mname) 99 method() 100 self.wfile.flush() 101 except socket.timeout as e: 102 self.log_error('Request timed out: %r', e) 103 self.close_connection = 1 104 return 105 106 def handle(self): 107 self.close_connection = 1 108 self.handle_one_request() 109 while not self.close_connection: 110 self.handle_one_request() 111 112 def send_error(self, code, message = None): 113 try: 114 short, long = self.responses[code] 115 except KeyError: 116 short, long = ('???', '???') 117 118 if message is None: 119 message = short 120 explain = long 121 self.log_error('code %d, message %s', code, message) 122 content = self.error_message_format % {'code': code, 123 'message': _quote_html(message), 124 'explain': explain} 125 self.send_response(code, message) 126 self.send_header('Content-Type', self.error_content_type) 127 self.send_header('Connection', 'close') 128 self.end_headers() 129 if self.command != 'HEAD' and code >= 200 and code not in (204, 304): 130 self.wfile.write(content) 131 132 error_message_format = DEFAULT_ERROR_MESSAGE 133 error_content_type = DEFAULT_ERROR_CONTENT_TYPE 134 135 def send_response(self, code, message = None): 136 self.log_request(code) 137 if message is None: 138 if code in self.responses: 139 message = self.responses[code][0] 140 else: 141 message = '' 142 if self.request_version != 'HTTP/0.9': 143 self.wfile.write('%s %d %s\r\n' % (self.protocol_version, code, message)) 144 self.send_header('Server', self.version_string()) 145 self.send_header('Date', self.date_time_string()) 146 147 def send_header(self, keyword, value): 148 if self.request_version != 'HTTP/0.9': 149 self.wfile.write('%s: %s\r\n' % (keyword, value)) 150 if keyword.lower() == 'connection': 151 if value.lower() == 'close': 152 self.close_connection = 1 153 elif value.lower() == 'keep-alive': 154 self.close_connection = 0 155 156 def end_headers(self): 157 if self.request_version != 'HTTP/0.9': 158 self.wfile.write('\r\n') 159 160 def log_request(self, code = '-', size = '-'): 161 self.log_message('"%s" %s %s', self.requestline, str(code), str(size)) 162 163 def log_error(self, format, *args): 164 self.log_message(format, *args) 165 166 def log_message(self, format, *args): 167 sys.stderr.write('%s - - [%s] %s\n' % (self.address_string(), self.log_date_time_string(), format % args)) 168 169 def version_string(self): 170 return self.server_version + ' ' + self.sys_version 171 172 def date_time_string(self, timestamp = None): 173 if timestamp is None: 174 timestamp = time.time() 175 year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp) 176 s = '%s, %02d %3s %4d %02d:%02d:%02d GMT' % (self.weekdayname[wd], 177 day, 178 self.monthname[month], 179 year, 180 hh, 181 mm, 182 ss) 183 return s 184 185 def log_date_time_string(self): 186 now = time.time() 187 year, month, day, hh, mm, ss, x, y, z = time.localtime(now) 188 s = '%02d/%3s/%04d %02d:%02d:%02d' % (day, 189 self.monthname[month], 190 year, 191 hh, 192 mm, 193 ss) 194 return s 195 196 weekdayname = ['Mon', 197 'Tue', 198 'Wed', 199 'Thu', 200 'Fri', 201 'Sat', 202 'Sun'] 203 monthname = [None, 204 'Jan', 205 'Feb', 206 'Mar', 207 'Apr', 208 'May', 209 'Jun', 210 'Jul', 211 'Aug', 212 'Sep', 213 'Oct', 214 'Nov', 215 'Dec'] 216 217 def address_string(self): 218 host, port = self.client_address[:2] 219 return socket.getfqdn(host) 220 221 protocol_version = 'HTTP/1.0' 222 MessageClass = mimetools.Message 223 responses = {100: ('Continue', 'Request received, please continue'), 224 101: ('Switching Protocols', 'Switching to new protocol; obey Upgrade header'), 225 200: ('OK', 'Request fulfilled, document follows'), 226 201: ('Created', 'Document created, URL follows'), 227 202: ('Accepted', 'Request accepted, processing continues off-line'), 228 203: ('Non-Authoritative Information', 'Request fulfilled from cache'), 229 204: ('No Content', 'Request fulfilled, nothing follows'), 230 205: ('Reset Content', 'Clear input form for further input.'), 231 206: ('Partial Content', 'Partial content follows.'), 232 300: ('Multiple Choices', 'Object has several resources -- see URI list'), 233 301: ('Moved Permanently', 'Object moved permanently -- see URI list'), 234 302: ('Found', 'Object moved temporarily -- see URI list'), 235 303: ('See Other', 'Object moved -- see Method and URL list'), 236 304: ('Not Modified', 'Document has not changed since given time'), 237 305: ('Use Proxy', 'You must use proxy specified in Location to access this resource.'), 238 307: ('Temporary Redirect', 'Object moved temporarily -- see URI list'), 239 400: ('Bad Request', 'Bad request syntax or unsupported method'), 240 401: ('Unauthorized', 'No permission -- see authorization schemes'), 241 402: ('Payment Required', 'No payment -- see charging schemes'), 242 403: ('Forbidden', 'Request forbidden -- authorization will not help'), 243 404: ('Not Found', 'Nothing matches the given URI'), 244 405: ('Method Not Allowed', 'Specified method is invalid for this resource.'), 245 406: ('Not Acceptable', 'URI not available in preferred format.'), 246 407: ('Proxy Authentication Required', 'You must authenticate with this proxy before proceeding.'), 247 408: ('Request Timeout', 'Request timed out; try again later.'), 248 409: ('Conflict', 'Request conflict.'), 249 410: ('Gone', 'URI no longer exists and has been permanently removed.'), 250 411: ('Length Required', 'Client must specify Content-Length.'), 251 412: ('Precondition Failed', 'Precondition in headers is false.'), 252 413: ('Request Entity Too Large', 'Entity is too large.'), 253 414: ('Request-URI Too Long', 'URI is too long.'), 254 415: ('Unsupported Media Type', 'Entity body in unsupported format.'), 255 416: ('Requested Range Not Satisfiable', 'Cannot satisfy request range.'), 256 417: ('Expectation Failed', 'Expect condition could not be satisfied.'), 257 500: ('Internal Server Error', 'Server got itself in trouble'), 258 501: ('Not Implemented', 'Server does not support this operation'), 259 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'), 260 503: ('Service Unavailable', 'The server cannot process the request due to a high load'), 261 504: ('Gateway Timeout', 'The gateway server did not receive a timely response'), 262 505: ('HTTP Version Not Supported', 'Cannot fulfill request.')} 263 264 265 def test(HandlerClass = BaseHTTPRequestHandler, ServerClass = HTTPServer, protocol = 'HTTP/1.0'): 266 if sys.argv[1:]: 267 port = int(sys.argv[1]) 268 else: 269 port = 8000 270 server_address = ('', port) 271 HandlerClass.protocol_version = protocol 272 httpd = ServerClass(server_address, HandlerClass) 273 sa = httpd.socket.getsockname() 274 print 'Serving HTTP on', sa[0], 'port', sa[1], '...' 275 httpd.serve_forever() 276 277 278 if __name__ == '__main__': 279 test()