blob: fbb810815f3bade3beba961168af093d8212ef81 [file] [log] [blame]
Guido van Rossume7e578f1995-08-04 04:00:20 +00001"""HTTP server base class.
2
3Note: the class in this module doesn't implement any HTTP request; see
4SimpleHTTPServer for simple implementations of GET, HEAD and POST
Martin v. Löwis587c98c2002-03-17 18:37:22 +00005(including CGI scripts). It does, however, optionally implement HTTP/1.1
6persistent connections, as of version 0.3.
Guido van Rossume7e578f1995-08-04 04:00:20 +00007
8Contents:
9
10- BaseHTTPRequestHandler: HTTP request handler base class
11- test: test function
12
13XXX To do:
14
Guido van Rossume7e578f1995-08-04 04:00:20 +000015- log requests even later (to capture byte count)
16- log user-agent header and other interesting goodies
17- send error log to separate file
Guido van Rossume7e578f1995-08-04 04:00:20 +000018"""
19
20
21# See also:
22#
23# HTTP Working Group T. Berners-Lee
24# INTERNET-DRAFT R. T. Fielding
25# <draft-ietf-http-v10-spec-00.txt> H. Frystyk Nielsen
26# Expires September 8, 1995 March 8, 1995
27#
28# URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt
Martin v. Löwis587c98c2002-03-17 18:37:22 +000029#
30# and
31#
32# Network Working Group R. Fielding
33# Request for Comments: 2616 et al
34# Obsoletes: 2068 June 1999
Tim Peters863ac442002-04-16 01:38:40 +000035# Category: Standards Track
Martin v. Löwis587c98c2002-03-17 18:37:22 +000036#
37# URL: http://www.faqs.org/rfcs/rfc2616.html
Guido van Rossume7e578f1995-08-04 04:00:20 +000038
39# Log files
40# ---------
Tim Peters11cf6052001-01-14 21:54:20 +000041#
Guido van Rossume7e578f1995-08-04 04:00:20 +000042# Here's a quote from the NCSA httpd docs about log file format.
Tim Peters11cf6052001-01-14 21:54:20 +000043#
44# | The logfile format is as follows. Each line consists of:
45# |
46# | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb
47# |
48# | host: Either the DNS name or the IP number of the remote client
Guido van Rossume7e578f1995-08-04 04:00:20 +000049# | rfc931: Any information returned by identd for this person,
Tim Peters11cf6052001-01-14 21:54:20 +000050# | - otherwise.
Guido van Rossume7e578f1995-08-04 04:00:20 +000051# | authuser: If user sent a userid for authentication, the user name,
Tim Peters11cf6052001-01-14 21:54:20 +000052# | - otherwise.
53# | DD: Day
54# | Mon: Month (calendar name)
55# | YYYY: Year
56# | hh: hour (24-hour format, the machine's timezone)
57# | mm: minutes
58# | ss: seconds
59# | request: The first line of the HTTP request as sent by the client.
60# | ddd: the status code returned by the server, - if not available.
Guido van Rossume7e578f1995-08-04 04:00:20 +000061# | bbbb: the total number of bytes sent,
Tim Peters11cf6052001-01-14 21:54:20 +000062# | *not including the HTTP/1.0 header*, - if not available
63# |
Guido van Rossume7e578f1995-08-04 04:00:20 +000064# | You can determine the name of the file accessed through request.
Tim Peters11cf6052001-01-14 21:54:20 +000065#
Guido van Rossume7e578f1995-08-04 04:00:20 +000066# (Actually, the latter is only true if you know the server configuration
67# at the time the request was made!)
68
Martin v. Löwis587c98c2002-03-17 18:37:22 +000069__version__ = "0.3"
Guido van Rossume7e578f1995-08-04 04:00:20 +000070
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000071__all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
Guido van Rossume7e578f1995-08-04 04:00:20 +000072
Jeremy Hylton7ffe2992007-08-10 18:49:32 +000073import io
Guido van Rossume7e578f1995-08-04 04:00:20 +000074import sys
75import time
76import socket # For gethostbyaddr()
Guido van Rossume7e578f1995-08-04 04:00:20 +000077import mimetools
78import SocketServer
79
Christian Heimes8640e742008-02-23 16:23:06 +000080# Default error message template
Guido van Rossume7e578f1995-08-04 04:00:20 +000081DEFAULT_ERROR_MESSAGE = """\
82<head>
83<title>Error response</title>
84</head>
85<body>
86<h1>Error response</h1>
87<p>Error code %(code)d.
88<p>Message: %(message)s.
89<p>Error code explanation: %(code)s = %(explain)s.
90</body>
91"""
92
Christian Heimes8640e742008-02-23 16:23:06 +000093DEFAULT_ERROR_CONTENT_TYPE = "text/html;charset=utf-8"
94
Georg Brandla2aa1ac2005-06-26 21:33:14 +000095def _quote_html(html):
96 return html.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
Guido van Rossume7e578f1995-08-04 04:00:20 +000097
98class HTTPServer(SocketServer.TCPServer):
99
Guido van Rossum18865de2000-05-09 14:54:13 +0000100 allow_reuse_address = 1 # Seems to make sense in testing environment
101
Guido van Rossume7e578f1995-08-04 04:00:20 +0000102 def server_bind(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000103 """Override server_bind to store the server name."""
104 SocketServer.TCPServer.server_bind(self)
Martin v. Löwis3c120de2003-05-31 07:55:43 +0000105 host, port = self.socket.getsockname()[:2]
Peter Schneider-Kamp2d2785a2000-08-16 20:30:21 +0000106 self.server_name = socket.getfqdn(host)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000107 self.server_port = port
Guido van Rossume7e578f1995-08-04 04:00:20 +0000108
109
110class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
111
112 """HTTP request handler base class.
113
114 The following explanation of HTTP serves to guide you through the
115 code as well as to expose any misunderstandings I may have about
116 HTTP (so you don't need to read the code to figure out I'm wrong
117 :-).
118
119 HTTP (HyperText Transfer Protocol) is an extensible protocol on
120 top of a reliable stream transport (e.g. TCP/IP). The protocol
121 recognizes three parts to a request:
122
123 1. One line identifying the request type and path
124 2. An optional set of RFC-822-style headers
125 3. An optional data part
126
127 The headers and data are separated by a blank line.
128
129 The first line of the request has the form
130
131 <command> <path> <version>
132
133 where <command> is a (case-sensitive) keyword such as GET or POST,
134 <path> is a string containing path information for the request,
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000135 and <version> should be the string "HTTP/1.0" or "HTTP/1.1".
136 <path> is encoded using the URL encoding scheme (using %xx to signify
137 the ASCII character with hex code xx).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000138
Andrew M. Kuchling8ca202e2003-02-03 15:21:15 +0000139 The specification specifies that lines are separated by CRLF but
140 for compatibility with the widest range of clients recommends
141 servers also handle LF. Similarly, whitespace in the request line
142 is treated sensibly (allowing multiple spaces between components
143 and allowing trailing whitespace).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000144
145 Similarly, for output, lines ought to be separated by CRLF pairs
146 but most clients grok LF characters just fine.
147
148 If the first line of the request has the form
149
150 <command> <path>
151
152 (i.e. <version> is left out) then this is assumed to be an HTTP
153 0.9 request; this form has no optional headers and data part and
154 the reply consists of just the data.
155
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000156 The reply form of the HTTP 1.x protocol again has three parts:
Guido van Rossume7e578f1995-08-04 04:00:20 +0000157
158 1. One line giving the response code
159 2. An optional set of RFC-822-style headers
160 3. The data
161
162 Again, the headers and data are separated by a blank line.
163
164 The response code line has the form
165
166 <version> <responsecode> <responsestring>
167
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000168 where <version> is the protocol version ("HTTP/1.0" or "HTTP/1.1"),
Guido van Rossume7e578f1995-08-04 04:00:20 +0000169 <responsecode> is a 3-digit response code indicating success or
170 failure of the request, and <responsestring> is an optional
171 human-readable string explaining what the response code means.
172
173 This server parses the request and the headers, and then calls a
174 function specific to the request type (<command>). Specifically,
Guido van Rossumba895d81999-09-15 15:28:25 +0000175 a request SPAM will be handled by a method do_SPAM(). If no
Guido van Rossume7e578f1995-08-04 04:00:20 +0000176 such method exists the server sends an error response to the
177 client. If it exists, it is called with no arguments:
178
179 do_SPAM()
180
181 Note that the request name is case sensitive (i.e. SPAM and spam
182 are different requests).
183
184 The various request details are stored in instance variables:
185
186 - client_address is the client IP address in the form (host,
187 port);
188
189 - command, path and version are the broken-down request line;
190
191 - headers is an instance of mimetools.Message (or a derived
192 class) containing the header information;
193
194 - rfile is a file object open for reading positioned at the
195 start of the optional input data part;
196
197 - wfile is a file object open for writing.
198
199 IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
200
201 The first thing to be written must be the response line. Then
202 follow 0 or more header lines, then a blank line, and then the
203 actual data (if any). The meaning of the header lines depends on
204 the command executed by the server; in most cases, when data is
205 returned, there should be at least one header line of the form
206
207 Content-type: <type>/<subtype>
208
209 where <type> and <subtype> should be registered MIME types,
210 e.g. "text/html" or "text/plain".
211
212 """
213
214 # The Python system version, truncated to its first component.
Eric S. Raymondb49f4a42001-02-09 05:07:04 +0000215 sys_version = "Python/" + sys.version.split()[0]
Guido van Rossume7e578f1995-08-04 04:00:20 +0000216
217 # The server software version. You may want to override this.
218 # The format is multiple whitespace-separated strings,
219 # where each string is of the form name[/version].
220 server_version = "BaseHTTP/" + __version__
221
Christian Heimes8640e742008-02-23 16:23:06 +0000222 error_message_format = DEFAULT_ERROR_MESSAGE
223 error_content_type = DEFAULT_ERROR_CONTENT_TYPE
224
Guido van Rossumd65b5391999-10-26 13:01:36 +0000225 def parse_request(self):
226 """Parse a request (internal).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000227
Raymond Hettingerbf68c782003-06-02 14:25:43 +0000228 The request should be stored in self.raw_requestline; the results
Guido van Rossumd65b5391999-10-26 13:01:36 +0000229 are in self.command, self.path, self.request_version and
230 self.headers.
231
Tim Petersbc0e9102002-04-04 22:55:58 +0000232 Return True for success, False for failure; on failure, an
Guido van Rossumd65b5391999-10-26 13:01:36 +0000233 error is sent back.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000234
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000235 """
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000236 self.command = None # set in case of error on the first line
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000237 self.request_version = version = "HTTP/0.9" # Default
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000238 self.close_connection = 1
Jeremy Hyltond2ef8642007-08-03 20:32:27 +0000239 requestline = str(self.raw_requestline, 'iso-8859-1')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000240 if requestline[-2:] == '\r\n':
241 requestline = requestline[:-2]
242 elif requestline[-1:] == '\n':
243 requestline = requestline[:-1]
244 self.requestline = requestline
Eric S. Raymondb49f4a42001-02-09 05:07:04 +0000245 words = requestline.split()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000246 if len(words) == 3:
247 [command, path, version] = words
248 if version[:5] != 'HTTP/':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000249 self.send_error(400, "Bad request version (%r)" % version)
Tim Petersbc0e9102002-04-04 22:55:58 +0000250 return False
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000251 try:
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000252 base_version_number = version.split('/', 1)[1]
253 version_number = base_version_number.split(".")
254 # RFC 2145 section 3.1 says there can be only one "." and
255 # - major and minor numbers MUST be treated as
256 # separate integers;
257 # - HTTP/2.4 is a lower version than HTTP/2.13, which in
258 # turn is lower than HTTP/12.3;
259 # - Leading zeros MUST be ignored by recipients.
260 if len(version_number) != 2:
261 raise ValueError
262 version_number = int(version_number[0]), int(version_number[1])
263 except (ValueError, IndexError):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000264 self.send_error(400, "Bad request version (%r)" % version)
Tim Petersbc0e9102002-04-04 22:55:58 +0000265 return False
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000266 if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000267 self.close_connection = 0
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000268 if version_number >= (2, 0):
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000269 self.send_error(505,
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000270 "Invalid HTTP Version (%s)" % base_version_number)
Tim Petersbc0e9102002-04-04 22:55:58 +0000271 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000272 elif len(words) == 2:
273 [command, path] = words
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000274 self.close_connection = 1
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000275 if command != 'GET':
276 self.send_error(400,
Walter Dörwald70a6b492004-02-12 17:35:32 +0000277 "Bad HTTP/0.9 request type (%r)" % command)
Tim Petersbc0e9102002-04-04 22:55:58 +0000278 return False
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000279 elif not words:
Tim Petersbc0e9102002-04-04 22:55:58 +0000280 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000281 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000282 self.send_error(400, "Bad request syntax (%r)" % requestline)
Tim Petersbc0e9102002-04-04 22:55:58 +0000283 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000284 self.command, self.path, self.request_version = command, path, version
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000285
Guido van Rossumcfe02a42007-08-22 23:45:42 +0000286 # Examine the headers and look for a Connection directive.
287
288 # MessageClass (rfc822) wants to see strings rather than bytes.
289 # But a TextIOWrapper around self.rfile would buffer too many bytes
290 # from the stream, bytes which we later need to read as bytes.
291 # So we read the correct bytes here, as bytes, then use StringIO
292 # to make them look like strings for MessageClass to parse.
293 headers = []
294 while True:
295 line = self.rfile.readline()
296 headers.append(line)
297 if line in (b'\r\n', b'\n', b''):
298 break
299 hfile = io.StringIO(b''.join(headers).decode('iso-8859-1'))
300 self.headers = self.MessageClass(hfile)
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000301
302 conntype = self.headers.get('Connection', "")
303 if conntype.lower() == 'close':
304 self.close_connection = 1
305 elif (conntype.lower() == 'keep-alive' and
306 self.protocol_version >= "HTTP/1.1"):
307 self.close_connection = 0
Tim Petersbc0e9102002-04-04 22:55:58 +0000308 return True
Guido van Rossumd65b5391999-10-26 13:01:36 +0000309
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000310 def handle_one_request(self):
Guido van Rossumd65b5391999-10-26 13:01:36 +0000311 """Handle a single HTTP request.
312
313 You normally don't need to override this method; see the class
314 __doc__ string for information on how to handle specific HTTP
315 commands such as GET and POST.
316
317 """
Guido van Rossumd65b5391999-10-26 13:01:36 +0000318 self.raw_requestline = self.rfile.readline()
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000319 if not self.raw_requestline:
320 self.close_connection = 1
321 return
Guido van Rossumd65b5391999-10-26 13:01:36 +0000322 if not self.parse_request(): # An error code has been sent, just exit
323 return
324 mname = 'do_' + self.command
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000325 if not hasattr(self, mname):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000326 self.send_error(501, "Unsupported method (%r)" % self.command)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000327 return
328 method = getattr(self, mname)
329 method()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000330
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000331 def handle(self):
332 """Handle multiple requests if necessary."""
333 self.close_connection = 1
334
335 self.handle_one_request()
336 while not self.close_connection:
337 self.handle_one_request()
338
Guido van Rossume7e578f1995-08-04 04:00:20 +0000339 def send_error(self, code, message=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000340 """Send and log an error reply.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000341
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000342 Arguments are the error code, and a detailed message.
343 The detailed message defaults to the short entry matching the
344 response code.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000345
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000346 This sends an error response (so it must be called before any
347 output has been generated), logs the error, and finally sends
348 a piece of HTML explaining the error to the user.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000349
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000350 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000351
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000352 try:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000353 shortmsg, longmsg = self.responses[code]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000354 except KeyError:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000355 shortmsg, longmsg = '???', '???'
Raymond Hettingerc0418602002-05-31 23:03:33 +0000356 if message is None:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000357 message = shortmsg
358 explain = longmsg
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000359 self.log_error("code %d, message %s", code, message)
Georg Brandla2aa1ac2005-06-26 21:33:14 +0000360 # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201)
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000361 content = (self.error_message_format %
Georg Brandla2aa1ac2005-06-26 21:33:14 +0000362 {'code': code, 'message': _quote_html(message), 'explain': explain})
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000363 self.send_response(code, message)
Christian Heimes8640e742008-02-23 16:23:06 +0000364 self.send_header("Content-Type", self.error_content_type)
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000365 self.send_header('Connection', 'close')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000366 self.end_headers()
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000367 if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
Bill Janssen1cd5bd22007-10-30 18:13:17 +0000368 self.wfile.write(content.encode('UTF-8', 'replace'))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000369
Guido van Rossume7e578f1995-08-04 04:00:20 +0000370 def send_response(self, code, message=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000371 """Send the response header and log the response code.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000372
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000373 Also send two standard headers with the server software
374 version and the current date.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000375
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000376 """
377 self.log_request(code)
378 if message is None:
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000379 if code in self.responses:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000380 message = self.responses[code][0]
381 else:
382 message = ''
383 if self.request_version != 'HTTP/0.9':
Bill Janssen1cd5bd22007-10-30 18:13:17 +0000384 self.wfile.write(("%s %d %s\r\n" %
385 (self.protocol_version, code, message)).encode('ASCII', 'strict'))
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000386 # print (self.protocol_version, code, message)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000387 self.send_header('Server', self.version_string())
388 self.send_header('Date', self.date_time_string())
Guido van Rossume7e578f1995-08-04 04:00:20 +0000389
390 def send_header(self, keyword, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000391 """Send a MIME header."""
392 if self.request_version != 'HTTP/0.9':
Bill Janssen1cd5bd22007-10-30 18:13:17 +0000393 self.wfile.write(("%s: %s\r\n" % (keyword, value)).encode('ASCII', 'strict'))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000394
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000395 if keyword.lower() == 'connection':
396 if value.lower() == 'close':
397 self.close_connection = 1
398 elif value.lower() == 'keep-alive':
399 self.close_connection = 0
400
Guido van Rossume7e578f1995-08-04 04:00:20 +0000401 def end_headers(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000402 """Send the blank line ending the MIME headers."""
403 if self.request_version != 'HTTP/0.9':
Bill Janssen1cd5bd22007-10-30 18:13:17 +0000404 self.wfile.write(b"\r\n")
Guido van Rossume7e578f1995-08-04 04:00:20 +0000405
406 def log_request(self, code='-', size='-'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000407 """Log an accepted request.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000408
Andrew M. Kuchlingec73cd42006-03-07 16:16:07 +0000409 This is called by send_response().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000410
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000411 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000412
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000413 self.log_message('"%s" %s %s',
414 self.requestline, str(code), str(size))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000415
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000416 def log_error(self, format, *args):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000417 """Log an error.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000418
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 This is called when a request cannot be fulfilled. By
420 default it passes the message on to log_message().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000421
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000422 Arguments are the same as for log_message().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000423
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000424 XXX This should go to the separate error log.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000425
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000426 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000427
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000428 self.log_message(format, *args)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000429
430 def log_message(self, format, *args):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000431 """Log an arbitrary message.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000432
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000433 This is used by all other logging functions. Override
434 it if you have specific logging wishes.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000435
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000436 The first argument, FORMAT, is a format string for the
437 message to be logged. If the format string contains
438 any % escapes requiring parameters, they should be
439 specified as subsequent arguments (it's just like
440 printf!).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000441
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000442 The client host and current date/time are prefixed to
443 every message.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000444
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000445 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000446
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000447 sys.stderr.write("%s - - [%s] %s\n" %
448 (self.address_string(),
449 self.log_date_time_string(),
450 format%args))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000451
452 def version_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000453 """Return the server software version string."""
454 return self.server_version + ' ' + self.sys_version
Guido van Rossume7e578f1995-08-04 04:00:20 +0000455
Georg Brandl5d076962006-02-17 13:34:16 +0000456 def date_time_string(self, timestamp=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000457 """Return the current date and time formatted for a message header."""
Georg Brandl5d076962006-02-17 13:34:16 +0000458 if timestamp is None:
459 timestamp = time.time()
460 year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000461 s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
462 self.weekdayname[wd],
463 day, self.monthname[month], year,
464 hh, mm, ss)
465 return s
Guido van Rossume7e578f1995-08-04 04:00:20 +0000466
467 def log_date_time_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000468 """Return the current time formatted for logging."""
469 now = time.time()
470 year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
471 s = "%02d/%3s/%04d %02d:%02d:%02d" % (
472 day, self.monthname[month], year, hh, mm, ss)
473 return s
Guido van Rossume7e578f1995-08-04 04:00:20 +0000474
475 weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
476
477 monthname = [None,
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000478 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
479 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
Guido van Rossume7e578f1995-08-04 04:00:20 +0000480
481 def address_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000482 """Return the client address formatted for logging.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000483
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000484 This version looks up the full hostname using gethostbyaddr(),
485 and tries to find a name that contains at least one dot.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000486
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000487 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000488
Martin v. Löwis3c120de2003-05-31 07:55:43 +0000489 host, port = self.client_address[:2]
Peter Schneider-Kamp2d2785a2000-08-16 20:30:21 +0000490 return socket.getfqdn(host)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000491
492 # Essentially static class variables
493
494 # The version of the HTTP protocol we support.
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000495 # Set this to HTTP/1.1 to enable automatic keepalive
Guido van Rossume7e578f1995-08-04 04:00:20 +0000496 protocol_version = "HTTP/1.0"
497
498 # The Message-like class used to parse headers
499 MessageClass = mimetools.Message
500
501 # Table mapping response codes to messages; entries have the
502 # form {code: (shortmessage, longmessage)}.
Georg Brandl6aab16e2006-02-17 19:17:25 +0000503 # See RFC 2616.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000504 responses = {
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000505 100: ('Continue', 'Request received, please continue'),
506 101: ('Switching Protocols',
507 'Switching to new protocol; obey Upgrade header'),
508
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000509 200: ('OK', 'Request fulfilled, document follows'),
510 201: ('Created', 'Document created, URL follows'),
511 202: ('Accepted',
512 'Request accepted, processing continues off-line'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000513 203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000514 204: ('No Content', 'Request fulfilled, nothing follows'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000515 205: ('Reset Content', 'Clear input form for further input.'),
516 206: ('Partial Content', 'Partial content follows.'),
Tim Peters11cf6052001-01-14 21:54:20 +0000517
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000518 300: ('Multiple Choices',
519 'Object has several resources -- see URI list'),
520 301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000521 302: ('Found', 'Object moved temporarily -- see URI list'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000522 303: ('See Other', 'Object moved -- see Method and URL list'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000523 304: ('Not Modified',
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000524 'Document has not changed since given time'),
525 305: ('Use Proxy',
526 'You must use proxy specified in Location to access this '
527 'resource.'),
528 307: ('Temporary Redirect',
529 'Object moved temporarily -- see URI list'),
Tim Peters11cf6052001-01-14 21:54:20 +0000530
Georg Brandl6aab16e2006-02-17 19:17:25 +0000531 400: ('Bad Request',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000532 'Bad request syntax or unsupported method'),
533 401: ('Unauthorized',
534 'No permission -- see authorization schemes'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000535 402: ('Payment Required',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000536 'No payment -- see charging schemes'),
537 403: ('Forbidden',
538 'Request forbidden -- authorization will not help'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000539 404: ('Not Found', 'Nothing matches the given URI'),
540 405: ('Method Not Allowed',
541 'Specified method is invalid for this server.'),
542 406: ('Not Acceptable', 'URI not available in preferred format.'),
543 407: ('Proxy Authentication Required', 'You must authenticate with '
544 'this proxy before proceeding.'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000545 408: ('Request Timeout', 'Request timed out; try again later.'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000546 409: ('Conflict', 'Request conflict.'),
547 410: ('Gone',
548 'URI no longer exists and has been permanently removed.'),
549 411: ('Length Required', 'Client must specify Content-Length.'),
550 412: ('Precondition Failed', 'Precondition in headers is false.'),
551 413: ('Request Entity Too Large', 'Entity is too large.'),
552 414: ('Request-URI Too Long', 'URI is too long.'),
553 415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
554 416: ('Requested Range Not Satisfiable',
555 'Cannot satisfy request range.'),
556 417: ('Expectation Failed',
557 'Expect condition could not be satisfied.'),
Tim Peters11cf6052001-01-14 21:54:20 +0000558
Georg Brandl6aab16e2006-02-17 19:17:25 +0000559 500: ('Internal Server Error', 'Server got itself in trouble'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000560 501: ('Not Implemented',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000561 'Server does not support this operation'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000562 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000563 503: ('Service Unavailable',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000564 'The server cannot process the request due to a high load'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000565 504: ('Gateway Timeout',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000566 'The gateway server did not receive a timely response'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000567 505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000568 }
Guido van Rossume7e578f1995-08-04 04:00:20 +0000569
570
571def test(HandlerClass = BaseHTTPRequestHandler,
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000572 ServerClass = HTTPServer, protocol="HTTP/1.0"):
Guido van Rossume7e578f1995-08-04 04:00:20 +0000573 """Test the HTTP request handler class.
574
575 This runs an HTTP server on port 8000 (or the first command line
576 argument).
577
578 """
579
580 if sys.argv[1:]:
Eric S. Raymond5ff63d62001-02-09 05:38:46 +0000581 port = int(sys.argv[1])
Guido van Rossume7e578f1995-08-04 04:00:20 +0000582 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000583 port = 8000
Guido van Rossume7e578f1995-08-04 04:00:20 +0000584 server_address = ('', port)
585
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000586 HandlerClass.protocol_version = protocol
Guido van Rossume7e578f1995-08-04 04:00:20 +0000587 httpd = ServerClass(server_address, HandlerClass)
588
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000589 sa = httpd.socket.getsockname()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000590 print("Serving HTTP on", sa[0], "port", sa[1], "...")
Guido van Rossume7e578f1995-08-04 04:00:20 +0000591 httpd.serve_forever()
592
593
594if __name__ == '__main__':
595 test()