1*6236dae4SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6236dae4SAndroid Build Coastguard Worker# -*- coding: utf-8 -*- 3*6236dae4SAndroid Build Coastguard Worker#*************************************************************************** 4*6236dae4SAndroid Build Coastguard Worker# _ _ ____ _ 5*6236dae4SAndroid Build Coastguard Worker# Project ___| | | | _ \| | 6*6236dae4SAndroid Build Coastguard Worker# / __| | | | |_) | | 7*6236dae4SAndroid Build Coastguard Worker# | (__| |_| | _ <| |___ 8*6236dae4SAndroid Build Coastguard Worker# \___|\___/|_| \_\_____| 9*6236dae4SAndroid Build Coastguard Worker# 10*6236dae4SAndroid Build Coastguard Worker# Copyright (C) Daniel Stenberg, <[email protected]>, et al. 11*6236dae4SAndroid Build Coastguard Worker# 12*6236dae4SAndroid Build Coastguard Worker# This software is licensed as described in the file COPYING, which 13*6236dae4SAndroid Build Coastguard Worker# you should have received as part of this distribution. The terms 14*6236dae4SAndroid Build Coastguard Worker# are also available at https://curl.se/docs/copyright.html. 15*6236dae4SAndroid Build Coastguard Worker# 16*6236dae4SAndroid Build Coastguard Worker# You may opt to use, copy, modify, merge, publish, distribute and/or sell 17*6236dae4SAndroid Build Coastguard Worker# copies of the Software, and permit persons to whom the Software is 18*6236dae4SAndroid Build Coastguard Worker# furnished to do so, under the terms of the COPYING file. 19*6236dae4SAndroid Build Coastguard Worker# 20*6236dae4SAndroid Build Coastguard Worker# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21*6236dae4SAndroid Build Coastguard Worker# KIND, either express or implied. 22*6236dae4SAndroid Build Coastguard Worker# 23*6236dae4SAndroid Build Coastguard Worker# SPDX-License-Identifier: curl 24*6236dae4SAndroid Build Coastguard Worker# 25*6236dae4SAndroid Build Coastguard Worker########################################################################### 26*6236dae4SAndroid Build Coastguard Worker# 27*6236dae4SAndroid Build Coastguard Workerimport inspect 28*6236dae4SAndroid Build Coastguard Workerimport logging 29*6236dae4SAndroid Build Coastguard Workerimport os 30*6236dae4SAndroid Build Coastguard Workerimport subprocess 31*6236dae4SAndroid Build Coastguard Workerfrom datetime import timedelta, datetime 32*6236dae4SAndroid Build Coastguard Workerfrom json import JSONEncoder 33*6236dae4SAndroid Build Coastguard Workerimport time 34*6236dae4SAndroid Build Coastguard Workerfrom typing import List, Union, Optional 35*6236dae4SAndroid Build Coastguard Workerimport copy 36*6236dae4SAndroid Build Coastguard Worker 37*6236dae4SAndroid Build Coastguard Workerfrom .curl import CurlClient, ExecResult 38*6236dae4SAndroid Build Coastguard Workerfrom .env import Env 39*6236dae4SAndroid Build Coastguard Worker 40*6236dae4SAndroid Build Coastguard Worker 41*6236dae4SAndroid Build Coastguard Workerlog = logging.getLogger(__name__) 42*6236dae4SAndroid Build Coastguard Worker 43*6236dae4SAndroid Build Coastguard Worker 44*6236dae4SAndroid Build Coastguard Workerclass Httpd: 45*6236dae4SAndroid Build Coastguard Worker 46*6236dae4SAndroid Build Coastguard Worker MODULES = [ 47*6236dae4SAndroid Build Coastguard Worker 'log_config', 'logio', 'unixd', 'version', 'watchdog', 48*6236dae4SAndroid Build Coastguard Worker 'authn_core', 'authn_file', 49*6236dae4SAndroid Build Coastguard Worker 'authz_user', 'authz_core', 'authz_host', 50*6236dae4SAndroid Build Coastguard Worker 'auth_basic', 'auth_digest', 51*6236dae4SAndroid Build Coastguard Worker 'alias', 'env', 'filter', 'headers', 'mime', 'setenvif', 52*6236dae4SAndroid Build Coastguard Worker 'socache_shmcb', 53*6236dae4SAndroid Build Coastguard Worker 'rewrite', 'http2', 'ssl', 'proxy', 'proxy_http', 'proxy_connect', 54*6236dae4SAndroid Build Coastguard Worker 'brotli', 55*6236dae4SAndroid Build Coastguard Worker 'mpm_event', 56*6236dae4SAndroid Build Coastguard Worker ] 57*6236dae4SAndroid Build Coastguard Worker COMMON_MODULES_DIRS = [ 58*6236dae4SAndroid Build Coastguard Worker '/usr/lib/apache2/modules', # debian 59*6236dae4SAndroid Build Coastguard Worker '/usr/libexec/apache2/', # macos 60*6236dae4SAndroid Build Coastguard Worker ] 61*6236dae4SAndroid Build Coastguard Worker 62*6236dae4SAndroid Build Coastguard Worker MOD_CURLTEST = None 63*6236dae4SAndroid Build Coastguard Worker 64*6236dae4SAndroid Build Coastguard Worker def __init__(self, env: Env, proxy_auth: bool = False): 65*6236dae4SAndroid Build Coastguard Worker self.env = env 66*6236dae4SAndroid Build Coastguard Worker self._cmd = env.apachectl 67*6236dae4SAndroid Build Coastguard Worker self._apache_dir = os.path.join(env.gen_dir, 'apache') 68*6236dae4SAndroid Build Coastguard Worker self._run_dir = os.path.join(self._apache_dir, 'run') 69*6236dae4SAndroid Build Coastguard Worker self._lock_dir = os.path.join(self._apache_dir, 'locks') 70*6236dae4SAndroid Build Coastguard Worker self._docs_dir = os.path.join(self._apache_dir, 'docs') 71*6236dae4SAndroid Build Coastguard Worker self._conf_dir = os.path.join(self._apache_dir, 'conf') 72*6236dae4SAndroid Build Coastguard Worker self._conf_file = os.path.join(self._conf_dir, 'test.conf') 73*6236dae4SAndroid Build Coastguard Worker self._logs_dir = os.path.join(self._apache_dir, 'logs') 74*6236dae4SAndroid Build Coastguard Worker self._error_log = os.path.join(self._logs_dir, 'error_log') 75*6236dae4SAndroid Build Coastguard Worker self._tmp_dir = os.path.join(self._apache_dir, 'tmp') 76*6236dae4SAndroid Build Coastguard Worker self._basic_passwords = os.path.join(self._conf_dir, 'basic.passwords') 77*6236dae4SAndroid Build Coastguard Worker self._digest_passwords = os.path.join(self._conf_dir, 'digest.passwords') 78*6236dae4SAndroid Build Coastguard Worker self._mods_dir = None 79*6236dae4SAndroid Build Coastguard Worker self._auth_digest = True 80*6236dae4SAndroid Build Coastguard Worker self._proxy_auth_basic = proxy_auth 81*6236dae4SAndroid Build Coastguard Worker self._extra_configs = {} 82*6236dae4SAndroid Build Coastguard Worker self._loaded_extra_configs = None 83*6236dae4SAndroid Build Coastguard Worker assert env.apxs 84*6236dae4SAndroid Build Coastguard Worker p = subprocess.run(args=[env.apxs, '-q', 'libexecdir'], 85*6236dae4SAndroid Build Coastguard Worker capture_output=True, text=True) 86*6236dae4SAndroid Build Coastguard Worker if p.returncode != 0: 87*6236dae4SAndroid Build Coastguard Worker raise Exception(f'{env.apxs} failed to query libexecdir: {p}') 88*6236dae4SAndroid Build Coastguard Worker self._mods_dir = p.stdout.strip() 89*6236dae4SAndroid Build Coastguard Worker if self._mods_dir is None: 90*6236dae4SAndroid Build Coastguard Worker raise Exception('apache modules dir cannot be found') 91*6236dae4SAndroid Build Coastguard Worker if not os.path.exists(self._mods_dir): 92*6236dae4SAndroid Build Coastguard Worker raise Exception(f'apache modules dir does not exist: {self._mods_dir}') 93*6236dae4SAndroid Build Coastguard Worker self._process = None 94*6236dae4SAndroid Build Coastguard Worker self._rmf(self._error_log) 95*6236dae4SAndroid Build Coastguard Worker self._init_curltest() 96*6236dae4SAndroid Build Coastguard Worker 97*6236dae4SAndroid Build Coastguard Worker @property 98*6236dae4SAndroid Build Coastguard Worker def docs_dir(self): 99*6236dae4SAndroid Build Coastguard Worker return self._docs_dir 100*6236dae4SAndroid Build Coastguard Worker 101*6236dae4SAndroid Build Coastguard Worker def clear_logs(self): 102*6236dae4SAndroid Build Coastguard Worker self._rmf(self._error_log) 103*6236dae4SAndroid Build Coastguard Worker 104*6236dae4SAndroid Build Coastguard Worker def exists(self): 105*6236dae4SAndroid Build Coastguard Worker return os.path.exists(self._cmd) 106*6236dae4SAndroid Build Coastguard Worker 107*6236dae4SAndroid Build Coastguard Worker def set_extra_config(self, domain: str, lines: Optional[Union[str, List[str]]]): 108*6236dae4SAndroid Build Coastguard Worker if lines is None: 109*6236dae4SAndroid Build Coastguard Worker self._extra_configs.pop(domain, None) 110*6236dae4SAndroid Build Coastguard Worker else: 111*6236dae4SAndroid Build Coastguard Worker self._extra_configs[domain] = lines 112*6236dae4SAndroid Build Coastguard Worker 113*6236dae4SAndroid Build Coastguard Worker def clear_extra_configs(self): 114*6236dae4SAndroid Build Coastguard Worker self._extra_configs = {} 115*6236dae4SAndroid Build Coastguard Worker 116*6236dae4SAndroid Build Coastguard Worker def set_proxy_auth(self, active: bool): 117*6236dae4SAndroid Build Coastguard Worker self._proxy_auth_basic = active 118*6236dae4SAndroid Build Coastguard Worker 119*6236dae4SAndroid Build Coastguard Worker def _run(self, args, intext=''): 120*6236dae4SAndroid Build Coastguard Worker env = os.environ.copy() 121*6236dae4SAndroid Build Coastguard Worker env['APACHE_RUN_DIR'] = self._run_dir 122*6236dae4SAndroid Build Coastguard Worker env['APACHE_RUN_USER'] = os.environ['USER'] 123*6236dae4SAndroid Build Coastguard Worker env['APACHE_LOCK_DIR'] = self._lock_dir 124*6236dae4SAndroid Build Coastguard Worker env['APACHE_CONFDIR'] = self._apache_dir 125*6236dae4SAndroid Build Coastguard Worker p = subprocess.run(args, stderr=subprocess.PIPE, stdout=subprocess.PIPE, 126*6236dae4SAndroid Build Coastguard Worker cwd=self.env.gen_dir, 127*6236dae4SAndroid Build Coastguard Worker input=intext.encode() if intext else None, 128*6236dae4SAndroid Build Coastguard Worker env=env) 129*6236dae4SAndroid Build Coastguard Worker start = datetime.now() 130*6236dae4SAndroid Build Coastguard Worker return ExecResult(args=args, exit_code=p.returncode, 131*6236dae4SAndroid Build Coastguard Worker stdout=p.stdout.decode().splitlines(), 132*6236dae4SAndroid Build Coastguard Worker stderr=p.stderr.decode().splitlines(), 133*6236dae4SAndroid Build Coastguard Worker duration=datetime.now() - start) 134*6236dae4SAndroid Build Coastguard Worker 135*6236dae4SAndroid Build Coastguard Worker def _apachectl(self, cmd: str): 136*6236dae4SAndroid Build Coastguard Worker args = [self.env.apachectl, 137*6236dae4SAndroid Build Coastguard Worker "-d", self._apache_dir, 138*6236dae4SAndroid Build Coastguard Worker "-f", self._conf_file, 139*6236dae4SAndroid Build Coastguard Worker "-k", cmd] 140*6236dae4SAndroid Build Coastguard Worker return self._run(args=args) 141*6236dae4SAndroid Build Coastguard Worker 142*6236dae4SAndroid Build Coastguard Worker def start(self): 143*6236dae4SAndroid Build Coastguard Worker if self._process: 144*6236dae4SAndroid Build Coastguard Worker self.stop() 145*6236dae4SAndroid Build Coastguard Worker self._write_config() 146*6236dae4SAndroid Build Coastguard Worker with open(self._error_log, 'a') as fd: 147*6236dae4SAndroid Build Coastguard Worker fd.write('start of server\n') 148*6236dae4SAndroid Build Coastguard Worker with open(os.path.join(self._apache_dir, 'xxx'), 'a') as fd: 149*6236dae4SAndroid Build Coastguard Worker fd.write('start of server\n') 150*6236dae4SAndroid Build Coastguard Worker r = self._apachectl('start') 151*6236dae4SAndroid Build Coastguard Worker if r.exit_code != 0: 152*6236dae4SAndroid Build Coastguard Worker log.error(f'failed to start httpd: {r}') 153*6236dae4SAndroid Build Coastguard Worker return False 154*6236dae4SAndroid Build Coastguard Worker self._loaded_extra_configs = copy.deepcopy(self._extra_configs) 155*6236dae4SAndroid Build Coastguard Worker return self.wait_live(timeout=timedelta(seconds=5)) 156*6236dae4SAndroid Build Coastguard Worker 157*6236dae4SAndroid Build Coastguard Worker def stop(self): 158*6236dae4SAndroid Build Coastguard Worker r = self._apachectl('stop') 159*6236dae4SAndroid Build Coastguard Worker self._loaded_extra_configs = None 160*6236dae4SAndroid Build Coastguard Worker if r.exit_code == 0: 161*6236dae4SAndroid Build Coastguard Worker return self.wait_dead(timeout=timedelta(seconds=5)) 162*6236dae4SAndroid Build Coastguard Worker log.fatal(f'stopping httpd failed: {r}') 163*6236dae4SAndroid Build Coastguard Worker return r.exit_code == 0 164*6236dae4SAndroid Build Coastguard Worker 165*6236dae4SAndroid Build Coastguard Worker def restart(self): 166*6236dae4SAndroid Build Coastguard Worker self.stop() 167*6236dae4SAndroid Build Coastguard Worker return self.start() 168*6236dae4SAndroid Build Coastguard Worker 169*6236dae4SAndroid Build Coastguard Worker def reload(self): 170*6236dae4SAndroid Build Coastguard Worker self._write_config() 171*6236dae4SAndroid Build Coastguard Worker r = self._apachectl("graceful") 172*6236dae4SAndroid Build Coastguard Worker self._loaded_extra_configs = None 173*6236dae4SAndroid Build Coastguard Worker if r.exit_code != 0: 174*6236dae4SAndroid Build Coastguard Worker log.error(f'failed to reload httpd: {r}') 175*6236dae4SAndroid Build Coastguard Worker self._loaded_extra_configs = copy.deepcopy(self._extra_configs) 176*6236dae4SAndroid Build Coastguard Worker return self.wait_live(timeout=timedelta(seconds=5)) 177*6236dae4SAndroid Build Coastguard Worker 178*6236dae4SAndroid Build Coastguard Worker def reload_if_config_changed(self): 179*6236dae4SAndroid Build Coastguard Worker if self._loaded_extra_configs == self._extra_configs: 180*6236dae4SAndroid Build Coastguard Worker return True 181*6236dae4SAndroid Build Coastguard Worker return self.reload() 182*6236dae4SAndroid Build Coastguard Worker 183*6236dae4SAndroid Build Coastguard Worker def wait_dead(self, timeout: timedelta): 184*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=self.env, run_dir=self._tmp_dir) 185*6236dae4SAndroid Build Coastguard Worker try_until = datetime.now() + timeout 186*6236dae4SAndroid Build Coastguard Worker while datetime.now() < try_until: 187*6236dae4SAndroid Build Coastguard Worker r = curl.http_get(url=f'http://{self.env.domain1}:{self.env.http_port}/') 188*6236dae4SAndroid Build Coastguard Worker if r.exit_code != 0: 189*6236dae4SAndroid Build Coastguard Worker return True 190*6236dae4SAndroid Build Coastguard Worker time.sleep(.1) 191*6236dae4SAndroid Build Coastguard Worker log.debug(f"Server still responding after {timeout}") 192*6236dae4SAndroid Build Coastguard Worker return False 193*6236dae4SAndroid Build Coastguard Worker 194*6236dae4SAndroid Build Coastguard Worker def wait_live(self, timeout: timedelta): 195*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=self.env, run_dir=self._tmp_dir, 196*6236dae4SAndroid Build Coastguard Worker timeout=timeout.total_seconds()) 197*6236dae4SAndroid Build Coastguard Worker try_until = datetime.now() + timeout 198*6236dae4SAndroid Build Coastguard Worker while datetime.now() < try_until: 199*6236dae4SAndroid Build Coastguard Worker r = curl.http_get(url=f'http://{self.env.domain1}:{self.env.http_port}/') 200*6236dae4SAndroid Build Coastguard Worker if r.exit_code == 0: 201*6236dae4SAndroid Build Coastguard Worker return True 202*6236dae4SAndroid Build Coastguard Worker time.sleep(.1) 203*6236dae4SAndroid Build Coastguard Worker log.debug(f"Server still not responding after {timeout}") 204*6236dae4SAndroid Build Coastguard Worker return False 205*6236dae4SAndroid Build Coastguard Worker 206*6236dae4SAndroid Build Coastguard Worker def _rmf(self, path): 207*6236dae4SAndroid Build Coastguard Worker if os.path.exists(path): 208*6236dae4SAndroid Build Coastguard Worker return os.remove(path) 209*6236dae4SAndroid Build Coastguard Worker 210*6236dae4SAndroid Build Coastguard Worker def _mkpath(self, path): 211*6236dae4SAndroid Build Coastguard Worker if not os.path.exists(path): 212*6236dae4SAndroid Build Coastguard Worker return os.makedirs(path) 213*6236dae4SAndroid Build Coastguard Worker 214*6236dae4SAndroid Build Coastguard Worker def _write_config(self): 215*6236dae4SAndroid Build Coastguard Worker domain1 = self.env.domain1 216*6236dae4SAndroid Build Coastguard Worker domain1brotli = self.env.domain1brotli 217*6236dae4SAndroid Build Coastguard Worker creds1 = self.env.get_credentials(domain1) 218*6236dae4SAndroid Build Coastguard Worker assert creds1 # convince pytype this isn't None 219*6236dae4SAndroid Build Coastguard Worker domain2 = self.env.domain2 220*6236dae4SAndroid Build Coastguard Worker creds2 = self.env.get_credentials(domain2) 221*6236dae4SAndroid Build Coastguard Worker assert creds2 # convince pytype this isn't None 222*6236dae4SAndroid Build Coastguard Worker proxy_domain = self.env.proxy_domain 223*6236dae4SAndroid Build Coastguard Worker proxy_creds = self.env.get_credentials(proxy_domain) 224*6236dae4SAndroid Build Coastguard Worker assert proxy_creds # convince pytype this isn't None 225*6236dae4SAndroid Build Coastguard Worker self._mkpath(self._conf_dir) 226*6236dae4SAndroid Build Coastguard Worker self._mkpath(self._logs_dir) 227*6236dae4SAndroid Build Coastguard Worker self._mkpath(self._tmp_dir) 228*6236dae4SAndroid Build Coastguard Worker self._mkpath(os.path.join(self._docs_dir, 'two')) 229*6236dae4SAndroid Build Coastguard Worker with open(os.path.join(self._docs_dir, 'data.json'), 'w') as fd: 230*6236dae4SAndroid Build Coastguard Worker data = { 231*6236dae4SAndroid Build Coastguard Worker 'server': f'{domain1}', 232*6236dae4SAndroid Build Coastguard Worker } 233*6236dae4SAndroid Build Coastguard Worker fd.write(JSONEncoder().encode(data)) 234*6236dae4SAndroid Build Coastguard Worker with open(os.path.join(self._docs_dir, 'two/data.json'), 'w') as fd: 235*6236dae4SAndroid Build Coastguard Worker data = { 236*6236dae4SAndroid Build Coastguard Worker 'server': f'{domain2}', 237*6236dae4SAndroid Build Coastguard Worker } 238*6236dae4SAndroid Build Coastguard Worker fd.write(JSONEncoder().encode(data)) 239*6236dae4SAndroid Build Coastguard Worker if self._proxy_auth_basic: 240*6236dae4SAndroid Build Coastguard Worker with open(self._basic_passwords, 'w') as fd: 241*6236dae4SAndroid Build Coastguard Worker fd.write('proxy:$apr1$FQfeInbs$WQZbODJlVg60j0ogEIlTW/\n') 242*6236dae4SAndroid Build Coastguard Worker if self._auth_digest: 243*6236dae4SAndroid Build Coastguard Worker with open(self._digest_passwords, 'w') as fd: 244*6236dae4SAndroid Build Coastguard Worker fd.write('test:restricted area:57123e269fd73d71ae0656594e938e2f\n') 245*6236dae4SAndroid Build Coastguard Worker self._mkpath(os.path.join(self.docs_dir, 'restricted/digest')) 246*6236dae4SAndroid Build Coastguard Worker with open(os.path.join(self.docs_dir, 'restricted/digest/data.json'), 'w') as fd: 247*6236dae4SAndroid Build Coastguard Worker fd.write('{"area":"digest"}\n') 248*6236dae4SAndroid Build Coastguard Worker with open(self._conf_file, 'w') as fd: 249*6236dae4SAndroid Build Coastguard Worker for m in self.MODULES: 250*6236dae4SAndroid Build Coastguard Worker if os.path.exists(os.path.join(self._mods_dir, f'mod_{m}.so')): 251*6236dae4SAndroid Build Coastguard Worker fd.write(f'LoadModule {m}_module "{self._mods_dir}/mod_{m}.so"\n') 252*6236dae4SAndroid Build Coastguard Worker if Httpd.MOD_CURLTEST is not None: 253*6236dae4SAndroid Build Coastguard Worker fd.write(f'LoadModule curltest_module "{Httpd.MOD_CURLTEST}"\n') 254*6236dae4SAndroid Build Coastguard Worker conf = [ # base server config 255*6236dae4SAndroid Build Coastguard Worker f'ServerRoot "{self._apache_dir}"', 256*6236dae4SAndroid Build Coastguard Worker 'DefaultRuntimeDir logs', 257*6236dae4SAndroid Build Coastguard Worker 'PidFile httpd.pid', 258*6236dae4SAndroid Build Coastguard Worker f'ErrorLog {self._error_log}', 259*6236dae4SAndroid Build Coastguard Worker f'LogLevel {self._get_log_level()}', 260*6236dae4SAndroid Build Coastguard Worker 'StartServers 4', 261*6236dae4SAndroid Build Coastguard Worker 'ReadBufferSize 16000', 262*6236dae4SAndroid Build Coastguard Worker 'H2MinWorkers 16', 263*6236dae4SAndroid Build Coastguard Worker 'H2MaxWorkers 256', 264*6236dae4SAndroid Build Coastguard Worker f'Listen {self.env.http_port}', 265*6236dae4SAndroid Build Coastguard Worker f'Listen {self.env.https_port}', 266*6236dae4SAndroid Build Coastguard Worker f'Listen {self.env.proxy_port}', 267*6236dae4SAndroid Build Coastguard Worker f'Listen {self.env.proxys_port}', 268*6236dae4SAndroid Build Coastguard Worker f'TypesConfig "{self._conf_dir}/mime.types', 269*6236dae4SAndroid Build Coastguard Worker 'SSLSessionCache "shmcb:ssl_gcache_data(32000)"', 270*6236dae4SAndroid Build Coastguard Worker ] 271*6236dae4SAndroid Build Coastguard Worker if 'base' in self._extra_configs: 272*6236dae4SAndroid Build Coastguard Worker conf.extend(self._extra_configs['base']) 273*6236dae4SAndroid Build Coastguard Worker conf.extend([ # plain http host for domain1 274*6236dae4SAndroid Build Coastguard Worker f'<VirtualHost *:{self.env.http_port}>', 275*6236dae4SAndroid Build Coastguard Worker f' ServerName {domain1}', 276*6236dae4SAndroid Build Coastguard Worker ' ServerAlias localhost', 277*6236dae4SAndroid Build Coastguard Worker f' DocumentRoot "{self._docs_dir}"', 278*6236dae4SAndroid Build Coastguard Worker ' Protocols h2c http/1.1', 279*6236dae4SAndroid Build Coastguard Worker ' H2Direct on', 280*6236dae4SAndroid Build Coastguard Worker ]) 281*6236dae4SAndroid Build Coastguard Worker conf.extend(self._curltest_conf(domain1)) 282*6236dae4SAndroid Build Coastguard Worker conf.extend([ 283*6236dae4SAndroid Build Coastguard Worker '</VirtualHost>', 284*6236dae4SAndroid Build Coastguard Worker '', 285*6236dae4SAndroid Build Coastguard Worker ]) 286*6236dae4SAndroid Build Coastguard Worker conf.extend([ # https host for domain1, h1 + h2 287*6236dae4SAndroid Build Coastguard Worker f'<VirtualHost *:{self.env.https_port}>', 288*6236dae4SAndroid Build Coastguard Worker f' ServerName {domain1}', 289*6236dae4SAndroid Build Coastguard Worker ' ServerAlias localhost', 290*6236dae4SAndroid Build Coastguard Worker ' Protocols h2 http/1.1', 291*6236dae4SAndroid Build Coastguard Worker ' SSLEngine on', 292*6236dae4SAndroid Build Coastguard Worker f' SSLCertificateFile {creds1.cert_file}', 293*6236dae4SAndroid Build Coastguard Worker f' SSLCertificateKeyFile {creds1.pkey_file}', 294*6236dae4SAndroid Build Coastguard Worker f' DocumentRoot "{self._docs_dir}"', 295*6236dae4SAndroid Build Coastguard Worker ]) 296*6236dae4SAndroid Build Coastguard Worker conf.extend(self._curltest_conf(domain1)) 297*6236dae4SAndroid Build Coastguard Worker if domain1 in self._extra_configs: 298*6236dae4SAndroid Build Coastguard Worker conf.extend(self._extra_configs[domain1]) 299*6236dae4SAndroid Build Coastguard Worker conf.extend([ 300*6236dae4SAndroid Build Coastguard Worker '</VirtualHost>', 301*6236dae4SAndroid Build Coastguard Worker '', 302*6236dae4SAndroid Build Coastguard Worker ]) 303*6236dae4SAndroid Build Coastguard Worker # Alternate to domain1 with BROTLI compression 304*6236dae4SAndroid Build Coastguard Worker conf.extend([ # https host for domain1, h1 + h2 305*6236dae4SAndroid Build Coastguard Worker f'<VirtualHost *:{self.env.https_port}>', 306*6236dae4SAndroid Build Coastguard Worker f' ServerName {domain1brotli}', 307*6236dae4SAndroid Build Coastguard Worker ' Protocols h2 http/1.1', 308*6236dae4SAndroid Build Coastguard Worker ' SSLEngine on', 309*6236dae4SAndroid Build Coastguard Worker f' SSLCertificateFile {creds1.cert_file}', 310*6236dae4SAndroid Build Coastguard Worker f' SSLCertificateKeyFile {creds1.pkey_file}', 311*6236dae4SAndroid Build Coastguard Worker f' DocumentRoot "{self._docs_dir}"', 312*6236dae4SAndroid Build Coastguard Worker ' SetOutputFilter BROTLI_COMPRESS', 313*6236dae4SAndroid Build Coastguard Worker ]) 314*6236dae4SAndroid Build Coastguard Worker conf.extend(self._curltest_conf(domain1)) 315*6236dae4SAndroid Build Coastguard Worker if domain1 in self._extra_configs: 316*6236dae4SAndroid Build Coastguard Worker conf.extend(self._extra_configs[domain1]) 317*6236dae4SAndroid Build Coastguard Worker conf.extend([ 318*6236dae4SAndroid Build Coastguard Worker '</VirtualHost>', 319*6236dae4SAndroid Build Coastguard Worker '', 320*6236dae4SAndroid Build Coastguard Worker ]) 321*6236dae4SAndroid Build Coastguard Worker conf.extend([ # plain http host for domain2 322*6236dae4SAndroid Build Coastguard Worker f'<VirtualHost *:{self.env.http_port}>', 323*6236dae4SAndroid Build Coastguard Worker f' ServerName {domain2}', 324*6236dae4SAndroid Build Coastguard Worker ' ServerAlias localhost', 325*6236dae4SAndroid Build Coastguard Worker f' DocumentRoot "{self._docs_dir}"', 326*6236dae4SAndroid Build Coastguard Worker ' Protocols h2c http/1.1', 327*6236dae4SAndroid Build Coastguard Worker ]) 328*6236dae4SAndroid Build Coastguard Worker conf.extend(self._curltest_conf(domain2)) 329*6236dae4SAndroid Build Coastguard Worker conf.extend([ 330*6236dae4SAndroid Build Coastguard Worker '</VirtualHost>', 331*6236dae4SAndroid Build Coastguard Worker '', 332*6236dae4SAndroid Build Coastguard Worker ]) 333*6236dae4SAndroid Build Coastguard Worker conf.extend([ # https host for domain2, no h2 334*6236dae4SAndroid Build Coastguard Worker f'<VirtualHost *:{self.env.https_port}>', 335*6236dae4SAndroid Build Coastguard Worker f' ServerName {domain2}', 336*6236dae4SAndroid Build Coastguard Worker ' Protocols http/1.1', 337*6236dae4SAndroid Build Coastguard Worker ' SSLEngine on', 338*6236dae4SAndroid Build Coastguard Worker f' SSLCertificateFile {creds2.cert_file}', 339*6236dae4SAndroid Build Coastguard Worker f' SSLCertificateKeyFile {creds2.pkey_file}', 340*6236dae4SAndroid Build Coastguard Worker f' DocumentRoot "{self._docs_dir}/two"', 341*6236dae4SAndroid Build Coastguard Worker ]) 342*6236dae4SAndroid Build Coastguard Worker conf.extend(self._curltest_conf(domain2)) 343*6236dae4SAndroid Build Coastguard Worker if domain2 in self._extra_configs: 344*6236dae4SAndroid Build Coastguard Worker conf.extend(self._extra_configs[domain2]) 345*6236dae4SAndroid Build Coastguard Worker conf.extend([ 346*6236dae4SAndroid Build Coastguard Worker '</VirtualHost>', 347*6236dae4SAndroid Build Coastguard Worker '', 348*6236dae4SAndroid Build Coastguard Worker ]) 349*6236dae4SAndroid Build Coastguard Worker conf.extend([ # http forward proxy 350*6236dae4SAndroid Build Coastguard Worker f'<VirtualHost *:{self.env.proxy_port}>', 351*6236dae4SAndroid Build Coastguard Worker f' ServerName {proxy_domain}', 352*6236dae4SAndroid Build Coastguard Worker ' Protocols h2c http/1.1', 353*6236dae4SAndroid Build Coastguard Worker ' ProxyRequests On', 354*6236dae4SAndroid Build Coastguard Worker ' H2ProxyRequests On', 355*6236dae4SAndroid Build Coastguard Worker ' ProxyVia On', 356*6236dae4SAndroid Build Coastguard Worker f' AllowCONNECT {self.env.http_port} {self.env.https_port}', 357*6236dae4SAndroid Build Coastguard Worker ]) 358*6236dae4SAndroid Build Coastguard Worker conf.extend(self._get_proxy_conf()) 359*6236dae4SAndroid Build Coastguard Worker conf.extend([ 360*6236dae4SAndroid Build Coastguard Worker '</VirtualHost>', 361*6236dae4SAndroid Build Coastguard Worker '', 362*6236dae4SAndroid Build Coastguard Worker ]) 363*6236dae4SAndroid Build Coastguard Worker conf.extend([ # https forward proxy 364*6236dae4SAndroid Build Coastguard Worker f'<VirtualHost *:{self.env.proxys_port}>', 365*6236dae4SAndroid Build Coastguard Worker f' ServerName {proxy_domain}', 366*6236dae4SAndroid Build Coastguard Worker ' Protocols h2 http/1.1', 367*6236dae4SAndroid Build Coastguard Worker ' SSLEngine on', 368*6236dae4SAndroid Build Coastguard Worker f' SSLCertificateFile {proxy_creds.cert_file}', 369*6236dae4SAndroid Build Coastguard Worker f' SSLCertificateKeyFile {proxy_creds.pkey_file}', 370*6236dae4SAndroid Build Coastguard Worker ' ProxyRequests On', 371*6236dae4SAndroid Build Coastguard Worker ' H2ProxyRequests On', 372*6236dae4SAndroid Build Coastguard Worker ' ProxyVia On', 373*6236dae4SAndroid Build Coastguard Worker f' AllowCONNECT {self.env.http_port} {self.env.https_port}', 374*6236dae4SAndroid Build Coastguard Worker ]) 375*6236dae4SAndroid Build Coastguard Worker conf.extend(self._get_proxy_conf()) 376*6236dae4SAndroid Build Coastguard Worker conf.extend([ 377*6236dae4SAndroid Build Coastguard Worker '</VirtualHost>', 378*6236dae4SAndroid Build Coastguard Worker '', 379*6236dae4SAndroid Build Coastguard Worker ]) 380*6236dae4SAndroid Build Coastguard Worker 381*6236dae4SAndroid Build Coastguard Worker fd.write("\n".join(conf)) 382*6236dae4SAndroid Build Coastguard Worker with open(os.path.join(self._conf_dir, 'mime.types'), 'w') as fd: 383*6236dae4SAndroid Build Coastguard Worker fd.write("\n".join([ 384*6236dae4SAndroid Build Coastguard Worker 'text/html html', 385*6236dae4SAndroid Build Coastguard Worker 'application/json json', 386*6236dae4SAndroid Build Coastguard Worker '' 387*6236dae4SAndroid Build Coastguard Worker ])) 388*6236dae4SAndroid Build Coastguard Worker 389*6236dae4SAndroid Build Coastguard Worker def _get_proxy_conf(self): 390*6236dae4SAndroid Build Coastguard Worker if self._proxy_auth_basic: 391*6236dae4SAndroid Build Coastguard Worker return [ 392*6236dae4SAndroid Build Coastguard Worker ' <Proxy "*">', 393*6236dae4SAndroid Build Coastguard Worker ' AuthType Basic', 394*6236dae4SAndroid Build Coastguard Worker ' AuthName "Restricted Proxy"', 395*6236dae4SAndroid Build Coastguard Worker ' AuthBasicProvider file', 396*6236dae4SAndroid Build Coastguard Worker f' AuthUserFile "{self._basic_passwords}"', 397*6236dae4SAndroid Build Coastguard Worker ' Require user proxy', 398*6236dae4SAndroid Build Coastguard Worker ' </Proxy>', 399*6236dae4SAndroid Build Coastguard Worker ] 400*6236dae4SAndroid Build Coastguard Worker else: 401*6236dae4SAndroid Build Coastguard Worker return [ 402*6236dae4SAndroid Build Coastguard Worker ' <Proxy "*">', 403*6236dae4SAndroid Build Coastguard Worker ' Require ip 127.0.0.1', 404*6236dae4SAndroid Build Coastguard Worker ' </Proxy>', 405*6236dae4SAndroid Build Coastguard Worker ] 406*6236dae4SAndroid Build Coastguard Worker 407*6236dae4SAndroid Build Coastguard Worker def _get_log_level(self): 408*6236dae4SAndroid Build Coastguard Worker if self.env.verbose > 3: 409*6236dae4SAndroid Build Coastguard Worker return 'trace2' 410*6236dae4SAndroid Build Coastguard Worker if self.env.verbose > 2: 411*6236dae4SAndroid Build Coastguard Worker return 'trace1' 412*6236dae4SAndroid Build Coastguard Worker if self.env.verbose > 1: 413*6236dae4SAndroid Build Coastguard Worker return 'debug' 414*6236dae4SAndroid Build Coastguard Worker return 'info' 415*6236dae4SAndroid Build Coastguard Worker 416*6236dae4SAndroid Build Coastguard Worker def _curltest_conf(self, servername) -> List[str]: 417*6236dae4SAndroid Build Coastguard Worker lines = [] 418*6236dae4SAndroid Build Coastguard Worker if Httpd.MOD_CURLTEST is not None: 419*6236dae4SAndroid Build Coastguard Worker lines.extend([ 420*6236dae4SAndroid Build Coastguard Worker ' Redirect 302 /data.json.302 /data.json', 421*6236dae4SAndroid Build Coastguard Worker ' Redirect 301 /curltest/echo301 /curltest/echo', 422*6236dae4SAndroid Build Coastguard Worker ' Redirect 302 /curltest/echo302 /curltest/echo', 423*6236dae4SAndroid Build Coastguard Worker ' Redirect 303 /curltest/echo303 /curltest/echo', 424*6236dae4SAndroid Build Coastguard Worker ' Redirect 307 /curltest/echo307 /curltest/echo', 425*6236dae4SAndroid Build Coastguard Worker ' <Location /curltest/sslinfo>', 426*6236dae4SAndroid Build Coastguard Worker ' SSLOptions StdEnvVars', 427*6236dae4SAndroid Build Coastguard Worker ' SetHandler curltest-sslinfo', 428*6236dae4SAndroid Build Coastguard Worker ' </Location>', 429*6236dae4SAndroid Build Coastguard Worker ' <Location /curltest/echo>', 430*6236dae4SAndroid Build Coastguard Worker ' SetHandler curltest-echo', 431*6236dae4SAndroid Build Coastguard Worker ' </Location>', 432*6236dae4SAndroid Build Coastguard Worker ' <Location /curltest/put>', 433*6236dae4SAndroid Build Coastguard Worker ' SetHandler curltest-put', 434*6236dae4SAndroid Build Coastguard Worker ' </Location>', 435*6236dae4SAndroid Build Coastguard Worker ' <Location /curltest/tweak>', 436*6236dae4SAndroid Build Coastguard Worker ' SetHandler curltest-tweak', 437*6236dae4SAndroid Build Coastguard Worker ' </Location>', 438*6236dae4SAndroid Build Coastguard Worker ' Redirect 302 /tweak /curltest/tweak', 439*6236dae4SAndroid Build Coastguard Worker ' <Location /curltest/1_1>', 440*6236dae4SAndroid Build Coastguard Worker ' SetHandler curltest-1_1-required', 441*6236dae4SAndroid Build Coastguard Worker ' </Location>', 442*6236dae4SAndroid Build Coastguard Worker ' <Location /curltest/shutdown_unclean>', 443*6236dae4SAndroid Build Coastguard Worker ' SetHandler curltest-tweak', 444*6236dae4SAndroid Build Coastguard Worker ' SetEnv force-response-1.0 1', 445*6236dae4SAndroid Build Coastguard Worker ' </Location>', 446*6236dae4SAndroid Build Coastguard Worker ' SetEnvIf Request_URI "/shutdown_unclean" ssl-unclean=1', 447*6236dae4SAndroid Build Coastguard Worker ]) 448*6236dae4SAndroid Build Coastguard Worker if self._auth_digest: 449*6236dae4SAndroid Build Coastguard Worker lines.extend([ 450*6236dae4SAndroid Build Coastguard Worker f' <Directory {self.docs_dir}/restricted/digest>', 451*6236dae4SAndroid Build Coastguard Worker ' AuthType Digest', 452*6236dae4SAndroid Build Coastguard Worker ' AuthName "restricted area"', 453*6236dae4SAndroid Build Coastguard Worker f' AuthDigestDomain "https://{servername}"', 454*6236dae4SAndroid Build Coastguard Worker ' AuthBasicProvider file', 455*6236dae4SAndroid Build Coastguard Worker f' AuthUserFile "{self._digest_passwords}"', 456*6236dae4SAndroid Build Coastguard Worker ' Require valid-user', 457*6236dae4SAndroid Build Coastguard Worker ' </Directory>', 458*6236dae4SAndroid Build Coastguard Worker 459*6236dae4SAndroid Build Coastguard Worker ]) 460*6236dae4SAndroid Build Coastguard Worker return lines 461*6236dae4SAndroid Build Coastguard Worker 462*6236dae4SAndroid Build Coastguard Worker def _init_curltest(self): 463*6236dae4SAndroid Build Coastguard Worker if Httpd.MOD_CURLTEST is not None: 464*6236dae4SAndroid Build Coastguard Worker return 465*6236dae4SAndroid Build Coastguard Worker local_dir = os.path.dirname(inspect.getfile(Httpd)) 466*6236dae4SAndroid Build Coastguard Worker p = subprocess.run([self.env.apxs, '-c', 'mod_curltest.c'], 467*6236dae4SAndroid Build Coastguard Worker capture_output=True, 468*6236dae4SAndroid Build Coastguard Worker cwd=os.path.join(local_dir, 'mod_curltest')) 469*6236dae4SAndroid Build Coastguard Worker rv = p.returncode 470*6236dae4SAndroid Build Coastguard Worker if rv != 0: 471*6236dae4SAndroid Build Coastguard Worker log.error(f"compiling mod_curltest failed: {p.stderr}") 472*6236dae4SAndroid Build Coastguard Worker raise Exception(f"compiling mod_curltest failed: {p.stderr}") 473*6236dae4SAndroid Build Coastguard Worker Httpd.MOD_CURLTEST = os.path.join( 474*6236dae4SAndroid Build Coastguard Worker local_dir, 'mod_curltest/.libs/mod_curltest.so') 475