From d41643ecb91b51b0fd7057a04230034d8feadaee Mon Sep 17 00:00:00 2001 From: Matt Spinler Date: Fri, 2 Feb 2018 13:51:38 -0600 Subject: Add web UI routing support Route the calls that a browser will request when it's pointed at https:// to the specified files in /usr/share/www, which come from the phosphor-webui repository. This takes over the '/' REST endpoint, but that provides no functionality to the customer anyway. The long term vision is to use a more advanced server like nginx, but this is needed until something else is ready. Tested: Served the phosphor-webui GUI from the BMC with the script. Resolves openbmc/openbmc#2821 Change-Id: Id491f9e0865a445160b91897082eb1c69695f562 Signed-off-by: Matt Spinler --- module/obmc/wsgi/apps/rest_dbus.py | 90 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'module/obmc/wsgi/apps') diff --git a/module/obmc/wsgi/apps/rest_dbus.py b/module/obmc/wsgi/apps/rest_dbus.py index cda23df..20294fd 100644 --- a/module/obmc/wsgi/apps/rest_dbus.py +++ b/module/obmc/wsgi/apps/rest_dbus.py @@ -29,6 +29,7 @@ import grp import crypt import tempfile import re +import mimetypes have_wsock = True try: from geventwebsocket import WebSocketError @@ -48,6 +49,8 @@ DELETE_IFACE = 'xyz.openbmc_project.Object.Delete' _4034_msg = "The specified %s cannot be %s: '%s'" +www_base_path = '/usr/share/www/' + def valid_user(session, *a, **kw): ''' Authorization plugin callback that checks @@ -905,6 +908,91 @@ class DownloadDumpHandler(RouteHandler): download=True, mimetype=self.content_type) +class WebHandler(RouteHandler): + ''' Handles the routes for the web UI files. ''' + + verbs = 'GET' + + # Match only what we know are web files, so everything else + # can get routed to the REST handlers. + rules = ['//', '/', '/', + '/', '/', + '/', '/', + '/', '/', + '/', '/', + '/'] + + # The mimetypes module knows about most types, but not these + content_types = { + '.eot': 'application/vnd.ms-fontobject', + '.woff': 'application/x-font-woff', + '.woff2': 'application/x-font-woff2', + '.ttf': 'application/x-font-ttf', + '.map': 'application/json' + } + + _require_auth = None + suppress_json_resp = True + + def __init__(self, app, bus): + super(WebHandler, self).__init__( + app, bus, self.verbs, self.rules) + + def get_type(self, filename): + ''' Returns the content type and encoding for a file ''' + + content_type, encoding = mimetypes.guess_type(filename) + + # Try our own list if mimetypes didn't recognize it + if content_type is None: + if filename[-3:] == '.gz': + filename = filename[:-3] + extension = filename[filename.rfind('.'):] + content_type = self.content_types.get(extension, None) + + return content_type, encoding + + def do_get(self, filename='index.html'): + + # If a gzipped version exists, use that instead. + # Possible future enhancement: if the client doesn't + # accept compressed files, unzip it ourselves before sending. + if not os.path.exists(os.path.join(www_base_path, filename)): + filename = filename + '.gz' + + # Though bottle should protect us, ensure path is valid + realpath = os.path.realpath(filename) + if realpath[0] == '/': + realpath = realpath[1:] + if not os.path.exists(os.path.join(www_base_path, realpath)): + abort(404, "Path not found") + + mimetype, encoding = self.get_type(filename) + + # Couldn't find the type - let static_file() deal with it, + # though this should never happen. + if mimetype is None: + print("Can't figure out content-type for %s" % filename) + mimetype = 'auto' + + # This call will set several header fields for us, + # including the charset if the type is text. + response = static_file(filename, www_base_path, mimetype) + + # static_file() will only set the encoding if the + # mimetype was auto, so set it here. + if encoding is not None: + response.set_header('Content-Encoding', encoding) + + return response + + def find(self, **kw): + pass + + def setup(self, **kw): + pass + + class AuthorizationPlugin(object): ''' Invokes an optional list of authorization callbacks. ''' @@ -1221,6 +1309,7 @@ class App(Bottle): def create_handlers(self): # create route handlers self.session_handler = SessionHandler(self, self.bus) + self.web_handler = WebHandler(self, self.bus) self.directory_handler = DirectoryHandler(self, self.bus) self.list_names_handler = ListNamesHandler(self, self.bus) self.list_handler = ListHandler(self, self.bus) @@ -1236,6 +1325,7 @@ class App(Bottle): def install_handlers(self): self.session_handler.install() + self.web_handler.install() self.directory_handler.install() self.list_names_handler.install() self.list_handler.install() -- cgit v1.2.1