xref: /aosp_15_r20/external/curl/tests/http/testenv/nghttpx.py (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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 logging
28*6236dae4SAndroid Build Coastguard Workerimport os
29*6236dae4SAndroid Build Coastguard Workerimport signal
30*6236dae4SAndroid Build Coastguard Workerimport subprocess
31*6236dae4SAndroid Build Coastguard Workerimport time
32*6236dae4SAndroid Build Coastguard Workerfrom typing import Optional
33*6236dae4SAndroid Build Coastguard Workerfrom datetime import datetime, timedelta
34*6236dae4SAndroid Build Coastguard Worker
35*6236dae4SAndroid Build Coastguard Workerfrom .env import Env
36*6236dae4SAndroid Build Coastguard Workerfrom .curl import CurlClient
37*6236dae4SAndroid Build Coastguard Worker
38*6236dae4SAndroid Build Coastguard Worker
39*6236dae4SAndroid Build Coastguard Workerlog = logging.getLogger(__name__)
40*6236dae4SAndroid Build Coastguard Worker
41*6236dae4SAndroid Build Coastguard Worker
42*6236dae4SAndroid Build Coastguard Workerclass Nghttpx:
43*6236dae4SAndroid Build Coastguard Worker
44*6236dae4SAndroid Build Coastguard Worker    def __init__(self, env: Env, port: int, https_port: int, name: str):
45*6236dae4SAndroid Build Coastguard Worker        self.env = env
46*6236dae4SAndroid Build Coastguard Worker        self._name = name
47*6236dae4SAndroid Build Coastguard Worker        self._port = port
48*6236dae4SAndroid Build Coastguard Worker        self._https_port = https_port
49*6236dae4SAndroid Build Coastguard Worker        self._cmd = env.nghttpx
50*6236dae4SAndroid Build Coastguard Worker        self._run_dir = os.path.join(env.gen_dir, name)
51*6236dae4SAndroid Build Coastguard Worker        self._pid_file = os.path.join(self._run_dir, 'nghttpx.pid')
52*6236dae4SAndroid Build Coastguard Worker        self._conf_file = os.path.join(self._run_dir, 'nghttpx.conf')
53*6236dae4SAndroid Build Coastguard Worker        self._error_log = os.path.join(self._run_dir, 'nghttpx.log')
54*6236dae4SAndroid Build Coastguard Worker        self._stderr = os.path.join(self._run_dir, 'nghttpx.stderr')
55*6236dae4SAndroid Build Coastguard Worker        self._tmp_dir = os.path.join(self._run_dir, 'tmp')
56*6236dae4SAndroid Build Coastguard Worker        self._process: Optional[subprocess.Popen] = None
57*6236dae4SAndroid Build Coastguard Worker        self._rmf(self._pid_file)
58*6236dae4SAndroid Build Coastguard Worker        self._rmf(self._error_log)
59*6236dae4SAndroid Build Coastguard Worker        self._mkpath(self._run_dir)
60*6236dae4SAndroid Build Coastguard Worker        self._write_config()
61*6236dae4SAndroid Build Coastguard Worker
62*6236dae4SAndroid Build Coastguard Worker    @property
63*6236dae4SAndroid Build Coastguard Worker    def https_port(self):
64*6236dae4SAndroid Build Coastguard Worker        return self._https_port
65*6236dae4SAndroid Build Coastguard Worker
66*6236dae4SAndroid Build Coastguard Worker    def exists(self):
67*6236dae4SAndroid Build Coastguard Worker        return self._cmd and os.path.exists(self._cmd)
68*6236dae4SAndroid Build Coastguard Worker
69*6236dae4SAndroid Build Coastguard Worker    def clear_logs(self):
70*6236dae4SAndroid Build Coastguard Worker        self._rmf(self._error_log)
71*6236dae4SAndroid Build Coastguard Worker        self._rmf(self._stderr)
72*6236dae4SAndroid Build Coastguard Worker
73*6236dae4SAndroid Build Coastguard Worker    def is_running(self):
74*6236dae4SAndroid Build Coastguard Worker        if self._process:
75*6236dae4SAndroid Build Coastguard Worker            self._process.poll()
76*6236dae4SAndroid Build Coastguard Worker            return self._process.returncode is None
77*6236dae4SAndroid Build Coastguard Worker        return False
78*6236dae4SAndroid Build Coastguard Worker
79*6236dae4SAndroid Build Coastguard Worker    def start_if_needed(self):
80*6236dae4SAndroid Build Coastguard Worker        if not self.is_running():
81*6236dae4SAndroid Build Coastguard Worker            return self.start()
82*6236dae4SAndroid Build Coastguard Worker        return True
83*6236dae4SAndroid Build Coastguard Worker
84*6236dae4SAndroid Build Coastguard Worker    def start(self, wait_live=True):
85*6236dae4SAndroid Build Coastguard Worker        pass
86*6236dae4SAndroid Build Coastguard Worker
87*6236dae4SAndroid Build Coastguard Worker    def stop_if_running(self):
88*6236dae4SAndroid Build Coastguard Worker        if self.is_running():
89*6236dae4SAndroid Build Coastguard Worker            return self.stop()
90*6236dae4SAndroid Build Coastguard Worker        return True
91*6236dae4SAndroid Build Coastguard Worker
92*6236dae4SAndroid Build Coastguard Worker    def stop(self, wait_dead=True):
93*6236dae4SAndroid Build Coastguard Worker        self._mkpath(self._tmp_dir)
94*6236dae4SAndroid Build Coastguard Worker        if self._process:
95*6236dae4SAndroid Build Coastguard Worker            self._process.terminate()
96*6236dae4SAndroid Build Coastguard Worker            self._process.wait(timeout=2)
97*6236dae4SAndroid Build Coastguard Worker            self._process = None
98*6236dae4SAndroid Build Coastguard Worker            return not wait_dead or self.wait_dead(timeout=timedelta(seconds=5))
99*6236dae4SAndroid Build Coastguard Worker        return True
100*6236dae4SAndroid Build Coastguard Worker
101*6236dae4SAndroid Build Coastguard Worker    def restart(self):
102*6236dae4SAndroid Build Coastguard Worker        self.stop()
103*6236dae4SAndroid Build Coastguard Worker        return self.start()
104*6236dae4SAndroid Build Coastguard Worker
105*6236dae4SAndroid Build Coastguard Worker    def reload(self, timeout: timedelta):
106*6236dae4SAndroid Build Coastguard Worker        if self._process:
107*6236dae4SAndroid Build Coastguard Worker            running = self._process
108*6236dae4SAndroid Build Coastguard Worker            self._process = None
109*6236dae4SAndroid Build Coastguard Worker            os.kill(running.pid, signal.SIGQUIT)
110*6236dae4SAndroid Build Coastguard Worker            end_wait = datetime.now() + timeout
111*6236dae4SAndroid Build Coastguard Worker            if not self.start(wait_live=False):
112*6236dae4SAndroid Build Coastguard Worker                self._process = running
113*6236dae4SAndroid Build Coastguard Worker                return False
114*6236dae4SAndroid Build Coastguard Worker            while datetime.now() < end_wait:
115*6236dae4SAndroid Build Coastguard Worker                try:
116*6236dae4SAndroid Build Coastguard Worker                    log.debug(f'waiting for nghttpx({running.pid}) to exit.')
117*6236dae4SAndroid Build Coastguard Worker                    running.wait(2)
118*6236dae4SAndroid Build Coastguard Worker                    log.debug(f'nghttpx({running.pid}) terminated -> {running.returncode}')
119*6236dae4SAndroid Build Coastguard Worker                    break
120*6236dae4SAndroid Build Coastguard Worker                except subprocess.TimeoutExpired:
121*6236dae4SAndroid Build Coastguard Worker                    log.warning(f'nghttpx({running.pid}), not shut down yet.')
122*6236dae4SAndroid Build Coastguard Worker                    os.kill(running.pid, signal.SIGQUIT)
123*6236dae4SAndroid Build Coastguard Worker            if datetime.now() >= end_wait:
124*6236dae4SAndroid Build Coastguard Worker                log.error(f'nghttpx({running.pid}), terminate forcefully.')
125*6236dae4SAndroid Build Coastguard Worker                os.kill(running.pid, signal.SIGKILL)
126*6236dae4SAndroid Build Coastguard Worker                running.terminate()
127*6236dae4SAndroid Build Coastguard Worker                running.wait(1)
128*6236dae4SAndroid Build Coastguard Worker            return self.wait_live(timeout=timedelta(seconds=5))
129*6236dae4SAndroid Build Coastguard Worker        return False
130*6236dae4SAndroid Build Coastguard Worker
131*6236dae4SAndroid Build Coastguard Worker    def wait_dead(self, timeout: timedelta):
132*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=self.env, run_dir=self._tmp_dir)
133*6236dae4SAndroid Build Coastguard Worker        try_until = datetime.now() + timeout
134*6236dae4SAndroid Build Coastguard Worker        while datetime.now() < try_until:
135*6236dae4SAndroid Build Coastguard Worker            if self._https_port > 0:
136*6236dae4SAndroid Build Coastguard Worker                check_url = f'https://{self.env.domain1}:{self._https_port}/'
137*6236dae4SAndroid Build Coastguard Worker                r = curl.http_get(url=check_url, extra_args=[
138*6236dae4SAndroid Build Coastguard Worker                    '--trace', 'curl.trace', '--trace-time',
139*6236dae4SAndroid Build Coastguard Worker                    '--connect-timeout', '1'
140*6236dae4SAndroid Build Coastguard Worker                ])
141*6236dae4SAndroid Build Coastguard Worker            else:
142*6236dae4SAndroid Build Coastguard Worker                check_url = f'https://{self.env.domain1}:{self._port}/'
143*6236dae4SAndroid Build Coastguard Worker                r = curl.http_get(url=check_url, extra_args=[
144*6236dae4SAndroid Build Coastguard Worker                    '--trace', 'curl.trace', '--trace-time',
145*6236dae4SAndroid Build Coastguard Worker                    '--http3-only', '--connect-timeout', '1'
146*6236dae4SAndroid Build Coastguard Worker                ])
147*6236dae4SAndroid Build Coastguard Worker            if r.exit_code != 0:
148*6236dae4SAndroid Build Coastguard Worker                return True
149*6236dae4SAndroid Build Coastguard Worker            log.debug(f'waiting for nghttpx to stop responding: {r}')
150*6236dae4SAndroid Build Coastguard Worker            time.sleep(.1)
151*6236dae4SAndroid Build Coastguard Worker        log.debug(f"Server still responding after {timeout}")
152*6236dae4SAndroid Build Coastguard Worker        return False
153*6236dae4SAndroid Build Coastguard Worker
154*6236dae4SAndroid Build Coastguard Worker    def wait_live(self, timeout: timedelta):
155*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=self.env, run_dir=self._tmp_dir)
156*6236dae4SAndroid Build Coastguard Worker        try_until = datetime.now() + timeout
157*6236dae4SAndroid Build Coastguard Worker        while datetime.now() < try_until:
158*6236dae4SAndroid Build Coastguard Worker            if self._https_port > 0:
159*6236dae4SAndroid Build Coastguard Worker                check_url = f'https://{self.env.domain1}:{self._https_port}/'
160*6236dae4SAndroid Build Coastguard Worker                r = curl.http_get(url=check_url, extra_args=[
161*6236dae4SAndroid Build Coastguard Worker                    '--trace', 'curl.trace', '--trace-time',
162*6236dae4SAndroid Build Coastguard Worker                    '--connect-timeout', '1'
163*6236dae4SAndroid Build Coastguard Worker                ])
164*6236dae4SAndroid Build Coastguard Worker            else:
165*6236dae4SAndroid Build Coastguard Worker                check_url = f'https://{self.env.domain1}:{self._port}/'
166*6236dae4SAndroid Build Coastguard Worker                r = curl.http_get(url=check_url, extra_args=[
167*6236dae4SAndroid Build Coastguard Worker                    '--http3-only', '--trace', 'curl.trace', '--trace-time',
168*6236dae4SAndroid Build Coastguard Worker                    '--connect-timeout', '1'
169*6236dae4SAndroid Build Coastguard Worker                ])
170*6236dae4SAndroid Build Coastguard Worker            if r.exit_code == 0:
171*6236dae4SAndroid Build Coastguard Worker                return True
172*6236dae4SAndroid Build Coastguard Worker            log.debug(f'waiting for nghttpx to become responsive: {r}')
173*6236dae4SAndroid Build Coastguard Worker            time.sleep(.1)
174*6236dae4SAndroid Build Coastguard Worker        log.error(f"Server still not responding after {timeout}")
175*6236dae4SAndroid Build Coastguard Worker        return False
176*6236dae4SAndroid Build Coastguard Worker
177*6236dae4SAndroid Build Coastguard Worker    def _rmf(self, path):
178*6236dae4SAndroid Build Coastguard Worker        if os.path.exists(path):
179*6236dae4SAndroid Build Coastguard Worker            return os.remove(path)
180*6236dae4SAndroid Build Coastguard Worker
181*6236dae4SAndroid Build Coastguard Worker    def _mkpath(self, path):
182*6236dae4SAndroid Build Coastguard Worker        if not os.path.exists(path):
183*6236dae4SAndroid Build Coastguard Worker            return os.makedirs(path)
184*6236dae4SAndroid Build Coastguard Worker
185*6236dae4SAndroid Build Coastguard Worker    def _write_config(self):
186*6236dae4SAndroid Build Coastguard Worker        with open(self._conf_file, 'w') as fd:
187*6236dae4SAndroid Build Coastguard Worker            fd.write('# nghttpx test config')
188*6236dae4SAndroid Build Coastguard Worker            fd.write("\n".join([
189*6236dae4SAndroid Build Coastguard Worker                '# do we need something here?'
190*6236dae4SAndroid Build Coastguard Worker            ]))
191*6236dae4SAndroid Build Coastguard Worker
192*6236dae4SAndroid Build Coastguard Worker
193*6236dae4SAndroid Build Coastguard Workerclass NghttpxQuic(Nghttpx):
194*6236dae4SAndroid Build Coastguard Worker
195*6236dae4SAndroid Build Coastguard Worker    def __init__(self, env: Env):
196*6236dae4SAndroid Build Coastguard Worker        super().__init__(env=env, name='nghttpx-quic', port=env.h3_port,
197*6236dae4SAndroid Build Coastguard Worker                         https_port=env.nghttpx_https_port)
198*6236dae4SAndroid Build Coastguard Worker
199*6236dae4SAndroid Build Coastguard Worker    def start(self, wait_live=True):
200*6236dae4SAndroid Build Coastguard Worker        self._mkpath(self._tmp_dir)
201*6236dae4SAndroid Build Coastguard Worker        if self._process:
202*6236dae4SAndroid Build Coastguard Worker            self.stop()
203*6236dae4SAndroid Build Coastguard Worker        creds = self.env.get_credentials(self.env.domain1)
204*6236dae4SAndroid Build Coastguard Worker        assert creds  # convince pytype this isn't None
205*6236dae4SAndroid Build Coastguard Worker        args = [
206*6236dae4SAndroid Build Coastguard Worker            self._cmd,
207*6236dae4SAndroid Build Coastguard Worker            f'--frontend=*,{self.env.h3_port};quic',
208*6236dae4SAndroid Build Coastguard Worker            f'--frontend=*,{self.env.nghttpx_https_port};tls',
209*6236dae4SAndroid Build Coastguard Worker            f'--backend=127.0.0.1,{self.env.https_port};{self.env.domain1};sni={self.env.domain1};proto=h2;tls',
210*6236dae4SAndroid Build Coastguard Worker            f'--backend=127.0.0.1,{self.env.http_port}',
211*6236dae4SAndroid Build Coastguard Worker            '--log-level=INFO',
212*6236dae4SAndroid Build Coastguard Worker            f'--pid-file={self._pid_file}',
213*6236dae4SAndroid Build Coastguard Worker            f'--errorlog-file={self._error_log}',
214*6236dae4SAndroid Build Coastguard Worker            f'--conf={self._conf_file}',
215*6236dae4SAndroid Build Coastguard Worker            f'--cacert={self.env.ca.cert_file}',
216*6236dae4SAndroid Build Coastguard Worker            creds.pkey_file,
217*6236dae4SAndroid Build Coastguard Worker            creds.cert_file,
218*6236dae4SAndroid Build Coastguard Worker            '--frontend-http3-window-size=1M',
219*6236dae4SAndroid Build Coastguard Worker            '--frontend-http3-max-window-size=10M',
220*6236dae4SAndroid Build Coastguard Worker            '--frontend-http3-connection-window-size=10M',
221*6236dae4SAndroid Build Coastguard Worker            '--frontend-http3-max-connection-window-size=100M',
222*6236dae4SAndroid Build Coastguard Worker            # f'--frontend-quic-debug-log',
223*6236dae4SAndroid Build Coastguard Worker        ]
224*6236dae4SAndroid Build Coastguard Worker        ngerr = open(self._stderr, 'a')
225*6236dae4SAndroid Build Coastguard Worker        self._process = subprocess.Popen(args=args, stderr=ngerr)
226*6236dae4SAndroid Build Coastguard Worker        if self._process.returncode is not None:
227*6236dae4SAndroid Build Coastguard Worker            return False
228*6236dae4SAndroid Build Coastguard Worker        return not wait_live or self.wait_live(timeout=timedelta(seconds=5))
229*6236dae4SAndroid Build Coastguard Worker
230*6236dae4SAndroid Build Coastguard Worker
231*6236dae4SAndroid Build Coastguard Workerclass NghttpxFwd(Nghttpx):
232*6236dae4SAndroid Build Coastguard Worker
233*6236dae4SAndroid Build Coastguard Worker    def __init__(self, env: Env):
234*6236dae4SAndroid Build Coastguard Worker        super().__init__(env=env, name='nghttpx-fwd', port=env.h2proxys_port,
235*6236dae4SAndroid Build Coastguard Worker                         https_port=0)
236*6236dae4SAndroid Build Coastguard Worker
237*6236dae4SAndroid Build Coastguard Worker    def start(self, wait_live=True):
238*6236dae4SAndroid Build Coastguard Worker        self._mkpath(self._tmp_dir)
239*6236dae4SAndroid Build Coastguard Worker        if self._process:
240*6236dae4SAndroid Build Coastguard Worker            self.stop()
241*6236dae4SAndroid Build Coastguard Worker        creds = self.env.get_credentials(self.env.proxy_domain)
242*6236dae4SAndroid Build Coastguard Worker        assert creds  # convince pytype this isn't None
243*6236dae4SAndroid Build Coastguard Worker        args = [
244*6236dae4SAndroid Build Coastguard Worker            self._cmd,
245*6236dae4SAndroid Build Coastguard Worker            '--http2-proxy',
246*6236dae4SAndroid Build Coastguard Worker            f'--frontend=*,{self.env.h2proxys_port}',
247*6236dae4SAndroid Build Coastguard Worker            f'--backend=127.0.0.1,{self.env.proxy_port}',
248*6236dae4SAndroid Build Coastguard Worker            '--log-level=INFO',
249*6236dae4SAndroid Build Coastguard Worker            f'--pid-file={self._pid_file}',
250*6236dae4SAndroid Build Coastguard Worker            f'--errorlog-file={self._error_log}',
251*6236dae4SAndroid Build Coastguard Worker            f'--conf={self._conf_file}',
252*6236dae4SAndroid Build Coastguard Worker            f'--cacert={self.env.ca.cert_file}',
253*6236dae4SAndroid Build Coastguard Worker            creds.pkey_file,
254*6236dae4SAndroid Build Coastguard Worker            creds.cert_file,
255*6236dae4SAndroid Build Coastguard Worker        ]
256*6236dae4SAndroid Build Coastguard Worker        ngerr = open(self._stderr, 'a')
257*6236dae4SAndroid Build Coastguard Worker        self._process = subprocess.Popen(args=args, stderr=ngerr)
258*6236dae4SAndroid Build Coastguard Worker        if self._process.returncode is not None:
259*6236dae4SAndroid Build Coastguard Worker            return False
260*6236dae4SAndroid Build Coastguard Worker        return not wait_live or self.wait_live(timeout=timedelta(seconds=5))
261*6236dae4SAndroid Build Coastguard Worker
262*6236dae4SAndroid Build Coastguard Worker    def wait_dead(self, timeout: timedelta):
263*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=self.env, run_dir=self._tmp_dir)
264*6236dae4SAndroid Build Coastguard Worker        try_until = datetime.now() + timeout
265*6236dae4SAndroid Build Coastguard Worker        while datetime.now() < try_until:
266*6236dae4SAndroid Build Coastguard Worker            check_url = f'https://{self.env.proxy_domain}:{self.env.h2proxys_port}/'
267*6236dae4SAndroid Build Coastguard Worker            r = curl.http_get(url=check_url)
268*6236dae4SAndroid Build Coastguard Worker            if r.exit_code != 0:
269*6236dae4SAndroid Build Coastguard Worker                return True
270*6236dae4SAndroid Build Coastguard Worker            log.debug(f'waiting for nghttpx-fwd to stop responding: {r}')
271*6236dae4SAndroid Build Coastguard Worker            time.sleep(.1)
272*6236dae4SAndroid Build Coastguard Worker        log.debug(f"Server still responding after {timeout}")
273*6236dae4SAndroid Build Coastguard Worker        return False
274*6236dae4SAndroid Build Coastguard Worker
275*6236dae4SAndroid Build Coastguard Worker    def wait_live(self, timeout: timedelta):
276*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=self.env, run_dir=self._tmp_dir)
277*6236dae4SAndroid Build Coastguard Worker        try_until = datetime.now() + timeout
278*6236dae4SAndroid Build Coastguard Worker        while datetime.now() < try_until:
279*6236dae4SAndroid Build Coastguard Worker            check_url = f'https://{self.env.proxy_domain}:{self.env.h2proxys_port}/'
280*6236dae4SAndroid Build Coastguard Worker            r = curl.http_get(url=check_url, extra_args=[
281*6236dae4SAndroid Build Coastguard Worker                '--trace', 'curl.trace', '--trace-time'
282*6236dae4SAndroid Build Coastguard Worker            ])
283*6236dae4SAndroid Build Coastguard Worker            if r.exit_code == 0:
284*6236dae4SAndroid Build Coastguard Worker                return True
285*6236dae4SAndroid Build Coastguard Worker            log.debug(f'waiting for nghttpx-fwd to become responsive: {r}')
286*6236dae4SAndroid Build Coastguard Worker            time.sleep(.1)
287*6236dae4SAndroid Build Coastguard Worker        log.error(f"Server still not responding after {timeout}")
288*6236dae4SAndroid Build Coastguard Worker        return False
289