13257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel"""Simple HTTP Server. 23257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 33257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielThis module builds on BaseHTTPServer by implementing the standard GET 43257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieland HEAD requests in a fairly straightforward manner. 53257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 63257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel""" 73257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 83257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 93257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel__version__ = "0.6" 103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel__all__ = ["SimpleHTTPRequestHandler"] 123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport os 143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport posixpath 153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport BaseHTTPServer 163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport urllib 173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport urlparse 183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport cgi 193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport sys 203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport shutil 213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport mimetypes 223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieltry: 233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel from cStringIO import StringIO 243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielexcept ImportError: 253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel from StringIO import StringIO 263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielclass SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Simple HTTP request handler with GET and HEAD commands. 313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel This serves files from the current directory and any of its 333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel subdirectories. The MIME type for files is determined by 343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel calling the .guess_type() method. 353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The GET and HEAD requests are identical except that the HEAD 373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel request omits the actual contents of the file. 383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel server_version = "SimpleHTTP/" + __version__ 423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def do_GET(self): 443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Serve a GET request.""" 453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f = self.send_head() 463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if f: 473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.copyfile(f, self.wfile) 493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel finally: 503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.close() 513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def do_HEAD(self): 533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Serve a HEAD request.""" 543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f = self.send_head() 553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if f: 563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.close() 573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def send_head(self): 593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Common code for GET and HEAD commands. 603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel This sends the response code and MIME headers. 623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Return value is either a file object (which has to be copied 643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel to the outputfile by the caller unless the command was HEAD, 653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel and must be closed by the caller under all circumstances), or 663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel None, in which case the caller has nothing further to do. 673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel path = self.translate_path(self.path) 703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f = None 713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if os.path.isdir(path): 723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel parts = urlparse.urlsplit(self.path) 733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not parts.path.endswith('/'): 743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # redirect browser - doing basically what apache does 753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_response(301) 763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new_parts = (parts[0], parts[1], parts[2] + '/', 773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel parts[3], parts[4]) 783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel new_url = urlparse.urlunsplit(new_parts) 793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_header("Location", new_url) 803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.end_headers() 813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return None 823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for index in "index.html", "index.htm": 833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel index = os.path.join(path, index) 843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if os.path.exists(index): 853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel path = index 863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel break 873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.list_directory(path) 893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel ctype = self.guess_type(path) 903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # Always read in binary mode. Opening files in text mode may cause 923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # newline translations, making the actual size of the content 933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # transmitted *less* than the content-length! 943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f = open(path, 'rb') 953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except IOError: 963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_error(404, "File not found") 973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return None 983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_response(200) 1003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_header("Content-type", ctype) 1013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel fs = os.fstat(f.fileno()) 1023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_header("Content-Length", str(fs[6])) 1033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) 1043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.end_headers() 1053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return f 1063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except: 1073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.close() 1083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel raise 1093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def list_directory(self, path): 1113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Helper to produce a directory listing (absent index.html). 1123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Return value is either a file object, or None (indicating an 1143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel error). In either case, the headers are sent, making the 1153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel interface the same as for send_head(). 1163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel try: 1193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel list = os.listdir(path) 1203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel except os.error: 1213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_error(404, "No permission to list directory") 1223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return None 1233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel list.sort(key=lambda a: a.lower()) 1243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f = StringIO() 1253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel displaypath = cgi.escape(urllib.unquote(self.path)) 1263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">') 1273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath) 1283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath) 1293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.write("<hr>\n<ul>\n") 1303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for name in list: 1313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel fullname = os.path.join(path, name) 1323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel displayname = linkname = name 1333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # Append / for directories or @ for symbolic links 1343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if os.path.isdir(fullname): 1353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel displayname = name + "/" 1363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel linkname = name + "/" 1373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if os.path.islink(fullname): 1383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel displayname = name + "@" 1393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # Note: a link to a directory displays with @ and links with / 1403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.write('<li><a href="%s">%s</a>\n' 1413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel % (urllib.quote(linkname), cgi.escape(displayname))) 1423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.write("</ul>\n<hr>\n</body>\n</html>\n") 1433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel length = f.tell() 1443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel f.seek(0) 1453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_response(200) 1463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel encoding = sys.getfilesystemencoding() 1473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_header("Content-type", "text/html; charset=%s" % encoding) 1483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.send_header("Content-Length", str(length)) 1493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel self.end_headers() 1503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return f 1513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def translate_path(self, path): 1533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Translate a /-separated PATH to the local filename syntax. 1543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Components that mean special things to the local file system 1563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel (e.g. drive or directory names) are ignored. (XXX They should 1573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel probably be diagnosed.) 1583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # abandon query parameters 1613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel path = path.split('?',1)[0] 1623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel path = path.split('#',1)[0] 1633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel # Don't forget explicit trailing slash when normalizing. Issue17324 1643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel trailing_slash = path.rstrip().endswith('/') 1653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel path = posixpath.normpath(urllib.unquote(path)) 1663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel words = path.split('/') 1673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel words = filter(None, words) 1683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel path = os.getcwd() 1693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel for word in words: 1703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel drive, word = os.path.splitdrive(word) 1713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel head, word = os.path.split(word) 1723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if word in (os.curdir, os.pardir): continue 1733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel path = os.path.join(path, word) 1743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if trailing_slash: 1753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel path += '/' 1763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return path 1773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def copyfile(self, source, outputfile): 1793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Copy all data between two file objects. 1803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The SOURCE argument is a file object open for reading 1823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel (or anything with a read() method) and the DESTINATION 1833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel argument is a file object open for writing (or 1843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel anything with a write() method). 1853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The only reason for overriding this would be to change 1873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel the block size or perhaps to replace newlines by CRLF 1883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel -- note however that this the default server uses this 1893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel to copy binary data as well. 1903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 1923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel shutil.copyfileobj(source, outputfile) 1933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel def guess_type(self, path): 1953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """Guess the type of a file. 1963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Argument is a PATH (a filename). 1983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 1993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel Return value is a string of the form type/subtype, 2003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel usable for a MIME Content-type header. 2013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel The default implementation looks the file's extension 2033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel up in the table self.extensions_map, using application/octet-stream 2043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel as a default; however it would be permissible (if 2053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel slow) to look inside the data to make a better guess. 2063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel """ 2083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel base, ext = posixpath.splitext(path) 2103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if ext in self.extensions_map: 2113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.extensions_map[ext] 2123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel ext = ext.lower() 2133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if ext in self.extensions_map: 2143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.extensions_map[ext] 2153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel else: 2163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel return self.extensions_map[''] 2173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel if not mimetypes.inited: 2193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel mimetypes.init() # try to read system mime.types 2203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel extensions_map = mimetypes.types_map.copy() 2213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel extensions_map.update({ 2223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel '': 'application/octet-stream', # Default 2233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel '.py': 'text/plain', 2243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel '.c': 'text/plain', 2253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel '.h': 'text/plain', 2263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel }) 2273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef test(HandlerClass = SimpleHTTPRequestHandler, 2303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel ServerClass = BaseHTTPServer.HTTPServer): 2313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel BaseHTTPServer.test(HandlerClass, ServerClass) 2323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel 2343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielif __name__ == '__main__': 2353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel test() 236