1 """HTTP server base class.
3 Note: the class in this module doesn't implement any HTTP request; see
4 SimpleHTTPServer for simple implementations of GET, HEAD and POST
5 (including CGI scripts).
9 - BaseHTTPRequestHandler: HTTP request handler base class
15 - log requests even later (to capture byte count)
16 - log user-agent header and other interesting goodies
17 - send error log to separate file
18 - are request names really case sensitive?
66 __all__ = [
"HTTPServer",
"BaseHTTPRequestHandler"]
75 DEFAULT_ERROR_MESSAGE =
"""\
77 <title>Error response</title>
80 <h1>Error response</h1>
81 <p>Error code %(code)d.
82 <p>Message: %(message)s.
83 <p>Error code explanation: %(code)s = %(explain)s.
90 allow_reuse_address = 1
93 """Override server_bind to store the server name."""
95 host, port = self.socket.getsockname()
102 """HTTP request handler base class.
104 The following explanation of HTTP serves to guide you through the
105 code as well as to expose any misunderstandings I may have about
106 HTTP (so you don't need to read the code to figure out I'm wrong
109 HTTP (HyperText Transfer Protocol) is an extensible protocol on
110 top of a reliable stream transport (e.g. TCP/IP). The protocol
111 recognizes three parts to a request:
113 1. One line identifying the request type and path
114 2. An optional set of RFC-822-style headers
115 3. An optional data part
117 The headers and data are separated by a blank line.
119 The first line of the request has the form
121 <command> <path> <version>
123 where <command> is a (case-sensitive) keyword such as GET or POST,
124 <path> is a string containing path information for the request,
125 and <version> should be the string "HTTP/1.0". <path> is encoded
126 using the URL encoding scheme (using %xx to signify the ASCII
127 character with hex code xx).
129 The protocol is vague about whether lines are separated by LF
130 characters or by CRLF pairs -- for compatibility with the widest
131 range of clients, both should be accepted. Similarly, whitespace
132 in the request line should be treated sensibly (allowing multiple
133 spaces between components and allowing trailing whitespace).
135 Similarly, for output, lines ought to be separated by CRLF pairs
136 but most clients grok LF characters just fine.
138 If the first line of the request has the form
142 (i.e. <version> is left out) then this is assumed to be an HTTP
143 0.9 request; this form has no optional headers and data part and
144 the reply consists of just the data.
146 The reply form of the HTTP 1.0 protocol again has three parts:
148 1. One line giving the response code
149 2. An optional set of RFC-822-style headers
152 Again, the headers and data are separated by a blank line.
154 The response code line has the form
156 <version> <responsecode> <responsestring>
158 where <version> is the protocol version (always "HTTP/1.0"),
159 <responsecode> is a 3-digit response code indicating success or
160 failure of the request, and <responsestring> is an optional
161 human-readable string explaining what the response code means.
163 This server parses the request and the headers, and then calls a
164 function specific to the request type (<command>). Specifically,
165 a request SPAM will be handled by a method do_SPAM(). If no
166 such method exists the server sends an error response to the
167 client. If it exists, it is called with no arguments:
171 Note that the request name is case sensitive (i.e. SPAM and spam
172 are different requests).
174 The various request details are stored in instance variables:
176 - client_address is the client IP address in the form (host,
179 - command, path and version are the broken-down request line;
181 - headers is an instance of mimetools.Message (or a derived
182 class) containing the header information;
184 - rfile is a file object open for reading positioned at the
185 start of the optional input data part;
187 - wfile is a file object open for writing.
189 IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
191 The first thing to be written must be the response line. Then
192 follow 0 or more header lines, then a blank line, and then the
193 actual data (if any). The meaning of the header lines depends on
194 the command executed by the server; in most cases, when data is
195 returned, there should be at least one header line of the form
197 Content-type: <type>/<subtype>
199 where <type> and <subtype> should be registered MIME types,
200 e.g. "text/html" or "text/plain".
205 sys_version =
"Python/" + sys.version.split()[0]
210 server_version =
"BaseHTTP/" + __version__
213 """Parse a request (internal).
215 The request should be stored in self.raw_request; the results
216 are in self.command, self.path, self.request_version and
219 Return value is 1 for success, 0 for failure; on failure, an
225 if requestline[-2:] ==
'\r\n':
226 requestline = requestline[:-2]
227 elif requestline[-1:] ==
'\n':
228 requestline = requestline[:-1]
230 words = requestline.split()
232 [command, path, version] = words
233 if version[:5] !=
'HTTP/':
234 self.
send_error(400,
"Bad request version (%s)" % `version`)
236 elif len(words) == 2:
237 [command, path] = words
240 "Bad HTTP/0.9 request type (%s)" % `command`)
243 self.
send_error(400,
"Bad request syntax (%s)" % `requestline`)
250 """Handle a single HTTP request.
252 You normally don't need to override this method; see the class
253 __doc__ string for information on how to handle specific HTTP
254 commands such as GET and POST.
261 mname =
'do_' + self.command
262 if not hasattr(self, mname):
263 self.
send_error(501,
"Unsupported method (%s)" % `self.command`)
265 method = getattr(self, mname)
269 """Send and log an error reply.
271 Arguments are the error code, and a detailed message.
272 The detailed message defaults to the short entry matching the
275 This sends an error response (so it must be called before any
276 output has been generated), logs the error, and finally sends
277 a piece of HTML explaining the error to the user.
284 short, long =
'???',
'???'
288 self.
log_error(
"code %d, message %s", code, message)
297 error_message_format = DEFAULT_ERROR_MESSAGE
300 """Send the response header and log the response code.
302 Also send two standard headers with the server software
303 version and the current date.
308 if self.responses.has_key(code):
313 self.wfile.write(
"%s %s %s\r\n" %
319 """Send a MIME header."""
321 self.wfile.write(
"%s: %s\r\n" % (keyword, value))
324 """Send the blank line ending the MIME headers."""
326 self.wfile.write(
"\r\n")
329 """Log an accepted request.
331 This is called by send_reponse().
341 This is called when a request cannot be fulfilled. By
342 default it passes the message on to log_message().
344 Arguments are the same as for log_message().
346 XXX This should go to the separate error log.
353 """Log an arbitrary message.
355 This is used by all other logging functions. Override
356 it if you have specific logging wishes.
358 The first argument, FORMAT, is a format string for the
359 message to be logged. If the format string contains
360 any % escapes requiring parameters, they should be
361 specified as subsequent arguments (it's just like
364 The client host and current date/time are prefixed to
369 sys.stderr.write(
"%s - - [%s] %s\n" %
375 """Return the server software version string."""
379 """Return the current date and time formatted for a message header."""
381 year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
382 s =
"%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
389 """Return the current time formatted for logging."""
391 year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
392 s =
"%02d/%3s/%04d %02d:%02d:%02d" % (
393 day, self.
monthname[month], year, hh, mm, ss)
396 weekdayname = [
'Mon',
'Tue',
'Wed',
'Thu',
'Fri',
'Sat',
'Sun']
399 'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
400 'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec']
403 """Return the client address formatted for logging.
405 This version looks up the full hostname using gethostbyaddr(),
406 and tries to find a name that contains at least one dot.
418 protocol_version =
"HTTP/1.0"
427 200: (
'OK',
'Request fulfilled, document follows'),
428 201: (
'Created',
'Document created, URL follows'),
430 'Request accepted, processing continues off-line'),
431 203: (
'Partial information',
'Request fulfilled from cache'),
432 204: (
'No response',
'Request fulfilled, nothing follows'),
434 301: (
'Moved',
'Object moved permanently -- see URI list'),
435 302: (
'Found',
'Object moved temporarily -- see URI list'),
436 303: (
'Method',
'Object moved -- see Method and URL list'),
437 304: (
'Not modified',
438 'Document has not changed singe given time'),
441 'Bad request syntax or unsupported method'),
442 401: (
'Unauthorized',
443 'No permission -- see authorization schemes'),
444 402: (
'Payment required',
445 'No payment -- see charging schemes'),
447 'Request forbidden -- authorization will not help'),
448 404: (
'Not found',
'Nothing matches the given URI'),
450 500: (
'Internal error',
'Server got itself in trouble'),
451 501: (
'Not implemented',
452 'Server does not support this operation'),
453 502: (
'Service temporarily overloaded',
454 'The server cannot process the request due to a high load'),
455 503: (
'Gateway timeout',
456 'The gateway server did not receive a timely response'),
461 def test(HandlerClass = BaseHTTPRequestHandler,
462 ServerClass = HTTPServer):
463 """Test the HTTP request handler class.
465 This runs an HTTP server on port 8000 (or the first command line
471 port = int(sys.argv[1])
474 server_address = (
'', port)
476 httpd = ServerClass(server_address, HandlerClass)
478 sa = httpd.socket.getsockname()
479 print "Serving HTTP on", sa[0],
"port", sa[1],
"..."
480 httpd.serve_forever()
483 if __name__ ==
'__main__':