1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
import json
import config
import cgi
import os
import sqlite3
import mimetypes
def playout(filename, content = "text/html"):
return ["", [('Content-Type', content if content else "application/octet-stream"), ("X-Accel-Redirect", filename)], None]
def home():
return ["", [('Content-Type','text/html'), ("Location", config.homepage)], "302 Home"]
def target_filename_internal(session, filename):
target = session["path"] + "/"
if filename:
target += filename
if config.user_subdirs:
target = session["user"] + "/" + target
return target
def target_filename(session, file):
return config.fileroot + target_filename_internal(session, file)
def resolve_alias(alias):
session = None
db = sqlite3.connect(config.database, check_same_thread = False)
cursor = db.cursor()
cursor.execute("SELECT user, real, access, storage, display FROM aliases WHERE alias=:alias", {"alias": alias})
data = cursor.fetchone()
if data:
session = {"user": data[0], "path": data[1], "access": data[2], "limit": data[3], "display": data[4]}
else:
print("Unknown alias " + alias)
db.close()
return session
def listing(session):
listing = {"total": 0, "files": [], "access": session["access"], "display": session["display"]}
# TODO make sorting configurable
if 'r' in session["access"]:
directory = target_filename(session, None)
files = sorted(os.listdir(directory))
for filename in files:
if os.path.isfile(directory + filename):
size = os.path.getsize(directory + filename)
listing["files"].append({"name": filename, "size": size})
listing["total"] += size
return [json.dumps(listing), [('Content-Type','application/json')], "200 OK"]
def upload(session, post):
if 'c' not in session["access"]:
return ["", [('Content-Type','text/html')], "403 No"]
if post["file"].filename:
target = target_filename(session, os.path.basename(post["file"].filename))
while os.path.isfile(target):
target += "_dup"
try:
open(target, 'wb').write(post["file"].file.read())
print("Uploaded " + target)
return ["", [('Content-Type','text/html')], "200 OK"]
except PermissionError as e:
print("Failed to store " + target + ": " + e.msg)
return ["", [('Content-Type','text/html')], "500 Error"]
else:
print("Upload failed")
return ["", [('Content-Type','text/html')], "500 Error"]
def route(path, env, session, post):
# Get mapped user/path/limits
session = resolve_alias(path[0])
if not session:
return home()
#print(json.dumps(session))
# Redirect if no slash after alias
if len(path) == 1:
return ["", [('Content-Type','text/html'), ("Location", path[0] + "/")], "302 Redirect"]
if len(path) > 1 and path[1] == "upload":
return upload(session, post)
if len(path) > 1 and path[1] == "listing":
return listing(session)
if len(path) > 1 and path[1] == "file":
print("/data/" + target_filename_internal(session, path[2]))
return playout("/data/" + target_filename_internal(session, path[2]), mimetypes.guess_type(path[2])[0])
if len(path) > 1 and path[1] == "preview" and session["display"] == "gallery":
return playout("/data/" + target_filename_internal(session, "preview/" + path[2]), mimetypes.guess_type(path[2])[0])
return playout("/interface/listing.htm")
def handle_request(env, response):
path = env.get('PATH_INFO', '').lstrip('/').split('/')
post = None
headers = []
session = None
# Read POST data
try:
if env.get('CONTENT_TYPE', '').startswith("multipart/form-data"):
post = cgi.FieldStorage(environ=env, fp=env['wsgi.input'], keep_blank_values=True)
else:
content_length = int(env.get('CONTENT_LENGTH', '0'))
post_raw = env["wsgi.input"].read(content_length).decode('utf-8')
post = post_raw
except ValueError as e:
post = None
# Route request
data, addtl_headers, code = route(path, env, session, post)
headers.extend(addtl_headers)
response(code if code else "200 OK", headers)
return [bytes(data, "utf-8")]
|