blob: 7fbbcf227cd60f31047ead31ff49861ba610d599 [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
Alexandre Vassalottice261952008-05-12 02:31:37 +000078import socketserver
Guido van Rossume7e578f1995-08-04 04:00:20 +000079
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
Alexandre Vassalottice261952008-05-12 02:31:37 +000098class HTTPServer(socketserver.TCPServer):
Guido van Rossume7e578f1995-08-04 04:00:20 +000099
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."""
Alexandre Vassalottice261952008-05-12 02:31:37 +0000104 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
Alexandre Vassalottice261952008-05-12 02:31:37 +0000110class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
Guido van Rossume7e578f1995-08-04 04:00:20 +0000111
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
Georg Brandlb533e262008-05-25 18:19:30 +0000225 # The default request version. This only affects responses up until
226 # the point where the request line is parsed, so it mainly decides what
227 # the client gets back when sending a malformed request line.
228 # Most web servers default to HTTP 0.9, i.e. don't send a status line.
229 default_request_version = "HTTP/0.9"
230
Guido van Rossumd65b5391999-10-26 13:01:36 +0000231 def parse_request(self):
232 """Parse a request (internal).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000233
Raymond Hettingerbf68c782003-06-02 14:25:43 +0000234 The request should be stored in self.raw_requestline; the results
Guido van Rossumd65b5391999-10-26 13:01:36 +0000235 are in self.command, self.path, self.request_version and
236 self.headers.
237
Tim Petersbc0e9102002-04-04 22:55:58 +0000238 Return True for success, False for failure; on failure, an
Guido van Rossumd65b5391999-10-26 13:01:36 +0000239 error is sent back.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000240
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000241 """
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000242 self.command = None # set in case of error on the first line
Georg Brandlb533e262008-05-25 18:19:30 +0000243 self.request_version = version = self.default_request_version
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000244 self.close_connection = 1
Jeremy Hyltond2ef8642007-08-03 20:32:27 +0000245 requestline = str(self.raw_requestline, 'iso-8859-1')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000246 if requestline[-2:] == '\r\n':
247 requestline = requestline[:-2]
248 elif requestline[-1:] == '\n':
249 requestline = requestline[:-1]
250 self.requestline = requestline
Eric S. Raymondb49f4a42001-02-09 05:07:04 +0000251 words = requestline.split()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000252 if len(words) == 3:
253 [command, path, version] = words
254 if version[:5] != 'HTTP/':
Walter Dörwald70a6b492004-02-12 17:35:32 +0000255 self.send_error(400, "Bad request version (%r)" % version)
Tim Petersbc0e9102002-04-04 22:55:58 +0000256 return False
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000257 try:
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000258 base_version_number = version.split('/', 1)[1]
259 version_number = base_version_number.split(".")
260 # RFC 2145 section 3.1 says there can be only one "." and
261 # - major and minor numbers MUST be treated as
262 # separate integers;
263 # - HTTP/2.4 is a lower version than HTTP/2.13, which in
264 # turn is lower than HTTP/12.3;
265 # - Leading zeros MUST be ignored by recipients.
266 if len(version_number) != 2:
267 raise ValueError
268 version_number = int(version_number[0]), int(version_number[1])
269 except (ValueError, IndexError):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000270 self.send_error(400, "Bad request version (%r)" % version)
Tim Petersbc0e9102002-04-04 22:55:58 +0000271 return False
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000272 if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000273 self.close_connection = 0
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000274 if version_number >= (2, 0):
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000275 self.send_error(505,
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000276 "Invalid HTTP Version (%s)" % base_version_number)
Tim Petersbc0e9102002-04-04 22:55:58 +0000277 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000278 elif len(words) == 2:
279 [command, path] = words
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000280 self.close_connection = 1
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000281 if command != 'GET':
282 self.send_error(400,
Walter Dörwald70a6b492004-02-12 17:35:32 +0000283 "Bad HTTP/0.9 request type (%r)" % command)
Tim Petersbc0e9102002-04-04 22:55:58 +0000284 return False
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000285 elif not words:
Tim Petersbc0e9102002-04-04 22:55:58 +0000286 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000287 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000288 self.send_error(400, "Bad request syntax (%r)" % requestline)
Tim Petersbc0e9102002-04-04 22:55:58 +0000289 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000290 self.command, self.path, self.request_version = command, path, version
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000291
Guido van Rossumcfe02a42007-08-22 23:45:42 +0000292 # Examine the headers and look for a Connection directive.
293
294 # MessageClass (rfc822) wants to see strings rather than bytes.
295 # But a TextIOWrapper around self.rfile would buffer too many bytes
296 # from the stream, bytes which we later need to read as bytes.
297 # So we read the correct bytes here, as bytes, then use StringIO
298 # to make them look like strings for MessageClass to parse.
299 headers = []
300 while True:
301 line = self.rfile.readline()
302 headers.append(line)
303 if line in (b'\r\n', b'\n', b''):
304 break
305 hfile = io.StringIO(b''.join(headers).decode('iso-8859-1'))
306 self.headers = self.MessageClass(hfile)
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000307
308 conntype = self.headers.get('Connection', "")
309 if conntype.lower() == 'close':
310 self.close_connection = 1
311 elif (conntype.lower() == 'keep-alive' and
312 self.protocol_version >= "HTTP/1.1"):
313 self.close_connection = 0
Tim Petersbc0e9102002-04-04 22:55:58 +0000314 return True
Guido van Rossumd65b5391999-10-26 13:01:36 +0000315
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000316 def handle_one_request(self):
Guido van Rossumd65b5391999-10-26 13:01:36 +0000317 """Handle a single HTTP request.
318
319 You normally don't need to override this method; see the class
320 __doc__ string for information on how to handle specific HTTP
321 commands such as GET and POST.
322
323 """
Guido van Rossumd65b5391999-10-26 13:01:36 +0000324 self.raw_requestline = self.rfile.readline()
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000325 if not self.raw_requestline:
326 self.close_connection = 1
327 return
Guido van Rossumd65b5391999-10-26 13:01:36 +0000328 if not self.parse_request(): # An error code has been sent, just exit
329 return
330 mname = 'do_' + self.command
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000331 if not hasattr(self, mname):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000332 self.send_error(501, "Unsupported method (%r)" % self.command)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000333 return
334 method = getattr(self, mname)
335 method()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000336
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000337 def handle(self):
338 """Handle multiple requests if necessary."""
339 self.close_connection = 1
340
341 self.handle_one_request()
342 while not self.close_connection:
343 self.handle_one_request()
344
Guido van Rossume7e578f1995-08-04 04:00:20 +0000345 def send_error(self, code, message=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000346 """Send and log an error reply.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000347
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000348 Arguments are the error code, and a detailed message.
349 The detailed message defaults to the short entry matching the
350 response code.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000351
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000352 This sends an error response (so it must be called before any
353 output has been generated), logs the error, and finally sends
354 a piece of HTML explaining the error to the user.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000355
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000356 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000357
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000358 try:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000359 shortmsg, longmsg = self.responses[code]
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000360 except KeyError:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000361 shortmsg, longmsg = '???', '???'
Raymond Hettingerc0418602002-05-31 23:03:33 +0000362 if message is None:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000363 message = shortmsg
364 explain = longmsg
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000365 self.log_error("code %d, message %s", code, message)
Georg Brandla2aa1ac2005-06-26 21:33:14 +0000366 # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201)
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000367 content = (self.error_message_format %
Georg Brandla2aa1ac2005-06-26 21:33:14 +0000368 {'code': code, 'message': _quote_html(message), 'explain': explain})
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000369 self.send_response(code, message)
Christian Heimes8640e742008-02-23 16:23:06 +0000370 self.send_header("Content-Type", self.error_content_type)
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000371 self.send_header('Connection', 'close')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000372 self.end_headers()
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000373 if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
Bill Janssen1cd5bd22007-10-30 18:13:17 +0000374 self.wfile.write(content.encode('UTF-8', 'replace'))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000375
Guido van Rossume7e578f1995-08-04 04:00:20 +0000376 def send_response(self, code, message=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000377 """Send the response header and log the response code.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000378
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000379 Also send two standard headers with the server software
380 version and the current date.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000381
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000382 """
383 self.log_request(code)
384 if message is None:
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000385 if code in self.responses:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000386 message = self.responses[code][0]
387 else:
388 message = ''
389 if self.request_version != 'HTTP/0.9':
Bill Janssen1cd5bd22007-10-30 18:13:17 +0000390 self.wfile.write(("%s %d %s\r\n" %
391 (self.protocol_version, code, message)).encode('ASCII', 'strict'))
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000392 # print (self.protocol_version, code, message)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000393 self.send_header('Server', self.version_string())
394 self.send_header('Date', self.date_time_string())
Guido van Rossume7e578f1995-08-04 04:00:20 +0000395
396 def send_header(self, keyword, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000397 """Send a MIME header."""
398 if self.request_version != 'HTTP/0.9':
Bill Janssen1cd5bd22007-10-30 18:13:17 +0000399 self.wfile.write(("%s: %s\r\n" % (keyword, value)).encode('ASCII', 'strict'))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000400
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000401 if keyword.lower() == 'connection':
402 if value.lower() == 'close':
403 self.close_connection = 1
404 elif value.lower() == 'keep-alive':
405 self.close_connection = 0
406
Guido van Rossume7e578f1995-08-04 04:00:20 +0000407 def end_headers(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000408 """Send the blank line ending the MIME headers."""
409 if self.request_version != 'HTTP/0.9':
Bill Janssen1cd5bd22007-10-30 18:13:17 +0000410 self.wfile.write(b"\r\n")
Guido van Rossume7e578f1995-08-04 04:00:20 +0000411
412 def log_request(self, code='-', size='-'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000413 """Log an accepted request.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000414
Andrew M. Kuchlingec73cd42006-03-07 16:16:07 +0000415 This is called by send_response().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000416
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000417 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000418
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000419 self.log_message('"%s" %s %s',
420 self.requestline, str(code), str(size))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000421
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000422 def log_error(self, format, *args):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000423 """Log an error.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000424
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000425 This is called when a request cannot be fulfilled. By
426 default it passes the message on to log_message().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000427
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000428 Arguments are the same as for log_message().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000429
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000430 XXX This should go to the separate error log.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000431
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000432 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000433
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000434 self.log_message(format, *args)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000435
436 def log_message(self, format, *args):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000437 """Log an arbitrary message.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000438
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000439 This is used by all other logging functions. Override
440 it if you have specific logging wishes.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000441
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000442 The first argument, FORMAT, is a format string for the
443 message to be logged. If the format string contains
444 any % escapes requiring parameters, they should be
445 specified as subsequent arguments (it's just like
446 printf!).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000447
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000448 The client host and current date/time are prefixed to
449 every message.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000450
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000451 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000452
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000453 sys.stderr.write("%s - - [%s] %s\n" %
454 (self.address_string(),
455 self.log_date_time_string(),
456 format%args))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000457
458 def version_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000459 """Return the server software version string."""
460 return self.server_version + ' ' + self.sys_version
Guido van Rossume7e578f1995-08-04 04:00:20 +0000461
Georg Brandl5d076962006-02-17 13:34:16 +0000462 def date_time_string(self, timestamp=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000463 """Return the current date and time formatted for a message header."""
Georg Brandl5d076962006-02-17 13:34:16 +0000464 if timestamp is None:
465 timestamp = time.time()
466 year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000467 s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
468 self.weekdayname[wd],
469 day, self.monthname[month], year,
470 hh, mm, ss)
471 return s
Guido van Rossume7e578f1995-08-04 04:00:20 +0000472
473 def log_date_time_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000474 """Return the current time formatted for logging."""
475 now = time.time()
476 year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
477 s = "%02d/%3s/%04d %02d:%02d:%02d" % (
478 day, self.monthname[month], year, hh, mm, ss)
479 return s
Guido van Rossume7e578f1995-08-04 04:00:20 +0000480
481 weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
482
483 monthname = [None,
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000484 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
485 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
Guido van Rossume7e578f1995-08-04 04:00:20 +0000486
487 def address_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000488 """Return the client address formatted for logging.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000489
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000490 This version looks up the full hostname using gethostbyaddr(),
491 and tries to find a name that contains at least one dot.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000492
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000493 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000494
Martin v. Löwis3c120de2003-05-31 07:55:43 +0000495 host, port = self.client_address[:2]
Peter Schneider-Kamp2d2785a2000-08-16 20:30:21 +0000496 return socket.getfqdn(host)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000497
498 # Essentially static class variables
499
500 # The version of the HTTP protocol we support.
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000501 # Set this to HTTP/1.1 to enable automatic keepalive
Guido van Rossume7e578f1995-08-04 04:00:20 +0000502 protocol_version = "HTTP/1.0"
503
504 # The Message-like class used to parse headers
505 MessageClass = mimetools.Message
506
507 # Table mapping response codes to messages; entries have the
508 # form {code: (shortmessage, longmessage)}.
Georg Brandl6aab16e2006-02-17 19:17:25 +0000509 # See RFC 2616.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000510 responses = {
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000511 100: ('Continue', 'Request received, please continue'),
512 101: ('Switching Protocols',
513 'Switching to new protocol; obey Upgrade header'),
514
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000515 200: ('OK', 'Request fulfilled, document follows'),
516 201: ('Created', 'Document created, URL follows'),
517 202: ('Accepted',
518 'Request accepted, processing continues off-line'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000519 203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000520 204: ('No Content', 'Request fulfilled, nothing follows'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000521 205: ('Reset Content', 'Clear input form for further input.'),
522 206: ('Partial Content', 'Partial content follows.'),
Tim Peters11cf6052001-01-14 21:54:20 +0000523
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000524 300: ('Multiple Choices',
525 'Object has several resources -- see URI list'),
526 301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000527 302: ('Found', 'Object moved temporarily -- see URI list'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000528 303: ('See Other', 'Object moved -- see Method and URL list'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000529 304: ('Not Modified',
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000530 'Document has not changed since given time'),
531 305: ('Use Proxy',
532 'You must use proxy specified in Location to access this '
533 'resource.'),
534 307: ('Temporary Redirect',
535 'Object moved temporarily -- see URI list'),
Tim Peters11cf6052001-01-14 21:54:20 +0000536
Georg Brandl6aab16e2006-02-17 19:17:25 +0000537 400: ('Bad Request',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000538 'Bad request syntax or unsupported method'),
539 401: ('Unauthorized',
540 'No permission -- see authorization schemes'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000541 402: ('Payment Required',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000542 'No payment -- see charging schemes'),
543 403: ('Forbidden',
544 'Request forbidden -- authorization will not help'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000545 404: ('Not Found', 'Nothing matches the given URI'),
546 405: ('Method Not Allowed',
547 'Specified method is invalid for this server.'),
548 406: ('Not Acceptable', 'URI not available in preferred format.'),
549 407: ('Proxy Authentication Required', 'You must authenticate with '
550 'this proxy before proceeding.'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000551 408: ('Request Timeout', 'Request timed out; try again later.'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000552 409: ('Conflict', 'Request conflict.'),
553 410: ('Gone',
554 'URI no longer exists and has been permanently removed.'),
555 411: ('Length Required', 'Client must specify Content-Length.'),
556 412: ('Precondition Failed', 'Precondition in headers is false.'),
557 413: ('Request Entity Too Large', 'Entity is too large.'),
558 414: ('Request-URI Too Long', 'URI is too long.'),
559 415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
560 416: ('Requested Range Not Satisfiable',
561 'Cannot satisfy request range.'),
562 417: ('Expectation Failed',
563 'Expect condition could not be satisfied.'),
Tim Peters11cf6052001-01-14 21:54:20 +0000564
Georg Brandl6aab16e2006-02-17 19:17:25 +0000565 500: ('Internal Server Error', 'Server got itself in trouble'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000566 501: ('Not Implemented',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000567 'Server does not support this operation'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000568 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000569 503: ('Service Unavailable',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000570 'The server cannot process the request due to a high load'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000571 504: ('Gateway Timeout',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000572 'The gateway server did not receive a timely response'),
Georg Brandl6aab16e2006-02-17 19:17:25 +0000573 505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000574 }
Guido van Rossume7e578f1995-08-04 04:00:20 +0000575
576
577def test(HandlerClass = BaseHTTPRequestHandler,
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000578 ServerClass = HTTPServer, protocol="HTTP/1.0"):
Guido van Rossume7e578f1995-08-04 04:00:20 +0000579 """Test the HTTP request handler class.
580
581 This runs an HTTP server on port 8000 (or the first command line
582 argument).
583
584 """
585
586 if sys.argv[1:]:
Eric S. Raymond5ff63d62001-02-09 05:38:46 +0000587 port = int(sys.argv[1])
Guido van Rossume7e578f1995-08-04 04:00:20 +0000588 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000589 port = 8000
Guido van Rossume7e578f1995-08-04 04:00:20 +0000590 server_address = ('', port)
591
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000592 HandlerClass.protocol_version = protocol
Guido van Rossume7e578f1995-08-04 04:00:20 +0000593 httpd = ServerClass(server_address, HandlerClass)
594
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000595 sa = httpd.socket.getsockname()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000596 print("Serving HTTP on", sa[0], "port", sa[1], "...")
Guido van Rossume7e578f1995-08-04 04:00:20 +0000597 httpd.serve_forever()
598
599
600if __name__ == '__main__':
601 test()