blob: 043f9b284f81c50b6e093a08c2aae37ae12b39c6 [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
73import sys
74import time
75import socket # For gethostbyaddr()
Guido van Rossume7e578f1995-08-04 04:00:20 +000076import mimetools
77import SocketServer
Martin v. Löwis587c98c2002-03-17 18:37:22 +000078import cStringIO
Guido van Rossume7e578f1995-08-04 04:00:20 +000079
80# Default error message
81DEFAULT_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
93
94class HTTPServer(SocketServer.TCPServer):
95
Guido van Rossum18865de2000-05-09 14:54:13 +000096 allow_reuse_address = 1 # Seems to make sense in testing environment
97
Guido van Rossume7e578f1995-08-04 04:00:20 +000098 def server_bind(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000099 """Override server_bind to store the server name."""
100 SocketServer.TCPServer.server_bind(self)
101 host, port = self.socket.getsockname()
Peter Schneider-Kamp2d2785a2000-08-16 20:30:21 +0000102 self.server_name = socket.getfqdn(host)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000103 self.server_port = port
Guido van Rossume7e578f1995-08-04 04:00:20 +0000104
105
106class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
107
108 """HTTP request handler base class.
109
110 The following explanation of HTTP serves to guide you through the
111 code as well as to expose any misunderstandings I may have about
112 HTTP (so you don't need to read the code to figure out I'm wrong
113 :-).
114
115 HTTP (HyperText Transfer Protocol) is an extensible protocol on
116 top of a reliable stream transport (e.g. TCP/IP). The protocol
117 recognizes three parts to a request:
118
119 1. One line identifying the request type and path
120 2. An optional set of RFC-822-style headers
121 3. An optional data part
122
123 The headers and data are separated by a blank line.
124
125 The first line of the request has the form
126
127 <command> <path> <version>
128
129 where <command> is a (case-sensitive) keyword such as GET or POST,
130 <path> is a string containing path information for the request,
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000131 and <version> should be the string "HTTP/1.0" or "HTTP/1.1".
132 <path> is encoded using the URL encoding scheme (using %xx to signify
133 the ASCII character with hex code xx).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000134
Andrew M. Kuchling8ca202e2003-02-03 15:21:15 +0000135 The specification specifies that lines are separated by CRLF but
136 for compatibility with the widest range of clients recommends
137 servers also handle LF. Similarly, whitespace in the request line
138 is treated sensibly (allowing multiple spaces between components
139 and allowing trailing whitespace).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000140
141 Similarly, for output, lines ought to be separated by CRLF pairs
142 but most clients grok LF characters just fine.
143
144 If the first line of the request has the form
145
146 <command> <path>
147
148 (i.e. <version> is left out) then this is assumed to be an HTTP
149 0.9 request; this form has no optional headers and data part and
150 the reply consists of just the data.
151
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000152 The reply form of the HTTP 1.x protocol again has three parts:
Guido van Rossume7e578f1995-08-04 04:00:20 +0000153
154 1. One line giving the response code
155 2. An optional set of RFC-822-style headers
156 3. The data
157
158 Again, the headers and data are separated by a blank line.
159
160 The response code line has the form
161
162 <version> <responsecode> <responsestring>
163
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000164 where <version> is the protocol version ("HTTP/1.0" or "HTTP/1.1"),
Guido van Rossume7e578f1995-08-04 04:00:20 +0000165 <responsecode> is a 3-digit response code indicating success or
166 failure of the request, and <responsestring> is an optional
167 human-readable string explaining what the response code means.
168
169 This server parses the request and the headers, and then calls a
170 function specific to the request type (<command>). Specifically,
Guido van Rossumba895d81999-09-15 15:28:25 +0000171 a request SPAM will be handled by a method do_SPAM(). If no
Guido van Rossume7e578f1995-08-04 04:00:20 +0000172 such method exists the server sends an error response to the
173 client. If it exists, it is called with no arguments:
174
175 do_SPAM()
176
177 Note that the request name is case sensitive (i.e. SPAM and spam
178 are different requests).
179
180 The various request details are stored in instance variables:
181
182 - client_address is the client IP address in the form (host,
183 port);
184
185 - command, path and version are the broken-down request line;
186
187 - headers is an instance of mimetools.Message (or a derived
188 class) containing the header information;
189
190 - rfile is a file object open for reading positioned at the
191 start of the optional input data part;
192
193 - wfile is a file object open for writing.
194
195 IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
196
197 The first thing to be written must be the response line. Then
198 follow 0 or more header lines, then a blank line, and then the
199 actual data (if any). The meaning of the header lines depends on
200 the command executed by the server; in most cases, when data is
201 returned, there should be at least one header line of the form
202
203 Content-type: <type>/<subtype>
204
205 where <type> and <subtype> should be registered MIME types,
206 e.g. "text/html" or "text/plain".
207
208 """
209
210 # The Python system version, truncated to its first component.
Eric S. Raymondb49f4a42001-02-09 05:07:04 +0000211 sys_version = "Python/" + sys.version.split()[0]
Guido van Rossume7e578f1995-08-04 04:00:20 +0000212
213 # The server software version. You may want to override this.
214 # The format is multiple whitespace-separated strings,
215 # where each string is of the form name[/version].
216 server_version = "BaseHTTP/" + __version__
217
Guido van Rossumd65b5391999-10-26 13:01:36 +0000218 def parse_request(self):
219 """Parse a request (internal).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000220
Guido van Rossumd65b5391999-10-26 13:01:36 +0000221 The request should be stored in self.raw_request; the results
222 are in self.command, self.path, self.request_version and
223 self.headers.
224
Tim Petersbc0e9102002-04-04 22:55:58 +0000225 Return True for success, False for failure; on failure, an
Guido van Rossumd65b5391999-10-26 13:01:36 +0000226 error is sent back.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000227
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000228 """
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000229 self.command = None # set in case of error on the first line
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000230 self.request_version = version = "HTTP/0.9" # Default
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000231 self.close_connection = 1
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000232 requestline = self.raw_requestline
233 if requestline[-2:] == '\r\n':
234 requestline = requestline[:-2]
235 elif requestline[-1:] == '\n':
236 requestline = requestline[:-1]
237 self.requestline = requestline
Eric S. Raymondb49f4a42001-02-09 05:07:04 +0000238 words = requestline.split()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000239 if len(words) == 3:
240 [command, path, version] = words
241 if version[:5] != 'HTTP/':
242 self.send_error(400, "Bad request version (%s)" % `version`)
Tim Petersbc0e9102002-04-04 22:55:58 +0000243 return False
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000244 try:
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000245 base_version_number = version.split('/', 1)[1]
246 version_number = base_version_number.split(".")
247 # RFC 2145 section 3.1 says there can be only one "." and
248 # - major and minor numbers MUST be treated as
249 # separate integers;
250 # - HTTP/2.4 is a lower version than HTTP/2.13, which in
251 # turn is lower than HTTP/12.3;
252 # - Leading zeros MUST be ignored by recipients.
253 if len(version_number) != 2:
254 raise ValueError
255 version_number = int(version_number[0]), int(version_number[1])
256 except (ValueError, IndexError):
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000257 self.send_error(400, "Bad request version (%s)" % `version`)
Tim Petersbc0e9102002-04-04 22:55:58 +0000258 return False
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000259 if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000260 self.close_connection = 0
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000261 if version_number >= (2, 0):
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000262 self.send_error(505,
Andrew M. Kuchling2de97d32003-02-03 19:11:18 +0000263 "Invalid HTTP Version (%s)" % base_version_number)
Tim Petersbc0e9102002-04-04 22:55:58 +0000264 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000265 elif len(words) == 2:
266 [command, path] = words
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000267 self.close_connection = 1
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000268 if command != 'GET':
269 self.send_error(400,
270 "Bad HTTP/0.9 request type (%s)" % `command`)
Tim Petersbc0e9102002-04-04 22:55:58 +0000271 return False
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000272 elif not words:
Tim Petersbc0e9102002-04-04 22:55:58 +0000273 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000274 else:
275 self.send_error(400, "Bad request syntax (%s)" % `requestline`)
Tim Petersbc0e9102002-04-04 22:55:58 +0000276 return False
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000277 self.command, self.path, self.request_version = command, path, version
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000278
279 # Deal with pipelining
280 bytes = ""
281 while 1:
282 line = self.rfile.readline()
283 bytes = bytes + line
284 if line == '\r\n' or line == '\n' or line == '':
285 break
286
287 # Examine the headers and look for a Connection directive
288 hfile = cStringIO.StringIO(bytes)
289 self.headers = self.MessageClass(hfile)
290
291 conntype = self.headers.get('Connection', "")
292 if conntype.lower() == 'close':
293 self.close_connection = 1
294 elif (conntype.lower() == 'keep-alive' and
295 self.protocol_version >= "HTTP/1.1"):
296 self.close_connection = 0
Tim Petersbc0e9102002-04-04 22:55:58 +0000297 return True
Guido van Rossumd65b5391999-10-26 13:01:36 +0000298
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000299 def handle_one_request(self):
Guido van Rossumd65b5391999-10-26 13:01:36 +0000300 """Handle a single HTTP request.
301
302 You normally don't need to override this method; see the class
303 __doc__ string for information on how to handle specific HTTP
304 commands such as GET and POST.
305
306 """
Guido van Rossumd65b5391999-10-26 13:01:36 +0000307 self.raw_requestline = self.rfile.readline()
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000308 if not self.raw_requestline:
309 self.close_connection = 1
310 return
Guido van Rossumd65b5391999-10-26 13:01:36 +0000311 if not self.parse_request(): # An error code has been sent, just exit
312 return
313 mname = 'do_' + self.command
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000314 if not hasattr(self, mname):
Guido van Rossumd65b5391999-10-26 13:01:36 +0000315 self.send_error(501, "Unsupported method (%s)" % `self.command`)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000316 return
317 method = getattr(self, mname)
318 method()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000319
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000320 def handle(self):
321 """Handle multiple requests if necessary."""
322 self.close_connection = 1
323
324 self.handle_one_request()
325 while not self.close_connection:
326 self.handle_one_request()
327
Guido van Rossume7e578f1995-08-04 04:00:20 +0000328 def send_error(self, code, message=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000329 """Send and log an error reply.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000330
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000331 Arguments are the error code, and a detailed message.
332 The detailed message defaults to the short entry matching the
333 response code.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000334
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000335 This sends an error response (so it must be called before any
336 output has been generated), logs the error, and finally sends
337 a piece of HTML explaining the error to the user.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000338
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000339 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000340
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000341 try:
342 short, long = self.responses[code]
343 except KeyError:
344 short, long = '???', '???'
Raymond Hettingerc0418602002-05-31 23:03:33 +0000345 if message is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000346 message = short
347 explain = long
348 self.log_error("code %d, message %s", code, message)
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000349 content = (self.error_message_format %
350 {'code': code, 'message': message, 'explain': explain})
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000351 self.send_response(code, message)
Skip Montanaro31fd86c2002-03-08 02:36:18 +0000352 self.send_header("Content-Type", "text/html")
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000353 self.send_header('Connection', 'close')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000354 self.end_headers()
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000355 if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
356 self.wfile.write(content)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000357
358 error_message_format = DEFAULT_ERROR_MESSAGE
359
360 def send_response(self, code, message=None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000361 """Send the response header and log the response code.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000362
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000363 Also send two standard headers with the server software
364 version and the current date.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000365
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000366 """
367 self.log_request(code)
368 if message is None:
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000369 if code in self.responses:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000370 message = self.responses[code][0]
371 else:
372 message = ''
373 if self.request_version != 'HTTP/0.9':
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000374 self.wfile.write("%s %d %s\r\n" %
375 (self.protocol_version, code, message))
376 # print (self.protocol_version, code, message)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000377 self.send_header('Server', self.version_string())
378 self.send_header('Date', self.date_time_string())
Guido van Rossume7e578f1995-08-04 04:00:20 +0000379
380 def send_header(self, keyword, value):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000381 """Send a MIME header."""
382 if self.request_version != 'HTTP/0.9':
383 self.wfile.write("%s: %s\r\n" % (keyword, value))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000384
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000385 if keyword.lower() == 'connection':
386 if value.lower() == 'close':
387 self.close_connection = 1
388 elif value.lower() == 'keep-alive':
389 self.close_connection = 0
390
Guido van Rossume7e578f1995-08-04 04:00:20 +0000391 def end_headers(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000392 """Send the blank line ending the MIME headers."""
393 if self.request_version != 'HTTP/0.9':
394 self.wfile.write("\r\n")
Guido van Rossume7e578f1995-08-04 04:00:20 +0000395
396 def log_request(self, code='-', size='-'):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000397 """Log an accepted request.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000398
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000399 This is called by send_reponse().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000400
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000401 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000402
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000403 self.log_message('"%s" %s %s',
404 self.requestline, str(code), str(size))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000405
406 def log_error(self, *args):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000407 """Log an error.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000408
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000409 This is called when a request cannot be fulfilled. By
410 default it passes the message on to log_message().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000411
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000412 Arguments are the same as for log_message().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000413
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000414 XXX This should go to the separate error log.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000415
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000416 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000417
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000418 apply(self.log_message, args)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000419
420 def log_message(self, format, *args):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000421 """Log an arbitrary message.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000422
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000423 This is used by all other logging functions. Override
424 it if you have specific logging wishes.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000425
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000426 The first argument, FORMAT, is a format string for the
427 message to be logged. If the format string contains
428 any % escapes requiring parameters, they should be
429 specified as subsequent arguments (it's just like
430 printf!).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000431
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000432 The client host and current date/time are prefixed to
433 every message.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000434
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000435 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000436
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000437 sys.stderr.write("%s - - [%s] %s\n" %
438 (self.address_string(),
439 self.log_date_time_string(),
440 format%args))
Guido van Rossume7e578f1995-08-04 04:00:20 +0000441
442 def version_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000443 """Return the server software version string."""
444 return self.server_version + ' ' + self.sys_version
Guido van Rossume7e578f1995-08-04 04:00:20 +0000445
446 def date_time_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000447 """Return the current date and time formatted for a message header."""
448 now = time.time()
449 year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
450 s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
451 self.weekdayname[wd],
452 day, self.monthname[month], year,
453 hh, mm, ss)
454 return s
Guido van Rossume7e578f1995-08-04 04:00:20 +0000455
456 def log_date_time_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000457 """Return the current time formatted for logging."""
458 now = time.time()
459 year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
460 s = "%02d/%3s/%04d %02d:%02d:%02d" % (
461 day, self.monthname[month], year, hh, mm, ss)
462 return s
Guido van Rossume7e578f1995-08-04 04:00:20 +0000463
464 weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
465
466 monthname = [None,
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000467 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
468 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
Guido van Rossume7e578f1995-08-04 04:00:20 +0000469
470 def address_string(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000471 """Return the client address formatted for logging.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000472
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000473 This version looks up the full hostname using gethostbyaddr(),
474 and tries to find a name that contains at least one dot.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000475
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000476 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000477
Peter Schneider-Kamp2d2785a2000-08-16 20:30:21 +0000478 host, port = self.client_address
479 return socket.getfqdn(host)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000480
481 # Essentially static class variables
482
483 # The version of the HTTP protocol we support.
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000484 # Set this to HTTP/1.1 to enable automatic keepalive
Guido van Rossume7e578f1995-08-04 04:00:20 +0000485 protocol_version = "HTTP/1.0"
486
487 # The Message-like class used to parse headers
488 MessageClass = mimetools.Message
489
490 # Table mapping response codes to messages; entries have the
491 # form {code: (shortmessage, longmessage)}.
492 # See http://www.w3.org/hypertext/WWW/Protocols/HTTP/HTRESP.html
493 responses = {
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000494 100: ('Continue', 'Request received, please continue'),
495 101: ('Switching Protocols',
496 'Switching to new protocol; obey Upgrade header'),
497
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000498 200: ('OK', 'Request fulfilled, document follows'),
499 201: ('Created', 'Document created, URL follows'),
500 202: ('Accepted',
501 'Request accepted, processing continues off-line'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000502 203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000503 204: ('No response', 'Request fulfilled, nothing follows'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000504 205: ('Reset Content', 'Clear input form for further input.'),
505 206: ('Partial Content', 'Partial content follows.'),
Tim Peters11cf6052001-01-14 21:54:20 +0000506
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000507 300: ('Multiple Choices',
508 'Object has several resources -- see URI list'),
509 301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000510 302: ('Found', 'Object moved temporarily -- see URI list'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000511 303: ('See Other', 'Object moved -- see Method and URL list'),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000512 304: ('Not modified',
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000513 'Document has not changed since given time'),
514 305: ('Use Proxy',
515 'You must use proxy specified in Location to access this '
516 'resource.'),
517 307: ('Temporary Redirect',
518 'Object moved temporarily -- see URI list'),
Tim Peters11cf6052001-01-14 21:54:20 +0000519
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000520 400: ('Bad request',
521 'Bad request syntax or unsupported method'),
522 401: ('Unauthorized',
523 'No permission -- see authorization schemes'),
524 402: ('Payment required',
525 'No payment -- see charging schemes'),
526 403: ('Forbidden',
527 'Request forbidden -- authorization will not help'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000528 404: ('Not Found', 'Nothing matches the given URI'),
529 405: ('Method Not Allowed',
530 'Specified method is invalid for this server.'),
531 406: ('Not Acceptable', 'URI not available in preferred format.'),
532 407: ('Proxy Authentication Required', 'You must authenticate with '
533 'this proxy before proceeding.'),
534 408: ('Request Time-out', 'Request timed out; try again later.'),
535 409: ('Conflict', 'Request conflict.'),
536 410: ('Gone',
537 'URI no longer exists and has been permanently removed.'),
538 411: ('Length Required', 'Client must specify Content-Length.'),
539 412: ('Precondition Failed', 'Precondition in headers is false.'),
540 413: ('Request Entity Too Large', 'Entity is too large.'),
541 414: ('Request-URI Too Long', 'URI is too long.'),
542 415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
543 416: ('Requested Range Not Satisfiable',
544 'Cannot satisfy request range.'),
545 417: ('Expectation Failed',
546 'Expect condition could not be satisfied.'),
Tim Peters11cf6052001-01-14 21:54:20 +0000547
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000548 500: ('Internal error', 'Server got itself in trouble'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000549 501: ('Not Implemented',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000550 'Server does not support this operation'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000551 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
552 503: ('Service temporarily overloaded',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000553 'The server cannot process the request due to a high load'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000554 504: ('Gateway timeout',
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000555 'The gateway server did not receive a timely response'),
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000556 505: ('HTTP Version not supported', 'Cannot fulfill request.'),
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000557 }
Guido van Rossume7e578f1995-08-04 04:00:20 +0000558
559
560def test(HandlerClass = BaseHTTPRequestHandler,
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000561 ServerClass = HTTPServer, protocol="HTTP/1.0"):
Guido van Rossume7e578f1995-08-04 04:00:20 +0000562 """Test the HTTP request handler class.
563
564 This runs an HTTP server on port 8000 (or the first command line
565 argument).
566
567 """
568
569 if sys.argv[1:]:
Eric S. Raymond5ff63d62001-02-09 05:38:46 +0000570 port = int(sys.argv[1])
Guido van Rossume7e578f1995-08-04 04:00:20 +0000571 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000572 port = 8000
Guido van Rossume7e578f1995-08-04 04:00:20 +0000573 server_address = ('', port)
574
Martin v. Löwis587c98c2002-03-17 18:37:22 +0000575 HandlerClass.protocol_version = protocol
Guido van Rossume7e578f1995-08-04 04:00:20 +0000576 httpd = ServerClass(server_address, HandlerClass)
577
Martin v. Löwisa43c2f82001-07-24 20:34:08 +0000578 sa = httpd.socket.getsockname()
579 print "Serving HTTP on", sa[0], "port", sa[1], "..."
Guido van Rossume7e578f1995-08-04 04:00:20 +0000580 httpd.serve_forever()
581
582
583if __name__ == '__main__':
584 test()