Skip to content

Commit

Permalink
Disable caching of index.html
Browse files Browse the repository at this point in the history
Disable caching of `index.html` on purpose so that the browser is always loading the latest app code, otherwise changes to the app are not taken into account when the browser is loading the file from the cache.

Fixes: https://github.com/aquarist-labs/s3gw/issues/730

Signed-off-by: Volker Theile <[email protected]>
  • Loading branch information
votdev committed Oct 5, 2023
1 parent 55612ff commit 9fe3dba
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 6 deletions.
50 changes: 50 additions & 0 deletions src/backend/tests/unit/test_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright 2023 SUSE LLC
#
# 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.

from fastapi import FastAPI
from fastapi.testclient import TestClient

from s3gw_ui_backend import NoCacheStaticFiles


def test_static_files_1() -> None:
app = FastAPI()
app.mount(
"/",
NoCacheStaticFiles(no_cache_files=["/test_api.py"], directory="api"),
name="static",
)
client = TestClient(app)
resp = client.get("/test_api.py")
assert resp.status_code == 200
assert (
resp.headers["cache-control"] == "no-cache, max-age=0, must-revalidate"
)
assert resp.headers["expires"] == "0"
assert resp.headers["pragma"] == "no-cache"


def test_static_files_2() -> None:
app = FastAPI()
app.mount(
"/",
NoCacheStaticFiles(no_cache_files=["/test_api.py"], directory="api"),
name="static",
)
client = TestClient(app)
resp = client.get("/test_api_admin.py")
assert resp.status_code == 200
assert "cache-control" not in resp.headers
assert "expires" not in resp.headers
assert "pragma" not in resp.headers
3 changes: 0 additions & 3 deletions src/frontend/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
<meta charset="utf-8">
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="0">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="apple-touch-icon" href="favicon_180x180.png">
<link rel="icon" href="favicon.svg" sizes="any" type="image/svg+xml">
Expand Down
40 changes: 37 additions & 3 deletions src/s3gw_ui_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,44 @@

import os
import sys
from typing import Awaitable, Callable
from typing import Awaitable, Callable, List

import uvicorn
from fastapi import FastAPI
from fastapi import FastAPI, Response
from fastapi.logger import logger
from fastapi.staticfiles import StaticFiles
from starlette.types import Scope

from backend.api import admin, auth, buckets, config, objects
from backend.config import Config
from backend.logging import setup_logging


class NoCacheStaticFiles(StaticFiles):
"""
Add HTTP headers to do not cache the specified files.
"""

def __init__(self, no_cache_files: List[str], *args, **kwargs):
"""
:param no_cache_files: The list of files that should not be cached.
"""
self.no_cache_files = no_cache_files
super().__init__(*args, **kwargs)

async def get_response(self, path: str, scope: Scope) -> Response:
resp = await super().get_response(path, scope)
if scope["path"] in self.no_cache_files:
resp.headers.update(
{
"Cache-Control": "no-cache, max-age=0, must-revalidate",
"Expires": "0",
"Pragma": "no-cache",
}
)
return resp


async def s3gw_startup(s3gw_app: FastAPI, s3gw_api: FastAPI) -> None:
setup_logging()
logger.info("Starting s3gw-ui backend")
Expand Down Expand Up @@ -89,8 +115,16 @@ async def on_shutdown(): # type: ignore

s3gw_app.mount("/api", s3gw_api, name="api")
if static_dir is not None:
# Disable caching of `index.html` on purpose so that the browser
# is always loading the latest app code, otherwise changes to the
# app are not taken into account when the browser is loading the
# file from the cache.
s3gw_app.mount(
"/", StaticFiles(directory=static_dir, html=True), name="static"
"/",
NoCacheStaticFiles(
no_cache_files=["/"], directory=static_dir, html=True
),
name="static",
)

return s3gw_app
Expand Down

0 comments on commit 9fe3dba

Please sign in to comment.