"""The checks that read a page's stylesheet and images from a live server.""" from pathlib import Path import zlib import pytest from mews.fetch import Fetcher from mews.lint import validate_bytes CANONICAL = (Path(__file__).resolve().parent.parent / "mews-0.1.css").read_bytes() FONT_FACE = b"""@font-face { font-family: "Atkinson Hyperlegible"; src: url(/fonts/atkinson.woff2) format("woff2"); } """ PNG = ( b"\x89PNG\r\n\x1a\n" b"\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00" b"\x1f\x15\xc4\x89" b"\x00\x00\x00\x00IEND\xaeB`\x82" ) @pytest.fixture def check(site): """Validate a page served by the local server, reading its sub-resources.""" def run(page: bytes, path: str = "/index.html"): url = site.add(path, page, headers={"ETag": '"v1"'}) with Fetcher(allow_loopback=True) as fetcher: return validate_bytes(page, url=url, fetcher=fetcher) return run def codes(report): return [finding.code for finding in report.findings] def test_an_unmodified_stylesheet_copy_passes(site, check, conforming): site.add("/mews-0.1.css", CANONICAL) report = check(conforming()) assert "stylesheet-modified" not in codes(report) def test_an_added_font_face_passes(site, check, conforming): site.add("/mews-0.1.css", FONT_FACE + CANONICAL) site.add("/fonts/atkinson.woff2", b"font") report = check(conforming()) assert "stylesheet-modified" not in codes(report) assert "font-offsite" not in codes(report) def test_a_changed_stylesheet_fails(site, check, conforming): site.add("/mews-0.1.css", CANONICAL.replace(b"#faf8f3", b"#ffffff")) report = check(conforming()) failure = [f for f in report.findings if f.code == "stylesheet-modified"] assert failure and failure[0].section == "5.2" assert not report.conforms def test_a_font_from_another_site_fails(site, check, conforming): off = FONT_FACE.replace(b"/fonts/atkinson.woff2", b"https://fonts.example.net/a") site.add("/mews-0.1.css", off + CANONICAL) report = check(conforming()) assert "font-offsite" in codes(report) assert not report.conforms def test_an_import_in_the_stylesheet_fails(site, check, conforming): site.add("/mews-0.1.css", b'@import url("x.css");\n' + CANONICAL) report = check(conforming()) assert "stylesheet-import" in codes(report) def test_a_missing_stylesheet_only_warns(site, check, conforming): report = check(conforming()) warning = [f for f in report.findings if f.code == "stylesheet-unreachable"] assert warning and warning[0].level == "should" def test_a_stylesheet_on_another_site_fails(site, check, conforming): site.add("/mews-0.1.css", CANONICAL) report = check(conforming(stylesheet="https://cdn.example.net/mews-0.1.css")) assert "stylesheet-offsite" in codes(report) assert not report.conforms def test_the_central_stylesheet_only_warns(site, check, conforming): """Linking mews.page's own copy is discouraged, not a failure.""" report = check(conforming(stylesheet="https://mews.page/mews-0.1.css")) assert "stylesheet-offsite" not in codes(report) canonical = [f for f in report.findings if f.code == "stylesheet-canonical"] assert canonical and canonical[0].level == "should" def test_a_cookie_on_the_stylesheet_fails(site, check, conforming): site.add("/mews-0.1.css", CANONICAL, headers={"Set-Cookie": "a=1"}) report = check(conforming()) assert "cookie" in codes(report) assert not report.conforms # --- images ------------------------------------------------------------ def test_a_small_png_passes(site, check, conforming): site.add("/mews-0.1.css", CANONICAL) site.add("/a.png", PNG, headers={"Content-Type": "image/png"}) report = check(conforming(body='

A dot

')) assert report.conforms assert not report.warnings def test_an_image_that_is_not_an_image_warns(site, check, conforming): site.add("/mews-0.1.css", CANONICAL) site.add("/a.png", b"") report = check(conforming(body='

x

')) warning = [f for f in report.findings if f.code == "image-format"] assert warning and warning[0].level == "should" assert report.conforms def test_a_large_image_warns(site, check, conforming): site.add("/mews-0.1.css", CANONICAL) site.add("/a.png", PNG + b"\x00" * 60_000) report = check(conforming(body='

x

')) assert "image-size" in codes(report) def test_camera_metadata_warns(site, check, conforming): site.add("/mews-0.1.css", CANONICAL) site.add("/a.jpg", b"\xff\xd8\xff\xe1\x00\x16Exif\x00\x00" + b"\x00" * 100) report = check(conforming(body='

x

')) assert "image-metadata" in codes(report) def test_a_missing_image_warns(site, check, conforming): site.add("/mews-0.1.css", CANONICAL) report = check(conforming(body='

x

')) assert "image-unreachable" in codes(report) def test_only_the_first_twenty_images_are_read(site, check, conforming): site.add("/mews-0.1.css", CANONICAL) site.add("/a.png", PNG) body = "".join(f'

x

' for i in range(25)) report = check(conforming(body=body)) assert "images-not-checked" in codes(report) assert len([r for r in site.requests if r[0].startswith("/a.png")]) == 20 def test_a_compression_bomb_is_refused(site, conforming): """A short download that expands enormously is not a page.""" body = zlib.compress(b"x" * 10_000_000) url = site.add( "/big.html", body, headers={"Content-Encoding": "deflate", "Content-Type": "text/html"}, declare_length=False, ) with Fetcher(allow_loopback=True) as fetcher: response = fetcher.get(url) assert response.truncated