]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/controllers/home.py
1 # -*- coding: utf-8 -*-
2 from __future__
import absolute_import
10 from functools
import lru_cache
12 from ..plugins
.lru_cache
import lru_cache
15 from cherrypy
.lib
.static
import serve_file
18 from . import BaseController
, Endpoint
, Proxy
, Router
, UIRouter
20 logger
= logging
.getLogger("controllers.home")
23 class LanguageMixin(object):
28 for f
in os
.listdir(mgr
.get_frontend_path())
29 if os
.path
.isdir(os
.path
.join(mgr
.get_frontend_path(), f
))
31 except FileNotFoundError
:
32 logger
.exception("Build directory missing")
35 self
.LANGUAGES_PATH_MAP
= {
38 'path': os
.path
.join(mgr
.get_frontend_path(), f
)
40 for f
in self
.LANGUAGES
42 # pre-populating with the primary language subtag.
43 for lang
in list(self
.LANGUAGES_PATH_MAP
.keys()):
45 self
.LANGUAGES_PATH_MAP
[lang
.split('-')[0]] = {
46 'lang': self
.LANGUAGES_PATH_MAP
[lang
]['lang'],
47 'path': self
.LANGUAGES_PATH_MAP
[lang
]['path']
49 with
open(os
.path
.normpath("{}/../package.json".format(mgr
.get_frontend_path())),
52 self
.DEFAULT_LANGUAGE
= config
['config']['locale']
53 self
.DEFAULT_LANGUAGE_PATH
= os
.path
.join(mgr
.get_frontend_path(),
54 self
.DEFAULT_LANGUAGE
)
58 @Router("/", secure
=False)
59 class HomeController(BaseController
, LanguageMixin
):
60 LANG_TAG_SEQ_RE
= re
.compile(r
'\s*([^,]+)\s*,?\s*')
61 LANG_TAG_RE
= re
.compile(
62 r
'^(?P<locale>[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*|\*)(;q=(?P<weight>[01]\.\d{0,3}))?$')
63 MAX_ACCEPTED_LANGS
= 10
66 def _parse_accept_language(self
, accept_lang_header
):
68 for i
, m
in enumerate(self
.LANG_TAG_SEQ_RE
.finditer(accept_lang_header
)):
69 if i
>= self
.MAX_ACCEPTED_LANGS
:
70 logger
.debug("reached max accepted languages, skipping remaining")
73 tag_match
= self
.LANG_TAG_RE
.match(m
.group(1))
75 raise cherrypy
.HTTPError(400, "Malformed 'Accept-Language' header")
76 locale
= tag_match
.group('locale').lower()
77 weight
= tag_match
.group('weight')
82 raise cherrypy
.HTTPError(400, "Malformed 'Accept-Language' header")
85 result
.append((locale
, ratio
))
87 result
.sort(key
=lambda l
: l
[0])
88 result
.sort(key
=lambda l
: l
[1], reverse
=True)
89 logger
.debug("language preference: %s", result
)
90 return [r
[0] for r
in result
]
92 def _language_dir(self
, langs
):
94 if lang
in self
.LANGUAGES_PATH_MAP
:
95 logger
.debug("found directory for language '%s'", lang
)
96 cherrypy
.response
.headers
[
97 'Content-Language'] = self
.LANGUAGES_PATH_MAP
[lang
]['lang']
98 return self
.LANGUAGES_PATH_MAP
[lang
]['path']
100 logger
.debug("Languages '%s' not available, falling back to %s",
101 langs
, self
.DEFAULT_LANGUAGE
)
102 cherrypy
.response
.headers
['Content-Language'] = self
.DEFAULT_LANGUAGE
103 return self
.DEFAULT_LANGUAGE_PATH
106 def __call__(self
, path
, **params
):
110 if 'cd-lang' in cherrypy
.request
.cookie
:
111 langs
= [cherrypy
.request
.cookie
['cd-lang'].value
.lower()]
112 logger
.debug("frontend language from cookie: %s", langs
)
114 if 'Accept-Language' in cherrypy
.request
.headers
:
115 accept_lang_header
= cherrypy
.request
.headers
['Accept-Language']
116 langs
= self
._parse
_accept
_language
(accept_lang_header
)
118 langs
= [self
.DEFAULT_LANGUAGE
.lower()]
119 logger
.debug("frontend language from headers: %s", langs
)
121 base_dir
= self
._language
_dir
(langs
)
122 full_path
= os
.path
.join(base_dir
, path
)
124 # Block uplevel attacks
125 if not os
.path
.normpath(full_path
).startswith(os
.path
.normpath(base_dir
)):
126 raise cherrypy
.HTTPError(403) # Forbidden
128 logger
.debug("serving static content: %s", full_path
)
129 if 'Vary' in cherrypy
.response
.headers
:
130 cherrypy
.response
.headers
['Vary'] = "{}, Accept-Language"
132 cherrypy
.response
.headers
['Vary'] = "Accept-Language"
134 cherrypy
.response
.headers
['Cache-control'] = "no-cache"
135 return serve_file(full_path
)
138 @UIRouter("/langs", secure
=False)
139 class LangsController(BaseController
, LanguageMixin
):
142 return list(self
.LANGUAGES
)