0
|
1 #!/usr/bin/env python
|
|
2
|
|
3 """
|
|
4 WSGI app for FileServer
|
|
5
|
|
6 Reference:
|
|
7 - http://docs.webob.org/en/latest/file-example.html
|
|
8 """
|
|
9
|
|
10 import mimetypes
|
1
|
11 import optparse
|
0
|
12 import os
|
1
|
13 import sys
|
0
|
14 from webob import Request, Response, exc
|
1
|
15 from wsgiref.simple_server import make_server
|
|
16
|
|
17 __all__ = ['get_mimetype', 'file_response', 'FileApp', 'DirectoryServer']
|
0
|
18
|
|
19 def get_mimetype(filename):
|
|
20 type, encoding = mimetypes.guess_type(filename)
|
|
21 # We'll ignore encoding, even though we shouldn't really
|
|
22 return type or 'application/octet-stream'
|
|
23
|
|
24 def file_response(filename):
|
|
25 res = Response(content_type=get_mimetype(filename))
|
|
26 res.body = open(filename, 'rb').read()
|
|
27 return res
|
|
28
|
|
29 class FileApp(object):
|
|
30 """
|
|
31 serve static files
|
|
32 """
|
|
33
|
|
34 def __init__(self, filename):
|
|
35 self.filename = filename
|
|
36
|
|
37 def __call__(self, environ, start_response):
|
|
38 res = file_response(self.filename)
|
|
39 return res(environ, start_response)
|
|
40
|
|
41 class DirectoryServer(object):
|
|
42
|
|
43 def __init__(self, directory):
|
|
44 assert os.path.exists(directory), "'%s' does not exist" % directory
|
|
45 assert os.path.isdir(directory), "'%s' is not a directory" % directory
|
|
46 self.directory = directory
|
|
47
|
|
48 @staticmethod
|
|
49 def normpath(path):
|
|
50 return os.path.normcase(os.path.abspath(path))
|
|
51
|
|
52 def __call__(self, environ, start_response):
|
|
53 request = Request(environ)
|
|
54 # TODO method_not_allowed: Allow: GET, HEAD
|
|
55 path_info = request.path_info
|
|
56 if not path_info:
|
|
57 pass # self.add slash
|
|
58 full = self.normpath(os.path.join(self.directory, path_info.strip('/')))
|
|
59 if not full.startswith(self.directory):
|
|
60 # Out of bounds
|
|
61 return exc.HTTPNotFound()(environ, start_response)
|
|
62 if not os.path.exists(full):
|
|
63 return exc.HTTPNotFound()(environ, start_response)
|
|
64
|
|
65 if os.path.isdir(full):
|
|
66 # serve directory index
|
|
67 if not path_info.endswith('/'):
|
|
68 return self.add_slash(environ, start_response)
|
|
69 index = self.index(full)
|
|
70 response_headers = [('Content-Type', 'text/html'),
|
|
71 ('Content-Length', str(len(index)))]
|
|
72 response = Response(index, content_type='text/html')
|
|
73 return response(environ, start_response)
|
|
74
|
|
75 # serve file
|
|
76 if path_info.endswith('/'):
|
|
77 # we create the `full` filename above by stripping off
|
|
78 # '/' from both sides; so we correct here
|
|
79 return exc.HTTPNotFound()(environ, start_response)
|
|
80 response = file_response(full)
|
|
81 return response(environ, start_response)
|
|
82
|
1
|
83 def main(args=sys.argv[1:]):
|
|
84
|
|
85 # parse command line arguments
|
|
86 usage = '%prog [options] directory'
|
|
87 class PlainDescriptionFormatter(optparse.IndentedHelpFormatter):
|
|
88 """description formatter"""
|
|
89 def format_description(self, description):
|
|
90 if description:
|
|
91 return description + '\n'
|
|
92 else:
|
|
93 return ''
|
|
94 parser = optparse.OptionParser(usage=usage, description=__doc__, formatter=PlainDescriptionFormatter())
|
|
95 parser.add_option('-p', '--port', dest='port',
|
|
96 type='int', default=9999,
|
|
97 help='port [DEFAULT: %default]')
|
|
98 parser.add_option('-H', '--host', dest='host', default='0.0.0.0',
|
|
99 help='host [DEFAULT: %default]')
|
|
100 options, args = parser.parse_args(args)
|
|
101
|
|
102 # get the directory
|
|
103 if not len(args) == 1:
|
|
104 parser.print_help()
|
|
105 sys.exit(1)
|
|
106 directory = args[0]
|
|
107 if not os.path.exists(directory):
|
|
108 parser.error("'%s' not found" % directory)
|
|
109 if not os.path.isdir(directory):
|
|
110 parser.error("'%s' not a directory" % directory)
|
|
111
|
|
112 # serve
|
|
113 app = DirectoryServer(directory)
|
|
114 try:
|
|
115 print 'http://%s:%s/' % (options.host, options.port)
|
|
116 make_server(options.host, options.port, app).serve_forever()
|
|
117 except KeyboardInterrupt, ki:
|
|
118 print "Cio, baby!"
|
|
119 except BaseException, e:
|
|
120 sys.exit("Problem initializing server: %s" % e)
|
|
121
|
0
|
122 if __name__ == '__main__':
|
1
|
123 main()
|