pytest: add a test case for PUSH related things.

- checking that "103 Early Hints" are visible in curl's header dump file

Closes #10452
This commit is contained in:
Stefan Eissing 2023-02-09 13:08:26 +01:00 committed by Daniel Stenberg
parent 01772a3c39
commit ca95d391ea
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
2 changed files with 91 additions and 7 deletions

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#***************************************************************************
# _ _ ____ _
# Project ___| | | | _ \| |
# / __| | | | |_) | |
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 2008 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
import logging
import os
import pytest
from testenv import Env, CurlClient
log = logging.getLogger(__name__)
@pytest.mark.skipif(condition=Env.setup_incomplete(),
reason=f"missing: {Env.incomplete_reason()}")
class TestPush:
@pytest.fixture(autouse=True, scope='class')
def _class_scope(self, env, httpd):
push_dir = os.path.join(httpd.docs_dir, 'push')
if not os.path.exists(push_dir):
os.makedirs(push_dir)
env.make_data_file(indir=push_dir, fname="data1", fsize=100*1024)
env.make_data_file(indir=push_dir, fname="data2", fsize=100*1024)
env.make_data_file(indir=push_dir, fname="data3", fsize=100*1024)
httpd.set_extra_config(env.domain1, [
f'H2EarlyHints on',
f'<Location /push/data1>',
f' H2PushResource /push/data2',
f'</Location>',
f'<Location /push/data2>',
f' H2PushResource /push/data1',
f' H2PushResource /push/data3',
f'</Location>',
])
# activate the new config
httpd.reload()
# download a file that triggers a "103 Early Hints" response
def test_09_01_early_hints(self, env: Env, httpd, repeat):
curl = CurlClient(env=env)
url = f'https://{env.domain1}:{env.https_port}/push/data1'
r = curl.http_download(urls=[url], alpn_proto='h2', with_stats=False,
with_headers=True)
assert r.exit_code == 0, f'{r}'
assert len(r.responses) == 2, f'{r.responses}'
assert r.responses[0]['status'] == 103, f'{r.responses}'
assert 'link' in r.responses[0]['header'], f'{r.responses[0]}'
assert r.responses[0]['header']['link'] == '</push/data2>; rel=preload', f'{r.responses[0]}'

View File

@ -31,7 +31,7 @@ import subprocess
from datetime import timedelta, datetime
from json import JSONEncoder
import time
from typing import List
from typing import List, Union, Optional
from .curl import CurlClient, ExecResult
from .env import Env
@ -69,6 +69,7 @@ class Httpd:
self._error_log = os.path.join(self._logs_dir, 'error_log')
self._tmp_dir = os.path.join(self._apache_dir, 'tmp')
self._mods_dir = None
self._extra_configs = {}
assert env.apxs
p = subprocess.run(args=[env.apxs, '-q', 'libexecdir'],
capture_output=True, text=True)
@ -93,6 +94,12 @@ class Httpd:
def exists(self):
return os.path.exists(self._cmd)
def set_extra_config(self, domain: str, lines: Optional[Union[str, List[str]]]):
if lines is None:
self._extra_configs.pop(domain, None)
else:
self._extra_configs[domain] = lines
def _run(self, args, intext=''):
env = {}
for key, val in os.environ.items():
@ -143,6 +150,7 @@ class Httpd:
return self.start()
def reload(self):
self._write_config()
r = self._apachectl("graceful")
if r.exit_code != 0:
log.error(f'failed to reload httpd: {r}')
@ -236,6 +244,8 @@ class Httpd:
f' DocumentRoot "{self._docs_dir}"',
])
conf.extend(self._curltest_conf())
if domain1 in self._extra_configs:
conf.extend(self._extra_configs[domain1])
conf.extend([
f'</VirtualHost>',
f'',
@ -250,6 +260,8 @@ class Httpd:
f' DocumentRoot "{self._docs_dir}/two"',
])
conf.extend(self._curltest_conf())
if domain2 in self._extra_configs:
conf.extend(self._extra_configs[domain2])
conf.extend([
f'</VirtualHost>',
f'',
@ -263,12 +275,12 @@ class Httpd:
]))
def _get_log_level(self):
#if self.env.verbose > 3:
# return 'trace2'
#if self.env.verbose > 2:
# return 'trace1'
#if self.env.verbose > 1:
# return 'debug'
if self.env.verbose > 3:
return 'trace2'
if self.env.verbose > 2:
return 'trace1'
if self.env.verbose > 1:
return 'debug'
return 'info'
def _curltest_conf(self) -> List[str]: