diff options
| author | Guido van Rossum <guido@python.org> | 1995-08-04 04:00:20 (GMT) | 
|---|---|---|
| committer | Guido van Rossum <guido@python.org> | 1995-08-04 04:00:20 (GMT) | 
| commit | e7e578ffe042ca84f5b57e8056cb5598c7b44e5a (patch) | |
| tree | 4a3b2e705ae78d7030280aef3f5839579755a698 /Lib/SimpleHTTPServer.py | |
| parent | 40d1ea3b9ccf9e779f253685d1f5f6cf530945fa (diff) | |
| download | cpython-e7e578ffe042ca84f5b57e8056cb5598c7b44e5a.zip cpython-e7e578ffe042ca84f5b57e8056cb5598c7b44e5a.tar.gz cpython-e7e578ffe042ca84f5b57e8056cb5598c7b44e5a.tar.bz2  | |
Initial revision
Diffstat (limited to 'Lib/SimpleHTTPServer.py')
| -rw-r--r-- | Lib/SimpleHTTPServer.py | 161 | 
1 files changed, 161 insertions, 0 deletions
diff --git a/Lib/SimpleHTTPServer.py b/Lib/SimpleHTTPServer.py new file mode 100644 index 0000000..67ec75a --- /dev/null +++ b/Lib/SimpleHTTPServer.py @@ -0,0 +1,161 @@ +"""Simple HTTP Server. + +This module builds on BaseHTTPServer by implementing the standard GET +and HEAD requests in a fairly straightforward manner. + +""" + + +__version__ = "0.2" + + +import os +import pwd +import sys +import time +import socket +import string +import posixpath +import SocketServer +import BaseHTTPServer + + +def nobody_uid(): +    """Internal routine to get nobody's uid""" +    try: +	nobody = pwd.getpwnam('nobody')[2] +    except pwd.error: +	nobody = 1 + max(map(lambda x: x[2], pwd.getpwall())) +    return nobody + +nobody = nobody_uid() + + +class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): + +    """Simple HTTP request handler with GET and HEAD commands. + +    This serves files from the current directory and any of its +    subdirectories.  It assumes that all files are plain text files +    unless they have the extension ".html" in which case it assumes +    they are HTML files. + +    The GET and HEAD requests are identical except that the HEAD +    request omits the actual contents of the file. + +    """ + +    server_version = "SimpleHTTP/" + __version__ + +    def do_GET(self): +	"""Serve a GET request.""" +	f = self.send_head() +	if f: +	    self.copyfile(f, self.wfile) +	    f.close() + +    def do_HEAD(self): +	"""Serve a HEAD request.""" +	f = self.send_head() +	if f: +	    f.close() + +    def send_head(self): +	"""Common code for GET and HEAD commands. + +	This sends the response code and MIME headers. + +	Return value is either a file object (which has to be copied +	to the outputfile by the caller unless the command was HEAD, +	and must be closed by the caller under all circumstances), or +	None, in which case the caller has nothing further to do. + +	""" +	path = self.translate_path(self.path) +	if os.path.isdir(path): +	    self.send_error(403, "Directory listing not supported") +	    return None +	try: +	    f = open(path) +	except IOError: +	    self.send_error(404, "File not found") +	    return None +	self.send_response(200) +	self.send_header("Content-type", self.guess_type(path)) +	self.end_headers() +	return f + +    def translate_path(self, path): +	"""Translate a /-separated PATH to the local filename syntax. + +	Components that mean special things to the local file system +	(e.g. drive or directory names) are ignored.  (XXX They should +	probably be diagnosed.) + +	""" +	path = posixpath.normpath(path) +	words = string.splitfields(path, '/') +	words = filter(None, words) +	path = os.getcwd() +	for word in words: +	    drive, word = os.path.splitdrive(word) +	    head, word = os.path.split(word) +	    if word in (os.curdir, os.pardir): continue +	    path = os.path.join(path, word) +	return path + +    def copyfile(self, source, outputfile): +	"""Copy all data between two file objects. + +	The SOURCE argument is a file object open for reading +	(or anything with a read() method) and the DESTINATION +	argument is a file object open for writing (or +	anything with a write() method). + +	The only reason for overriding this would be to change +	the block size or perhaps to replace newlines by CRLF +	-- note however that this the default server uses this +	to copy binary data as well. + +	""" + +	BLOCKSIZE = 8192 +	while 1: +	    data = source.read(BLOCKSIZE) +	    if not data: break +	    outputfile.write(data) + +    def guess_type(self, path): +	"""Guess the type of a file. + +	Argument is a PATH (a filename). + +	Return value is a string of the form type/subtype, +	usable for a MIME Content-type header. + +	The default implementation looks the file's extension +	up in the table self.extensions_map, using text/plain +	as a default; however it would be permissible (if +	slow) to look inside the data to make a better guess. + +	""" + +	base, ext = posixpath.splitext(path) +	if self.extensions_map.has_key(ext): +	    return self.extensions_map[ext] +	else: +	    return self.extensions_map[''] + +    extensions_map = { +	    '': 'text/plain',	# Default, *must* be present +	    '.html': 'text/html', +	    } + + +def test(HandlerClass = SimpleHTTPRequestHandler, +	 ServerClass = SocketServer.TCPServer): +    BaseHTTPServer.test(HandlerClass, ServerClass) + + +if __name__ == '__main__': +    test()  | 
