We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
webserver static file caching is disabled above 2.3.0 version.
### Apache Airflow version

Other Airflow 2 version (please specify below)

### If "Other Airflow 2 version" selected, which one?

2.3.x ~ 2.9.x

### What happened?

Recently, I migrated airflow version 2.2.0 to 2.9.0 and python 3.8 to 3.12.

and i experienced too much load time in airflow web dashboard.
in airflow 2.2.0, airflow dashboard loaded almost instantly. but in 2.9.0, it tooks almost 10 seconds.

## Airflow 2.2.0
<img width="960" alt="image" src="https://github.com/apache/airflow/assets/37045096/1d648049-424c-44a1-a505-24fe213f43a7">

## Airflow 2.9.0
<img width="960" alt="image" src="https://github.com/apache/airflow/assets/37045096/ecb58aca-93e9-483f-8e14-d0dc3ce3df6f">



### What you think should happen instead?

I think there is no reason to make slow page loading time because of not using static file caching.

And I figured out the root cause. the problem is airflow webserver's caching is disabled because of bumping up Flask version 1.x to 2.x.

In Flask, there is Configuration Option for static file's Expire time for cache-control.
it is `SEND_FILE_MAX_AGE_DEFAULT`.

In Flask 1.1.x, the default value of `SEND_FILE_MAX_AGE_DEFAULT` is 12 hours.
https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.send_file_max_age_default
![image](https://github.com/apache/airflow/assets/37045096/145d6241-ee75-4210-9355-b57c379cbcd8)

After Flask 2.0.x, the default value of `SEND_FILE_MAX_AGE_DEFAULT` is changed to None.
https://flask.palletsprojects.com/en/2.0.x/api/#flask.Flask.send_file_max_age_default
![image](https://github.com/apache/airflow/assets/37045096/e95ed8a3-2cab-47f8-8de4-99a8beb9e8c5)

after Airflow 2.3.0, Flask version is upgraded to 2.0.x.

When i added flask configuration in app.py
static file caching works well.
![image](https://github.com/apache/airflow/assets/37045096/1b3a02a4-8d7a-4ba9-9e2c-cea3857a0a8e)
![290_with_caching](https://github.com/apache/airflow/assets/37045096/be05516e-31e4-4c2d-bf79-173ad28e0d58)
example is here. https://github.com/VertexToEdge/airflow-docker-compose



### How to reproduce

I followed setup instruction in https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html
1. Setup Airflow 2.9.0 with docker-compose
``` bash
curl -LfO 'https://airflow.apache.org/docs/apache-airflow/2.9.0/docker-compose.yaml'
AIRFLOW_UID=$(id -u) docker compose up
```

2. access airflow webserver with webbrowser. and refresh the page.



### Operating System

Ubuntu 22.04.3 LTS

### Versions of Apache Airflow Providers

_No response_

### Deployment

Docker-Compose

### Deployment details

_No response_

### Anything else?

I am newbie in Airflow.
I read airflow installation guide and configruation reference. but I'm not sure if there is a better way to do this without changing the code.
Is there any way to configure static file caching? please just talk to me.

thanks for reading. have a good day.

### Are you willing to submit PR?

- [X] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `airflow/www/app.py`
Content:
```
1 #
2 # Licensed to the Apache Software Foundation (ASF) under one
3 # or more contributor license agreements.  See the NOTICE file
4 # distributed with this work for additional information
5 # regarding copyright ownership.  The ASF licenses this file
6 # to you under the Apache License, Version 2.0 (the
7 # "License"); you may not use this file except in compliance
8 # with the License.  You may obtain a copy of the License at
9 #
10 #   http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing,
13 # software distributed under the License is distributed on an
14 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 # KIND, either express or implied.  See the License for the
16 # specific language governing permissions and limitations
17 # under the License.
18 from __future__ import annotations
19 
20 import warnings
21 from datetime import timedelta
22 
23 from flask import Flask
24 from flask_appbuilder import SQLA
25 from flask_wtf.csrf import CSRFProtect
26 from markupsafe import Markup
27 from sqlalchemy.engine.url import make_url
28 
29 from airflow import settings
30 from airflow.api_internal.internal_api_call import InternalApiConfig
31 from airflow.configuration import conf
32 from airflow.exceptions import AirflowConfigException, RemovedInAirflow3Warning
33 from airflow.logging_config import configure_logging
34 from airflow.models import import_all_models
35 from airflow.settings import _ENABLE_AIP_44
36 from airflow.utils.json import AirflowJsonProvider
37 from airflow.www.extensions.init_appbuilder import init_appbuilder
38 from airflow.www.extensions.init_appbuilder_links import init_appbuilder_links
39 from airflow.www.extensions.init_auth_manager import get_auth_manager
40 from airflow.www.extensions.init_cache import init_cache
41 from airflow.www.extensions.init_dagbag import init_dagbag
42 from airflow.www.extensions.init_jinja_globals import init_jinja_globals
43 from airflow.www.extensions.init_manifest_files import configure_manifest_files
44 from airflow.www.extensions.init_robots import init_robots
45 from airflow.www.extensions.init_security import (
46     init_api_experimental_auth,
47     init_check_user_active,
48     init_xframe_protection,
49 )
50 from airflow.www.extensions.init_session import init_airflow_session_interface
51 from airflow.www.extensions.init_views import (
52     init_api_auth_provider,
53     init_api_connexion,
54     init_api_error_handlers,
55     init_api_experimental,
56     init_api_internal,
57     init_appbuilder_views,
58     init_error_handlers,
59     init_flash_views,
60     init_plugins,
61 )
62 from airflow.www.extensions.init_wsgi_middlewares import init_wsgi_middleware
63 
64 app: Flask | None = None
65 
66 # Initializes at the module level, so plugins can access it.
67 # See: /docs/plugins.rst
68 csrf = CSRFProtect()
69 
70 
71 def create_app(config=None, testing=False):
72     """Create a new instance of Airflow WWW app."""
73     flask_app = Flask(__name__)
74     flask_app.secret_key = conf.get("webserver", "SECRET_KEY")
75 
76     flask_app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=settings.get_session_lifetime_config())
77 
78     flask_app.config["MAX_CONTENT_LENGTH"] = conf.getfloat("webserver", "allowed_payload_size") * 1024 * 1024
79 
80     webserver_config = conf.get_mandatory_value("webserver", "config_file")
81     # Enable customizations in webserver_config.py to be applied via Flask.current_app.
82     with flask_app.app_context():
83         flask_app.config.from_pyfile(webserver_config, silent=True)
84 
85     flask_app.config["TESTING"] = testing
86     flask_app.config["SQLALCHEMY_DATABASE_URI"] = conf.get("database", "SQL_ALCHEMY_CONN")
87 
88     instance_name = conf.get(section="webserver", key="instance_name", fallback="Airflow")
89     require_confirmation_dag_change = conf.getboolean(
90         section="webserver", key="require_confirmation_dag_change", fallback=False
91     )
92     instance_name_has_markup = conf.getboolean(
93         section="webserver", key="instance_name_has_markup", fallback=False
94     )
95     if instance_name_has_markup:
96         instance_name = Markup(instance_name).striptags()
97 
98     flask_app.config["APP_NAME"] = instance_name
99     flask_app.config["REQUIRE_CONFIRMATION_DAG_CHANGE"] = require_confirmation_dag_change
100 
101     url = make_url(flask_app.config["SQLALCHEMY_DATABASE_URI"])
102     if url.drivername == "sqlite" and url.database and not url.database.startswith("/"):
103         raise AirflowConfigException(
104             f'Cannot use relative path: `{conf.get("database", "SQL_ALCHEMY_CONN")}` to connect to sqlite. '
105             "Please use absolute path such as `sqlite:////tmp/airflow.db`."
106         )
107 
108     flask_app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
109 
110     flask_app.config["SESSION_COOKIE_HTTPONLY"] = True
111     flask_app.config["SESSION_COOKIE_SECURE"] = conf.getboolean("webserver", "COOKIE_SECURE")
112 
113     cookie_samesite_config = conf.get("webserver", "COOKIE_SAMESITE")
114     if cookie_samesite_config == "":
115         warnings.warn(
116             "Old deprecated value found for `cookie_samesite` option in `[webserver]` section. "
117             "Using `Lax` instead. Change the value to `Lax` in airflow.cfg to remove this warning.",
118             RemovedInAirflow3Warning,
119             stacklevel=2,
120         )
121         cookie_samesite_config = "Lax"
122     flask_app.config["SESSION_COOKIE_SAMESITE"] = cookie_samesite_config
123 
124     if config:
125         flask_app.config.from_mapping(config)
126 
127     if "SQLALCHEMY_ENGINE_OPTIONS" not in flask_app.config:
128         flask_app.config["SQLALCHEMY_ENGINE_OPTIONS"] = settings.prepare_engine_args()
129 
130     # Configure the JSON encoder used by `|tojson` filter from Flask
131     flask_app.json_provider_class = AirflowJsonProvider
132     flask_app.json = AirflowJsonProvider(flask_app)
133 
134     InternalApiConfig.force_database_direct_access()
135 
136     csrf.init_app(flask_app)
137 
138     init_wsgi_middleware(flask_app)
139 
140     db = SQLA()
141     db.session = settings.Session
142     db.init_app(flask_app)
143 
144     init_dagbag(flask_app)
145 
146     init_api_experimental_auth(flask_app)
147 
148     init_robots(flask_app)
149 
150     init_cache(flask_app)
151 
152     init_flash_views(flask_app)
153 
154     configure_logging()
155     configure_manifest_files(flask_app)
156 
157     import_all_models()
158 
159     with flask_app.app_context():
160         init_appbuilder(flask_app)
161 
162         init_appbuilder_views(flask_app)
163         init_appbuilder_links(flask_app)
164         init_plugins(flask_app)
165         init_error_handlers(flask_app)
166         init_api_connexion(flask_app)
167         if conf.getboolean("webserver", "run_internal_api", fallback=False):
168             if not _ENABLE_AIP_44:
169                 raise RuntimeError("The AIP_44 is not enabled so you cannot use it.")
170             init_api_internal(flask_app)
171         init_api_experimental(flask_app)
172         init_api_auth_provider(flask_app)
173         init_api_error_handlers(flask_app)  # needs to be after all api inits to let them add their path first
174 
175         get_auth_manager().init()
176 
177         init_jinja_globals(flask_app)
178         init_xframe_protection(flask_app)
179         init_airflow_session_interface(flask_app)
180         init_check_user_active(flask_app)
181     return flask_app
182 
183 
184 def cached_app(config=None, testing=False):
185     """Return cached instance of Airflow WWW app."""
186     global app
187     if not app:
188         app = create_app(config=config, testing=testing)
189     return app
190 
191 
192 def purge_cached_app():
193     """Remove the cached version of the app in global state."""
194     global app
195     app = None
196
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/airflow/www/app.py b/airflow/www/app.py
--- a/airflow/www/app.py
+++ b/airflow/www/app.py
@@ -121,6 +121,10 @@
         cookie_samesite_config = "Lax"
     flask_app.config["SESSION_COOKIE_SAMESITE"] = cookie_samesite_config
 
+    # Above Flask 2.0.x, default value of SEND_FILE_MAX_AGE_DEFAULT changed 12 hours to None.
+    # for static file caching, it needs to set value explicitly.
+    flask_app.config["SEND_FILE_MAX_AGE_DEFAULT"] = timedelta(seconds=43200)
+
     if config:
         flask_app.config.from_mapping(config)

{"golden_diff": "diff --git a/airflow/www/app.py b/airflow/www/app.py\n--- a/airflow/www/app.py\n+++ b/airflow/www/app.py\n@@ -121,6 +121,10 @@\n         cookie_samesite_config = \"Lax\"\n     flask_app.config[\"SESSION_COOKIE_SAMESITE\"] = cookie_samesite_config\n \n+    # Above Flask 2.0.x, default value of SEND_FILE_MAX_AGE_DEFAULT changed 12 hours to None.\n+    # for static file caching, it needs to set value explicitly.\n+    flask_app.config[\"SEND_FILE_MAX_AGE_DEFAULT\"] = timedelta(seconds=43200)\n+\n     if config:\n         flask_app.config.from_mapping(config)\n", "issue": "webserver static file caching is disabled above 2.3.0 version.\n### Apache Airflow version\n\nOther Airflow 2 version (please specify below)\n\n### If \"Other Airflow 2 version\" selected, which one?\n\n2.3.x ~ 2.9.x\n\n### What happened?\n\nRecently, I migrated airflow version 2.2.0 to 2.9.0 and python 3.8 to 3.12.\r\n\r\nand i experienced too much load time in airflow web dashboard.\r\nin airflow 2.2.0, airflow dashboard loaded almost instantly. but in 2.9.0, it tooks almost 10 seconds.\r\n\r\n## Airflow 2.2.0\r\n<img width=\"960\" alt=\"image\" src=\"https://github.com/apache/airflow/assets/37045096/1d648049-424c-44a1-a505-24fe213f43a7\">\r\n\r\n## Airflow 2.9.0\r\n<img width=\"960\" alt=\"image\" src=\"https://github.com/apache/airflow/assets/37045096/ecb58aca-93e9-483f-8e14-d0dc3ce3df6f\">\r\n\r\n\n\n### What you think should happen instead?\n\nI think there is no reason to make slow page loading time because of not using static file caching.\r\n\r\nAnd I figured out the root cause. the problem is airflow webserver's caching is disabled because of bumping up Flask version 1.x to 2.x.\r\n\r\nIn Flask, there is Configuration Option for static file's Expire time for cache-control.\r\nit is `SEND_FILE_MAX_AGE_DEFAULT`.\r\n\r\nIn Flask 1.1.x, the default value of `SEND_FILE_MAX_AGE_DEFAULT` is 12 hours.\r\nhttps://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.send_file_max_age_default\r\n![image](https://github.com/apache/airflow/assets/37045096/145d6241-ee75-4210-9355-b57c379cbcd8)\r\n\r\nAfter Flask 2.0.x, the default value of `SEND_FILE_MAX_AGE_DEFAULT` is changed to None.\r\nhttps://flask.palletsprojects.com/en/2.0.x/api/#flask.Flask.send_file_max_age_default\r\n![image](https://github.com/apache/airflow/assets/37045096/e95ed8a3-2cab-47f8-8de4-99a8beb9e8c5)\r\n\r\nafter Airflow 2.3.0, Flask version is upgraded to 2.0.x.\r\n\r\nWhen i added flask configuration in app.py\r\nstatic file caching works well.\r\n![image](https://github.com/apache/airflow/assets/37045096/1b3a02a4-8d7a-4ba9-9e2c-cea3857a0a8e)\r\n![290_with_caching](https://github.com/apache/airflow/assets/37045096/be05516e-31e4-4c2d-bf79-173ad28e0d58)\r\nexample is here. https://github.com/VertexToEdge/airflow-docker-compose\r\n\r\n\n\n### How to reproduce\n\nI followed setup instruction in https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html\r\n1. Setup Airflow 2.9.0 with docker-compose\r\n``` bash\r\ncurl -LfO 'https://airflow.apache.org/docs/apache-airflow/2.9.0/docker-compose.yaml'\r\nAIRFLOW_UID=$(id -u) docker compose up\r\n```\r\n\r\n2. access airflow webserver with webbrowser. and refresh the page.\r\n\r\n\n\n### Operating System\n\nUbuntu 22.04.3 LTS\n\n### Versions of Apache Airflow Providers\n\n_No response_\n\n### Deployment\n\nDocker-Compose\n\n### Deployment details\n\n_No response_\n\n### Anything else?\n\nI am newbie in Airflow.\r\nI read airflow installation guide and configruation reference. but I'm not sure if there is a better way to do this without changing the code.\r\nIs there any way to configure static file caching? please just talk to me.\r\n\r\nthanks for reading. have a good day.\n\n### Are you willing to submit PR?\n\n- [X] Yes I am willing to submit a PR!\n\n### Code of Conduct\n\n- [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)\n\n", "before_files": [{"content": "#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\nfrom __future__ import annotations\n\nimport warnings\nfrom datetime import timedelta\n\nfrom flask import Flask\nfrom flask_appbuilder import SQLA\nfrom flask_wtf.csrf import CSRFProtect\nfrom markupsafe import Markup\nfrom sqlalchemy.engine.url import make_url\n\nfrom airflow import settings\nfrom airflow.api_internal.internal_api_call import InternalApiConfig\nfrom airflow.configuration import conf\nfrom airflow.exceptions import AirflowConfigException, RemovedInAirflow3Warning\nfrom airflow.logging_config import configure_logging\nfrom airflow.models import import_all_models\nfrom airflow.settings import _ENABLE_AIP_44\nfrom airflow.utils.json import AirflowJsonProvider\nfrom airflow.www.extensions.init_appbuilder import init_appbuilder\nfrom airflow.www.extensions.init_appbuilder_links import init_appbuilder_links\nfrom airflow.www.extensions.init_auth_manager import get_auth_manager\nfrom airflow.www.extensions.init_cache import init_cache\nfrom airflow.www.extensions.init_dagbag import init_dagbag\nfrom airflow.www.extensions.init_jinja_globals import init_jinja_globals\nfrom airflow.www.extensions.init_manifest_files import configure_manifest_files\nfrom airflow.www.extensions.init_robots import init_robots\nfrom airflow.www.extensions.init_security import (\n    init_api_experimental_auth,\n    init_check_user_active,\n    init_xframe_protection,\n)\nfrom airflow.www.extensions.init_session import init_airflow_session_interface\nfrom airflow.www.extensions.init_views import (\n    init_api_auth_provider,\n    init_api_connexion,\n    init_api_error_handlers,\n    init_api_experimental,\n    init_api_internal,\n    init_appbuilder_views,\n    init_error_handlers,\n    init_flash_views,\n    init_plugins,\n)\nfrom airflow.www.extensions.init_wsgi_middlewares import init_wsgi_middleware\n\napp: Flask | None = None\n\n# Initializes at the module level, so plugins can access it.\n# See: /docs/plugins.rst\ncsrf = CSRFProtect()\n\n\ndef create_app(config=None, testing=False):\n    \"\"\"Create a new instance of Airflow WWW app.\"\"\"\n    flask_app = Flask(__name__)\n    flask_app.secret_key = conf.get(\"webserver\", \"SECRET_KEY\")\n\n    flask_app.config[\"PERMANENT_SESSION_LIFETIME\"] = timedelta(minutes=settings.get_session_lifetime_config())\n\n    flask_app.config[\"MAX_CONTENT_LENGTH\"] = conf.getfloat(\"webserver\", \"allowed_payload_size\") * 1024 * 1024\n\n    webserver_config = conf.get_mandatory_value(\"webserver\", \"config_file\")\n    # Enable customizations in webserver_config.py to be applied via Flask.current_app.\n    with flask_app.app_context():\n        flask_app.config.from_pyfile(webserver_config, silent=True)\n\n    flask_app.config[\"TESTING\"] = testing\n    flask_app.config[\"SQLALCHEMY_DATABASE_URI\"] = conf.get(\"database\", \"SQL_ALCHEMY_CONN\")\n\n    instance_name = conf.get(section=\"webserver\", key=\"instance_name\", fallback=\"Airflow\")\n    require_confirmation_dag_change = conf.getboolean(\n        section=\"webserver\", key=\"require_confirmation_dag_change\", fallback=False\n    )\n    instance_name_has_markup = conf.getboolean(\n        section=\"webserver\", key=\"instance_name_has_markup\", fallback=False\n    )\n    if instance_name_has_markup:\n        instance_name = Markup(instance_name).striptags()\n\n    flask_app.config[\"APP_NAME\"] = instance_name\n    flask_app.config[\"REQUIRE_CONFIRMATION_DAG_CHANGE\"] = require_confirmation_dag_change\n\n    url = make_url(flask_app.config[\"SQLALCHEMY_DATABASE_URI\"])\n    if url.drivername == \"sqlite\" and url.database and not url.database.startswith(\"/\"):\n        raise AirflowConfigException(\n            f'Cannot use relative path: `{conf.get(\"database\", \"SQL_ALCHEMY_CONN\")}` to connect to sqlite. '\n            \"Please use absolute path such as `sqlite:////tmp/airflow.db`.\"\n        )\n\n    flask_app.config[\"SQLALCHEMY_TRACK_MODIFICATIONS\"] = False\n\n    flask_app.config[\"SESSION_COOKIE_HTTPONLY\"] = True\n    flask_app.config[\"SESSION_COOKIE_SECURE\"] = conf.getboolean(\"webserver\", \"COOKIE_SECURE\")\n\n    cookie_samesite_config = conf.get(\"webserver\", \"COOKIE_SAMESITE\")\n    if cookie_samesite_config == \"\":\n        warnings.warn(\n            \"Old deprecated value found for `cookie_samesite` option in `[webserver]` section. \"\n            \"Using `Lax` instead. Change the value to `Lax` in airflow.cfg to remove this warning.\",\n            RemovedInAirflow3Warning,\n            stacklevel=2,\n        )\n        cookie_samesite_config = \"Lax\"\n    flask_app.config[\"SESSION_COOKIE_SAMESITE\"] = cookie_samesite_config\n\n    if config:\n        flask_app.config.from_mapping(config)\n\n    if \"SQLALCHEMY_ENGINE_OPTIONS\" not in flask_app.config:\n        flask_app.config[\"SQLALCHEMY_ENGINE_OPTIONS\"] = settings.prepare_engine_args()\n\n    # Configure the JSON encoder used by `|tojson` filter from Flask\n    flask_app.json_provider_class = AirflowJsonProvider\n    flask_app.json = AirflowJsonProvider(flask_app)\n\n    InternalApiConfig.force_database_direct_access()\n\n    csrf.init_app(flask_app)\n\n    init_wsgi_middleware(flask_app)\n\n    db = SQLA()\n    db.session = settings.Session\n    db.init_app(flask_app)\n\n    init_dagbag(flask_app)\n\n    init_api_experimental_auth(flask_app)\n\n    init_robots(flask_app)\n\n    init_cache(flask_app)\n\n    init_flash_views(flask_app)\n\n    configure_logging()\n    configure_manifest_files(flask_app)\n\n    import_all_models()\n\n    with flask_app.app_context():\n        init_appbuilder(flask_app)\n\n        init_appbuilder_views(flask_app)\n        init_appbuilder_links(flask_app)\n        init_plugins(flask_app)\n        init_error_handlers(flask_app)\n        init_api_connexion(flask_app)\n        if conf.getboolean(\"webserver\", \"run_internal_api\", fallback=False):\n            if not _ENABLE_AIP_44:\n                raise RuntimeError(\"The AIP_44 is not enabled so you cannot use it.\")\n            init_api_internal(flask_app)\n        init_api_experimental(flask_app)\n        init_api_auth_provider(flask_app)\n        init_api_error_handlers(flask_app)  # needs to be after all api inits to let them add their path first\n\n        get_auth_manager().init()\n\n        init_jinja_globals(flask_app)\n        init_xframe_protection(flask_app)\n        init_airflow_session_interface(flask_app)\n        init_check_user_active(flask_app)\n    return flask_app\n\n\ndef cached_app(config=None, testing=False):\n    \"\"\"Return cached instance of Airflow WWW app.\"\"\"\n    global app\n    if not app:\n        app = create_app(config=config, testing=testing)\n    return app\n\n\ndef purge_cached_app():\n    \"\"\"Remove the cached version of the app in global state.\"\"\"\n    global app\n    app = None\n", "path": "airflow/www/app.py"}], "after_files": [{"content": "#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\nfrom __future__ import annotations\n\nimport warnings\nfrom datetime import timedelta\n\nfrom flask import Flask\nfrom flask_appbuilder import SQLA\nfrom flask_wtf.csrf import CSRFProtect\nfrom markupsafe import Markup\nfrom sqlalchemy.engine.url import make_url\n\nfrom airflow import settings\nfrom airflow.api_internal.internal_api_call import InternalApiConfig\nfrom airflow.configuration import conf\nfrom airflow.exceptions import AirflowConfigException, RemovedInAirflow3Warning\nfrom airflow.logging_config import configure_logging\nfrom airflow.models import import_all_models\nfrom airflow.settings import _ENABLE_AIP_44\nfrom airflow.utils.json import AirflowJsonProvider\nfrom airflow.www.extensions.init_appbuilder import init_appbuilder\nfrom airflow.www.extensions.init_appbuilder_links import init_appbuilder_links\nfrom airflow.www.extensions.init_auth_manager import get_auth_manager\nfrom airflow.www.extensions.init_cache import init_cache\nfrom airflow.www.extensions.init_dagbag import init_dagbag\nfrom airflow.www.extensions.init_jinja_globals import init_jinja_globals\nfrom airflow.www.extensions.init_manifest_files import configure_manifest_files\nfrom airflow.www.extensions.init_robots import init_robots\nfrom airflow.www.extensions.init_security import (\n    init_api_experimental_auth,\n    init_check_user_active,\n    init_xframe_protection,\n)\nfrom airflow.www.extensions.init_session import init_airflow_session_interface\nfrom airflow.www.extensions.init_views import (\n    init_api_auth_provider,\n    init_api_connexion,\n    init_api_error_handlers,\n    init_api_experimental,\n    init_api_internal,\n    init_appbuilder_views,\n    init_error_handlers,\n    init_flash_views,\n    init_plugins,\n)\nfrom airflow.www.extensions.init_wsgi_middlewares import init_wsgi_middleware\n\napp: Flask | None = None\n\n# Initializes at the module level, so plugins can access it.\n# See: /docs/plugins.rst\ncsrf = CSRFProtect()\n\n\ndef create_app(config=None, testing=False):\n    \"\"\"Create a new instance of Airflow WWW app.\"\"\"\n    flask_app = Flask(__name__)\n    flask_app.secret_key = conf.get(\"webserver\", \"SECRET_KEY\")\n\n    flask_app.config[\"PERMANENT_SESSION_LIFETIME\"] = timedelta(minutes=settings.get_session_lifetime_config())\n\n    flask_app.config[\"MAX_CONTENT_LENGTH\"] = conf.getfloat(\"webserver\", \"allowed_payload_size\") * 1024 * 1024\n\n    webserver_config = conf.get_mandatory_value(\"webserver\", \"config_file\")\n    # Enable customizations in webserver_config.py to be applied via Flask.current_app.\n    with flask_app.app_context():\n        flask_app.config.from_pyfile(webserver_config, silent=True)\n\n    flask_app.config[\"TESTING\"] = testing\n    flask_app.config[\"SQLALCHEMY_DATABASE_URI\"] = conf.get(\"database\", \"SQL_ALCHEMY_CONN\")\n\n    instance_name = conf.get(section=\"webserver\", key=\"instance_name\", fallback=\"Airflow\")\n    require_confirmation_dag_change = conf.getboolean(\n        section=\"webserver\", key=\"require_confirmation_dag_change\", fallback=False\n    )\n    instance_name_has_markup = conf.getboolean(\n        section=\"webserver\", key=\"instance_name_has_markup\", fallback=False\n    )\n    if instance_name_has_markup:\n        instance_name = Markup(instance_name).striptags()\n\n    flask_app.config[\"APP_NAME\"] = instance_name\n    flask_app.config[\"REQUIRE_CONFIRMATION_DAG_CHANGE\"] = require_confirmation_dag_change\n\n    url = make_url(flask_app.config[\"SQLALCHEMY_DATABASE_URI\"])\n    if url.drivername == \"sqlite\" and url.database and not url.database.startswith(\"/\"):\n        raise AirflowConfigException(\n            f'Cannot use relative path: `{conf.get(\"database\", \"SQL_ALCHEMY_CONN\")}` to connect to sqlite. '\n            \"Please use absolute path such as `sqlite:////tmp/airflow.db`.\"\n        )\n\n    flask_app.config[\"SQLALCHEMY_TRACK_MODIFICATIONS\"] = False\n\n    flask_app.config[\"SESSION_COOKIE_HTTPONLY\"] = True\n    flask_app.config[\"SESSION_COOKIE_SECURE\"] = conf.getboolean(\"webserver\", \"COOKIE_SECURE\")\n\n    cookie_samesite_config = conf.get(\"webserver\", \"COOKIE_SAMESITE\")\n    if cookie_samesite_config == \"\":\n        warnings.warn(\n            \"Old deprecated value found for `cookie_samesite` option in `[webserver]` section. \"\n            \"Using `Lax` instead. Change the value to `Lax` in airflow.cfg to remove this warning.\",\n            RemovedInAirflow3Warning,\n            stacklevel=2,\n        )\n        cookie_samesite_config = \"Lax\"\n    flask_app.config[\"SESSION_COOKIE_SAMESITE\"] = cookie_samesite_config\n\n    # Above Flask 2.0.x, default value of SEND_FILE_MAX_AGE_DEFAULT changed 12 hours to None.\n    # for static file caching, it needs to set value explicitly.\n    flask_app.config[\"SEND_FILE_MAX_AGE_DEFAULT\"] = timedelta(seconds=43200)\n\n    if config:\n        flask_app.config.from_mapping(config)\n\n    if \"SQLALCHEMY_ENGINE_OPTIONS\" not in flask_app.config:\n        flask_app.config[\"SQLALCHEMY_ENGINE_OPTIONS\"] = settings.prepare_engine_args()\n\n    # Configure the JSON encoder used by `|tojson` filter from Flask\n    flask_app.json_provider_class = AirflowJsonProvider\n    flask_app.json = AirflowJsonProvider(flask_app)\n\n    InternalApiConfig.force_database_direct_access()\n\n    csrf.init_app(flask_app)\n\n    init_wsgi_middleware(flask_app)\n\n    db = SQLA()\n    db.session = settings.Session\n    db.init_app(flask_app)\n\n    init_dagbag(flask_app)\n\n    init_api_experimental_auth(flask_app)\n\n    init_robots(flask_app)\n\n    init_cache(flask_app)\n\n    init_flash_views(flask_app)\n\n    configure_logging()\n    configure_manifest_files(flask_app)\n\n    import_all_models()\n\n    with flask_app.app_context():\n        init_appbuilder(flask_app)\n\n        init_appbuilder_views(flask_app)\n        init_appbuilder_links(flask_app)\n        init_plugins(flask_app)\n        init_error_handlers(flask_app)\n        init_api_connexion(flask_app)\n        if conf.getboolean(\"webserver\", \"run_internal_api\", fallback=False):\n            if not _ENABLE_AIP_44:\n                raise RuntimeError(\"The AIP_44 is not enabled so you cannot use it.\")\n            init_api_internal(flask_app)\n        init_api_experimental(flask_app)\n        init_api_auth_provider(flask_app)\n        init_api_error_handlers(flask_app)  # needs to be after all api inits to let them add their path first\n\n        get_auth_manager().init()\n\n        init_jinja_globals(flask_app)\n        init_xframe_protection(flask_app)\n        init_airflow_session_interface(flask_app)\n        init_check_user_active(flask_app)\n    return flask_app\n\n\ndef cached_app(config=None, testing=False):\n    \"\"\"Return cached instance of Airflow WWW app.\"\"\"\n    global app\n    if not app:\n        app = create_app(config=config, testing=testing)\n    return app\n\n\ndef purge_cached_app():\n    \"\"\"Remove the cached version of the app in global state.\"\"\"\n    global app\n    app = None\n", "path": "airflow/www/app.py"}]}