-
Notifications
You must be signed in to change notification settings - Fork 0
/
webdav_get.py
113 lines (96 loc) · 3.94 KB
/
webdav_get.py
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
from app import app, config, auth
import parse
import os
import inspect
import base64
from flask import request, Response, stream_with_context, abort, redirect
import azure.storage.filedatalake
def get_directory(path):
if path != "/" and not path.endswith("/"):
return redirect("/" + path + "/", 301)
filesystem_client = azure.storage.filedatalake.FileSystemClient("https://{}.dfs.core.windows.net".format(
config.storage_account_name), config.storage_container, credential=config.storage_account_key)
if path == "/":
paths = filesystem_client.get_paths(recursive=False)
else:
paths = filesystem_client.get_paths(path=path, recursive=False)
list_content = "<a href=\"../\">../</a>\r\n"
for p in paths:
p_name = os.path.basename(p.name)
if p.is_directory:
p_name += "/"
list_content += "<a href=\"{link}\">{name}</a>".format(
link=p_name, name=p_name)
list_content += "\t"
list_content += p.last_modified.ctime()
list_content += "\t"
if p.is_directory:
list_content += "-"
else:
list_content += str(p.content_length)
list_content += "\r\n"
html = inspect.cleandoc("""
<html>
<head><title>Index of {path}</title></head>
<body>
<h1>Index of {path}</h1>
<hr><pre>""".format(path=path)) + list_content + inspect.cleandoc("""
</pre></hr>
</body>
</html>
""")
return Response(html, mimetype="text/html")
@app.route("/", defaults={"path": "/"})
@app.route("/<path:path>")
@auth.login_required
def get(path):
if path == "/":
return get_directory(path)
file_client = azure.storage.filedatalake.DataLakeFileClient(
"https://{}.dfs.core.windows.net".format(config.storage_account_name), config.storage_container, path, credential=config.storage_account_key)
file_offset = None
file_length = None
if request.headers.get("Range"):
nums = parse.parse("bytes={:d}-{:d}", request.headers.get("Range"))
if not nums:
nums = parse.parse("bytes={:d}-", request.headers.get("Range"))
if not nums or len(nums.fixed) < 1 or len(nums.fixed) > 2:
abort(400)
file_offset = nums[0]
if len(nums.fixed) == 2:
file_length = nums[1] - file_offset + 1
raw_response = None
def callback(response):
nonlocal raw_response
raw_response = response.http_response
try:
download_response = file_client.download_file(
offset=file_offset, length=file_length, raw_response_hook=callback)
except azure.core.exceptions.ResourceNotFoundError:
abort(404)
properties = download_response.properties
content_settings = dict(properties["content_settings"].items())
is_directory = properties.metadata.get("hdi_isfolder", False)
if is_directory:
return get_directory(path)
response = Response(stream_with_context(
download_response.chunks()), status=206 if file_offset else 200)
response.accept_ranges = "bytes"
response.set_etag(properties.etag.strip("\""))
if content_settings["cache_control"]:
response.cache_control = content_settings["cache_control"]
if content_settings["content_encoding"]:
response.content_encoding = content_settings["content_encoding"]
if content_settings["content_language"]:
response.content_language = content_settings["content_language"]
if content_settings["content_md5"]:
response.content_md5 = base64.b64encode(
content_settings["content_md5"])
if content_settings["content_type"]:
response.content_type = content_settings["content_type"]
if file_offset:
nums = parse.parse("bytes {:d}-{:d}/{:d}",
raw_response.headers["Content-Range"])
response.content_range.set(nums[0], nums[1] + 1, nums[2])
response.content_length = int(raw_response.headers["Content-Length"])
return response