| import os | |
| import pytest | |
| from .env import H2Conf, H2TestEnv | |
| # The push tests depend on "nghttp" | |
| @pytest.mark.skipif(condition=H2TestEnv.is_unsupported(), reason="mod_http2 not supported here") | |
| @H2TestEnv.needs_nghttp() | |
| class TestPush: | |
| @pytest.fixture(autouse=True, scope='class') | |
| def _class_scope(self, env): | |
| H2Conf(env).start_vhost(domains=[f"push.{env.http_tld}"], | |
| port=env.https_port, doc_root="htdocs/test1" | |
| ).add(r""" | |
| RewriteEngine on | |
| RewriteRule ^/006-push(.*)?\.html$ /006.html | |
| <Location /006-push.html> | |
| Header add Link "</006/006.css>;rel=preload" | |
| Header add Link "</006/006.js>;rel=preloadX" | |
| </Location> | |
| <Location /006-push2.html> | |
| Header add Link "</006/006.css>;rel=preloadX, </006/006.js>; rel=preload" | |
| </Location> | |
| <Location /006-push3.html> | |
| Header add Link "</006/006.css>;rel=preloa,</006/006.js>;rel=preload" | |
| </Location> | |
| <Location /006-push4.html> | |
| Header add Link "</006/006.css;rel=preload, </006/006.js>; preload" | |
| </Location> | |
| <Location /006-push5.html> | |
| Header add Link '</006/006.css>;rel="preload push"' | |
| </Location> | |
| <Location /006-push6.html> | |
| Header add Link '</006/006.css>;rel="push preload"' | |
| </Location> | |
| <Location /006-push7.html> | |
| Header add Link '</006/006.css>;rel="abc preload push"' | |
| </Location> | |
| <Location /006-push8.html> | |
| Header add Link '</006/006.css>;rel="preload"; nopush' | |
| </Location> | |
| <Location /006-push20.html> | |
| H2PushResource "/006/006.css" critical | |
| H2PushResource "/006/006.js" | |
| </Location> | |
| <Location /006-push30.html> | |
| H2Push off | |
| Header add Link '</006/006.css>;rel="preload"' | |
| </Location> | |
| <Location /006-push31.html> | |
| H2PushResource "/006/006.css" critical | |
| </Location> | |
| <Location /006-push32.html> | |
| Header add Link "</006/006.css>;rel=preload" | |
| </Location> | |
| """).end_vhost( | |
| ).install() | |
| assert env.apache_restart() == 0 | |
| ############################ | |
| # Link: header handling, various combinations | |
| # plain resource without configured pushes | |
| def test_h2_400_00(self, env): | |
| url = env.mkurl("https", "push", "/006.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 0 == len(promises) | |
| # 2 link headers configured, only 1 triggers push | |
| def test_h2_400_01(self, env): | |
| url = env.mkurl("https", "push", "/006-push.html") | |
| r = env.nghttp().get(url, options=["-Haccept-encoding: none"]) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) | |
| assert '/006/006.css' == promises[0]["request"]["header"][":path"] | |
| assert 216 == len(promises[0]["response"]["body"]) | |
| # Same as 400_01, but with single header line configured | |
| def test_h2_400_02(self, env): | |
| url = env.mkurl("https", "push", "/006-push2.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) | |
| assert '/006/006.js' == promises[0]["request"]["header"][":path"] | |
| # 2 Links, only one with correct rel attribute | |
| def test_h2_400_03(self, env): | |
| url = env.mkurl("https", "push", "/006-push3.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) | |
| assert '/006/006.js' == promises[0]["request"]["header"][":path"] | |
| # Missing > in Link header, PUSH not triggered | |
| def test_h2_400_04(self, env): | |
| url = env.mkurl("https", "push", "/006-push4.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 0 == len(promises) | |
| # More than one value in "rel" parameter | |
| def test_h2_400_05(self, env): | |
| url = env.mkurl("https", "push", "/006-push5.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) | |
| assert '/006/006.css' == promises[0]["request"]["header"][":path"] | |
| # Another "rel" parameter variation | |
| def test_h2_400_06(self, env): | |
| url = env.mkurl("https", "push", "/006-push6.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) | |
| assert '/006/006.css' == promises[0]["request"]["header"][":path"] | |
| # Another "rel" parameter variation | |
| def test_h2_400_07(self, env): | |
| url = env.mkurl("https", "push", "/006-push7.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) | |
| assert '/006/006.css' == promises[0]["request"]["header"][":path"] | |
| # Pushable link header with "nopush" attribute | |
| def test_h2_400_08(self, env): | |
| url = env.mkurl("https", "push", "/006-push8.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 0 == len(promises) | |
| # 2 H2PushResource config trigger on GET, but not on POST | |
| def test_h2_400_20(self, env): | |
| url = env.mkurl("https", "push", "/006-push20.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 2 == len(promises) | |
| fpath = os.path.join(env.gen_dir, "data-400-20") | |
| with open(fpath, 'w') as f: | |
| f.write("test upload data") | |
| r = env.nghttp().upload(url, fpath) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 0 == len(promises) | |
| # H2Push configured Off in location | |
| def test_h2_400_30(self, env): | |
| url = env.mkurl("https", "push", "/006-push30.html") | |
| r = env.nghttp().get(url) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 0 == len(promises) | |
| # - suppress PUSH | |
| def test_h2_400_50(self, env): | |
| url = env.mkurl("https", "push", "/006-push.html") | |
| r = env.nghttp().get(url, options=['-H', 'accept-push-policy: none']) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 0 == len(promises) | |
| # - default pushes desired | |
| def test_h2_400_51(self, env): | |
| url = env.mkurl("https", "push", "/006-push.html") | |
| r = env.nghttp().get(url, options=['-H', 'accept-push-policy: default']) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) | |
| # - HEAD pushes desired | |
| def test_h2_400_52(self, env): | |
| url = env.mkurl("https", "push", "/006-push.html") | |
| r = env.nghttp().get(url, options=['-H', 'accept-push-policy: head']) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) | |
| assert '/006/006.css' == promises[0]["request"]["header"][":path"] | |
| assert b"" == promises[0]["response"]["body"] | |
| assert 0 == len(promises[0]["response"]["body"]) | |
| # - fast-load pushes desired | |
| def test_h2_400_53(self, env): | |
| url = env.mkurl("https", "push", "/006-push.html") | |
| r = env.nghttp().get(url, options=['-H', 'accept-push-policy: fast-load']) | |
| assert r.response["status"] == 200 | |
| promises = r.results["streams"][r.response["id"]]["promises"] | |
| assert 1 == len(promises) |