PyXR

c:\python24\lib \ SimpleHTTPServer.py



0001 """Simple HTTP Server.
0002 
0003 This module builds on BaseHTTPServer by implementing the standard GET
0004 and HEAD requests in a fairly straightforward manner.
0005 
0006 """
0007 
0008 
0009 __version__ = "0.6"
0010 
0011 __all__ = ["SimpleHTTPRequestHandler"]
0012 
0013 import os
0014 import posixpath
0015 import BaseHTTPServer
0016 import urllib
0017 import cgi
0018 import shutil
0019 import mimetypes
0020 from StringIO import StringIO
0021 
0022 
0023 class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
0024 
0025     """Simple HTTP request handler with GET and HEAD commands.
0026 
0027     This serves files from the current directory and any of its
0028     subdirectories.  The MIME type for files is determined by
0029     calling the .guess_type() method.
0030 
0031     The GET and HEAD requests are identical except that the HEAD
0032     request omits the actual contents of the file.
0033 
0034     """
0035 
0036     server_version = "SimpleHTTP/" + __version__
0037 
0038     def do_GET(self):
0039         """Serve a GET request."""
0040         f = self.send_head()
0041         if f:
0042             self.copyfile(f, self.wfile)
0043             f.close()
0044 
0045     def do_HEAD(self):
0046         """Serve a HEAD request."""
0047         f = self.send_head()
0048         if f:
0049             f.close()
0050 
0051     def send_head(self):
0052         """Common code for GET and HEAD commands.
0053 
0054         This sends the response code and MIME headers.
0055 
0056         Return value is either a file object (which has to be copied
0057         to the outputfile by the caller unless the command was HEAD,
0058         and must be closed by the caller under all circumstances), or
0059         None, in which case the caller has nothing further to do.
0060 
0061         """
0062         path = self.translate_path(self.path)
0063         f = None
0064         if os.path.isdir(path):
0065             for index in "index.html", "index.htm":
0066                 index = os.path.join(path, index)
0067                 if os.path.exists(index):
0068                     path = index
0069                     break
0070             else:
0071                 return self.list_directory(path)
0072         ctype = self.guess_type(path)
0073         if ctype.startswith('text/'):
0074             mode = 'r'
0075         else:
0076             mode = 'rb'
0077         try:
0078             f = open(path, mode)
0079         except IOError:
0080             self.send_error(404, "File not found")
0081             return None
0082         self.send_response(200)
0083         self.send_header("Content-type", ctype)
0084         self.send_header("Content-Length", str(os.fstat(f.fileno())[6]))
0085         self.end_headers()
0086         return f
0087 
0088     def list_directory(self, path):
0089         """Helper to produce a directory listing (absent index.html).
0090 
0091         Return value is either a file object, or None (indicating an
0092         error).  In either case, the headers are sent, making the
0093         interface the same as for send_head().
0094 
0095         """
0096         try:
0097             list = os.listdir(path)
0098         except os.error:
0099             self.send_error(404, "No permission to list directory")
0100             return None
0101         list.sort(key=lambda a: a.lower())
0102         f = StringIO()
0103         f.write("<title>Directory listing for %s</title>\n" % self.path)
0104         f.write("<h2>Directory listing for %s</h2>\n" % self.path)
0105         f.write("<hr>\n<ul>\n")
0106         for name in list:
0107             fullname = os.path.join(path, name)
0108             displayname = linkname = name
0109             # Append / for directories or @ for symbolic links
0110             if os.path.isdir(fullname):
0111                 displayname = name + "/"
0112                 linkname = name + "/"
0113             if os.path.islink(fullname):
0114                 displayname = name + "@"
0115                 # Note: a link to a directory displays with @ and links with /
0116             f.write('<li><a href="%s">%s</a>\n'
0117                     % (urllib.quote(linkname), cgi.escape(displayname)))
0118         f.write("</ul>\n<hr>\n")
0119         length = f.tell()
0120         f.seek(0)
0121         self.send_response(200)
0122         self.send_header("Content-type", "text/html")
0123         self.send_header("Content-Length", str(length))
0124         self.end_headers()
0125         return f
0126 
0127     def translate_path(self, path):
0128         """Translate a /-separated PATH to the local filename syntax.
0129 
0130         Components that mean special things to the local file system
0131         (e.g. drive or directory names) are ignored.  (XXX They should
0132         probably be diagnosed.)
0133 
0134         """
0135         path = posixpath.normpath(urllib.unquote(path))
0136         words = path.split('/')
0137         words = filter(None, words)
0138         path = os.getcwd()
0139         for word in words:
0140             drive, word = os.path.splitdrive(word)
0141             head, word = os.path.split(word)
0142             if word in (os.curdir, os.pardir): continue
0143             path = os.path.join(path, word)
0144         return path
0145 
0146     def copyfile(self, source, outputfile):
0147         """Copy all data between two file objects.
0148 
0149         The SOURCE argument is a file object open for reading
0150         (or anything with a read() method) and the DESTINATION
0151         argument is a file object open for writing (or
0152         anything with a write() method).
0153 
0154         The only reason for overriding this would be to change
0155         the block size or perhaps to replace newlines by CRLF
0156         -- note however that this the default server uses this
0157         to copy binary data as well.
0158 
0159         """
0160         shutil.copyfileobj(source, outputfile)
0161 
0162     def guess_type(self, path):
0163         """Guess the type of a file.
0164 
0165         Argument is a PATH (a filename).
0166 
0167         Return value is a string of the form type/subtype,
0168         usable for a MIME Content-type header.
0169 
0170         The default implementation looks the file's extension
0171         up in the table self.extensions_map, using application/octet-stream
0172         as a default; however it would be permissible (if
0173         slow) to look inside the data to make a better guess.
0174 
0175         """
0176 
0177         base, ext = posixpath.splitext(path)
0178         if ext in self.extensions_map:
0179             return self.extensions_map[ext]
0180         ext = ext.lower()
0181         if ext in self.extensions_map:
0182             return self.extensions_map[ext]
0183         else:
0184             return self.extensions_map['']
0185 
0186     extensions_map = mimetypes.types_map.copy()
0187     extensions_map.update({
0188         '': 'application/octet-stream', # Default
0189         '.py': 'text/plain',
0190         '.c': 'text/plain',
0191         '.h': 'text/plain',
0192         })
0193 
0194 
0195 def test(HandlerClass = SimpleHTTPRequestHandler,
0196          ServerClass = BaseHTTPServer.HTTPServer):
0197     BaseHTTPServer.test(HandlerClass, ServerClass)
0198 
0199 
0200 if __name__ == '__main__':
0201     test()
0202 

Generated by PyXR 0.9.4
SourceForge.net Logo