|
45 | 45 | # transition to 'text/javascript'. |
46 | 46 | JS_MIMETYPES = ["text/javascript", "application/javascript"] |
47 | 47 | JS_CACHE_EXPIRATION_IN_SECS = 86400 |
| 48 | +# Th paths that the application should be served at |
| 49 | +# Note that paths other than "/" should NOT end in '/' because trailing '/' |
| 50 | +# characters are removed by the serving logic in tensorboard/backend/application.py |
| 51 | +APP_PATHS = ["/", "/flags"] |
48 | 52 |
|
49 | 53 |
|
50 | 54 | class CorePlugin(base_plugin.TBPlugin): |
@@ -109,17 +113,34 @@ def get_resource_apps(self): |
109 | 113 | content = zip_.read(path) |
110 | 114 | # Opt out of gzipping index.html |
111 | 115 | if path == "index.html": |
112 | | - apps["/" + path] = functools.partial( |
113 | | - self._serve_index, content |
114 | | - ) |
| 116 | + for app_path in APP_PATHS: |
| 117 | + path_with_slash = ( |
| 118 | + app_path |
| 119 | + if app_path.endswith("/") |
| 120 | + else app_path + "/" |
| 121 | + ) |
| 122 | + apps[path_with_slash + path] = functools.partial( |
| 123 | + self._serve_index, content, app_path |
| 124 | + ) |
115 | 125 | continue |
116 | 126 |
|
117 | 127 | gzipped_asset_bytes = _gzip(content) |
118 | 128 | wsgi_app = functools.partial( |
119 | 129 | self._serve_asset, path, gzipped_asset_bytes |
120 | 130 | ) |
121 | | - apps["/" + path] = wsgi_app |
122 | | - apps["/"] = apps["/index.html"] |
| 131 | + for app_path in APP_PATHS: |
| 132 | + path_with_slash = ( |
| 133 | + app_path |
| 134 | + if app_path.endswith("/") |
| 135 | + else app_path + "/" |
| 136 | + ) |
| 137 | + apps[path_with_slash + path] = wsgi_app |
| 138 | + for app_path in APP_PATHS: |
| 139 | + if app_path.endswith("/"): |
| 140 | + apps[app_path] = apps[app_path + "index.html"] |
| 141 | + else: |
| 142 | + apps[app_path] = apps[app_path + "/index.html"] |
| 143 | + apps[app_path] = apps[app_path] |
123 | 144 | return apps |
124 | 145 |
|
125 | 146 | @wrappers.Request.application |
@@ -151,21 +172,23 @@ def _serve_asset(self, path, gzipped_asset_bytes, request): |
151 | 172 | ) |
152 | 173 |
|
153 | 174 | @wrappers.Request.application |
154 | | - def _serve_index(self, index_asset_bytes, request): |
| 175 | + def _serve_index(self, index_asset_bytes, content_path, request): |
155 | 176 | """Serves index.html content. |
156 | 177 |
|
157 | 178 | Note that we opt out of gzipping index.html to write preamble before the |
158 | 179 | resource content. This inflates the resource size from 2x kiB to 1xx |
159 | 180 | kiB, but we require an ability to flush preamble with the HTML content. |
160 | 181 | """ |
| 182 | + if not request.path.endswith("/"): |
| 183 | + return utils.redirect(request.path + "/") |
161 | 184 | relpath = ( |
162 | 185 | posixpath.relpath(self._path_prefix, request.script_root) |
163 | 186 | if self._path_prefix |
164 | 187 | else "." |
165 | 188 | ) |
166 | 189 | meta_header = ( |
167 | | - '<!doctype html><meta name="tb-relative-root" content="%s/">' |
168 | | - % relpath |
| 190 | + '<!doctype html><meta name="tb-relative-root" content="%s%s">' |
| 191 | + % (relpath, content_path) |
169 | 192 | ) |
170 | 193 | content = meta_header.encode("utf-8") + index_asset_bytes |
171 | 194 | # By passing content_encoding, disallow gzipping. Bloats the content |
|
0 commit comments