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 socket 30*6236dae4SAndroid Build Coastguard Workerfrom threading import Thread 31*6236dae4SAndroid Build Coastguard Workerfrom typing import Generator 32*6236dae4SAndroid Build Coastguard Worker 33*6236dae4SAndroid Build Coastguard Workerimport pytest 34*6236dae4SAndroid Build Coastguard Worker 35*6236dae4SAndroid Build Coastguard Workerfrom testenv import Env, CurlClient 36*6236dae4SAndroid Build Coastguard Worker 37*6236dae4SAndroid Build Coastguard Worker 38*6236dae4SAndroid Build Coastguard Workerlog = logging.getLogger(__name__) 39*6236dae4SAndroid Build Coastguard Worker 40*6236dae4SAndroid Build Coastguard Workerclass UDSFaker: 41*6236dae4SAndroid Build Coastguard Worker 42*6236dae4SAndroid Build Coastguard Worker def __init__(self, path): 43*6236dae4SAndroid Build Coastguard Worker self._uds_path = path 44*6236dae4SAndroid Build Coastguard Worker self._done = False 45*6236dae4SAndroid Build Coastguard Worker self._socket = None 46*6236dae4SAndroid Build Coastguard Worker 47*6236dae4SAndroid Build Coastguard Worker @property 48*6236dae4SAndroid Build Coastguard Worker def path(self): 49*6236dae4SAndroid Build Coastguard Worker return self._uds_path 50*6236dae4SAndroid Build Coastguard Worker 51*6236dae4SAndroid Build Coastguard Worker def start(self): 52*6236dae4SAndroid Build Coastguard Worker def process(self): 53*6236dae4SAndroid Build Coastguard Worker self._socket.listen(1) 54*6236dae4SAndroid Build Coastguard Worker self._process() 55*6236dae4SAndroid Build Coastguard Worker 56*6236dae4SAndroid Build Coastguard Worker try: 57*6236dae4SAndroid Build Coastguard Worker os.unlink(self._uds_path) 58*6236dae4SAndroid Build Coastguard Worker except OSError: 59*6236dae4SAndroid Build Coastguard Worker if os.path.exists(self._uds_path): 60*6236dae4SAndroid Build Coastguard Worker raise 61*6236dae4SAndroid Build Coastguard Worker self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 62*6236dae4SAndroid Build Coastguard Worker self._socket.bind(self._uds_path) 63*6236dae4SAndroid Build Coastguard Worker self._thread = Thread(target=process, daemon=True, args=[self]) 64*6236dae4SAndroid Build Coastguard Worker self._thread.start() 65*6236dae4SAndroid Build Coastguard Worker 66*6236dae4SAndroid Build Coastguard Worker def stop(self): 67*6236dae4SAndroid Build Coastguard Worker self._done = True 68*6236dae4SAndroid Build Coastguard Worker self._socket.close() 69*6236dae4SAndroid Build Coastguard Worker 70*6236dae4SAndroid Build Coastguard Worker def _process(self): 71*6236dae4SAndroid Build Coastguard Worker while self._done is False: 72*6236dae4SAndroid Build Coastguard Worker try: 73*6236dae4SAndroid Build Coastguard Worker c, client_address = self._socket.accept() 74*6236dae4SAndroid Build Coastguard Worker try: 75*6236dae4SAndroid Build Coastguard Worker c.recv(16) 76*6236dae4SAndroid Build Coastguard Worker c.sendall("""HTTP/1.1 200 Ok 77*6236dae4SAndroid Build Coastguard WorkerServer: UdsFaker 78*6236dae4SAndroid Build Coastguard WorkerContent-Type: application/json 79*6236dae4SAndroid Build Coastguard WorkerContent-Length: 19 80*6236dae4SAndroid Build Coastguard Worker 81*6236dae4SAndroid Build Coastguard Worker{ "host": "faked" }""".encode()) 82*6236dae4SAndroid Build Coastguard Worker finally: 83*6236dae4SAndroid Build Coastguard Worker c.close() 84*6236dae4SAndroid Build Coastguard Worker 85*6236dae4SAndroid Build Coastguard Worker except ConnectionAbortedError: 86*6236dae4SAndroid Build Coastguard Worker self._done = True 87*6236dae4SAndroid Build Coastguard Worker except OSError: 88*6236dae4SAndroid Build Coastguard Worker self._done = True 89*6236dae4SAndroid Build Coastguard Worker 90*6236dae4SAndroid Build Coastguard Worker 91*6236dae4SAndroid Build Coastguard Workerclass TestUnix: 92*6236dae4SAndroid Build Coastguard Worker 93*6236dae4SAndroid Build Coastguard Worker @pytest.fixture(scope="class") 94*6236dae4SAndroid Build Coastguard Worker def uds_faker(self, env: Env) -> Generator[UDSFaker, None, None]: 95*6236dae4SAndroid Build Coastguard Worker uds_path = os.path.join(env.gen_dir, 'uds_11.sock') 96*6236dae4SAndroid Build Coastguard Worker faker = UDSFaker(path=uds_path) 97*6236dae4SAndroid Build Coastguard Worker faker.start() 98*6236dae4SAndroid Build Coastguard Worker yield faker 99*6236dae4SAndroid Build Coastguard Worker faker.stop() 100*6236dae4SAndroid Build Coastguard Worker 101*6236dae4SAndroid Build Coastguard Worker # download http: via Unix socket 102*6236dae4SAndroid Build Coastguard Worker def test_11_01_unix_connect_http(self, env: Env, httpd, uds_faker, repeat): 103*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 104*6236dae4SAndroid Build Coastguard Worker url = f'http://{env.domain1}:{env.http_port}/data.json' 105*6236dae4SAndroid Build Coastguard Worker r = curl.http_download(urls=[url], with_stats=True, 106*6236dae4SAndroid Build Coastguard Worker extra_args=[ 107*6236dae4SAndroid Build Coastguard Worker '--unix-socket', uds_faker.path, 108*6236dae4SAndroid Build Coastguard Worker ]) 109*6236dae4SAndroid Build Coastguard Worker r.check_response(count=1, http_status=200) 110*6236dae4SAndroid Build Coastguard Worker 111*6236dae4SAndroid Build Coastguard Worker # download https: via Unix socket 112*6236dae4SAndroid Build Coastguard Worker @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") 113*6236dae4SAndroid Build Coastguard Worker def test_11_02_unix_connect_http(self, env: Env, httpd, uds_faker, repeat): 114*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 115*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.domain1}:{env.https_port}/data.json' 116*6236dae4SAndroid Build Coastguard Worker r = curl.http_download(urls=[url], with_stats=True, 117*6236dae4SAndroid Build Coastguard Worker extra_args=[ 118*6236dae4SAndroid Build Coastguard Worker '--unix-socket', uds_faker.path, 119*6236dae4SAndroid Build Coastguard Worker ]) 120*6236dae4SAndroid Build Coastguard Worker r.check_response(exitcode=35, http_status=None) 121*6236dae4SAndroid Build Coastguard Worker 122*6236dae4SAndroid Build Coastguard Worker # download HTTP/3 via Unix socket 123*6236dae4SAndroid Build Coastguard Worker @pytest.mark.skipif(condition=not Env.have_h3(), reason='h3 not supported') 124*6236dae4SAndroid Build Coastguard Worker def test_11_03_unix_connect_quic(self, env: Env, httpd, uds_faker, repeat): 125*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 126*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.domain1}:{env.https_port}/data.json' 127*6236dae4SAndroid Build Coastguard Worker r = curl.http_download(urls=[url], with_stats=True, 128*6236dae4SAndroid Build Coastguard Worker alpn_proto='h3', 129*6236dae4SAndroid Build Coastguard Worker extra_args=[ 130*6236dae4SAndroid Build Coastguard Worker '--unix-socket', uds_faker.path, 131*6236dae4SAndroid Build Coastguard Worker ]) 132*6236dae4SAndroid Build Coastguard Worker r.check_response(exitcode=96, http_status=None) 133