3 # Copyright 2016 RIFT.IO Inc
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
26 """Convenience class that represents the file
28 def __init__(self
, root_dir
, path
):
30 self
.root_dir
= root_dir
34 def relative_path(self
):
35 return os
.path
.relpath(self
.path
, start
=self
.root_dir
)
39 """Fetch the meta data for the file.
42 self
._meta
= os
.stat(self
.path
)
46 """Converts the object to dict that can be exposed via rest.
49 data
['name'] = self
.relative_path
50 data
['last_modified_time'] = self
.meta
.st_mtime
51 data
['byte_size'] = self
.meta
.st_size
56 Convenience class that represents the folder.
58 def __init__(self
, root_dir
, path
):
59 super().__init
__(root_dir
, path
)
63 """Converts the object to dict that can be exposed via rest.
65 data
= super().serialize()
67 for node
in self
.contents
:
68 data
['contents'].append(node
.serialize())
72 class FileRestApiHandler(tornado
.web
.StaticFileHandler
):
73 """Requesthandler class that extends StaticFileHandler. Difference being
74 GETS are now handled at folder level as well and for files we default to
77 for the following directory structure
83 will generate the list of all files in the directory!
86 will download the file.
90 def validate_absolute_path(self
, root
, absolute_path
):
91 """Override the method to disable path validation for directory.
93 root
= os
.path
.abspath(root
)
94 if not root
.endswith(os
.path
.sep
):
97 if not (absolute_path
+ os
.path
.sep
).startswith(root
):
98 raise tornado
.web
.HTTPError(403, "%s is not in root static directory",
100 if (os
.path
.isdir(absolute_path
) and
101 self
.default_filename
is not None):
102 if not self
.request
.path
.endswith("/"):
103 self
.redirect(self
.request
.path
+ "/", permanent
=True)
106 absolute_path
= os
.path
.join(absolute_path
, self
.default_filename
)
107 if not os
.path
.exists(absolute_path
):
108 raise tornado
.web
.HTTPError(404)
113 def _get_cached_version(cls
, abs_path
):
114 """Overridden method to disable caching for folder.
116 if os
.path
.isdir(abs_path
):
119 return super()._get
_cached
_version
(abs_path
)
121 @tornado.gen
.coroutine
122 def get(self
, path
, include_body
=True):
123 """Override the get method to support both file and folder handling
124 File handling will be handled by StaticFileHandler
125 Folder handling will be done by the derived class.
127 self
.path
= self
.parse_url_path(path
)
128 del path
# make sure we don't refer to path instead of self.path again
129 absolute_path
= self
.get_absolute_path(self
.root
, self
.path
)
131 self
.absolute_path
= self
.validate_absolute_path(
132 self
.root
, absolute_path
)
134 if self
.absolute_path
is None:
137 if os
.path
.isfile(absolute_path
):
138 super().get(absolute_path
)
142 root_dir
= absolute_path
144 if not os
.path
.exists(root_dir
):
145 raise tornado
.web
.HTTPError(404, "File/Folder not found")
148 for root
, dirs
, files
in os
.walk(root_dir
):
149 folder
= folder_cache
.setdefault(
151 Folder(root_dir
, root
))
155 file_path
= os
.path
.join(root
, file)
156 folder
.contents
.append(
157 File(root_dir
, file_path
))
160 for dir_name
in dirs
:
161 dir_path
= os
.path
.join(root
, dir_name
)
162 sub_folder
= folder_cache
.setdefault(
164 Folder(root_dir
, dir_path
))
166 folder
.contents
.append(sub_folder
)
168 # Return the root object!
169 structure
= folder_cache
[root_dir
].serialize()
170 self
.set_header('Content-Type','application/json')
171 self
.write(tornado
.escape
.json_encode(structure
))