X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=rwlaunchpad%2Fplugins%2Frwlaunchpadtasklet%2Frift%2Fpackage%2Fhandler.py;fp=rwlaunchpad%2Fplugins%2Frwlaunchpadtasklet%2Frift%2Fpackage%2Fhandler.py;h=4c000cdaa8495c206526ed2e6583f99db0846c05;hb=07b439824b5eac4dc760ce56b52fbdcf5539db4c;hp=0000000000000000000000000000000000000000;hpb=39b275b4ba816363b2dcdf403f70daffdeddabcc;p=osm%2FSO.git diff --git a/rwlaunchpad/plugins/rwlaunchpadtasklet/rift/package/handler.py b/rwlaunchpad/plugins/rwlaunchpadtasklet/rift/package/handler.py new file mode 100644 index 00000000..4c000cda --- /dev/null +++ b/rwlaunchpad/plugins/rwlaunchpadtasklet/rift/package/handler.py @@ -0,0 +1,170 @@ + +# +# Copyright 2016 RIFT.IO Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import os + +import tornado +import tornado.web +import tornado.gen + + +class File: + """Convenience class that represents the file + """ + def __init__(self, root_dir, path): + self.path = path + self.root_dir = root_dir + self._meta = None + + @property + def relative_path(self): + return os.path.relpath(self.path, start=self.root_dir) + + @property + def meta(self): + """Fetch the meta data for the file. + """ + if not self._meta: + self._meta = os.stat(self.path) + return self._meta + + def serialize(self): + """Converts the object to dict that can be exposed via rest. + """ + data = {} + data['name'] = self.relative_path + data['last_modified_time'] = self.meta.st_mtime + data['byte_size'] = self.meta.st_size + return data + +class Folder(File): + """ + Convenience class that represents the folder. + """ + def __init__(self, root_dir, path): + super().__init__(root_dir, path) + self.contents = [] + + def serialize(self): + """Converts the object to dict that can be exposed via rest. + """ + data = super().serialize() + data['contents'] = [] + for node in self.contents: + data['contents'].append(node.serialize()) + return data + + +class FileRestApiHandler(tornado.web.StaticFileHandler): + """Requesthandler class that extends StaticFileHandler. Difference being + GETS are now handled at folder level as well and for files we default to + the StaticFileHandler + + for the following directory structure + Foo + | + --> bar.py + + /Foo + will generate the list of all files in the directory! + + /Foo./bar.py + will download the file. + + """ + + def validate_absolute_path(self, root, absolute_path): + """Override the method to disable path validation for directory. + """ + root = os.path.abspath(root) + if not root.endswith(os.path.sep): + root += os.path.sep + + if not (absolute_path + os.path.sep).startswith(root): + raise tornado.web.HTTPError(403, "%s is not in root static directory", + self.path) + if (os.path.isdir(absolute_path) and + self.default_filename is not None): + if not self.request.path.endswith("/"): + self.redirect(self.request.path + "/", permanent=True) + return + + absolute_path = os.path.join(absolute_path, self.default_filename) + if not os.path.exists(absolute_path): + raise tornado.web.HTTPError(404) + + return absolute_path + + @classmethod + def _get_cached_version(cls, abs_path): + """Overridden method to disable caching for folder. + """ + if os.path.isdir(abs_path): + return None + + return super()._get_cached_version(abs_path) + + @tornado.gen.coroutine + def get(self, path, include_body=True): + """Override the get method to support both file and folder handling + File handling will be handled by StaticFileHandler + Folder handling will be done by the derived class. + """ + self.path = self.parse_url_path(path) + del path # make sure we don't refer to path instead of self.path again + absolute_path = self.get_absolute_path(self.root, self.path) + + self.absolute_path = self.validate_absolute_path( + self.root, absolute_path) + + if self.absolute_path is None: + return + + if os.path.isfile(absolute_path): + super().get(absolute_path) + return + + # More meaningful! + root_dir = absolute_path + + if not os.path.exists(root_dir): + raise tornado.web.HTTPError(404, "File/Folder not found") + + folder_cache = {} + for root, dirs, files in os.walk(root_dir): + folder = folder_cache.setdefault( + root, + Folder(root_dir, root)) + + # Files + for file in files: + file_path = os.path.join(root, file) + folder.contents.append( + File(root_dir, file_path)) + + # Sub folders + for dir_name in dirs: + dir_path = os.path.join(root, dir_name) + sub_folder = folder_cache.setdefault( + dir_path, + Folder(root_dir, dir_path)) + + folder.contents.append(sub_folder) + + # Return the root object! + structure = folder_cache[root_dir].serialize() + self.write(tornado.escape.json_encode(structure))