diff options
author | Stefan Eissing <icing@apache.org> | 2023-05-02 10:05:52 +0000 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2023-05-02 10:05:52 +0000 |
commit | cb6fbeb6db4d83b855d98a9d98b26269365d3849 (patch) | |
tree | 20e3f57169681ab26aae7d33804e15e14d3b3a2e | |
parent | 0495a95f511c0bc7f34dc1b706d6d8276865743b (diff) | |
download | httpd-cb6fbeb6db4d83b855d98a9d98b26269365d3849.tar.gz |
*) tests: backport changes to make pytest tests work
again, fixing mainly cgi vs. multipart issues.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1909564 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | test/modules/http2/htdocs/cgi/echohd.py | 17 | ||||
-rw-r--r-- | test/modules/http2/htdocs/cgi/env.py | 17 | ||||
-rw-r--r-- | test/modules/http2/htdocs/cgi/hecho.py | 17 | ||||
-rw-r--r-- | test/modules/http2/htdocs/cgi/mnot164.py | 17 | ||||
-rw-r--r-- | test/modules/http2/htdocs/cgi/necho.py | 24 | ||||
-rw-r--r-- | test/modules/http2/htdocs/cgi/requestparser.py | 57 | ||||
-rw-r--r-- | test/modules/http2/htdocs/cgi/upload.py | 29 | ||||
-rw-r--r-- | test/modules/http2/test_003_get.py | 11 | ||||
-rw-r--r-- | test/modules/proxy/test_01_http.py | 2 | ||||
-rw-r--r-- | test/modules/proxy/test_02_unix.py | 2 | ||||
-rw-r--r-- | test/modules/tls/env.py | 4 | ||||
-rwxr-xr-x | test/modules/tls/htdocs/a.mod-tls.test/vars.py | 20 | ||||
-rwxr-xr-x | test/modules/tls/htdocs/b.mod-tls.test/vars.py | 20 | ||||
-rw-r--r-- | test/modules/tls/test_04_get.py | 2 | ||||
-rw-r--r-- | test/modules/tls/test_05_proto.py | 12 | ||||
-rw-r--r-- | test/pyhttpd/env.py | 29 | ||||
-rw-r--r-- | test/pyhttpd/nghttp.py | 44 | ||||
-rw-r--r-- | test/pyhttpd/result.py | 9 |
18 files changed, 173 insertions, 160 deletions
diff --git a/test/modules/http2/htdocs/cgi/echohd.py b/test/modules/http2/htdocs/cgi/echohd.py index 2a138cd844..a85a4e3d7a 100644 --- a/test/modules/http2/htdocs/cgi/echohd.py +++ b/test/modules/http2/htdocs/cgi/echohd.py @@ -1,21 +1,6 @@ #!/usr/bin/env python3 import os, sys -import multipart -from urllib import parse - - -def get_request_params(): - oforms = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - myenv = os.environ.copy() - myenv['wsgi.input'] = sys.stdin.buffer - mforms, ofiles = multipart.parse_form_data(environ=myenv) - for name, item in mforms.items(): - oforms[name] = item - return oforms, ofiles +from requestparser import get_request_params forms, files = get_request_params() diff --git a/test/modules/http2/htdocs/cgi/env.py b/test/modules/http2/htdocs/cgi/env.py index 3af576496a..455c623a2f 100644 --- a/test/modules/http2/htdocs/cgi/env.py +++ b/test/modules/http2/htdocs/cgi/env.py @@ -1,21 +1,6 @@ #!/usr/bin/env python3 import os, sys -import multipart -from urllib import parse - - -def get_request_params(): - oforms = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - myenv = os.environ.copy() - myenv['wsgi.input'] = sys.stdin.buffer - mforms, ofiles = multipart.parse_form_data(environ=myenv) - for name, item in mforms.items(): - oforms[name] = item - return oforms, ofiles +from requestparser import get_request_params forms, files = get_request_params() diff --git a/test/modules/http2/htdocs/cgi/hecho.py b/test/modules/http2/htdocs/cgi/hecho.py index fb9e330b60..abffd33be6 100644 --- a/test/modules/http2/htdocs/cgi/hecho.py +++ b/test/modules/http2/htdocs/cgi/hecho.py @@ -1,21 +1,6 @@ #!/usr/bin/env python3 import os, sys -import multipart -from urllib import parse - - -def get_request_params(): - oforms = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - myenv = os.environ.copy() - myenv['wsgi.input'] = sys.stdin.buffer - mforms, ofiles = multipart.parse_form_data(environ=myenv) - for name, item in mforms.items(): - oforms[name] = item - return oforms, ofiles +from requestparser import get_request_params forms, files = get_request_params() diff --git a/test/modules/http2/htdocs/cgi/mnot164.py b/test/modules/http2/htdocs/cgi/mnot164.py index c29ccc185b..43a86ea109 100644 --- a/test/modules/http2/htdocs/cgi/mnot164.py +++ b/test/modules/http2/htdocs/cgi/mnot164.py @@ -1,21 +1,6 @@ #!/usr/bin/env python3 import os, sys -import multipart -from urllib import parse - - -def get_request_params(): - oforms = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - myenv = os.environ.copy() - myenv['wsgi.input'] = sys.stdin.buffer - mforms, ofiles = multipart.parse_form_data(environ=myenv) - for name, item in mforms.items(): - oforms[name] = item - return oforms, ofiles +from requestparser import get_request_params forms, files = get_request_params() diff --git a/test/modules/http2/htdocs/cgi/necho.py b/test/modules/http2/htdocs/cgi/necho.py index 78e2aad302..715904b4a3 100644 --- a/test/modules/http2/htdocs/cgi/necho.py +++ b/test/modules/http2/htdocs/cgi/necho.py @@ -1,22 +1,7 @@ #!/usr/bin/env python3 import time import os, sys -import multipart -from urllib import parse - - -def get_request_params(): - oforms = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - myenv = os.environ.copy() - myenv['wsgi.input'] = sys.stdin.buffer - mforms, ofiles = multipart.parse_form_data(environ=myenv) - for name, item in mforms.items(): - oforms[name] = item - return oforms, ofiles +from requestparser import get_request_params forms, files = get_request_params() @@ -55,11 +40,12 @@ Content-Type: text/html\n <p>No count was specified: %s</p> </body></html>""" % (count)) -except KeyError: +except KeyError as ex: print("Status: 200 Ok") - print("""\ + print(f"""\ Content-Type: text/html\n - <html><body> + <html><body>uri: uri={os.environ['REQUEST_URI']} ct={os.environ['CONTENT_TYPE']} ex={ex} + forms={forms} Echo <form method="POST" enctype="application/x-www-form-urlencoded"> <input type="text" name="count"> <input type="text" name="text"> diff --git a/test/modules/http2/htdocs/cgi/requestparser.py b/test/modules/http2/htdocs/cgi/requestparser.py new file mode 100644 index 0000000000..c7e0648224 --- /dev/null +++ b/test/modules/http2/htdocs/cgi/requestparser.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +import os +import sys +from urllib import parse +import multipart # https://github.com/andrew-d/python-multipart (`apt install python3-multipart`) +import shutil + + +try: # Windows needs stdio set for binary mode. + import msvcrt + + msvcrt.setmode(0, os.O_BINARY) # stdin = 0 + msvcrt.setmode(1, os.O_BINARY) # stdout = 1 +except ImportError: + pass + + +class FileItem: + + def __init__(self, mparse_item): + self.item = mparse_item + + @property + def file_name(self): + return os.path.basename(self.item.file_name.decode()) + + def save_to(self, destpath: str): + fsrc = self.item.file_object + fsrc.seek(0) + with open(destpath, 'wb') as fd: + shutil.copyfileobj(fsrc, fd) + + +def get_request_params(): + oforms = {} + ofiles = {} + if "REQUEST_URI" in os.environ: + qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) + for name, values in qforms.items(): + oforms[name] = values[0] + if "CONTENT_TYPE" in os.environ: + ctype = os.environ["CONTENT_TYPE"] + if ctype == "application/x-www-form-urlencoded": + s = sys.stdin.read() + qforms = parse.parse_qs(s) + for name, values in qforms.items(): + oforms[name] = values[0] + elif ctype.startswith("multipart/"): + def on_field(field): + oforms[field.field_name.decode()] = field.value.decode() + def on_file(file): + ofiles[file.field_name.decode()] = FileItem(file) + multipart.parse_form(headers={"Content-Type": ctype}, + input_stream=sys.stdin.buffer, + on_field=on_field, on_file=on_file) + return oforms, ofiles + diff --git a/test/modules/http2/htdocs/cgi/upload.py b/test/modules/http2/htdocs/cgi/upload.py index 59fbb5866d..fa1e5d6466 100644 --- a/test/modules/http2/htdocs/cgi/upload.py +++ b/test/modules/http2/htdocs/cgi/upload.py @@ -1,30 +1,7 @@ #!/usr/bin/env python3 import os import sys -import multipart -from urllib import parse - - -try: # Windows needs stdio set for binary mode. - import msvcrt - - msvcrt.setmode(0, os.O_BINARY) # stdin = 0 - msvcrt.setmode(1, os.O_BINARY) # stdout = 1 -except ImportError: - pass - -def get_request_params(): - oforms = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - myenv = os.environ.copy() - myenv['wsgi.input'] = sys.stdin.buffer - mforms, ofiles = multipart.parse_form_data(environ=myenv) - for name, item in mforms.items(): - oforms[name] = item - return oforms, ofiles +from requestparser import get_request_params forms, files = get_request_params() @@ -35,9 +12,9 @@ status = '200 Ok' if 'file' in files: fitem = files['file'] # strip leading path from file name to avoid directory traversal attacks - fname = fitem.filename + fname = os.path.basename(fitem.file_name) fpath = f'{os.environ["DOCUMENT_ROOT"]}/files/{fname}' - fitem.save_as(fpath) + fitem.save_to(fpath) message = "The file %s was uploaded successfully" % (fname) print("Status: 201 Created") print("Content-Type: text/html") diff --git a/test/modules/http2/test_003_get.py b/test/modules/http2/test_003_get.py index 410097a52a..43751063e0 100644 --- a/test/modules/http2/test_003_get.py +++ b/test/modules/http2/test_003_get.py @@ -197,7 +197,11 @@ content-type: text/html def test_h2_003_50(self, env, path): # check that the resource supports ranges and we see its raw content-length url = env.mkurl("https", "test1", path) - r = env.curl_get(url, 5) + # TODO: sometimes we see a 503 here from h2proxy + for i in range(10): + r = env.curl_get(url, 5) + if r.response["status"] != 503: + break assert r.response["status"] == 200 assert "HTTP/2" == r.response["protocol"] h = r.response["header"] @@ -206,7 +210,10 @@ content-type: text/html assert "content-length" in h clen = h["content-length"] # get the first 1024 bytes of the resource, 206 status, but content-length as original - r = env.curl_get(url, 5, options=["-H", "range: bytes=0-1023"]) + for i in range(10): + r = env.curl_get(url, 5, options=["-H", "range: bytes=0-1023"]) + if r.response["status"] != 503: + break assert 206 == r.response["status"] assert "HTTP/2" == r.response["protocol"] assert 1024 == len(r.response["body"]) diff --git a/test/modules/proxy/test_01_http.py b/test/modules/proxy/test_01_http.py index 7763565242..ef71b16e47 100644 --- a/test/modules/proxy/test_01_http.py +++ b/test/modules/proxy/test_01_http.py @@ -59,6 +59,8 @@ class TestProxyHttp: # check that we see the document we expect there (host matching worked) # we need to explicitly provide a Host: header since mod_proxy cannot # resolve the name via DNS. + if not env.curl_is_at_least('8.0.0'): + pytest.skip(f'need at least curl v8.0.0 for this') domain = f"{via}.{env.http_tld}" r = env.curl_get(f"http://127.0.0.1:{env.http_port}/alive.json", 5, options=[ '-H', f"Host: {domain}", diff --git a/test/modules/proxy/test_02_unix.py b/test/modules/proxy/test_02_unix.py index a66cdf7462..7f3d4d55b2 100644 --- a/test/modules/proxy/test_02_unix.py +++ b/test/modules/proxy/test_02_unix.py @@ -110,6 +110,8 @@ class TestProxyUds: # check that we see the document we expect there (host matching worked) # we need to explicitly provide a Host: header since mod_proxy cannot # resolve the name via DNS. + if not env.curl_is_at_least('8.0.0'): + pytest.skip(f'need at least curl v8.0.0 for this') domain = f"{via}.{env.http_tld}" r = env.curl_get(f"http://127.0.0.1:{env.http_port}/alive.json", 5, options=[ '-H', f"Host: {domain}", diff --git a/test/modules/tls/env.py b/test/modules/tls/env.py index a39fcaaa64..0e457bf137 100644 --- a/test/modules/tls/env.py +++ b/test/modules/tls/env.py @@ -145,11 +145,11 @@ class TlsTestEnv(HttpdTestEnv): def domain_b(self) -> str: return self._domain_b - def tls_get(self, domain, paths: Union[str, List[str]], options: List[str] = None) -> ExecResult: + def tls_get(self, domain, paths: Union[str, List[str]], options: List[str] = None, no_stdout_list = False) -> ExecResult: if isinstance(paths, str): paths = [paths] urls = [f"https://{domain}:{self.https_port}{path}" for path in paths] - return self.curl_raw(urls=urls, options=options) + return self.curl_raw(urls=urls, options=options, no_stdout_list=no_stdout_list) def tls_get_json(self, domain: str, path: str, options=None): r = self.tls_get(domain=domain, paths=path, options=options) diff --git a/test/modules/tls/htdocs/a.mod-tls.test/vars.py b/test/modules/tls/htdocs/a.mod-tls.test/vars.py index f41ec6a5e8..bd520e27bb 100755 --- a/test/modules/tls/htdocs/a.mod-tls.test/vars.py +++ b/test/modules/tls/htdocs/a.mod-tls.test/vars.py @@ -1,21 +1,29 @@ #!/usr/bin/env python3 import json import os, sys -import multipart from urllib import parse +import multipart # https://github.com/andrew-d/python-multipart (`apt install python3-multipart`) def get_request_params(): oforms = {} + ofiles = {} if "REQUEST_URI" in os.environ: qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) for name, values in qforms.items(): oforms[name] = values[0] - myenv = os.environ.copy() - myenv['wsgi.input'] = sys.stdin.buffer - mforms, ofiles = multipart.parse_form_data(environ=myenv) - for name, item in mforms.items(): - oforms[name] = item + if "HTTP_CONTENT_TYPE" in os.environ: + ctype = os.environ["HTTP_CONTENT_TYPE"] + if ctype == "application/x-www-form-urlencoded": + qforms = parse.parse_qs(parse.urlsplit(sys.stdin.read()).query) + for name, values in qforms.items(): + oforms[name] = values[0] + elif ctype.startswith("multipart/"): + def on_field(field): + oforms[field.field_name] = field.value + def on_file(file): + ofiles[field.field_name] = field.value + multipart.parse_form(headers={"Content-Type": ctype}, input_stream=sys.stdin.buffer, on_field=on_field, on_file=on_file) return oforms, ofiles diff --git a/test/modules/tls/htdocs/b.mod-tls.test/vars.py b/test/modules/tls/htdocs/b.mod-tls.test/vars.py index f41ec6a5e8..bd520e27bb 100755 --- a/test/modules/tls/htdocs/b.mod-tls.test/vars.py +++ b/test/modules/tls/htdocs/b.mod-tls.test/vars.py @@ -1,21 +1,29 @@ #!/usr/bin/env python3 import json import os, sys -import multipart from urllib import parse +import multipart # https://github.com/andrew-d/python-multipart (`apt install python3-multipart`) def get_request_params(): oforms = {} + ofiles = {} if "REQUEST_URI" in os.environ: qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) for name, values in qforms.items(): oforms[name] = values[0] - myenv = os.environ.copy() - myenv['wsgi.input'] = sys.stdin.buffer - mforms, ofiles = multipart.parse_form_data(environ=myenv) - for name, item in mforms.items(): - oforms[name] = item + if "HTTP_CONTENT_TYPE" in os.environ: + ctype = os.environ["HTTP_CONTENT_TYPE"] + if ctype == "application/x-www-form-urlencoded": + qforms = parse.parse_qs(parse.urlsplit(sys.stdin.read()).query) + for name, values in qforms.items(): + oforms[name] = values[0] + elif ctype.startswith("multipart/"): + def on_field(field): + oforms[field.field_name] = field.value + def on_file(file): + ofiles[field.field_name] = field.value + multipart.parse_form(headers={"Content-Type": ctype}, input_stream=sys.stdin.buffer, on_field=on_field, on_file=on_file) return oforms, ofiles diff --git a/test/modules/tls/test_04_get.py b/test/modules/tls/test_04_get.py index 4412a66d9a..6944381307 100644 --- a/test/modules/tls/test_04_get.py +++ b/test/modules/tls/test_04_get.py @@ -59,7 +59,7 @@ class TestGet: # we'd like to check that we can do >1 requests on the same connection # however curl hides that from us, unless we analyze its verbose output docs_a = os.path.join(env.server_docs_dir, env.domain_a) - r = env.tls_get(env.domain_a, paths=[ + r = env.tls_get(env.domain_a, no_stdout_list=True, paths=[ "/{0}".format(fname), "/{0}".format(fname) ]) diff --git a/test/modules/tls/test_05_proto.py b/test/modules/tls/test_05_proto.py index 447d052b42..d874a905ef 100644 --- a/test/modules/tls/test_05_proto.py +++ b/test/modules/tls/test_05_proto.py @@ -33,16 +33,14 @@ class TestProto: def test_tls_05_proto_1_2(self, env): r = env.tls_get(env.domain_b, "/index.json", options=["--tlsv1.2"]) assert r.exit_code == 0, r.stderr - if TlsTestEnv.curl_supports_tls_1_3(): - r = env.tls_get(env.domain_b, "/index.json", options=["--tlsv1.3"]) - assert r.exit_code == 0, r.stderr + @pytest.mark.skip('curl does not have TLSv1.3 on all platforms') def test_tls_05_proto_1_3(self, env): - r = env.tls_get(env.domain_a, "/index.json", options=["--tlsv1.3"]) - if TlsTestEnv.curl_supports_tls_1_3(): - assert r.exit_code == 0, r.stderr + r = env.tls_get(env.domain_a, "/index.json", options=["--tlsv1.3", '-v']) + if True: # testing TlsTestEnv.curl_supports_tls_1_3() is unreliable (curl should support TLS1.3 nowadays..) + assert r.exit_code == 0, f'{r}' else: - assert r.exit_code == 4, r.stderr + assert r.exit_code == 4, f'{r}' def test_tls_05_proto_close(self, env): s = socket.create_connection(('localhost', env.https_port)) diff --git a/test/pyhttpd/env.py b/test/pyhttpd/env.py index 2c91859328..818f18a5c4 100644 --- a/test/pyhttpd/env.py +++ b/test/pyhttpd/env.py @@ -96,9 +96,8 @@ class HttpdTestSetup: self.env.clear_curl_headerfiles() def _make_dirs(self): - if os.path.exists(self.env.gen_dir): - shutil.rmtree(self.env.gen_dir) - os.makedirs(self.env.gen_dir) + if not os.path.exists(self.env.gen_dir): + os.makedirs(self.env.gen_dir) if not os.path.exists(self.env.server_logs_dir): os.makedirs(self.env.server_logs_dir) @@ -288,6 +287,7 @@ class HttpdTestEnv: self._verify_certs = False self._curl_headerfiles_n = 0 + self._curl_version = None self._h2load_version = None self._current_test = None @@ -473,6 +473,20 @@ class HttpdTestEnv: return self._h2load_version >= self._versiontuple(minv) return False + def curl_is_at_least(self, minv): + if self._curl_version is None: + p = subprocess.run([self._curl, '-V'], capture_output=True, text=True) + if p.returncode != 0: + return False + for l in p.stdout.splitlines(): + m = re.match(r'curl ([0-9.]+)[- ].*', l) + if m: + self._curl_version = self._versiontuple(m.group(1)) + break + if self._curl_version is not None: + return self._curl_version >= self._versiontuple(minv) + return False + def has_nghttp(self): return self._nghttp != "" @@ -530,7 +544,7 @@ class HttpdTestEnv: fd.write('\n'.join(self._httpd_base_conf)) fd.write('\n') if self._verbosity >= 2: - fd.write(f"LogLevel core:trace5 {self.mpm_module}:trace5\n") + fd.write(f"LogLevel core:trace5 {self.mpm_module}:trace5 http:trace5\n") if self._log_interesting: fd.write(self._log_interesting) fd.write('\n\n') @@ -745,11 +759,11 @@ class HttpdTestEnv: return r def curl_raw(self, urls, timeout=10, options=None, insecure=False, - force_resolve=True): + force_resolve=True, no_stdout_list=False): if not isinstance(urls, list): urls = [urls] stdout_list = False - if len(urls) > 1: + if len(urls) > 1 and not no_stdout_list: stdout_list = True args, headerfile = self.curl_complete_args( urls=urls, stdout_list=stdout_list, @@ -760,7 +774,8 @@ class HttpdTestEnv: self.curl_parse_headerfile(headerfile, r=r) if r.json: r.response["json"] = r.json - os.remove(headerfile) + if os.path.isfile(headerfile): + os.remove(headerfile) return r def curl_get(self, url, insecure=False, options=None): diff --git a/test/pyhttpd/nghttp.py b/test/pyhttpd/nghttp.py index f27e40d319..43721f599a 100644 --- a/test/pyhttpd/nghttp.py +++ b/test/pyhttpd/nghttp.py @@ -37,6 +37,7 @@ class Nghttp: "id": sid, "body": b'' }, + "data_lengths": [], "paddings": [], "promises": [] } @@ -131,12 +132,13 @@ class Nghttp: s = self.get_stream(streams, m.group(3)) blen = int(m.group(2)) if s: - print("stream %d: %d DATA bytes added" % (s["id"], blen)) + print(f'stream {s["id"]}: {blen} DATA bytes added via "{l}"') padlen = 0 if len(lines) > lidx + 2: mpad = re.match(r' +\(padlen=(\d+)\)', lines[lidx+2]) if mpad: padlen = int(mpad.group(1)) + s["data_lengths"].append(blen) s["paddings"].append(padlen) blen -= padlen s["response"]["body"] += body[-blen:].encode() @@ -196,6 +198,7 @@ class Nghttp: if main_stream in streams: output["response"] = streams[main_stream]["response"] output["paddings"] = streams[main_stream]["paddings"] + output["data_lengths"] = streams[main_stream]["data_lengths"] return output def _raw(self, url, timeout, options): @@ -244,11 +247,11 @@ class Nghttp: def post_name(self, url, name, timeout=5, options=None): reqbody = ("%s/nghttp.req.body" % self.TMP_DIR) with open(reqbody, 'w') as f: - f.write("--DSAJKcd9876\n") - f.write("Content-Disposition: form-data; name=\"value\"; filename=\"xxxxx\"\n") - f.write("Content-Type: text/plain\n") - f.write("\n%s\n" % name) - f.write("--DSAJKcd9876\n") + f.write("--DSAJKcd9876\r\n") + f.write("Content-Disposition: form-data; name=\"value\"; filename=\"xxxxx\"\r\n") + f.write("Content-Type: text/plain\r\n") + f.write(f"\r\n{name}") + f.write("\r\n--DSAJKcd9876\r\n") if not options: options = [] options.extend([ @@ -267,20 +270,23 @@ class Nghttp: reqbody = ("%s/nghttp.req.body" % self.TMP_DIR) with open(fpath, 'rb') as fin: with open(reqbody, 'wb') as f: - f.write(("""--DSAJKcd9876 -Content-Disposition: form-data; name="xxx"; filename="xxxxx" -Content-Type: text/plain - -testing mod_h2 ---DSAJKcd9876 -Content-Disposition: form-data; name="file"; filename="%s" -Content-Type: application/octet-stream -Content-Transfer-Encoding: binary - -""" % fname).encode('utf-8')) + preamble = [ + '--DSAJKcd9876', + 'Content-Disposition: form-data; name="xxx"; filename="xxxxx"', + 'Content-Type: text/plain', + '', + 'testing mod_h2', + '\r\n--DSAJKcd9876', + f'Content-Disposition: form-data; name="file"; filename="{fname}"', + 'Content-Type: application/octet-stream', + 'Content-Transfer-Encoding: binary', + '', '' + ] + f.write('\r\n'.join(preamble).encode('utf-8')) f.write(fin.read()) - f.write(""" ---DSAJKcd9876""".encode('utf-8')) + f.write('\r\n'.join([ + '\r\n--DSAJKcd9876', '' + ]).encode('utf-8')) if not options: options = [] options.extend([ diff --git a/test/pyhttpd/result.py b/test/pyhttpd/result.py index 3789461be4..4bf9ff200d 100644 --- a/test/pyhttpd/result.py +++ b/test/pyhttpd/result.py @@ -28,7 +28,14 @@ class ExecResult: self._json_out = None def __repr__(self): - return f"ExecResult[code={self.exit_code}, args={self._args}, stdout={self._stdout}, stderr={self._stderr}]" + out = [ + f"ExecResult[code={self.exit_code}, args={self._args}\n", + "----stdout---------------------------------------\n", + self._stdout.decode(), + "----stderr---------------------------------------\n", + self._stderr.decode() + ] + return ''.join(out) @property def exit_code(self) -> int: |