blob: fc1824c2a1acddf0ba8c33e1a831c2f637fcb19c [file] [log] [blame]
Guido van Rossume7e578f1995-08-04 04:00:20 +00001"""Simple HTTP Server.
2
3This module builds on BaseHTTPServer by implementing the standard GET
4and HEAD requests in a fairly straightforward manner.
5
6"""
7
8
Guido van Rossum3b7b8131995-09-18 21:50:43 +00009__version__ = "0.3"
Guido van Rossume7e578f1995-08-04 04:00:20 +000010
11
12import os
Guido van Rossume7e578f1995-08-04 04:00:20 +000013import string
14import posixpath
Guido van Rossume7e578f1995-08-04 04:00:20 +000015import BaseHTTPServer
16
17
Guido van Rossume7e578f1995-08-04 04:00:20 +000018class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
19
20 """Simple HTTP request handler with GET and HEAD commands.
21
22 This serves files from the current directory and any of its
23 subdirectories. It assumes that all files are plain text files
24 unless they have the extension ".html" in which case it assumes
25 they are HTML files.
26
27 The GET and HEAD requests are identical except that the HEAD
28 request omits the actual contents of the file.
29
30 """
31
32 server_version = "SimpleHTTP/" + __version__
33
34 def do_GET(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000035 """Serve a GET request."""
36 f = self.send_head()
37 if f:
38 self.copyfile(f, self.wfile)
39 f.close()
Guido van Rossume7e578f1995-08-04 04:00:20 +000040
41 def do_HEAD(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000042 """Serve a HEAD request."""
43 f = self.send_head()
44 if f:
45 f.close()
Guido van Rossume7e578f1995-08-04 04:00:20 +000046
47 def send_head(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000048 """Common code for GET and HEAD commands.
Guido van Rossume7e578f1995-08-04 04:00:20 +000049
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000050 This sends the response code and MIME headers.
Guido van Rossume7e578f1995-08-04 04:00:20 +000051
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000052 Return value is either a file object (which has to be copied
53 to the outputfile by the caller unless the command was HEAD,
54 and must be closed by the caller under all circumstances), or
55 None, in which case the caller has nothing further to do.
Guido van Rossume7e578f1995-08-04 04:00:20 +000056
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000057 """
58 path = self.translate_path(self.path)
59 if os.path.isdir(path):
60 self.send_error(403, "Directory listing not supported")
61 return None
62 try:
Guido van Rossum391c8b41998-12-07 03:53:18 +000063 f = open(path, 'rb')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000064 except IOError:
65 self.send_error(404, "File not found")
66 return None
67 self.send_response(200)
68 self.send_header("Content-type", self.guess_type(path))
69 self.end_headers()
70 return f
Guido van Rossume7e578f1995-08-04 04:00:20 +000071
72 def translate_path(self, path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000073 """Translate a /-separated PATH to the local filename syntax.
Guido van Rossume7e578f1995-08-04 04:00:20 +000074
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000075 Components that mean special things to the local file system
76 (e.g. drive or directory names) are ignored. (XXX They should
77 probably be diagnosed.)
Guido van Rossume7e578f1995-08-04 04:00:20 +000078
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000079 """
80 path = posixpath.normpath(path)
81 words = string.splitfields(path, '/')
82 words = filter(None, words)
83 path = os.getcwd()
84 for word in words:
85 drive, word = os.path.splitdrive(word)
86 head, word = os.path.split(word)
87 if word in (os.curdir, os.pardir): continue
88 path = os.path.join(path, word)
89 return path
Guido van Rossume7e578f1995-08-04 04:00:20 +000090
91 def copyfile(self, source, outputfile):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000092 """Copy all data between two file objects.
Guido van Rossume7e578f1995-08-04 04:00:20 +000093
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000094 The SOURCE argument is a file object open for reading
95 (or anything with a read() method) and the DESTINATION
96 argument is a file object open for writing (or
97 anything with a write() method).
Guido van Rossume7e578f1995-08-04 04:00:20 +000098
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000099 The only reason for overriding this would be to change
100 the block size or perhaps to replace newlines by CRLF
101 -- note however that this the default server uses this
102 to copy binary data as well.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000103
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000104 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000105
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000106 BLOCKSIZE = 8192
107 while 1:
108 data = source.read(BLOCKSIZE)
109 if not data: break
110 outputfile.write(data)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000111
112 def guess_type(self, path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000113 """Guess the type of a file.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000114
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000115 Argument is a PATH (a filename).
Guido van Rossume7e578f1995-08-04 04:00:20 +0000116
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000117 Return value is a string of the form type/subtype,
118 usable for a MIME Content-type header.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000119
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000120 The default implementation looks the file's extension
121 up in the table self.extensions_map, using text/plain
122 as a default; however it would be permissible (if
123 slow) to look inside the data to make a better guess.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000124
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000125 """
Guido van Rossume7e578f1995-08-04 04:00:20 +0000126
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000127 base, ext = posixpath.splitext(path)
128 if self.extensions_map.has_key(ext):
129 return self.extensions_map[ext]
130 ext = string.lower(ext)
131 if self.extensions_map.has_key(ext):
132 return self.extensions_map[ext]
133 else:
134 return self.extensions_map['']
Guido van Rossume7e578f1995-08-04 04:00:20 +0000135
136 extensions_map = {
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000137 '': 'text/plain', # Default, *must* be present
138 '.html': 'text/html',
139 '.htm': 'text/html',
140 '.gif': 'image/gif',
141 '.jpg': 'image/jpeg',
142 '.jpeg': 'image/jpeg',
143 }
Guido van Rossume7e578f1995-08-04 04:00:20 +0000144
145
146def test(HandlerClass = SimpleHTTPRequestHandler,
Guido van Rossum5c3b3841998-12-07 04:08:30 +0000147 ServerClass = BaseHTTPServer.HTTPServer):
Guido van Rossume7e578f1995-08-04 04:00:20 +0000148 BaseHTTPServer.test(HandlerClass, ServerClass)
149
150
151if __name__ == '__main__':
152 test()