Skip to content

Commit aaa7819

Browse files
authored
Create simple_getfile.py
1 parent 90d4ad8 commit aaa7819

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

Diff for: simple_getfile.py

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from flask import Flask, render_template, send_file, redirect, Response
2+
import os
3+
import sys
4+
5+
app = Flask(__name__)
6+
7+
CWD = '.'
8+
9+
TXT_FILES = ['py', 'txt', 'md', 'yaml', 'json', 'html', 'log']
10+
MIMETYPES = {
11+
'html': 'text/html',
12+
'json': 'application/json',
13+
}
14+
15+
def get_mimetype(format):
16+
"""Return mimetype metadata according to file format"""
17+
return MIMETYPES.get(format, 'text/plain')
18+
19+
def get_format(fname):
20+
"""Infer file format from file name"""
21+
return fname.split('.')[-1]
22+
23+
def simplify_logic_path(url_path: str) -> str:
24+
"""Simplify the logic path.
25+
26+
Input should not contain leading slash, and the simplified path
27+
will also not contain leading /. The simplified path will not contain
28+
trailing / unless original path does.
29+
30+
Examples
31+
=========
32+
'/' => 无效输入
33+
'' => ''
34+
'a/' => 'a/'
35+
'a/b/..' => 'a'
36+
'a/../..' => ''
37+
"""
38+
assert (not url_path) or url_path[0] != '/', "path should not contain leading /"
39+
stack = []
40+
for sub in url_path.split('/'):
41+
if sub == '..':
42+
if stack:
43+
stack.pop()
44+
elif sub != '.' and sub:
45+
stack.append(sub)
46+
if url_path.endswith('/'):
47+
stack.append('')
48+
return '/'.join(stack)
49+
50+
def path_exists(fs_path):
51+
"""Decide that the dir or file exists
52+
53+
fs_path indicates directory or file by trailing slash
54+
"""
55+
if fs_path.endswith('/') and not os.path.isdir(fs_path):
56+
return False
57+
if not fs_path.endswith('/') and not os.path.isfile(fs_path):
58+
return False
59+
return True
60+
61+
def redirect_and_404(url_path):
62+
"""重定向和404等异常路径"""
63+
# simplify path.
64+
simplified = simplify_logic_path(url_path)
65+
if simplified != url_path:
66+
return redirect(simplified)
67+
68+
fs_path = os.path.join(CWD, simplified)
69+
70+
# redirect directory with no slash /
71+
if not fs_path.endswith('/') and os.path.isdir(fs_path):
72+
return redirect(url_path + '/')
73+
74+
# report 404 if file/dir is not found.
75+
if not path_exists(fs_path):
76+
return render_template('404.html'), 404
77+
78+
def handle_directory(url_path, fs_path):
79+
"""Handle directory"""
80+
# fs_path points to a dir
81+
subs = ['../']
82+
subs += [x.name + '/' if x.is_dir() else x.name for x in os.scandir(fs_path)]
83+
subs.sort()
84+
85+
# index.html is supplied
86+
if 'index.html' in subs:
87+
with open(fs_path + 'index.html') as page:
88+
contents = page.read()
89+
return contents
90+
return render_template("directfor.html", cur_dir = '/' + url_path, subs = subs)
91+
92+
def handle_file(url_path, fs_path):
93+
"""Handle file"""
94+
format = get_format(fs_path)
95+
# send file
96+
if format not in TXT_FILES:
97+
return send_file(fs_path, as_attachment=True)
98+
99+
# send contents
100+
with open(fs_path) as f:
101+
contents = f.read()
102+
return Response(contents, status=200, mimetype=get_mimetype(format))
103+
104+
@app.route('/', defaults = {'url_path':''})
105+
@app.route('/<path:url_path>')
106+
def direct(url_path):
107+
redirect_response = redirect_and_404(url_path)
108+
if redirect_response:
109+
return redirect_response
110+
111+
# path is already simplified, so we just join current to get actual path
112+
fs_path = os.path.join(CWD, url_path)
113+
if fs_path.endswith('/'):
114+
return handle_directory(url_path, fs_path)
115+
return handle_file(url_path, fs_path)
116+
117+
118+
if __name__ == "__main__":
119+
if len(sys.argv) > 1:
120+
CWD = sys.argv[1]
121+
app.run(debug = True, port=5000)

0 commit comments

Comments
 (0)