31 | This is a dynamically generated page, and thus should not be cached. 32 | The current date is passed to the template and gets printed, to verify that no cache problems appear 33 |
34 |{{ data }}
36 | 48 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /flask_squeeze/flask_squeeze.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import hashlib 4 | from pathlib import Path 5 | from typing import cast 6 | 7 | from flask import Flask, Response, request 8 | 9 | from .cache import Cache, CacheKey 10 | from .compress import CompressionInfo, compress 11 | from .log import log 12 | from .minify import MinificationInfo, minify 13 | from .models import Encoding, Minification, ResourceType 14 | from .utils import add_breach_exploit_protection_header, update_response_headers 15 | 16 | 17 | class Squeeze: 18 | __slots__ = "app", "cache_static" 19 | app: Flask 20 | 21 | cache_static: Cache 22 | """ (request.path, encoding) -> (original file sha256 hash, compressed bytes) """ 23 | 24 | def __init__(self, app: Flask | None = None) -> None: 25 | """Initialize Flask-Squeeze with or without app.""" 26 | if app is None: 27 | return 28 | self.app = app 29 | self.init_app(app) 30 | 31 | def init_app(self, app: Flask) -> None: 32 | """Initialize Flask-Squeeze with app""" 33 | self.app = app 34 | # Compression options 35 | app.config.setdefault("SQUEEZE_COMPRESS", True) 36 | app.config.setdefault("SQUEEZE_MIN_SIZE", 500) 37 | # Compression levels 38 | app.config.setdefault("SQUEEZE_LEVEL_GZIP_STATIC", 9) 39 | app.config.setdefault("SQUEEZE_LEVEL_GZIP_DYNAMIC", 1) 40 | app.config.setdefault("SQUEEZE_LEVEL_BROTLI_STATIC", 11) 41 | app.config.setdefault("SQUEEZE_LEVEL_BROTLI_DYNAMIC", 1) 42 | app.config.setdefault("SQUEEZE_LEVEL_DEFLATE_STATIC", 9) 43 | app.config.setdefault("SQUEEZE_LEVEL_DEFLATE_DYNAMIC", 1) 44 | # Minification options 45 | app.config.setdefault("SQUEEZE_MINIFY_JS", True) 46 | app.config.setdefault("SQUEEZE_MINIFY_CSS", True) 47 | app.config.setdefault("SQUEEZE_MINIFY_HTML", True) 48 | # Caching options 49 | app.config.setdefault("SQUEEZE_CACHE_DIR", None) 50 | # Logging options 51 | app.config.setdefault("SQUEEZE_VERBOSE_LOGGING", False) 52 | 53 | # Initialize cache 54 | 55 | cache_dir = app.config.get("SQUEEZE_CACHE_DIR") 56 | self.cache_static = Cache( 57 | data={}, 58 | cache_dir=Path(cache_dir) if cache_dir else None, 59 | ) 60 | 61 | # Initialize after_request hook 62 | 63 | if ( 64 | app.config["SQUEEZE_COMPRESS"] 65 | or app.config["SQUEEZE_MINIFY_JS"] 66 | or app.config["SQUEEZE_MINIFY_CSS"] 67 | or app.config["SQUEEZE_MINIFY_HTML"] 68 | ): 69 | app.after_request(self.after_request) 70 | 71 | #################################################################################### 72 | #### MARK: Utils 73 | 74 | def get_configured_quality(self, encode_choice: Encoding, resource_type: ResourceType) -> int: 75 | options = { 76 | (Encoding.br, ResourceType.static): "SQUEEZE_LEVEL_BROTLI_STATIC", 77 | (Encoding.br, ResourceType.dynamic): "SQUEEZE_LEVEL_BROTLI_DYNAMIC", 78 | (Encoding.deflate, ResourceType.static): "SQUEEZE_LEVEL_DEFLATE_STATIC", 79 | (Encoding.deflate, ResourceType.dynamic): "SQUEEZE_LEVEL_DEFLATE_DYNAMIC", 80 | (Encoding.gzip, ResourceType.static): "SQUEEZE_LEVEL_GZIP_STATIC", 81 | (Encoding.gzip, ResourceType.dynamic): "SQUEEZE_LEVEL_GZIP_DYNAMIC", 82 | } 83 | 84 | option = options[(encode_choice, resource_type)] 85 | 86 | return cast("int", self.app.config[option]) 87 | 88 | #################################################################################### 89 | #### MARK: Dynamic 90 | 91 | def run_dynamic( 92 | self, 93 | response: Response, 94 | encode_choice: Encoding | None, 95 | minify_choice: Minification | None, 96 | ) -> None: 97 | assert encode_choice or minify_choice 98 | 99 | data, minification_info, compression_info = self.squeeze( 100 | response.get_data(as_text=False), 101 | ResourceType.dynamic, 102 | minify_choice, 103 | encode_choice, 104 | ) 105 | 106 | response.set_data(data) 107 | 108 | if minification_info: 109 | response.headers.update(minification_info.headers) 110 | 111 | if compression_info: 112 | response.headers.update(compression_info.headers) 113 | add_breach_exploit_protection_header(response) 114 | 115 | #################################################################################### 116 | #### MARK: Static 117 | 118 | def run_static( 119 | self, 120 | response: Response, 121 | encode_choice: Encoding | None, 122 | minify_choice: Minification | None, 123 | ) -> None: 124 | """ 125 | If the hash of the current response matches the hash of the cached response, 126 | return the cached response. Otherwise, compress and minify the response and 127 | cache the compressed response. 128 | """ 129 | assert encode_choice or minify_choice 130 | 131 | data = response.get_data(as_text=False) 132 | data_hash = hashlib.sha256(data).hexdigest() 133 | 134 | cache_key = CacheKey(request.path, encode_choice) 135 | cached = self.cache_static.get(cache_key) 136 | 137 | if cached is not None and data_hash == cached.original_hash: 138 | log(2, "Found in cache, hashes match. RETURN") 139 | response.set_data(cached.data) 140 | response.headers["X-Flask-Squeeze-Cache"] = "HIT" 141 | return 142 | 143 | # Not in cache, compress and minify 144 | 145 | log(2, "Not in cache or hashes don't match. Squeeze and cache.") 146 | data, minification_info, compression_info = self.squeeze( 147 | data, 148 | ResourceType.static, 149 | minify_choice, 150 | encode_choice, 151 | ) 152 | 153 | response.set_data(data) 154 | 155 | if minification_info: 156 | response.headers.update(minification_info.headers) 157 | 158 | if compression_info: 159 | response.headers.update(compression_info.headers) 160 | 161 | response.headers["X-Flask-Squeeze-Cache"] = "MISS" 162 | 163 | # Cache the compressed data, with the dash of the original data 164 | self.cache_static.set(cache_key, data_hash, data) 165 | 166 | def squeeze( 167 | self, 168 | data: bytes, 169 | resource_type: ResourceType, 170 | minify_choice: Minification | None, 171 | encode_choice: Encoding | None, 172 | ) -> tuple[bytes, MinificationInfo | None, CompressionInfo | None]: 173 | assert encode_choice or minify_choice 174 | 175 | minification_info = None 176 | if minify_choice is not None: 177 | data, minification_info = minify(data, minify_choice) 178 | 179 | compression_info = None 180 | if encode_choice is not None: 181 | data, compression_info = compress( 182 | data, 183 | encode_choice, 184 | self.get_configured_quality(encode_choice, resource_type), 185 | ) 186 | 187 | return data, minification_info, compression_info 188 | 189 | #################################################################################### 190 | #### MARK: After Request 191 | 192 | def after_request(self, response: Response) -> Response: 193 | log(1, f"Enter after_request({response})") 194 | 195 | if response.status_code is None or response.content_length is None: 196 | log(1, "Response status code or content length is None. RETURN") 197 | return response 198 | 199 | if response.status_code not in range(200, 300): 200 | log(1, "Response status code is not ok. RETURN") 201 | return response 202 | 203 | if response.content_length < self.app.config["SQUEEZE_MIN_SIZE"]: 204 | log(1, "Response size is smaller than the defined minimum. RETURN") 205 | return response 206 | 207 | if "Content-Encoding" in response.headers: 208 | log(1, "Response already encoded. RETURN") 209 | return response 210 | 211 | # Assert: The response is ok, the size is above threshold, and the response is 212 | # not already encoded. 213 | 214 | encode_choice = Encoding.get_from_headers_and_config( 215 | request.headers, 216 | self.app.config, 217 | ) 218 | 219 | minify_choice = Minification.get_from_mimetype_and_config( 220 | response.mimetype, 221 | self.app.config, 222 | ) 223 | 224 | if encode_choice is None and minify_choice is None: 225 | log(1, "No compression or minification requested. RETURN") 226 | return response 227 | 228 | # At least one of minify or compress is requested 229 | 230 | response.direct_passthrough = False # In both cases, we need to read the data 231 | 232 | if request.path.startswith("/static/"): 233 | self.run_static(response, encode_choice, minify_choice) 234 | else: 235 | self.run_dynamic(response, encode_choice, minify_choice) 236 | 237 | update_response_headers(response, encode_choice) 238 | 239 | log(1, f"Static cache: {self.cache_static.data.keys()}") 240 | return response 241 | -------------------------------------------------------------------------------- /tests/test_app/static/text.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 2 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 3 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 4 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 5 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 6 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 7 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 8 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 9 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 10 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 11 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 12 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 13 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 14 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 15 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 16 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 17 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 18 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 19 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 20 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 21 | -------------------------------------------------------------------------------- /tests/test_flask_squeeze.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import contextlib 4 | import tempfile 5 | from pathlib import Path 6 | from typing import TYPE_CHECKING, Any 7 | 8 | import pytest 9 | from test_app import create_app 10 | 11 | if TYPE_CHECKING: 12 | from collections.abc import Generator 13 | 14 | from flask.testing import FlaskClient 15 | from werkzeug.wrappers import Response 16 | 17 | STATUS_CODE_NOT_FOUND_404 = 404 18 | STATUS_CODE_OK_200 = 200 19 | 20 | ######################################################################################## 21 | #### MARK: Fixtures 22 | 23 | 24 | @pytest.fixture 25 | def client() -> Generator[FlaskClient, Any, None]: 26 | app = create_app() 27 | app.testing = True 28 | with app.test_client() as test_client: 29 | yield test_client 30 | 31 | 32 | @pytest.fixture(params=["", "gzip", "br", "deflate"]) 33 | def use_encoding(request: pytest.FixtureRequest) -> str: 34 | return str(request.param) 35 | 36 | 37 | @pytest.fixture(params=[False, True]) 38 | def use_minify_js(request: pytest.FixtureRequest) -> bool: 39 | return bool(request.param) 40 | 41 | 42 | @pytest.fixture(params=[False, True]) 43 | def use_minify_css(request: pytest.FixtureRequest) -> bool: 44 | return bool(request.param) 45 | 46 | 47 | ######################################################################################## 48 | #### MARK: Utilities 49 | 50 | 51 | def almost_equal(a: float, b: float, percent: float = 0.01) -> bool: 52 | diff = abs(int(a) - int(b)) 53 | return diff < percent * int(a) and diff < percent * int(b) 54 | 55 | 56 | def content_length_correct(r: Response) -> bool: 57 | return r.headers.get("Content-Length", 0) == str(len(r.data)) 58 | 59 | 60 | ######################################################################################## 61 | #### MARK: Tests 62 | 63 | 64 | def test_init_app_with_existing_app() -> None: 65 | app = create_app() 66 | 67 | from flask_squeeze import Squeeze 68 | 69 | _squeeze = Squeeze(app) 70 | 71 | 72 | def test_get_index(client: FlaskClient, use_encoding: str) -> None: 73 | print("test_get_index") 74 | r = client.get("/", headers={"Accept-Encoding": use_encoding}) 75 | assert content_length_correct(r) 76 | length = int(r.headers.get("Content-Length", "0")) 77 | encoding = r.headers.get("Content-Encoding", "") 78 | 79 | assert use_encoding == encoding 80 | 81 | sizes = { 82 | "": 3_932_146, 83 | "br": 8_164, 84 | "deflate": 83_554, 85 | "gzip": 83_566, 86 | } 87 | 88 | assert almost_equal(length, sizes[use_encoding]) 89 | 90 | 91 | def test_get_css_file(client: FlaskClient, use_encoding: str, use_minify_css: bool) -> None: 92 | print("test_get_css_file with", use_encoding, "minify:", use_minify_css) 93 | client.application.config.update({"SQUEEZE_MINIFY_CSS": use_minify_css}) 94 | url = "/static/fomantic.css" 95 | r = client.get(url, headers={"Accept-Encoding": use_encoding}) 96 | assert content_length_correct(r) 97 | response_length = int(r.headers.get("Content-Length", "0")) 98 | encoding = r.headers.get("Content-Encoding", "") 99 | 100 | assert use_encoding == encoding 101 | 102 | sizes = { 103 | ("", True): 1_377_522, 104 | ("br", True): 117_261, 105 | ("deflate", True): 157_184, 106 | ("gzip", True): 157_196, 107 | ("", False): 1_642_530, 108 | ("br", False): 130_781, 109 | ("deflate", False): 179_986, 110 | ("gzip", False): 179_998, 111 | } 112 | 113 | assert almost_equal(response_length, sizes[(use_encoding, use_minify_css)]) 114 | 115 | 116 | def test_get_js_file(client: FlaskClient, use_encoding: str, use_minify_js: bool) -> None: 117 | print("test_get_js_file with", use_encoding, "minify:", use_minify_js) 118 | client.application.config.update({"SQUEEZE_MINIFY_JS": use_minify_js}) 119 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": use_encoding}) 120 | assert content_length_correct(r) 121 | assert use_encoding == r.headers.get("Content-Encoding", "") 122 | 123 | 124 | def test_get_jquery_no_minify(client: FlaskClient) -> None: 125 | client.application.config.update({"SQUEEZE_MINIFY_JS": False}) 126 | r_orig = client.get("/static/jquery.js", headers={}) 127 | assert content_length_correct(r_orig) 128 | assert "Content-Encoding" not in r_orig.headers 129 | assert r_orig.headers["Content-Length"] == "292458" 130 | 131 | 132 | def test_get_from_cache(client: FlaskClient, use_encoding: str) -> None: 133 | client.application.config.update({"SQUEEZE_MINIFY_JS": False}) 134 | r = client.get("/static/jquery.min.js", headers={"Accept-Encoding": use_encoding}) 135 | r_2 = client.get("/static/jquery.min.js", headers={"Accept-Encoding": use_encoding}) 136 | assert r.data == r_2.data 137 | 138 | 139 | def test_get_unknown_url(client: FlaskClient) -> None: 140 | r = client.get("/static/unknown.js", headers={"Accept-Encoding": "gzip"}) 141 | assert r.status_code == STATUS_CODE_NOT_FOUND_404 142 | 143 | 144 | def test_get_same_repeatedly(client: FlaskClient) -> None: 145 | client.application.config.update({"SQUEEZE_MINIFY_JS": True}) 146 | for i in range(100): 147 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "br"}) 148 | if i == 0: 149 | assert r.headers.get("X-Flask-Squeeze-Cache") == "MISS" 150 | else: 151 | assert r.headers.get("X-Flask-Squeeze-Cache") == "HIT" 152 | for i in range(100): 153 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 154 | if i == 0: 155 | assert r.headers.get("X-Flask-Squeeze-Cache") == "MISS" 156 | else: 157 | assert r.headers.get("X-Flask-Squeeze-Cache") == "HIT" 158 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "br"}) 159 | assert r.headers.get("X-Flask-Squeeze-Cache") == "HIT" 160 | 161 | 162 | def response_has_breach_header(r: Response) -> bool: 163 | return "X-Flask-Squeeze-Breach-Protection" in r.headers 164 | 165 | 166 | def response_has_vary_header(r: Response) -> bool: 167 | return "Vary" in r.headers and "Accept-Encoding" in r.headers["Vary"] 168 | 169 | 170 | ######################################################################################## 171 | #### MARK: Additional Tests 172 | 173 | 174 | def test_disable_compression(client: FlaskClient) -> None: 175 | """Test that compression can be disabled.""" 176 | client.application.config.update({"SQUEEZE_COMPRESS": False}) 177 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 178 | assert "Content-Encoding" not in r.headers 179 | assert not response_has_breach_header(r) 180 | 181 | 182 | def test_disable_minification(client: FlaskClient) -> None: 183 | """Test that minification can be disabled.""" 184 | client.application.config.update( 185 | { 186 | "SQUEEZE_MINIFY_JS": False, 187 | "SQUEEZE_MINIFY_CSS": False, 188 | "SQUEEZE_MINIFY_HTML": False, 189 | }, 190 | ) 191 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 192 | assert "X-Flask-Squeeze-Minify" not in r.headers 193 | 194 | 195 | def test_html_response_minification(client: FlaskClient) -> None: 196 | """Test minification of HTML responses.""" 197 | client.application.config.update({"SQUEEZE_MINIFY_HTML": True}) 198 | r = client.get("/", headers={"Accept-Encoding": "gzip"}) 199 | assert "X-Flask-Squeeze-Minify" in r.headers, r.headers 200 | 201 | 202 | def test_breach_header_presence(client: FlaskClient) -> None: 203 | """Test the presence of the breach exploit protection header.""" 204 | r = client.get("/", headers={"Accept-Encoding": "br"}) 205 | assert response_has_breach_header(r) 206 | 207 | 208 | def test_vary_header_presence(client: FlaskClient) -> None: 209 | """Test the presence of the Vary header after compression.""" 210 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 211 | assert response_has_vary_header(r) 212 | 213 | 214 | def test_minification_and_compression_together(client: FlaskClient) -> None: 215 | """Test both minification and compression are applied together.""" 216 | client.application.config.update({"SQUEEZE_MINIFY_CSS": True}) 217 | r = client.get("/static/fomantic.css", headers={"Accept-Encoding": "gzip"}) 218 | assert "Content-Encoding" in r.headers 219 | assert "X-Flask-Squeeze-Minify" in r.headers 220 | assert content_length_correct(r) 221 | 222 | 223 | def test_no_minify_no_compress(client: FlaskClient) -> None: 224 | client.application.config.update( 225 | { 226 | "SQUEEZE_MINIFY_JS": False, 227 | "SQUEEZE_MINIFY_CSS": False, 228 | "SQUEEZE_MINIFY_HTML": False, 229 | "SQUEEZE_COMPRESS": False, 230 | }, 231 | ) 232 | 233 | # Static file with no minification or compression 234 | 235 | r = client.get("/static/fomantic.css", headers={"Accept-Encoding": "gzip"}) 236 | assert "Content-Encoding" not in r.headers 237 | assert "X-Flask-Squeeze-Minify" not in r.headers 238 | assert "X-Flask-Squeeze-Compress" not in r.headers 239 | 240 | # Dynamic file with no minification or compression 241 | 242 | r = client.get("/", headers={"Accept-Encoding": "gzip"}) 243 | assert "Content-Encoding" not in r.headers 244 | assert "X-Flask-Squeeze-Minify" not in r.headers 245 | assert "X-Flask-Squeeze-Compress" not in r.headers 246 | 247 | 248 | def test_static_file_cache_behavior( 249 | client: FlaskClient, 250 | use_encoding: str, 251 | use_minify_css: bool, 252 | ) -> None: 253 | """Test cache behavior for a temporary static file.""" 254 | 255 | # Skip if encoding is not set 256 | if not use_encoding: 257 | return 258 | 259 | client.application.config.update({"SQUEEZE_MINIFY_CSS": use_minify_css}) 260 | 261 | # Ensure the static directory is set 262 | if (static_dir := client.application.static_folder) is None: 263 | msg = "Static directory not found" 264 | raise ValueError(msg) 265 | 266 | # Use a temporary file within the static directory 267 | with tempfile.NamedTemporaryFile(dir=static_dir, suffix=".css", delete=True) as temp_file: 268 | file_path = temp_file.name 269 | url_path = "/static/" + Path(file_path).name 270 | temp_file.write(b"body { color: #000; } " * 1000) 271 | temp_file.flush() # Ensure content is written to disk 272 | 273 | # First request: MISS 274 | r = client.get(url_path, headers={"Accept-Encoding": use_encoding}) 275 | assert r.headers.get("X-Flask-Squeeze-Cache") == "MISS" 276 | 277 | # Second request: HIT 278 | r = client.get(url_path, headers={"Accept-Encoding": use_encoding}) 279 | assert r.headers.get("X-Flask-Squeeze-Cache") == "HIT" 280 | 281 | # Modify the file content 282 | temp_file.write(b"body { color: #123456; } " * 1000) 283 | temp_file.flush() # Ensure the new content is written 284 | 285 | # Third request: MISS 286 | r = client.get(url_path, headers={"Accept-Encoding": use_encoding}) 287 | assert r.headers.get("X-Flask-Squeeze-Cache") == "MISS" 288 | 289 | # Fourth request: HIT 290 | r = client.get(url_path, headers={"Accept-Encoding": use_encoding}) 291 | assert r.headers.get("X-Flask-Squeeze-Cache") == "HIT" 292 | 293 | 294 | def test_malformed_accept_encoding(client: FlaskClient) -> None: 295 | # Case 1: Missing Accept-Encoding 296 | r = client.get("/static/jquery.js") 297 | assert "Content-Encoding" not in r.headers 298 | 299 | # Case 2: Malformed Accept-Encoding 300 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "invalid-encoding"}) 301 | assert "Content-Encoding" not in r.headers 302 | 303 | # Case 3: Conflicting Accept-Encoding values 304 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip, br"}) 305 | assert r.headers.get("Content-Encoding") in {"gzip", "br"} 306 | 307 | 308 | def test_cache_invalidation_on_compression_disable(client: FlaskClient) -> None: 309 | # Enable compression and fetch the file 310 | client.application.config.update({"SQUEEZE_COMPRESS": True}) 311 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 312 | assert r.headers.get("X-Flask-Squeeze-Cache") == "MISS" 313 | 314 | # Fetch again to ensure it is cached 315 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 316 | assert r.headers.get("X-Flask-Squeeze-Cache") == "HIT" 317 | 318 | # Disable compression 319 | client.application.config.update({"SQUEEZE_COMPRESS": False}) 320 | 321 | # Fetch again, cache should be invalidated 322 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 323 | assert r.headers.get("X-Flask-Squeeze-Cache") == "MISS" 324 | assert "Content-Encoding" not in r.headers 325 | 326 | 327 | def test_small_response_below_min_size(client: FlaskClient) -> None: 328 | min_size = 1000 329 | client.application.config.update({"SQUEEZE_MIN_SIZE": min_size}) 330 | 331 | # A small response 332 | r = client.get("/static/smallfile.js", headers={"Accept-Encoding": "gzip"}) 333 | assert r.content_length < min_size # Ensure response is small 334 | assert "Content-Encoding" not in r.headers 335 | assert "X-Flask-Squeeze-Minify" not in r.headers 336 | 337 | 338 | def test_persistent_cache_basic(client: FlaskClient) -> None: 339 | """Test basic persistent caching functionality.""" 340 | with tempfile.TemporaryDirectory() as temp_dir: 341 | cache_dir = Path(temp_dir) / "flask_squeeze_cache" 342 | 343 | # Configure persistent caching 344 | client.application.config.update({"SQUEEZE_CACHE_DIR": str(cache_dir)}) 345 | 346 | # Reinitialize the squeeze instance with the new config 347 | from flask_squeeze import Squeeze 348 | 349 | squeeze = Squeeze() 350 | squeeze.init_app(client.application) 351 | 352 | # First request - should be a cache miss 353 | r1 = client.get("/static/jquery.min.js", headers={"Accept-Encoding": "gzip"}) 354 | assert r1.headers.get("X-Flask-Squeeze-Cache") == "MISS" 355 | 356 | # Second request - should be a cache hit from memory 357 | r2 = client.get("/static/jquery.min.js", headers={"Accept-Encoding": "gzip"}) 358 | assert r2.headers.get("X-Flask-Squeeze-Cache") == "HIT" 359 | assert r1.data == r2.data 360 | 361 | # Verify cache files were created 362 | cache_files = list(cache_dir.glob("*.cache")) 363 | meta_files = list(cache_dir.glob("*.meta")) 364 | assert len(cache_files) > 0 365 | assert len(meta_files) > 0 366 | 367 | 368 | def test_persistent_cache_across_restarts(client: FlaskClient) -> None: 369 | """Test that cache persists across application restarts.""" 370 | with tempfile.TemporaryDirectory() as temp_dir: 371 | cache_dir = Path(temp_dir) / "flask_squeeze_cache" 372 | 373 | # Configure persistent caching 374 | client.application.config.update({"SQUEEZE_CACHE_DIR": str(cache_dir)}) 375 | 376 | # Create first squeeze instance 377 | from flask_squeeze import Squeeze 378 | 379 | squeeze1 = Squeeze() 380 | squeeze1.init_app(client.application) 381 | 382 | # First request 383 | r1 = client.get("/static/jquery.min.js", headers={"Accept-Encoding": "gzip"}) 384 | assert r1.headers.get("X-Flask-Squeeze-Cache") == "MISS" 385 | 386 | # Create a second squeeze instance to simulate a restart 387 | 388 | app_2 = create_app() 389 | app_2.testing = True 390 | client_2 = app_2.test_client() 391 | client_2.application.config.update({"SQUEEZE_CACHE_DIR": str(cache_dir)}) 392 | squeeze2 = Squeeze() 393 | squeeze2.init_app(client_2.application) 394 | 395 | # Second request after "restart" - should be cache hit from disk 396 | r2 = client_2.get("/static/jquery.min.js", headers={"Accept-Encoding": "gzip"}) 397 | assert r2.headers.get("X-Flask-Squeeze-Cache") == "HIT" 398 | assert r1.data == r2.data 399 | 400 | 401 | def test_persistent_cache_disabled(client: FlaskClient) -> None: 402 | """Test that without cache directory, only in-memory cache is used.""" 403 | # Don't set SQUEEZE_CACHE_DIR 404 | from flask_squeeze import Squeeze 405 | 406 | squeeze = Squeeze() 407 | squeeze.init_app(client.application) 408 | 409 | # First request 410 | r1 = client.get("/static/jquery.min.js", headers={"Accept-Encoding": "gzip"}) 411 | assert r1.headers.get("X-Flask-Squeeze-Cache") == "MISS" 412 | 413 | # Second request - should be cache hit from memory 414 | r2 = client.get("/static/jquery.min.js", headers={"Accept-Encoding": "gzip"}) 415 | assert r2.headers.get("X-Flask-Squeeze-Cache") == "HIT" 416 | 417 | 418 | def test_mimetype_detection_comprehensive(client: FlaskClient) -> None: 419 | """Test comprehensive mimetype detection for various file types.""" 420 | test_cases = [ 421 | ("/static/main.js", "text/javascript", True), 422 | ("/static/main.css", "text/css", True), 423 | ("/", "text/html", True), # HTML from template 424 | ] 425 | 426 | for url, expected_mimetype, should_process in test_cases: 427 | r = client.get(url, headers={"Accept-Encoding": "gzip"}) 428 | assert expected_mimetype in (r.mimetype or "") 429 | if should_process: 430 | assert "Content-Encoding" in r.headers or "X-Flask-Squeeze-Minify" in r.headers 431 | 432 | 433 | def test_encoding_priority_selection(client: FlaskClient) -> None: 434 | """Test that encodings are selected in correct priority order.""" 435 | # Test brotli preferred over gzip 436 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip, br, deflate"}) 437 | assert r.headers.get("Content-Encoding") == "br" 438 | 439 | # Test deflate preferred over none when br/gzip unavailable 440 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "deflate"}) 441 | assert r.headers.get("Content-Encoding") == "deflate" 442 | 443 | # Test gzip when only gzip available 444 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 445 | assert r.headers.get("Content-Encoding") == "gzip" 446 | 447 | 448 | def test_quality_levels_configuration(client: FlaskClient) -> None: 449 | """Test different compression quality levels.""" 450 | configs = [ 451 | {"SQUEEZE_LEVEL_GZIP_STATIC": 1, "SQUEEZE_LEVEL_BROTLI_STATIC": 1}, 452 | {"SQUEEZE_LEVEL_GZIP_STATIC": 9, "SQUEEZE_LEVEL_BROTLI_STATIC": 11}, 453 | ] 454 | 455 | for config in configs: 456 | client.application.config.update(config) 457 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 458 | assert content_length_correct(r) 459 | assert "Content-Encoding" in r.headers 460 | 461 | 462 | def test_cache_file_corruption_recovery(client: FlaskClient) -> None: 463 | """Test recovery from corrupted cache files.""" 464 | with tempfile.TemporaryDirectory() as temp_dir: 465 | cache_dir = Path(temp_dir) / "cache" 466 | client.application.config.update({"SQUEEZE_CACHE_DIR": str(cache_dir)}) 467 | 468 | from flask_squeeze import Squeeze 469 | 470 | squeeze = Squeeze() 471 | squeeze.init_app(client.application) 472 | 473 | # Create initial cache entry 474 | r1 = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 475 | assert r1.headers.get("X-Flask-Squeeze-Cache") == "MISS" 476 | 477 | # Corrupt cache files 478 | for cache_file in cache_dir.glob("*.cache"): 479 | with cache_file.open("wb") as f: 480 | f.write(b"corrupted data") 481 | 482 | # Should recover gracefully 483 | r2 = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 484 | assert content_length_correct(r2) 485 | 486 | 487 | def test_very_large_files(client: FlaskClient) -> None: 488 | """Test handling of very large files.""" 489 | # Create a large CSS file 490 | large_content = "body { color: #000; } " * 10000 # ~200KB 491 | 492 | static_dir = client.application.static_folder 493 | if static_dir is None: 494 | pytest.skip("Static directory not configured") 495 | 496 | large_file_path = Path(static_dir) / "large_test.css" 497 | try: 498 | with large_file_path.open("w") as f: 499 | f.write(large_content) 500 | 501 | # Test compression of large file 502 | r = client.get("/static/large_test.css", headers={"Accept-Encoding": "gzip"}) 503 | assert content_length_correct(r) 504 | assert "Content-Encoding" in r.headers 505 | 506 | # Verify significant compression ratio 507 | original_size = len(large_content.encode()) 508 | compressed_size = len(r.data) 509 | compression_ratio = original_size / compressed_size 510 | minimum_compression_ratio = 2.0 # Expect at least 2:1 compression ratio 511 | assert compression_ratio > minimum_compression_ratio 512 | 513 | finally: 514 | large_file_path.unlink(missing_ok=True) 515 | 516 | 517 | def test_binary_file_handling(client: FlaskClient) -> None: 518 | """Test handling of binary files that shouldn't be processed.""" 519 | # Create a small binary file 520 | static_dir = client.application.static_folder 521 | if static_dir is None: 522 | pytest.skip("Static directory not configured") 523 | 524 | binary_file_path = Path(static_dir) / "test.bin" 525 | try: 526 | with binary_file_path.open("wb") as f: 527 | f.write(b"\x00\x01\x02\x03" * 100) 528 | 529 | r = client.get("/static/test.bin", headers={"Accept-Encoding": "gzip"}) 530 | assert "Content-Encoding" in r.headers 531 | assert "X-Flask-Squeeze-Minify" not in r.headers 532 | 533 | finally: 534 | binary_file_path.unlink(missing_ok=True) 535 | 536 | 537 | def test_empty_file_handling(client: FlaskClient) -> None: 538 | """Test handling of empty files.""" 539 | r = client.get("/static/empty.js", headers={"Accept-Encoding": "gzip"}) 540 | assert r.status_code == STATUS_CODE_OK_200 541 | 542 | 543 | def test_malformed_content_handling(client: FlaskClient) -> None: 544 | """Test handling of malformed CSS/JS content.""" 545 | static_dir = client.application.static_folder 546 | if static_dir is None: 547 | pytest.skip("Static directory not configured") 548 | 549 | # Test malformed CSS 550 | malformed_css_path = Path(static_dir) / "malformed.css" 551 | try: 552 | with malformed_css_path.open("w") as f: 553 | f.write("body { color: #000; /* unclosed comment") 554 | 555 | client.application.config.update({"SQUEEZE_MINIFY_CSS": True}) 556 | r = client.get("/static/malformed.css", headers={"Accept-Encoding": "gzip"}) 557 | # Should handle gracefully, might not minify but shouldn't crash 558 | assert r.status_code == STATUS_CODE_OK_200 559 | assert content_length_correct(r) 560 | 561 | finally: 562 | malformed_css_path.unlink(missing_ok=True) 563 | 564 | 565 | def test_security_headers_comprehensive(client: FlaskClient) -> None: 566 | """Test comprehensive security header behavior.""" 567 | # Test BREACH protection header 568 | r = client.get("/", headers={"Accept-Encoding": "gzip"}) 569 | breach_header = r.headers.get("X-Flask-Squeeze-Breach-Protection") 570 | assert breach_header is not None 571 | assert len(breach_header) > 0 572 | 573 | # Test that BREACH protection varies between requests 574 | r2 = client.get("/", headers={"Accept-Encoding": "gzip"}) 575 | breach_header2 = r2.headers.get("X-Flask-Squeeze-Breach-Protection") 576 | assert breach_header != breach_header2 # Should be different 577 | 578 | # Test Vary header 579 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 580 | vary_header = r.headers.get("Vary", "") 581 | assert "Accept-Encoding" in vary_header 582 | 583 | 584 | def test_content_length_edge_cases(client: FlaskClient) -> None: 585 | """Test edge cases around content length handling.""" 586 | # Test exactly at min size threshold 587 | min_size_threshold = 100 588 | client.application.config.update({"SQUEEZE_MIN_SIZE": min_size_threshold}) 589 | 590 | static_dir = client.application.static_folder 591 | if static_dir is None: 592 | pytest.skip("Static directory not configured") 593 | 594 | # Create file exactly one above the threshold 595 | 596 | threshold_file_path = Path(static_dir) / "threshold.js" 597 | try: 598 | with threshold_file_path.open("w") as f: 599 | f.write("x" * (min_size_threshold + 1)) # Create a file of size min_size_threshold + 1 600 | 601 | r = client.get("/static/threshold.js", headers={"Accept-Encoding": "gzip"}) 602 | 603 | assert "Content-Encoding" in r.headers 604 | 605 | finally: 606 | threshold_file_path.unlink(missing_ok=True) 607 | 608 | # Create file exactly one below the threshold 609 | 610 | below_threshold_file_path = Path(static_dir) / "below_threshold.js" 611 | try: 612 | with below_threshold_file_path.open("w") as f: 613 | f.write("x" * (min_size_threshold - 1)) # Create a file of size min_size_threshold 614 | 615 | r = client.get("/static/below_threshold.js", headers={"Accept-Encoding": "gzip"}) 616 | 617 | assert "Content-Encoding" not in r.headers 618 | finally: 619 | below_threshold_file_path.unlink(missing_ok=True) 620 | 621 | 622 | def test_configuration_validation(client: FlaskClient) -> None: 623 | """Test various configuration combinations.""" 624 | configs_to_test: list[dict[str, bool | int]] = [ 625 | # All disabled 626 | { 627 | "SQUEEZE_COMPRESS": False, 628 | "SQUEEZE_MINIFY_JS": False, 629 | "SQUEEZE_MINIFY_CSS": False, 630 | "SQUEEZE_MINIFY_HTML": False, 631 | }, 632 | # Only compression 633 | { 634 | "SQUEEZE_COMPRESS": True, 635 | "SQUEEZE_MINIFY_JS": False, 636 | "SQUEEZE_MINIFY_CSS": False, 637 | "SQUEEZE_MINIFY_HTML": False, 638 | }, 639 | # Only minification 640 | { 641 | "SQUEEZE_COMPRESS": False, 642 | "SQUEEZE_MINIFY_JS": True, 643 | "SQUEEZE_MINIFY_CSS": True, 644 | "SQUEEZE_MINIFY_HTML": True, 645 | }, 646 | # Extreme quality settings 647 | { 648 | "SQUEEZE_LEVEL_GZIP_STATIC": 9, 649 | "SQUEEZE_LEVEL_BROTLI_STATIC": 11, 650 | "SQUEEZE_LEVEL_DEFLATE_STATIC": 9, 651 | }, 652 | ] 653 | 654 | for config in configs_to_test: 655 | client.application.config.update(config) 656 | 657 | # Test should not crash with any config 658 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 659 | assert r.status_code == STATUS_CODE_OK_200 660 | assert content_length_correct(r) 661 | 662 | 663 | def test_cache_key_normalization(client: FlaskClient) -> None: 664 | """Test that cache keys are properly normalized.""" 665 | # Test paths with special characters 666 | paths_to_test = [ 667 | "/static/file-with-dashes.js", 668 | "/static/file_with_underscores.js", 669 | "/static/file.with.dots.js", 670 | "/static/deeply/nested/file.js", 671 | ] 672 | 673 | static_dir = client.application.static_folder 674 | if static_dir is None: 675 | pytest.skip("Static directory not configured") 676 | 677 | created_files: list[Path] = [] 678 | try: 679 | for path in paths_to_test: 680 | file_path = Path(static_dir) / Path(path).name 681 | with file_path.open("w") as f: 682 | f.write("var test = 1;") 683 | created_files.append(file_path) 684 | 685 | # Test that these can be cached without issues 686 | r = client.get(path, headers={"Accept-Encoding": "gzip"}) 687 | if r.status_code == STATUS_CODE_OK_200: # File exists 688 | assert content_length_correct(r) 689 | 690 | finally: 691 | for file_path in created_files: 692 | file_path.unlink(missing_ok=True) 693 | 694 | 695 | def test_memory_usage_stability(client: FlaskClient) -> None: 696 | """Test that memory usage remains stable with many requests.""" 697 | import gc 698 | 699 | # Get initial memory baseline 700 | gc.collect() 701 | initial_objects = len(gc.get_objects()) 702 | 703 | # Make many requests 704 | for _ in range(100): 705 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 706 | assert r.status_code == STATUS_CODE_OK_200 707 | 708 | # Check memory didn't grow significantly 709 | gc.collect() 710 | final_objects = len(gc.get_objects()) 711 | growth = final_objects - initial_objects 712 | 713 | # Allow some growth but not excessive (arbitrary threshold) 714 | max_objects_growth = 1100 715 | assert growth < max_objects_growth, f"Excessive memory growth: {growth} objects" 716 | 717 | 718 | def test_error_recovery_after_failures(client: FlaskClient) -> None: 719 | """Test that the system recovers properly after various failures.""" 720 | # Test recovery after cache directory becomes unavailable 721 | with tempfile.TemporaryDirectory() as temp_dir: 722 | cache_dir = Path(temp_dir) / "cache" 723 | client.application.config.update({"SQUEEZE_CACHE_DIR": str(cache_dir)}) 724 | 725 | from flask_squeeze import Squeeze 726 | 727 | squeeze = Squeeze() 728 | squeeze.init_app(client.application) 729 | 730 | # First request should work 731 | r1 = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 732 | assert r1.status_code == STATUS_CODE_OK_200 733 | 734 | # Simulate cache directory becoming unavailable 735 | try: 736 | cache_dir.chmod(0o000) # Remove all permissions 737 | 738 | # Should still work, just without caching 739 | r2 = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 740 | assert r2.status_code == STATUS_CODE_OK_200 741 | assert content_length_correct(r2) 742 | 743 | finally: 744 | # Restore permissions for cleanup 745 | with contextlib.suppress(Exception): 746 | cache_dir.chmod(0o755) 747 | 748 | 749 | def test_header_preservation(client: FlaskClient) -> None: 750 | """Test that important headers are preserved during processing.""" 751 | r = client.get("/static/jquery.js", headers={"Accept-Encoding": "gzip"}) 752 | 753 | # Content-Length should be accurate 754 | assert content_length_correct(r) 755 | 756 | # ETag should be preserved if present 757 | if "ETag" in r.headers: 758 | assert r.headers["ETag"] 759 | 760 | # Last-Modified should be preserved if present 761 | if "Last-Modified" in r.headers: 762 | assert r.headers["Last-Modified"] 763 | -------------------------------------------------------------------------------- /tests/test_app/static/main.js: -------------------------------------------------------------------------------- 1 | let content = `Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 2 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 3 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 4 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 5 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 6 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 7 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 8 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 9 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 10 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 11 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 12 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 13 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 14 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 15 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 16 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 17 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 18 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 19 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 20 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 21 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 22 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 23 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 24 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 25 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 26 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 27 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 28 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 29 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 30 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 31 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 32 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 33 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 34 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 35 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 36 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 37 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 38 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 39 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 40 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 41 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 42 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 43 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 44 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 45 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 46 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 47 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 48 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 49 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 50 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 51 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 52 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 53 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 54 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 55 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 56 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 57 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 58 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 59 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 60 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 61 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 62 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 63 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 64 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 65 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 66 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 67 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 68 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 69 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 70 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 71 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 72 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 73 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 74 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 75 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 76 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 77 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 78 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 79 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 80 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 81 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 82 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 83 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 84 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 85 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 86 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 87 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 88 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 89 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 90 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 91 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 92 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 93 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 94 | Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 95 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 96 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. 97 | At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat. 98 | Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus. 99 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. 100 | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. ` 101 | 102 | console.log(`main.js has str on length: ${content.length}`) -------------------------------------------------------------------------------- /tests/test_app/static/jquery.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v3.6.4 | (c) OpenJS Foundation and other contributors | jquery.org/license */ 2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.4",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0