]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/controllers/home.py
1 # -*- coding: utf-8 -*-
9 from functools
import lru_cache
11 from ..plugins
.lru_cache
import lru_cache
14 from cherrypy
.lib
.static
import serve_file
17 from . import BaseController
, Endpoint
, Proxy
, Router
, UIRouter
19 logger
= logging
.getLogger("controllers.home")
22 class LanguageMixin(object):
27 for f
in os
.listdir(mgr
.get_frontend_path())
28 if os
.path
.isdir(os
.path
.join(mgr
.get_frontend_path(), f
))
30 except FileNotFoundError
:
31 logger
.exception("Build directory missing")
34 self
.LANGUAGES_PATH_MAP
= {
37 'path': os
.path
.join(mgr
.get_frontend_path(), f
)
39 for f
in self
.LANGUAGES
41 # pre-populating with the primary language subtag.
42 for lang
in list(self
.LANGUAGES_PATH_MAP
.keys()):
44 self
.LANGUAGES_PATH_MAP
[lang
.split('-')[0]] = {
45 'lang': self
.LANGUAGES_PATH_MAP
[lang
]['lang'],
46 'path': self
.LANGUAGES_PATH_MAP
[lang
]['path']
48 with
open(os
.path
.normpath("{}/../package.json".format(mgr
.get_frontend_path())),
51 self
.DEFAULT_LANGUAGE
= config
['config']['locale']
52 self
.DEFAULT_LANGUAGE_PATH
= os
.path
.join(mgr
.get_frontend_path(),
53 self
.DEFAULT_LANGUAGE
)
57 @Router("/", secure
=False)
58 class HomeController(BaseController
, LanguageMixin
):
59 LANG_TAG_SEQ_RE
= re
.compile(r
'\s*([^,]+)\s*,?\s*')
60 LANG_TAG_RE
= re
.compile(
61 r
'^(?P<locale>[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*|\*)(;q=(?P<weight>[01]\.\d{0,3}))?$')
62 MAX_ACCEPTED_LANGS
= 10
65 def _parse_accept_language(self
, accept_lang_header
):
67 for i
, m
in enumerate(self
.LANG_TAG_SEQ_RE
.finditer(accept_lang_header
)):
68 if i
>= self
.MAX_ACCEPTED_LANGS
:
69 logger
.debug("reached max accepted languages, skipping remaining")
72 tag_match
= self
.LANG_TAG_RE
.match(m
.group(1))
74 raise cherrypy
.HTTPError(400, "Malformed 'Accept-Language' header")
75 locale
= tag_match
.group('locale').lower()
76 weight
= tag_match
.group('weight')
81 raise cherrypy
.HTTPError(400, "Malformed 'Accept-Language' header")
84 result
.append((locale
, ratio
))
86 result
.sort(key
=lambda l
: l
[0])
87 result
.sort(key
=lambda l
: l
[1], reverse
=True)
88 logger
.debug("language preference: %s", result
)
89 return [r
[0] for r
in result
]
91 def _language_dir(self
, langs
):
93 if lang
in self
.LANGUAGES_PATH_MAP
:
94 logger
.debug("found directory for language '%s'", lang
)
95 cherrypy
.response
.headers
[
96 'Content-Language'] = self
.LANGUAGES_PATH_MAP
[lang
]['lang']
97 return self
.LANGUAGES_PATH_MAP
[lang
]['path']
99 logger
.debug("Languages '%s' not available, falling back to %s",
100 langs
, self
.DEFAULT_LANGUAGE
)
101 cherrypy
.response
.headers
['Content-Language'] = self
.DEFAULT_LANGUAGE
102 return self
.DEFAULT_LANGUAGE_PATH
105 def __call__(self
, path
, **params
):
109 if 'cd-lang' in cherrypy
.request
.cookie
:
110 langs
= [cherrypy
.request
.cookie
['cd-lang'].value
.lower()]
111 logger
.debug("frontend language from cookie: %s", langs
)
113 if 'Accept-Language' in cherrypy
.request
.headers
:
114 accept_lang_header
= cherrypy
.request
.headers
['Accept-Language']
115 langs
= self
._parse
_accept
_language
(accept_lang_header
)
117 langs
= [self
.DEFAULT_LANGUAGE
.lower()]
118 logger
.debug("frontend language from headers: %s", langs
)
120 base_dir
= self
._language
_dir
(langs
)
121 full_path
= os
.path
.join(base_dir
, path
)
123 # Block uplevel attacks
124 if not os
.path
.normpath(full_path
).startswith(os
.path
.normpath(base_dir
)):
125 raise cherrypy
.HTTPError(403) # Forbidden
127 logger
.debug("serving static content: %s", full_path
)
128 if 'Vary' in cherrypy
.response
.headers
:
129 cherrypy
.response
.headers
['Vary'] = "{}, Accept-Language"
131 cherrypy
.response
.headers
['Vary'] = "Accept-Language"
133 cherrypy
.response
.headers
['Cache-control'] = "no-cache"
134 return serve_file(full_path
)
137 @UIRouter("/langs", secure
=False)
138 class LangsController(BaseController
, LanguageMixin
):
141 return list(self
.LANGUAGES
)