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 difflib 28*6236dae4SAndroid Build Coastguard Workerimport filecmp 29*6236dae4SAndroid Build Coastguard Workerimport logging 30*6236dae4SAndroid Build Coastguard Workerimport os 31*6236dae4SAndroid Build Coastguard Workerimport re 32*6236dae4SAndroid Build Coastguard Workerimport pytest 33*6236dae4SAndroid Build Coastguard Workerfrom typing import List 34*6236dae4SAndroid Build Coastguard Worker 35*6236dae4SAndroid Build Coastguard Workerfrom testenv import Env, CurlClient, LocalClient 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 Worker 41*6236dae4SAndroid Build Coastguard Workerclass TestUpload: 42*6236dae4SAndroid Build Coastguard Worker 43*6236dae4SAndroid Build Coastguard Worker @pytest.fixture(autouse=True, scope='class') 44*6236dae4SAndroid Build Coastguard Worker def _class_scope(self, env, httpd, nghttpx): 45*6236dae4SAndroid Build Coastguard Worker if env.have_h3(): 46*6236dae4SAndroid Build Coastguard Worker nghttpx.start_if_needed() 47*6236dae4SAndroid Build Coastguard Worker env.make_data_file(indir=env.gen_dir, fname="data-10k", fsize=10*1024) 48*6236dae4SAndroid Build Coastguard Worker env.make_data_file(indir=env.gen_dir, fname="data-63k", fsize=63*1024) 49*6236dae4SAndroid Build Coastguard Worker env.make_data_file(indir=env.gen_dir, fname="data-64k", fsize=64*1024) 50*6236dae4SAndroid Build Coastguard Worker env.make_data_file(indir=env.gen_dir, fname="data-100k", fsize=100*1024) 51*6236dae4SAndroid Build Coastguard Worker env.make_data_file(indir=env.gen_dir, fname="data-1m+", fsize=(1024*1024)+1) 52*6236dae4SAndroid Build Coastguard Worker env.make_data_file(indir=env.gen_dir, fname="data-10m", fsize=10*1024*1024) 53*6236dae4SAndroid Build Coastguard Worker httpd.clear_extra_configs() 54*6236dae4SAndroid Build Coastguard Worker httpd.reload() 55*6236dae4SAndroid Build Coastguard Worker 56*6236dae4SAndroid Build Coastguard Worker # upload small data, check that this is what was echoed 57*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 58*6236dae4SAndroid Build Coastguard Worker def test_07_01_upload_1_small(self, env: Env, httpd, nghttpx, repeat, proto): 59*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 60*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 61*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 62*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 63*6236dae4SAndroid Build Coastguard Worker data = '0123456789' 64*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 65*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' 66*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=data, alpn_proto=proto) 67*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=1, http_status=200, exitcode=0) 68*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(0)).readlines() 69*6236dae4SAndroid Build Coastguard Worker assert respdata == [data] 70*6236dae4SAndroid Build Coastguard Worker 71*6236dae4SAndroid Build Coastguard Worker # upload large data, check that this is what was echoed 72*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 73*6236dae4SAndroid Build Coastguard Worker def test_07_02_upload_1_large(self, env: Env, httpd, nghttpx, repeat, proto): 74*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 75*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 76*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 77*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 78*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-100k') 79*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 80*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' 81*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto) 82*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=1, http_status=200, exitcode=0) 83*6236dae4SAndroid Build Coastguard Worker indata = open(fdata).readlines() 84*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(0)).readlines() 85*6236dae4SAndroid Build Coastguard Worker assert respdata == indata 86*6236dae4SAndroid Build Coastguard Worker 87*6236dae4SAndroid Build Coastguard Worker # upload data sequentially, check that they were echoed 88*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 89*6236dae4SAndroid Build Coastguard Worker def test_07_10_upload_sequential(self, env: Env, httpd, nghttpx, repeat, proto): 90*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 91*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 92*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 93*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 stalls here") 94*6236dae4SAndroid Build Coastguard Worker count = 20 95*6236dae4SAndroid Build Coastguard Worker data = '0123456789' 96*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 97*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' 98*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=data, alpn_proto=proto) 99*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 100*6236dae4SAndroid Build Coastguard Worker for i in range(count): 101*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(i)).readlines() 102*6236dae4SAndroid Build Coastguard Worker assert respdata == [data] 103*6236dae4SAndroid Build Coastguard Worker 104*6236dae4SAndroid Build Coastguard Worker # upload data parallel, check that they were echoed 105*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['h2', 'h3']) 106*6236dae4SAndroid Build Coastguard Worker def test_07_11_upload_parallel(self, env: Env, httpd, nghttpx, repeat, proto): 107*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 108*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 109*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 110*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 stalls here") 111*6236dae4SAndroid Build Coastguard Worker # limit since we use a separate connection in h1 112*6236dae4SAndroid Build Coastguard Worker count = 20 113*6236dae4SAndroid Build Coastguard Worker data = '0123456789' 114*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 115*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' 116*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=data, alpn_proto=proto, 117*6236dae4SAndroid Build Coastguard Worker extra_args=['--parallel']) 118*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 119*6236dae4SAndroid Build Coastguard Worker for i in range(count): 120*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(i)).readlines() 121*6236dae4SAndroid Build Coastguard Worker assert respdata == [data] 122*6236dae4SAndroid Build Coastguard Worker 123*6236dae4SAndroid Build Coastguard Worker # upload large data sequentially, check that this is what was echoed 124*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 125*6236dae4SAndroid Build Coastguard Worker def test_07_12_upload_seq_large(self, env: Env, httpd, nghttpx, repeat, proto): 126*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 127*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 128*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 129*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 stalls here") 130*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-100k') 131*6236dae4SAndroid Build Coastguard Worker count = 10 132*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 133*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' 134*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto) 135*6236dae4SAndroid Build Coastguard Worker r.check_response(count=count, http_status=200) 136*6236dae4SAndroid Build Coastguard Worker indata = open(fdata).readlines() 137*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 138*6236dae4SAndroid Build Coastguard Worker for i in range(count): 139*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(i)).readlines() 140*6236dae4SAndroid Build Coastguard Worker assert respdata == indata 141*6236dae4SAndroid Build Coastguard Worker 142*6236dae4SAndroid Build Coastguard Worker # upload very large data sequentially, check that this is what was echoed 143*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 144*6236dae4SAndroid Build Coastguard Worker def test_07_13_upload_seq_large(self, env: Env, httpd, nghttpx, repeat, proto): 145*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 146*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 147*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 148*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 stalls here") 149*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-10m') 150*6236dae4SAndroid Build Coastguard Worker count = 2 151*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 152*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' 153*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto) 154*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 155*6236dae4SAndroid Build Coastguard Worker indata = open(fdata).readlines() 156*6236dae4SAndroid Build Coastguard Worker for i in range(count): 157*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(i)).readlines() 158*6236dae4SAndroid Build Coastguard Worker assert respdata == indata 159*6236dae4SAndroid Build Coastguard Worker 160*6236dae4SAndroid Build Coastguard Worker # upload from stdin, issue #14870 161*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 162*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("indata", [ 163*6236dae4SAndroid Build Coastguard Worker '', '1', '123\n456andsomething\n\n' 164*6236dae4SAndroid Build Coastguard Worker ]) 165*6236dae4SAndroid Build Coastguard Worker def test_07_14_upload_stdin(self, env: Env, httpd, nghttpx, proto, indata): 166*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 167*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 168*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 169*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 stalls here") 170*6236dae4SAndroid Build Coastguard Worker count = 1 171*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 172*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-{count-1}]' 173*6236dae4SAndroid Build Coastguard Worker r = curl.http_put(urls=[url], data=indata, alpn_proto=proto) 174*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 175*6236dae4SAndroid Build Coastguard Worker for i in range(count): 176*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(i)).readlines() 177*6236dae4SAndroid Build Coastguard Worker assert respdata == [f'{len(indata)}'] 178*6236dae4SAndroid Build Coastguard Worker 179*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 180*6236dae4SAndroid Build Coastguard Worker def test_07_15_hx_put(self, env: Env, httpd, nghttpx, proto): 181*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 182*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 183*6236dae4SAndroid Build Coastguard Worker count = 2 184*6236dae4SAndroid Build Coastguard Worker upload_size = 128*1024 185*6236dae4SAndroid Build Coastguard Worker url = f'https://localhost:{env.https_port}/curltest/put?id=[0-{count-1}]' 186*6236dae4SAndroid Build Coastguard Worker client = LocalClient(name='hx-upload', env=env) 187*6236dae4SAndroid Build Coastguard Worker if not client.exists(): 188*6236dae4SAndroid Build Coastguard Worker pytest.skip(f'example client not built: {client.name}') 189*6236dae4SAndroid Build Coastguard Worker r = client.run(args=[ 190*6236dae4SAndroid Build Coastguard Worker '-n', f'{count}', '-S', f'{upload_size}', '-V', proto, url 191*6236dae4SAndroid Build Coastguard Worker ]) 192*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(0) 193*6236dae4SAndroid Build Coastguard Worker self.check_downloads(client, [f"{upload_size}"], count) 194*6236dae4SAndroid Build Coastguard Worker 195*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 196*6236dae4SAndroid Build Coastguard Worker def test_07_16_hx_put_reuse(self, env: Env, httpd, nghttpx, proto): 197*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 198*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 199*6236dae4SAndroid Build Coastguard Worker count = 2 200*6236dae4SAndroid Build Coastguard Worker upload_size = 128*1024 201*6236dae4SAndroid Build Coastguard Worker url = f'https://localhost:{env.https_port}/curltest/put?id=[0-{count-1}]' 202*6236dae4SAndroid Build Coastguard Worker client = LocalClient(name='hx-upload', env=env) 203*6236dae4SAndroid Build Coastguard Worker if not client.exists(): 204*6236dae4SAndroid Build Coastguard Worker pytest.skip(f'example client not built: {client.name}') 205*6236dae4SAndroid Build Coastguard Worker r = client.run(args=[ 206*6236dae4SAndroid Build Coastguard Worker '-n', f'{count}', '-S', f'{upload_size}', '-R', '-V', proto, url 207*6236dae4SAndroid Build Coastguard Worker ]) 208*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(0) 209*6236dae4SAndroid Build Coastguard Worker self.check_downloads(client, [f"{upload_size}"], count) 210*6236dae4SAndroid Build Coastguard Worker 211*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 212*6236dae4SAndroid Build Coastguard Worker def test_07_17_hx_post_reuse(self, env: Env, httpd, nghttpx, proto): 213*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 214*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 215*6236dae4SAndroid Build Coastguard Worker count = 2 216*6236dae4SAndroid Build Coastguard Worker upload_size = 128*1024 217*6236dae4SAndroid Build Coastguard Worker url = f'https://localhost:{env.https_port}/curltest/echo?id=[0-{count-1}]' 218*6236dae4SAndroid Build Coastguard Worker client = LocalClient(name='hx-upload', env=env) 219*6236dae4SAndroid Build Coastguard Worker if not client.exists(): 220*6236dae4SAndroid Build Coastguard Worker pytest.skip(f'example client not built: {client.name}') 221*6236dae4SAndroid Build Coastguard Worker r = client.run(args=[ 222*6236dae4SAndroid Build Coastguard Worker '-n', f'{count}', '-M', 'POST', '-S', f'{upload_size}', '-R', '-V', proto, url 223*6236dae4SAndroid Build Coastguard Worker ]) 224*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(0) 225*6236dae4SAndroid Build Coastguard Worker self.check_downloads(client, ["x" * upload_size], count) 226*6236dae4SAndroid Build Coastguard Worker 227*6236dae4SAndroid Build Coastguard Worker # upload data parallel, check that they were echoed 228*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['h2', 'h3']) 229*6236dae4SAndroid Build Coastguard Worker def test_07_20_upload_parallel(self, env: Env, httpd, nghttpx, repeat, proto): 230*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 231*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 232*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 233*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 stalls here") 234*6236dae4SAndroid Build Coastguard Worker # limit since we use a separate connection in h1 235*6236dae4SAndroid Build Coastguard Worker count = 10 236*6236dae4SAndroid Build Coastguard Worker data = '0123456789' 237*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 238*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' 239*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=data, alpn_proto=proto, 240*6236dae4SAndroid Build Coastguard Worker extra_args=['--parallel']) 241*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 242*6236dae4SAndroid Build Coastguard Worker for i in range(count): 243*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(i)).readlines() 244*6236dae4SAndroid Build Coastguard Worker assert respdata == [data] 245*6236dae4SAndroid Build Coastguard Worker 246*6236dae4SAndroid Build Coastguard Worker # upload large data parallel, check that this is what was echoed 247*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['h2', 'h3']) 248*6236dae4SAndroid Build Coastguard Worker def test_07_21_upload_parallel_large(self, env: Env, httpd, nghttpx, repeat, proto): 249*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 250*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 251*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 252*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 stalls here") 253*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-100k') 254*6236dae4SAndroid Build Coastguard Worker # limit since we use a separate connection in h1 255*6236dae4SAndroid Build Coastguard Worker count = 10 256*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 257*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' 258*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, 259*6236dae4SAndroid Build Coastguard Worker extra_args=['--parallel']) 260*6236dae4SAndroid Build Coastguard Worker r.check_response(count=count, http_status=200) 261*6236dae4SAndroid Build Coastguard Worker self.check_download(count, fdata, curl) 262*6236dae4SAndroid Build Coastguard Worker 263*6236dae4SAndroid Build Coastguard Worker # upload large data parallel to a URL that denies uploads 264*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['h2', 'h3']) 265*6236dae4SAndroid Build Coastguard Worker def test_07_22_upload_parallel_fail(self, env: Env, httpd, nghttpx, repeat, proto): 266*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 267*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 268*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 269*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 stalls here") 270*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-10m') 271*6236dae4SAndroid Build Coastguard Worker count = 20 272*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 273*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}'\ 274*6236dae4SAndroid Build Coastguard Worker f'/curltest/tweak?status=400&delay=5ms&chunks=1&body_error=reset&id=[0-{count-1}]' 275*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, 276*6236dae4SAndroid Build Coastguard Worker extra_args=['--parallel']) 277*6236dae4SAndroid Build Coastguard Worker exp_exit = 92 if proto == 'h2' else 95 278*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, exitcode=exp_exit) 279*6236dae4SAndroid Build Coastguard Worker 280*6236dae4SAndroid Build Coastguard Worker # PUT 100k 281*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 282*6236dae4SAndroid Build Coastguard Worker def test_07_30_put_100k(self, env: Env, httpd, nghttpx, repeat, proto): 283*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 284*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 285*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 286*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 287*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-100k') 288*6236dae4SAndroid Build Coastguard Worker count = 1 289*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 290*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-{count-1}]' 291*6236dae4SAndroid Build Coastguard Worker r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, 292*6236dae4SAndroid Build Coastguard Worker extra_args=['--parallel']) 293*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 294*6236dae4SAndroid Build Coastguard Worker exp_data = [f'{os.path.getsize(fdata)}'] 295*6236dae4SAndroid Build Coastguard Worker r.check_response(count=count, http_status=200) 296*6236dae4SAndroid Build Coastguard Worker for i in range(count): 297*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(i)).readlines() 298*6236dae4SAndroid Build Coastguard Worker assert respdata == exp_data 299*6236dae4SAndroid Build Coastguard Worker 300*6236dae4SAndroid Build Coastguard Worker # PUT 10m 301*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 302*6236dae4SAndroid Build Coastguard Worker def test_07_31_put_10m(self, env: Env, httpd, nghttpx, repeat, proto): 303*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 304*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 305*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 306*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 307*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-10m') 308*6236dae4SAndroid Build Coastguard Worker count = 1 309*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 310*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-{count-1}]&chunk_delay=2ms' 311*6236dae4SAndroid Build Coastguard Worker r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, 312*6236dae4SAndroid Build Coastguard Worker extra_args=['--parallel']) 313*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 314*6236dae4SAndroid Build Coastguard Worker exp_data = [f'{os.path.getsize(fdata)}'] 315*6236dae4SAndroid Build Coastguard Worker r.check_response(count=count, http_status=200) 316*6236dae4SAndroid Build Coastguard Worker for i in range(count): 317*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(i)).readlines() 318*6236dae4SAndroid Build Coastguard Worker assert respdata == exp_data 319*6236dae4SAndroid Build Coastguard Worker 320*6236dae4SAndroid Build Coastguard Worker # issue #10591 321*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 322*6236dae4SAndroid Build Coastguard Worker def test_07_32_issue_10591(self, env: Env, httpd, nghttpx, repeat, proto): 323*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 324*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 325*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 326*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 327*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-10m') 328*6236dae4SAndroid Build Coastguard Worker count = 1 329*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 330*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-{count-1}]' 331*6236dae4SAndroid Build Coastguard Worker r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto) 332*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=200, exitcode=0) 333*6236dae4SAndroid Build Coastguard Worker 334*6236dae4SAndroid Build Coastguard Worker # issue #11157, upload that is 404'ed by server, needs to terminate 335*6236dae4SAndroid Build Coastguard Worker # correctly and not time out on sending 336*6236dae4SAndroid Build Coastguard Worker def test_07_33_issue_11157a(self, env: Env, httpd, nghttpx, repeat): 337*6236dae4SAndroid Build Coastguard Worker proto = 'h2' 338*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-10m') 339*6236dae4SAndroid Build Coastguard Worker # send a POST to our PUT handler which will send immediately a 404 back 340*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put' 341*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 342*6236dae4SAndroid Build Coastguard Worker r = curl.run_direct(with_stats=True, args=[ 343*6236dae4SAndroid Build Coastguard Worker '--resolve', f'{env.authority_for(env.domain1, proto)}:127.0.0.1', 344*6236dae4SAndroid Build Coastguard Worker '--cacert', env.ca.cert_file, 345*6236dae4SAndroid Build Coastguard Worker '--request', 'POST', 346*6236dae4SAndroid Build Coastguard Worker '--max-time', '5', '-v', 347*6236dae4SAndroid Build Coastguard Worker '--url', url, 348*6236dae4SAndroid Build Coastguard Worker '--form', 'idList=12345678', 349*6236dae4SAndroid Build Coastguard Worker '--form', 'pos=top', 350*6236dae4SAndroid Build Coastguard Worker '--form', 'name=mr_test', 351*6236dae4SAndroid Build Coastguard Worker '--form', f'fileSource=@{fdata};type=application/pdf', 352*6236dae4SAndroid Build Coastguard Worker ]) 353*6236dae4SAndroid Build Coastguard Worker assert r.exit_code == 0, f'{r}' 354*6236dae4SAndroid Build Coastguard Worker r.check_stats(1, 404) 355*6236dae4SAndroid Build Coastguard Worker 356*6236dae4SAndroid Build Coastguard Worker # issue #11157, send upload that is slowly read in 357*6236dae4SAndroid Build Coastguard Worker def test_07_33_issue_11157b(self, env: Env, httpd, nghttpx, repeat): 358*6236dae4SAndroid Build Coastguard Worker proto = 'h2' 359*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-10m') 360*6236dae4SAndroid Build Coastguard Worker # tell our test PUT handler to read the upload more slowly, so 361*6236dae4SAndroid Build Coastguard Worker # that the send buffering and transfer loop needs to wait 362*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?chunk_delay=2ms' 363*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 364*6236dae4SAndroid Build Coastguard Worker r = curl.run_direct(with_stats=True, args=[ 365*6236dae4SAndroid Build Coastguard Worker '--verbose', '--trace-config', 'ids,time', 366*6236dae4SAndroid Build Coastguard Worker '--resolve', f'{env.authority_for(env.domain1, proto)}:127.0.0.1', 367*6236dae4SAndroid Build Coastguard Worker '--cacert', env.ca.cert_file, 368*6236dae4SAndroid Build Coastguard Worker '--request', 'PUT', 369*6236dae4SAndroid Build Coastguard Worker '--max-time', '10', '-v', 370*6236dae4SAndroid Build Coastguard Worker '--url', url, 371*6236dae4SAndroid Build Coastguard Worker '--form', 'idList=12345678', 372*6236dae4SAndroid Build Coastguard Worker '--form', 'pos=top', 373*6236dae4SAndroid Build Coastguard Worker '--form', 'name=mr_test', 374*6236dae4SAndroid Build Coastguard Worker '--form', f'fileSource=@{fdata};type=application/pdf', 375*6236dae4SAndroid Build Coastguard Worker ]) 376*6236dae4SAndroid Build Coastguard Worker assert r.exit_code == 0, r.dump_logs() 377*6236dae4SAndroid Build Coastguard Worker r.check_stats(1, 200) 378*6236dae4SAndroid Build Coastguard Worker 379*6236dae4SAndroid Build Coastguard Worker def test_07_34_issue_11194(self, env: Env, httpd, nghttpx, repeat): 380*6236dae4SAndroid Build Coastguard Worker proto = 'h2' 381*6236dae4SAndroid Build Coastguard Worker # tell our test PUT handler to read the upload more slowly, so 382*6236dae4SAndroid Build Coastguard Worker # that the send buffering and transfer loop needs to wait 383*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-100k') 384*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put' 385*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 386*6236dae4SAndroid Build Coastguard Worker r = curl.run_direct(with_stats=True, args=[ 387*6236dae4SAndroid Build Coastguard Worker '--verbose', '--trace-config', 'ids,time', 388*6236dae4SAndroid Build Coastguard Worker '--resolve', f'{env.authority_for(env.domain1, proto)}:127.0.0.1', 389*6236dae4SAndroid Build Coastguard Worker '--cacert', env.ca.cert_file, 390*6236dae4SAndroid Build Coastguard Worker '--request', 'PUT', 391*6236dae4SAndroid Build Coastguard Worker '--digest', '--user', 'test:test', 392*6236dae4SAndroid Build Coastguard Worker '--data-binary', f'@{fdata}', 393*6236dae4SAndroid Build Coastguard Worker '--url', url, 394*6236dae4SAndroid Build Coastguard Worker ]) 395*6236dae4SAndroid Build Coastguard Worker assert r.exit_code == 0, r.dump_logs() 396*6236dae4SAndroid Build Coastguard Worker r.check_stats(1, 200) 397*6236dae4SAndroid Build Coastguard Worker 398*6236dae4SAndroid Build Coastguard Worker # upload large data on a h1 to h2 upgrade 399*6236dae4SAndroid Build Coastguard Worker def test_07_35_h1_h2_upgrade_upload(self, env: Env, httpd, nghttpx, repeat): 400*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-100k') 401*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 402*6236dae4SAndroid Build Coastguard Worker url = f'http://{env.domain1}:{env.http_port}/curltest/echo?id=[0-0]' 403*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', extra_args=[ 404*6236dae4SAndroid Build Coastguard Worker '--http2' 405*6236dae4SAndroid Build Coastguard Worker ]) 406*6236dae4SAndroid Build Coastguard Worker r.check_response(count=1, http_status=200) 407*6236dae4SAndroid Build Coastguard Worker # apache does not Upgrade on request with a body 408*6236dae4SAndroid Build Coastguard Worker assert r.stats[0]['http_version'] == '1.1', f'{r}' 409*6236dae4SAndroid Build Coastguard Worker indata = open(fdata).readlines() 410*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(0)).readlines() 411*6236dae4SAndroid Build Coastguard Worker assert respdata == indata 412*6236dae4SAndroid Build Coastguard Worker 413*6236dae4SAndroid Build Coastguard Worker # upload to a 301,302,303 response 414*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("redir", ['301', '302', '303']) 415*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 416*6236dae4SAndroid Build Coastguard Worker def test_07_36_upload_30x(self, env: Env, httpd, nghttpx, repeat, redir, proto): 417*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 418*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 419*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 420*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 421*6236dae4SAndroid Build Coastguard Worker data = '0123456789' * 10 422*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 423*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo{redir}?id=[0-0]' 424*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=data, alpn_proto=proto, extra_args=[ 425*6236dae4SAndroid Build Coastguard Worker '-L', '--trace-config', 'http/2,http/3' 426*6236dae4SAndroid Build Coastguard Worker ]) 427*6236dae4SAndroid Build Coastguard Worker r.check_response(count=1, http_status=200) 428*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(0)).readlines() 429*6236dae4SAndroid Build Coastguard Worker assert respdata == [] # was transformed to a GET 430*6236dae4SAndroid Build Coastguard Worker 431*6236dae4SAndroid Build Coastguard Worker # upload to a 307 response 432*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 433*6236dae4SAndroid Build Coastguard Worker def test_07_37_upload_307(self, env: Env, httpd, nghttpx, repeat, proto): 434*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 435*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 436*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 437*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 438*6236dae4SAndroid Build Coastguard Worker data = '0123456789' * 10 439*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 440*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo307?id=[0-0]' 441*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=data, alpn_proto=proto, extra_args=[ 442*6236dae4SAndroid Build Coastguard Worker '-L', '--trace-config', 'http/2,http/3' 443*6236dae4SAndroid Build Coastguard Worker ]) 444*6236dae4SAndroid Build Coastguard Worker r.check_response(count=1, http_status=200) 445*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(0)).readlines() 446*6236dae4SAndroid Build Coastguard Worker assert respdata == [data] # was POST again 447*6236dae4SAndroid Build Coastguard Worker 448*6236dae4SAndroid Build Coastguard Worker # POST form data, yet another code path in transfer 449*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 450*6236dae4SAndroid Build Coastguard Worker def test_07_38_form_small(self, env: Env, httpd, nghttpx, repeat, proto): 451*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 452*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 453*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 454*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 455*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 456*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' 457*6236dae4SAndroid Build Coastguard Worker r = curl.http_form(urls=[url], alpn_proto=proto, form={ 458*6236dae4SAndroid Build Coastguard Worker 'name1': 'value1', 459*6236dae4SAndroid Build Coastguard Worker }) 460*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=1, http_status=200, exitcode=0) 461*6236dae4SAndroid Build Coastguard Worker 462*6236dae4SAndroid Build Coastguard Worker # POST data urlencoded, small enough to be sent with request headers 463*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 464*6236dae4SAndroid Build Coastguard Worker def test_07_39_post_urlenc_small(self, env: Env, httpd, nghttpx, repeat, proto): 465*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 466*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 467*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 468*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 469*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-63k') 470*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 471*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' 472*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, extra_args=[ 473*6236dae4SAndroid Build Coastguard Worker '--trace-config', 'http/2,http/3' 474*6236dae4SAndroid Build Coastguard Worker ]) 475*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=1, http_status=200, exitcode=0) 476*6236dae4SAndroid Build Coastguard Worker indata = open(fdata).readlines() 477*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(0)).readlines() 478*6236dae4SAndroid Build Coastguard Worker assert respdata == indata 479*6236dae4SAndroid Build Coastguard Worker 480*6236dae4SAndroid Build Coastguard Worker # POST data urlencoded, large enough to be sent separate from request headers 481*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 482*6236dae4SAndroid Build Coastguard Worker def test_07_40_post_urlenc_large(self, env: Env, httpd, nghttpx, repeat, proto): 483*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 484*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 485*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 486*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 487*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-64k') 488*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 489*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' 490*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, extra_args=[ 491*6236dae4SAndroid Build Coastguard Worker '--trace-config', 'http/2,http/3' 492*6236dae4SAndroid Build Coastguard Worker ]) 493*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=1, http_status=200, exitcode=0) 494*6236dae4SAndroid Build Coastguard Worker indata = open(fdata).readlines() 495*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(0)).readlines() 496*6236dae4SAndroid Build Coastguard Worker assert respdata == indata 497*6236dae4SAndroid Build Coastguard Worker 498*6236dae4SAndroid Build Coastguard Worker # POST data urlencoded, small enough to be sent with request headers 499*6236dae4SAndroid Build Coastguard Worker # and request headers are so large that the first send is larger 500*6236dae4SAndroid Build Coastguard Worker # than our default upload buffer length (64KB). 501*6236dae4SAndroid Build Coastguard Worker # Unfixed, this will fail when run with CURL_DBG_SOCK_WBLOCK=80 most 502*6236dae4SAndroid Build Coastguard Worker # of the time 503*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 504*6236dae4SAndroid Build Coastguard Worker def test_07_41_post_urlenc_small(self, env: Env, httpd, nghttpx, repeat, proto): 505*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 506*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 507*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 508*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 509*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('quiche'): 510*6236dae4SAndroid Build Coastguard Worker pytest.skip("quiche has CWND issues with large requests") 511*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-63k') 512*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 513*6236dae4SAndroid Build Coastguard Worker extra_args = ['--trace-config', 'http/2,http/3'] 514*6236dae4SAndroid Build Coastguard Worker # add enough headers so that the first send chunk is > 64KB 515*6236dae4SAndroid Build Coastguard Worker for i in range(63): 516*6236dae4SAndroid Build Coastguard Worker extra_args.extend(['-H', f'x{i:02d}: {"y"*1019}']) 517*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' 518*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, extra_args=extra_args) 519*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=1, http_status=200, exitcode=0) 520*6236dae4SAndroid Build Coastguard Worker indata = open(fdata).readlines() 521*6236dae4SAndroid Build Coastguard Worker respdata = open(curl.response_file(0)).readlines() 522*6236dae4SAndroid Build Coastguard Worker assert respdata == indata 523*6236dae4SAndroid Build Coastguard Worker 524*6236dae4SAndroid Build Coastguard Worker def check_download(self, count, srcfile, curl): 525*6236dae4SAndroid Build Coastguard Worker for i in range(count): 526*6236dae4SAndroid Build Coastguard Worker dfile = curl.download_file(i) 527*6236dae4SAndroid Build Coastguard Worker assert os.path.exists(dfile) 528*6236dae4SAndroid Build Coastguard Worker if not filecmp.cmp(srcfile, dfile, shallow=False): 529*6236dae4SAndroid Build Coastguard Worker diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(), 530*6236dae4SAndroid Build Coastguard Worker b=open(dfile).readlines(), 531*6236dae4SAndroid Build Coastguard Worker fromfile=srcfile, 532*6236dae4SAndroid Build Coastguard Worker tofile=dfile, 533*6236dae4SAndroid Build Coastguard Worker n=1)) 534*6236dae4SAndroid Build Coastguard Worker assert False, f'download {dfile} differs:\n{diff}' 535*6236dae4SAndroid Build Coastguard Worker 536*6236dae4SAndroid Build Coastguard Worker # upload data, pause, let connection die with an incomplete response 537*6236dae4SAndroid Build Coastguard Worker # issues #11769 #13260 538*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 539*6236dae4SAndroid Build Coastguard Worker def test_07_42a_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto): 540*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 541*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 542*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 543*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 544*6236dae4SAndroid Build Coastguard Worker client = LocalClient(name='upload-pausing', env=env, timeout=60) 545*6236dae4SAndroid Build Coastguard Worker if not client.exists(): 546*6236dae4SAndroid Build Coastguard Worker pytest.skip(f'example client not built: {client.name}') 547*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]&die_after=0' 548*6236dae4SAndroid Build Coastguard Worker r = client.run(['-V', proto, url]) 549*6236dae4SAndroid Build Coastguard Worker if r.exit_code == 18: # PARTIAL_FILE is always ok 550*6236dae4SAndroid Build Coastguard Worker pass 551*6236dae4SAndroid Build Coastguard Worker elif proto == 'h2': 552*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(92) # CURLE_HTTP2_STREAM also ok 553*6236dae4SAndroid Build Coastguard Worker elif proto == 'h3': 554*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(95) # CURLE_HTTP3 also ok 555*6236dae4SAndroid Build Coastguard Worker else: 556*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(18) # will fail as it should 557*6236dae4SAndroid Build Coastguard Worker 558*6236dae4SAndroid Build Coastguard Worker # upload data, pause, let connection die without any response at all 559*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 560*6236dae4SAndroid Build Coastguard Worker def test_07_42b_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto): 561*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 562*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 563*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 564*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 565*6236dae4SAndroid Build Coastguard Worker client = LocalClient(name='upload-pausing', env=env, timeout=60) 566*6236dae4SAndroid Build Coastguard Worker if not client.exists(): 567*6236dae4SAndroid Build Coastguard Worker pytest.skip(f'example client not built: {client.name}') 568*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]&just_die=1' 569*6236dae4SAndroid Build Coastguard Worker r = client.run(['-V', proto, url]) 570*6236dae4SAndroid Build Coastguard Worker exp_code = 52 # GOT_NOTHING 571*6236dae4SAndroid Build Coastguard Worker if proto == 'h2' or proto == 'h3': 572*6236dae4SAndroid Build Coastguard Worker exp_code = 0 # we get a 500 from the server 573*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(exp_code) # GOT_NOTHING 574*6236dae4SAndroid Build Coastguard Worker 575*6236dae4SAndroid Build Coastguard Worker # upload data, pause, let connection die after 100 continue 576*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 577*6236dae4SAndroid Build Coastguard Worker def test_07_42c_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto): 578*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 579*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 580*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 581*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 582*6236dae4SAndroid Build Coastguard Worker client = LocalClient(name='upload-pausing', env=env, timeout=60) 583*6236dae4SAndroid Build Coastguard Worker if not client.exists(): 584*6236dae4SAndroid Build Coastguard Worker pytest.skip(f'example client not built: {client.name}') 585*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]&die_after_100=1' 586*6236dae4SAndroid Build Coastguard Worker r = client.run(['-V', proto, url]) 587*6236dae4SAndroid Build Coastguard Worker exp_code = 52 # GOT_NOTHING 588*6236dae4SAndroid Build Coastguard Worker if proto == 'h2' or proto == 'h3': 589*6236dae4SAndroid Build Coastguard Worker exp_code = 0 # we get a 500 from the server 590*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(exp_code) # GOT_NOTHING 591*6236dae4SAndroid Build Coastguard Worker 592*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 593*6236dae4SAndroid Build Coastguard Worker def test_07_43_upload_denied(self, env: Env, httpd, nghttpx, repeat, proto): 594*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 595*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 596*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and env.curl_uses_lib('msh3'): 597*6236dae4SAndroid Build Coastguard Worker pytest.skip("msh3 fails here") 598*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-10m') 599*6236dae4SAndroid Build Coastguard Worker count = 1 600*6236dae4SAndroid Build Coastguard Worker max_upload = 128 * 1024 601*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 602*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?'\ 603*6236dae4SAndroid Build Coastguard Worker f'id=[0-{count-1}]&max_upload={max_upload}' 604*6236dae4SAndroid Build Coastguard Worker r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, 605*6236dae4SAndroid Build Coastguard Worker extra_args=['--trace-config', 'all']) 606*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=count, http_status=413, exitcode=0) 607*6236dae4SAndroid Build Coastguard Worker 608*6236dae4SAndroid Build Coastguard Worker # speed limited on put handler 609*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 610*6236dae4SAndroid Build Coastguard Worker def test_07_50_put_speed_limit(self, env: Env, httpd, nghttpx, proto, repeat): 611*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 612*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 613*6236dae4SAndroid Build Coastguard Worker count = 1 614*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-100k') 615*6236dae4SAndroid Build Coastguard Worker up_len = 100 * 1024 616*6236dae4SAndroid Build Coastguard Worker speed_limit = 50 * 1024 617*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 618*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-0]' 619*6236dae4SAndroid Build Coastguard Worker r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, 620*6236dae4SAndroid Build Coastguard Worker with_headers=True, extra_args=[ 621*6236dae4SAndroid Build Coastguard Worker '--limit-rate', f'{speed_limit}' 622*6236dae4SAndroid Build Coastguard Worker ]) 623*6236dae4SAndroid Build Coastguard Worker r.check_response(count=count, http_status=200) 624*6236dae4SAndroid Build Coastguard Worker assert r.responses[0]['header']['received-length'] == f'{up_len}', f'{r.responses[0]}' 625*6236dae4SAndroid Build Coastguard Worker up_speed = r.stats[0]['speed_upload'] 626*6236dae4SAndroid Build Coastguard Worker assert (speed_limit * 0.5) <= up_speed <= (speed_limit * 1.5), f'{r.stats[0]}' 627*6236dae4SAndroid Build Coastguard Worker 628*6236dae4SAndroid Build Coastguard Worker # speed limited on echo handler 629*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) 630*6236dae4SAndroid Build Coastguard Worker def test_07_51_echo_speed_limit(self, env: Env, httpd, nghttpx, proto, repeat): 631*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 632*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 633*6236dae4SAndroid Build Coastguard Worker count = 1 634*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-100k') 635*6236dae4SAndroid Build Coastguard Worker speed_limit = 50 * 1024 636*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 637*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' 638*6236dae4SAndroid Build Coastguard Worker r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, 639*6236dae4SAndroid Build Coastguard Worker with_headers=True, extra_args=[ 640*6236dae4SAndroid Build Coastguard Worker '--limit-rate', f'{speed_limit}' 641*6236dae4SAndroid Build Coastguard Worker ]) 642*6236dae4SAndroid Build Coastguard Worker r.check_response(count=count, http_status=200) 643*6236dae4SAndroid Build Coastguard Worker up_speed = r.stats[0]['speed_upload'] 644*6236dae4SAndroid Build Coastguard Worker assert (speed_limit * 0.5) <= up_speed <= (speed_limit * 1.5), f'{r.stats[0]}' 645*6236dae4SAndroid Build Coastguard Worker 646*6236dae4SAndroid Build Coastguard Worker # upload larger data, triggering "Expect: 100-continue" code paths 647*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1']) 648*6236dae4SAndroid Build Coastguard Worker def test_07_60_upload_exp100(self, env: Env, httpd, nghttpx, repeat, proto): 649*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-1m+') 650*6236dae4SAndroid Build Coastguard Worker read_delay = 1 651*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 652*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-0]'\ 653*6236dae4SAndroid Build Coastguard Worker f'&read_delay={read_delay}s' 654*6236dae4SAndroid Build Coastguard Worker r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, extra_args=[ 655*6236dae4SAndroid Build Coastguard Worker '--expect100-timeout', f'{read_delay+1}' 656*6236dae4SAndroid Build Coastguard Worker ]) 657*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=1, http_status=200, exitcode=0) 658*6236dae4SAndroid Build Coastguard Worker 659*6236dae4SAndroid Build Coastguard Worker # upload larger data, triggering "Expect: 100-continue" code paths 660*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto", ['http/1.1']) 661*6236dae4SAndroid Build Coastguard Worker def test_07_61_upload_exp100_timeout(self, env: Env, httpd, nghttpx, repeat, proto): 662*6236dae4SAndroid Build Coastguard Worker fdata = os.path.join(env.gen_dir, 'data-1m+') 663*6236dae4SAndroid Build Coastguard Worker read_delay = 2 664*6236dae4SAndroid Build Coastguard Worker curl = CurlClient(env=env) 665*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-0]'\ 666*6236dae4SAndroid Build Coastguard Worker f'&read_delay={read_delay}s' 667*6236dae4SAndroid Build Coastguard Worker r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, extra_args=[ 668*6236dae4SAndroid Build Coastguard Worker '--expect100-timeout', f'{read_delay-1}' 669*6236dae4SAndroid Build Coastguard Worker ]) 670*6236dae4SAndroid Build Coastguard Worker r.check_stats(count=1, http_status=200, exitcode=0) 671*6236dae4SAndroid Build Coastguard Worker 672*6236dae4SAndroid Build Coastguard Worker # nghttpx is the only server we have that supports TLS early data and 673*6236dae4SAndroid Build Coastguard Worker # has a limit of 16k it announces 674*6236dae4SAndroid Build Coastguard Worker @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx") 675*6236dae4SAndroid Build Coastguard Worker @pytest.mark.parametrize("proto,upload_size,exp_early", [ 676*6236dae4SAndroid Build Coastguard Worker ['http/1.1', 100, 203], # headers+body 677*6236dae4SAndroid Build Coastguard Worker ['http/1.1', 10*1024, 10345], # headers+body 678*6236dae4SAndroid Build Coastguard Worker ['http/1.1', 32*1024, 16384], # headers+body, limited by server max 679*6236dae4SAndroid Build Coastguard Worker ['h2', 10*1024, 10378], # headers+body 680*6236dae4SAndroid Build Coastguard Worker ['h2', 32*1024, 16384], # headers+body, limited by server max 681*6236dae4SAndroid Build Coastguard Worker ['h3', 1024, 0], # earlydata not supported 682*6236dae4SAndroid Build Coastguard Worker ]) 683*6236dae4SAndroid Build Coastguard Worker def test_07_70_put_earlydata(self, env: Env, httpd, nghttpx, proto, upload_size, exp_early): 684*6236dae4SAndroid Build Coastguard Worker if not env.curl_uses_lib('gnutls'): 685*6236dae4SAndroid Build Coastguard Worker pytest.skip('TLS earlydata only implemented in GnuTLS') 686*6236dae4SAndroid Build Coastguard Worker if proto == 'h3' and not env.have_h3(): 687*6236dae4SAndroid Build Coastguard Worker pytest.skip("h3 not supported") 688*6236dae4SAndroid Build Coastguard Worker count = 2 689*6236dae4SAndroid Build Coastguard Worker # we want this test to always connect to nghttpx, since it is 690*6236dae4SAndroid Build Coastguard Worker # the only server we have that supports TLS earlydata 691*6236dae4SAndroid Build Coastguard Worker port = env.port_for(proto) 692*6236dae4SAndroid Build Coastguard Worker if proto != 'h3': 693*6236dae4SAndroid Build Coastguard Worker port = env.nghttpx_https_port 694*6236dae4SAndroid Build Coastguard Worker url = f'https://{env.domain1}:{port}/curltest/put?id=[0-{count-1}]' 695*6236dae4SAndroid Build Coastguard Worker client = LocalClient(name='hx-upload', env=env) 696*6236dae4SAndroid Build Coastguard Worker if not client.exists(): 697*6236dae4SAndroid Build Coastguard Worker pytest.skip(f'example client not built: {client.name}') 698*6236dae4SAndroid Build Coastguard Worker r = client.run(args=[ 699*6236dae4SAndroid Build Coastguard Worker '-n', f'{count}', 700*6236dae4SAndroid Build Coastguard Worker '-e', # use TLS earlydata 701*6236dae4SAndroid Build Coastguard Worker '-f', # forbid reuse of connections 702*6236dae4SAndroid Build Coastguard Worker '-l', # announce upload length, no 'Expect: 100' 703*6236dae4SAndroid Build Coastguard Worker '-S', f'{upload_size}', 704*6236dae4SAndroid Build Coastguard Worker '-r', f'{env.domain1}:{port}:127.0.0.1', 705*6236dae4SAndroid Build Coastguard Worker '-V', proto, url 706*6236dae4SAndroid Build Coastguard Worker ]) 707*6236dae4SAndroid Build Coastguard Worker r.check_exit_code(0) 708*6236dae4SAndroid Build Coastguard Worker self.check_downloads(client, [f"{upload_size}"], count) 709*6236dae4SAndroid Build Coastguard Worker earlydata = {} 710*6236dae4SAndroid Build Coastguard Worker for line in r.trace_lines: 711*6236dae4SAndroid Build Coastguard Worker m = re.match(r'^\[t-(\d+)] EarlyData: (\d+)', line) 712*6236dae4SAndroid Build Coastguard Worker if m: 713*6236dae4SAndroid Build Coastguard Worker earlydata[int(m.group(1))] = int(m.group(2)) 714*6236dae4SAndroid Build Coastguard Worker assert earlydata[0] == 0, f'{earlydata}' 715*6236dae4SAndroid Build Coastguard Worker assert earlydata[1] == exp_early, f'{earlydata}' 716*6236dae4SAndroid Build Coastguard Worker 717*6236dae4SAndroid Build Coastguard Worker def check_downloads(self, client, source: List[str], count: int, 718*6236dae4SAndroid Build Coastguard Worker complete: bool = True): 719*6236dae4SAndroid Build Coastguard Worker for i in range(count): 720*6236dae4SAndroid Build Coastguard Worker dfile = client.download_file(i) 721*6236dae4SAndroid Build Coastguard Worker assert os.path.exists(dfile) 722*6236dae4SAndroid Build Coastguard Worker if complete: 723*6236dae4SAndroid Build Coastguard Worker diff = "".join(difflib.unified_diff(a=source, 724*6236dae4SAndroid Build Coastguard Worker b=open(dfile).readlines(), 725*6236dae4SAndroid Build Coastguard Worker fromfile='-', 726*6236dae4SAndroid Build Coastguard Worker tofile=dfile, 727*6236dae4SAndroid Build Coastguard Worker n=1)) 728*6236dae4SAndroid Build Coastguard Worker assert not diff, f'download {dfile} differs:\n{diff}' 729