xref: /aosp_15_r20/external/curl/tests/http/test_11_unix.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 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